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()); |