Comparison

net/http.lua @ 3569:f30da46e0add

net.http: Removed old HTTP parser, and updated to use util.httpstream.
author Waqas Hussain <waqas20@gmail.com>
date Sat, 06 Nov 2010 03:46:00 +0500
parent 3540:bc139431830b
child 4338:5d5d6c6d121a
comparison
equal deleted inserted replaced
3568:51d5578965a5 3569:f30da46e0add
8 8
9 9
10 local socket = require "socket" 10 local socket = require "socket"
11 local mime = require "mime" 11 local mime = require "mime"
12 local url = require "socket.url" 12 local url = require "socket.url"
13 local httpstream_new = require "util.httpstream".new;
13 14
14 local server = require "net.server" 15 local server = require "net.server"
15 16
16 local connlisteners_get = require "net.connlisteners".get; 17 local connlisteners_get = require "net.connlisteners".get;
17 local listener = connlisteners_get("httpclient") or error("No httpclient listener!"); 18 local listener = connlisteners_get("httpclient") or error("No httpclient listener!");
43 t_insert(result, _formencodepart(field.name).."=".._formencodepart(field.value)); 44 t_insert(result, _formencodepart(field.name).."=".._formencodepart(field.value));
44 end 45 end
45 return t_concat(result, "&"); 46 return t_concat(result, "&");
46 end 47 end
47 48
48 local function expectbody(reqt, code)
49 if reqt.method == "HEAD" then return nil end
50 if code == 204 or code == 304 or code == 301 then return nil end
51 if code >= 100 and code < 200 then return nil end
52 return 1
53 end
54
55 local function request_reader(request, data, startpos) 49 local function request_reader(request, data, startpos)
56 if not data then 50 if not request.parser then
57 if request.body then 51 local function success_cb(r)
58 log("debug", "Connection closed, but we have data, calling callback...");
59 request.callback(t_concat(request.body), request.code, request);
60 elseif request.state ~= "completed" then
61 -- Error.. connection was closed prematurely
62 request.callback("connection-closed", 0, request);
63 return;
64 end
65 destroy_request(request);
66 request.body = nil;
67 request.state = "completed";
68 return;
69 end
70 if request.state == "body" and request.state ~= "completed" then
71 log("debug", "Reading body...")
72 if not request.body then request.body = {}; request.havebodylength, request.bodylength = 0, tonumber(request.responseheaders["content-length"]); end
73 if startpos then
74 data = data:sub(startpos, -1)
75 end
76 t_insert(request.body, data);
77 if request.bodylength then
78 request.havebodylength = request.havebodylength + #data;
79 if request.havebodylength >= request.bodylength then
80 -- We have the body
81 log("debug", "Have full body, calling callback");
82 if request.callback then
83 request.callback(t_concat(request.body), request.code, request);
84 end
85 request.body = nil;
86 request.state = "completed";
87 else
88 log("debug", "Have "..request.havebodylength.." bytes out of "..request.bodylength);
89 end
90 end
91 elseif request.state == "headers" then
92 log("debug", "Reading headers...")
93 local pos = startpos;
94 local headers, headers_complete = request.responseheaders;
95 if not headers then
96 headers = {};
97 request.responseheaders = headers;
98 end
99 for line in data:sub(startpos, -1):gmatch("(.-)\r\n") do
100 startpos = startpos + #line + 2;
101 local k, v = line:match("(%S+): (.+)");
102 if k and v then
103 headers[k:lower()] = v;
104 --log("debug", "Header: "..k:lower().." = "..v);
105 elseif #line == 0 then
106 headers_complete = true;
107 break;
108 else
109 log("warn", "Unhandled header line: "..line);
110 end
111 end
112 if not headers_complete then return; end
113 -- Reached the end of the headers
114 if not expectbody(request, request.code) then
115 request.callback(nil, request.code, request);
116 return;
117 end
118 request.state = "body";
119 if #data > startpos then
120 return request_reader(request, data, startpos);
121 end
122 elseif request.state == "status" then
123 log("debug", "Reading status...")
124 local http, code, text, linelen = data:match("^HTTP/(%S+) (%d+) (.-)\r\n()", startpos);
125 code = tonumber(code);
126 if not code then
127 log("warn", "Invalid HTTP status line, telling callback then closing");
128 local ret = request.callback("invalid-status-line", 0, request);
129 destroy_request(request);
130 return ret;
131 end
132
133 request.code, request.responseversion = code, http;
134
135 if request.onlystatus then
136 if request.callback then 52 if request.callback then
137 request.callback(nil, code, request); 53 for k,v in pairs(r) do request[k] = v; end
54 request.callback(r.body, r.code, request);
55 request.callback = nil;
138 end 56 end
139 destroy_request(request); 57 destroy_request(request);
140 return;
141 end 58 end
142 59 local function error_cb(r)
143 request.state = "headers"; 60 if request.callback then
144 61 request.callback(r or "connection-closed", 0, request);
145 if #data > linelen then 62 request.callback = nil;
146 return request_reader(request, data, linelen); 63 end
64 destroy_request(request);
147 end 65 end
66 local function options_cb()
67 return request;
68 end
69 request.parser = httpstream_new(success_cb, error_cb, "client", options_cb);
148 end 70 end
71 request.parser:feed(data);
149 end 72 end
150 73
151 local function handleerr(err) log("error", "Traceback[http]: %s: %s", tostring(err), debug_traceback()); end 74 local function handleerr(err) log("error", "Traceback[http]: %s: %s", tostring(err), debug_traceback()); end
152 function request(u, ex, callback) 75 function request(u, ex, callback)
153 local req = url.parse(u); 76 local req = url.parse(u);