Software /
code /
prosody
Comparison
util/httpstream.lua @ 3564:90f4e6dc1c11
util.httpstream: Added support for HTTP response parsing.
author | Waqas Hussain <waqas20@gmail.com> |
---|---|
date | Fri, 05 Nov 2010 03:07:36 +0500 |
parent | 3563:544d9d2e3046 |
child | 3565:e2cc09e83a3e |
comparison
equal
deleted
inserted
replaced
3563:544d9d2e3046 | 3564:90f4e6dc1c11 |
---|---|
5 local deadroutine = coroutine.create(function() end); | 5 local deadroutine = coroutine.create(function() end); |
6 coroutine.resume(deadroutine); | 6 coroutine.resume(deadroutine); |
7 | 7 |
8 module("httpstream") | 8 module("httpstream") |
9 | 9 |
10 local function parser(data, success_cb) | 10 local function parser(data, success_cb, parser_type) |
11 local function readline() | 11 local function readline() |
12 local pos = data:find("\r\n", nil, true); | 12 local pos = data:find("\r\n", nil, true); |
13 while not pos do | 13 while not pos do |
14 data = data..coroutine.yield(); | 14 data = data..coroutine.yield(); |
15 pos = data:find("\r\n", nil, true); | 15 pos = data:find("\r\n", nil, true); |
37 headers[key] = headers[key] and headers[key]..","..val or val; | 37 headers[key] = headers[key] and headers[key]..","..val or val; |
38 end | 38 end |
39 return headers; | 39 return headers; |
40 end | 40 end |
41 | 41 |
42 while true do | 42 if not parser_type or parser_type == "server" then |
43 -- read status line | 43 while true do |
44 local status_line = readline(); | 44 -- read status line |
45 local method, path, httpversion = status_line:match("^(%S+)%s+(%S+)%s+HTTP/(%S+)$"); | 45 local status_line = readline(); |
46 if not method then coroutine.yield("invalid-status-line"); end | 46 local method, path, httpversion = status_line:match("^(%S+)%s+(%S+)%s+HTTP/(%S+)$"); |
47 -- TODO parse url | 47 if not method then coroutine.yield("invalid-status-line"); end |
48 local headers = readheaders(); | 48 -- TODO parse url |
49 | 49 local headers = readheaders(); |
50 -- read body | 50 |
51 local len = tonumber(headers["content-length"]); | 51 -- read body |
52 len = len or 0; -- TODO check for invalid len | 52 local len = tonumber(headers["content-length"]); |
53 local body = readlength(len); | 53 len = len or 0; -- TODO check for invalid len |
54 | 54 local body = readlength(len); |
55 success_cb({ | 55 |
56 method = method; | 56 success_cb({ |
57 path = path; | 57 method = method; |
58 httpversion = httpversion; | 58 path = path; |
59 headers = headers; | 59 httpversion = httpversion; |
60 body = body; | 60 headers = headers; |
61 }); | 61 body = body; |
62 end | 62 }); |
63 end | |
64 elseif parser_type == "client" then | |
65 while true do | |
66 -- read status line | |
67 local status_line = readline(); | |
68 local httpversion, status_code, reason_phrase = status_line:match("^HTTP/(%S+)%s+(%d%d%d)%s+(.*)$"); | |
69 if not httpversion then coroutine.yield("invalid-status-line"); end | |
70 local headers = readheaders(); | |
71 | |
72 -- read body | |
73 local body; | |
74 local len = tonumber(headers["content-length"]); | |
75 if len then -- TODO check for invalid len | |
76 body = readlength(len); | |
77 else -- read to end | |
78 repeat | |
79 local newdata = coroutine.yield(); | |
80 data = data..newdata; | |
81 until newdata == ""; | |
82 body, data = data, ""; | |
83 end | |
84 | |
85 success_cb({ | |
86 code = status_code; | |
87 responseversion = httpversion; | |
88 responseheaders = headers; | |
89 body = body; | |
90 }); | |
91 end | |
92 else coroutine.yield("unknown-parser-type"); end | |
63 end | 93 end |
64 | 94 |
65 function new(success_cb, error_cb) | 95 function new(success_cb, error_cb, parser_type) |
66 local co = coroutine.create(parser); | 96 local co = coroutine.create(parser); |
67 return { | 97 return { |
68 feed = function(self, data) | 98 feed = function(self, data) |
69 if not data then | 99 if not data then |
100 if parser_type == "client" then coroutine.resume(co, "", success_cb, parser_type); end | |
70 co = deadroutine; | 101 co = deadroutine; |
71 return error_cb(); | 102 return error_cb(); |
72 end | 103 end |
73 local success, result = coroutine.resume(co, data, success_cb); | 104 local success, result = coroutine.resume(co, data, success_cb, parser_type); |
74 if result then | 105 if result then |
75 co = deadroutine; | 106 co = deadroutine; |
76 return error_cb(result); | 107 return error_cb(result); |
77 end | 108 end |
78 end; | 109 end; |