net/httpserver.lua

changeset 3497
e9159b325e33
parent 3473
84fe4d5ac2ed
child 3540
bc139431830b
equal deleted inserted replaced
3496:9408d1e10e17 3497:e9159b325e33
8 8
9 9
10 local socket = require "socket" 10 local socket = require "socket"
11 local server = require "net.server" 11 local server = require "net.server"
12 local url_parse = require "socket.url".parse; 12 local url_parse = require "socket.url".parse;
13 local httpstream_new = require "util.httpstream".new;
13 14
14 local connlisteners_start = require "net.connlisteners".start; 15 local connlisteners_start = require "net.connlisteners".start;
15 local connlisteners_get = require "net.connlisteners".get; 16 local connlisteners_get = require "net.connlisteners".get;
16 local listener; 17 local listener;
17 18
112 end 113 end
113 end 114 end
114 end 115 end
115 116
116 local function request_reader(request, data, startpos) 117 local function request_reader(request, data, startpos)
117 if not data then 118 if not request.parser then
118 if request.body then 119 local function success_cb(r)
120 for k,v in pairs(r) do request[k] = v; end
121 request.url = url_parse(request.path);
122 request.body = { request.body };
119 call_callback(request); 123 call_callback(request);
120 else 124 end
121 -- Error.. connection was closed prematurely 125 local function error_cb(r)
122 call_callback(request, "connection-closed"); 126 call_callback(request, r or "connection-closed");
123 end 127 destroy_request(request);
124 -- Here we force a destroy... the connection is gone, so we can't reply later 128 end
125 destroy_request(request); 129 request.parser = httpstream_new(success_cb, error_cb);
126 return; 130 end
127 end 131 request.parser:feed(data);
128 if request.state == "body" then
129 log("debug", "Reading body...")
130 if not request.body then request.body = {}; request.havebodylength, request.bodylength = 0, tonumber(request.headers["content-length"]); end
131 if startpos then
132 data = data:sub(startpos, -1)
133 end
134 t_insert(request.body, data);
135 if request.bodylength then
136 request.havebodylength = request.havebodylength + #data;
137 if request.havebodylength >= request.bodylength then
138 -- We have the body
139 call_callback(request);
140 end
141 end
142 elseif request.state == "headers" then
143 log("debug", "Reading headers...")
144 local pos = startpos;
145 local headers, headers_complete = request.headers;
146 if not headers then
147 headers = {};
148 request.headers = headers;
149 end
150
151 for line in data:gmatch("(.-)\r\n") do
152 startpos = (startpos or 1) + #line + 2;
153 local k, v = line:match("(%S+): (.+)");
154 if k and v then
155 k = k:lower();
156 if headers[k] then
157 headers[k] = headers[k]..", "..v;
158 else
159 headers[k] = v;
160 end
161 --log("debug", "Header: '"..k:lower().."' = '"..v.."'");
162 elseif #line == 0 then
163 headers_complete = true;
164 break;
165 else
166 log("debug", "Unhandled header line: "..line);
167 end
168 end
169
170 if not headers_complete then return; end
171
172 if not expectbody(request) then
173 call_callback(request);
174 return;
175 end
176
177 -- Reached the end of the headers
178 request.state = "body";
179 if #data > startpos then
180 return request_reader(request, data:sub(startpos, -1));
181 end
182 elseif request.state == "request" then
183 log("debug", "Reading request line...")
184 local method, path, http, linelen = data:match("^(%S+) (%S+) HTTP/(%S+)\r\n()", startpos);
185 if not method then
186 log("warn", "Invalid HTTP status line, telling callback then closing");
187 local ret = call_callback(request, "invalid-status-line");
188 request:destroy();
189 return ret;
190 end
191
192 request.method, request.path, request.httpversion = method, path, http;
193
194 request.url = url_parse(request.path);
195
196 log("debug", method.." request for "..tostring(request.path) .. " on port "..request.handler:serverport());
197
198 if request.onlystatus then
199 if not call_callback(request) then
200 return;
201 end
202 end
203
204 request.state = "headers";
205
206 if #data > linelen then
207 return request_reader(request, data:sub(linelen, -1));
208 end
209 end
210 end 132 end
211 133
212 -- The default handler for requests 134 -- The default handler for requests
213 default_handler = function (method, body, request) 135 default_handler = function (method, body, request)
214 log("debug", method.." request for "..tostring(request.path) .. " on port "..request.handler:serverport()); 136 log("debug", method.." request for "..tostring(request.path) .. " on port "..request.handler:serverport());

mercurial