diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-03-16 06:42:53 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-03-16 06:42:53 +0000 |
commit | bcc0c2a9f0be2ca796ef5206a78e283fe15e6186 (patch) | |
tree | 65c269d4854aa5ff4a0b2c8eede5cdb18d716033 /src/http.lua | |
parent | b6edaac2841137cf0ef5105f75358bbab4570d87 (diff) | |
download | luasocket-bcc0c2a9f0be2ca796ef5206a78e283fe15e6186.tar.gz luasocket-bcc0c2a9f0be2ca796ef5206a78e283fe15e6186.tar.bz2 luasocket-bcc0c2a9f0be2ca796ef5206a78e283fe15e6186.zip |
New filter scheme.
ltn12 and mime updated.
smtp/ftp broken.
Diffstat (limited to 'src/http.lua')
-rw-r--r-- | src/http.lua | 219 |
1 files changed, 104 insertions, 115 deletions
diff --git a/src/http.lua b/src/http.lua index 74c29ba..629bf65 100644 --- a/src/http.lua +++ b/src/http.lua | |||
@@ -10,12 +10,11 @@ if not LUASOCKET_LIBNAME then error('module requires LuaSocket') end | |||
10 | -- get LuaSocket namespace | 10 | -- get LuaSocket namespace |
11 | local socket = _G[LUASOCKET_LIBNAME] | 11 | local socket = _G[LUASOCKET_LIBNAME] |
12 | if not socket then error('module requires LuaSocket') end | 12 | if not socket then error('module requires LuaSocket') end |
13 | -- create smtp namespace inside LuaSocket namespace | 13 | -- create namespace inside LuaSocket namespace |
14 | local http = socket.http or {} | 14 | socket.http = socket.http or {} |
15 | socket.http = http | 15 | -- make all module globals fall into namespace |
16 | -- make all module globals fall into smtp namespace | 16 | setmetatable(socket.http, { __index = _G }) |
17 | setmetatable(http, { __index = _G }) | 17 | setfenv(1, socket.http) |
18 | setfenv(1, http) | ||
19 | 18 | ||
20 | ----------------------------------------------------------------------------- | 19 | ----------------------------------------------------------------------------- |
21 | -- Program constants | 20 | -- Program constants |
@@ -27,7 +26,18 @@ PORT = 80 | |||
27 | -- user agent field sent in request | 26 | -- user agent field sent in request |
28 | USERAGENT = socket.version | 27 | USERAGENT = socket.version |
29 | -- block size used in transfers | 28 | -- block size used in transfers |
30 | BLOCKSIZE = 8192 | 29 | BLOCKSIZE = 2048 |
30 | |||
31 | ----------------------------------------------------------------------------- | ||
32 | -- Function return value selectors | ||
33 | ----------------------------------------------------------------------------- | ||
34 | local function second(a, b) | ||
35 | return b | ||
36 | end | ||
37 | |||
38 | local function third(a, b, c) | ||
39 | return c | ||
40 | end | ||
31 | 41 | ||
32 | ----------------------------------------------------------------------------- | 42 | ----------------------------------------------------------------------------- |
33 | -- Tries to get a pattern from the server and closes socket on error | 43 | -- Tries to get a pattern from the server and closes socket on error |
@@ -47,7 +57,7 @@ end | |||
47 | ----------------------------------------------------------------------------- | 57 | ----------------------------------------------------------------------------- |
48 | -- Tries to send data to the server and closes socket on error | 58 | -- Tries to send data to the server and closes socket on error |
49 | -- sock: socket connected to the server | 59 | -- sock: socket connected to the server |
50 | -- data: data to send | 60 | -- ...: data to send |
51 | -- Returns | 61 | -- Returns |
52 | -- err: error message if any, nil if successfull | 62 | -- err: error message if any, nil if successfull |
53 | ----------------------------------------------------------------------------- | 63 | ----------------------------------------------------------------------------- |
@@ -68,11 +78,9 @@ end | |||
68 | -- err: error message if any | 78 | -- err: error message if any |
69 | ----------------------------------------------------------------------------- | 79 | ----------------------------------------------------------------------------- |
70 | local function receive_status(sock) | 80 | local function receive_status(sock) |
71 | local line, err | 81 | local line, err = try_receiving(sock) |
72 | line, err = try_receiving(sock) | ||
73 | if not err then | 82 | if not err then |
74 | local code, _ | 83 | local code = third(string.find(line, "HTTP/%d*%.%d* (%d%d%d)")) |
75 | _, _, code = string.find(line, "HTTP/%d*%.%d* (%d%d%d)") | ||
76 | return tonumber(code), line | 84 | return tonumber(code), line |
77 | else return nil, nil, err end | 85 | else return nil, nil, err end |
78 | end | 86 | end |
@@ -121,7 +129,7 @@ local function receive_headers(sock, headers) | |||
121 | end | 129 | end |
122 | 130 | ||
123 | ----------------------------------------------------------------------------- | 131 | ----------------------------------------------------------------------------- |
124 | -- Aborts a receive callback | 132 | -- Aborts a sink with an error message |
125 | -- Input | 133 | -- Input |
126 | -- cb: callback function | 134 | -- cb: callback function |
127 | -- err: error message to pass to callback | 135 | -- err: error message to pass to callback |
@@ -129,8 +137,8 @@ end | |||
129 | -- callback return or if nil err | 137 | -- callback return or if nil err |
130 | ----------------------------------------------------------------------------- | 138 | ----------------------------------------------------------------------------- |
131 | local function abort(cb, err) | 139 | local function abort(cb, err) |
132 | local go, err_or_f = cb(nil, err) | 140 | local go, cb_err = cb(nil, err) |
133 | return err_or_f or err | 141 | return cb_err or err |
134 | end | 142 | end |
135 | 143 | ||
136 | ----------------------------------------------------------------------------- | 144 | ----------------------------------------------------------------------------- |
@@ -138,41 +146,36 @@ end | |||
138 | -- Input | 146 | -- Input |
139 | -- sock: socket connected to the server | 147 | -- sock: socket connected to the server |
140 | -- headers: header set in which to include trailer headers | 148 | -- headers: header set in which to include trailer headers |
141 | -- receive_cb: function to receive chunks | 149 | -- sink: response message body sink |
142 | -- Returns | 150 | -- Returns |
143 | -- nil if successfull or an error message in case of error | 151 | -- nil if successfull or an error message in case of error |
144 | ----------------------------------------------------------------------------- | 152 | ----------------------------------------------------------------------------- |
145 | local function receive_body_bychunks(sock, headers, receive_cb) | 153 | local function receive_body_bychunks(sock, headers, sink) |
146 | local chunk, size, line, err, go, err_or_f, _ | 154 | local chunk, size, line, err, go |
147 | while 1 do | 155 | while 1 do |
148 | -- get chunk size, skip extention | 156 | -- get chunk size, skip extention |
149 | line, err = try_receiving(sock) | 157 | line, err = try_receiving(sock) |
150 | if err then return abort(receive_cb, err) end | 158 | if err then return abort(sink, err) end |
151 | size = tonumber(string.gsub(line, ";.*", ""), 16) | 159 | size = tonumber(string.gsub(line, ";.*", ""), 16) |
152 | if not size then return abort(receive_cb, "invalid chunk size") end | 160 | if not size then return abort(sink, "invalid chunk size") end |
153 | -- was it the last chunk? | 161 | -- was it the last chunk? |
154 | if size <= 0 then break end | 162 | if size <= 0 then break end |
155 | -- get chunk | 163 | -- get chunk |
156 | chunk, err = try_receiving(sock, size) | 164 | chunk, err = try_receiving(sock, size) |
157 | if err then return abort(receive_cb, err) end | 165 | if err then return abort(sink, err) end |
158 | -- pass chunk to callback | 166 | -- pass chunk to callback |
159 | go, err_or_f = receive_cb(chunk) | 167 | go, err = sink(chunk) |
160 | -- see if callback needs to be replaced | ||
161 | receive_cb = err_or_f or receive_cb | ||
162 | -- see if callback aborted | 168 | -- see if callback aborted |
163 | if not go then return err_or_f or "aborted by callback" end | 169 | if not go then return err or "aborted by callback" end |
164 | -- skip CRLF on end of chunk | 170 | -- skip CRLF on end of chunk |
165 | _, err = try_receiving(sock) | 171 | err = second(try_receiving(sock)) |
166 | if err then return abort(receive_cb, err) end | 172 | if err then return abort(sink, err) end |
167 | end | 173 | end |
168 | -- the server should not send trailer headers because we didn't send a | 174 | -- servers shouldn't send trailer headers, but who trusts them? |
169 | -- header informing it we know how to deal with them. we do not risk | 175 | err = second(receive_headers(sock, headers)) |
170 | -- being caught unprepaired. | 176 | if err then return abort(sink, err) end |
171 | _, err = receive_headers(sock, headers) | ||
172 | if err then return abort(receive_cb, err) end | ||
173 | -- let callback know we are done | 177 | -- let callback know we are done |
174 | _, err_or_f = receive_cb("") | 178 | return second(sink(nil)) |
175 | return err_or_f | ||
176 | end | 179 | end |
177 | 180 | ||
178 | ----------------------------------------------------------------------------- | 181 | ----------------------------------------------------------------------------- |
@@ -180,94 +183,84 @@ end | |||
180 | -- Input | 183 | -- Input |
181 | -- sock: socket connected to the server | 184 | -- sock: socket connected to the server |
182 | -- length: message body length | 185 | -- length: message body length |
183 | -- receive_cb: function to receive chunks | 186 | -- sink: response message body sink |
184 | -- Returns | 187 | -- Returns |
185 | -- nil if successfull or an error message in case of error | 188 | -- nil if successfull or an error message in case of error |
186 | ----------------------------------------------------------------------------- | 189 | ----------------------------------------------------------------------------- |
187 | local function receive_body_bylength(sock, length, receive_cb) | 190 | local function receive_body_bylength(sock, length, sink) |
188 | while length > 0 do | 191 | while length > 0 do |
189 | local size = math.min(BLOCKSIZE, length) | 192 | local size = math.min(BLOCKSIZE, length) |
190 | local chunk, err = sock:receive(size) | 193 | local chunk, err = sock:receive(size) |
191 | local go, err_or_f = receive_cb(chunk) | 194 | local go, cb_err = sink(chunk) |
192 | length = length - string.len(chunk) | 195 | length = length - string.len(chunk) |
193 | -- see if callback aborted | 196 | -- see if callback aborted |
194 | if not go then return err_or_f or "aborted by callback" end | 197 | if not go then return cb_err or "aborted by callback" end |
195 | -- see if callback needs to be replaced | ||
196 | receive_cb = err_or_f or receive_cb | ||
197 | -- see if there was an error | 198 | -- see if there was an error |
198 | if err and length > 0 then return abort(receive_cb, err) end | 199 | if err and length > 0 then return abort(sink, err) end |
199 | end | 200 | end |
200 | local _, err_or_f = receive_cb("") | 201 | return second(sink(nil)) |
201 | return err_or_f | ||
202 | end | 202 | end |
203 | 203 | ||
204 | ----------------------------------------------------------------------------- | 204 | ----------------------------------------------------------------------------- |
205 | -- Receives a message body by content-length | 205 | -- Receives a message body until the conection is closed |
206 | -- Input | 206 | -- Input |
207 | -- sock: socket connected to the server | 207 | -- sock: socket connected to the server |
208 | -- receive_cb: function to receive chunks | 208 | -- sink: response message body sink |
209 | -- Returns | 209 | -- Returns |
210 | -- nil if successfull or an error message in case of error | 210 | -- nil if successfull or an error message in case of error |
211 | ----------------------------------------------------------------------------- | 211 | ----------------------------------------------------------------------------- |
212 | local function receive_body_untilclosed(sock, receive_cb) | 212 | local function receive_body_untilclosed(sock, sink) |
213 | while 1 do | 213 | while 1 do |
214 | local chunk, err = sock:receive(BLOCKSIZE) | 214 | local chunk, err = sock:receive(BLOCKSIZE) |
215 | local go, err_or_f = receive_cb(chunk) | 215 | local go, cb_err = sink(chunk) |
216 | -- see if callback aborted | 216 | -- see if callback aborted |
217 | if not go then return err_or_f or "aborted by callback" end | 217 | if not go then return cb_err or "aborted by callback" end |
218 | -- see if callback needs to be replaced | ||
219 | receive_cb = err_or_f or receive_cb | ||
220 | -- see if we are done | 218 | -- see if we are done |
221 | if err == "closed" then | 219 | if err == "closed" then return chunk and second(sink(nil)) end |
222 | if chunk ~= "" then | ||
223 | go, err_or_f = receive_cb("") | ||
224 | return err_or_f | ||
225 | end | ||
226 | end | ||
227 | -- see if there was an error | 220 | -- see if there was an error |
228 | if err then return abort(receive_cb, err) end | 221 | if err then return abort(sink, err) end |
229 | end | 222 | end |
230 | end | 223 | end |
231 | 224 | ||
232 | ----------------------------------------------------------------------------- | 225 | ----------------------------------------------------------------------------- |
233 | -- Receives HTTP response body | 226 | -- Receives the HTTP response body |
234 | -- Input | 227 | -- Input |
235 | -- sock: socket connected to the server | 228 | -- sock: socket connected to the server |
236 | -- headers: response header fields | 229 | -- headers: response header fields |
237 | -- receive_cb: function to receive chunks | 230 | -- sink: response message body sink |
238 | -- Returns | 231 | -- Returns |
239 | -- nil if successfull or an error message in case of error | 232 | -- nil if successfull or an error message in case of error |
240 | ----------------------------------------------------------------------------- | 233 | ----------------------------------------------------------------------------- |
241 | local function receive_body(sock, headers, receive_cb) | 234 | local function receive_body(sock, headers, sink) |
235 | -- make sure sink is not fancy | ||
236 | sink = ltn12.sink.simplify(sink) | ||
242 | local te = headers["transfer-encoding"] | 237 | local te = headers["transfer-encoding"] |
243 | if te and te ~= "identity" then | 238 | if te and te ~= "identity" then |
244 | -- get by chunked transfer-coding of message body | 239 | -- get by chunked transfer-coding of message body |
245 | return receive_body_bychunks(sock, headers, receive_cb) | 240 | return receive_body_bychunks(sock, headers, sink) |
246 | elseif tonumber(headers["content-length"]) then | 241 | elseif tonumber(headers["content-length"]) then |
247 | -- get by content-length | 242 | -- get by content-length |
248 | local length = tonumber(headers["content-length"]) | 243 | local length = tonumber(headers["content-length"]) |
249 | return receive_body_bylength(sock, length, receive_cb) | 244 | return receive_body_bylength(sock, length, sink) |
250 | else | 245 | else |
251 | -- get it all until connection closes | 246 | -- get it all until connection closes |
252 | return receive_body_untilclosed(sock, receive_cb) | 247 | return receive_body_untilclosed(sock, sink) |
253 | end | 248 | end |
254 | end | 249 | end |
255 | 250 | ||
256 | ----------------------------------------------------------------------------- | 251 | ----------------------------------------------------------------------------- |
257 | -- Sends data comming from a callback | 252 | -- Sends the HTTP request message body in chunks |
258 | -- Input | 253 | -- Input |
259 | -- data: data connection | 254 | -- data: data connection |
260 | -- send_cb: callback to produce file contents | 255 | -- source: request message body source |
261 | -- Returns | 256 | -- Returns |
262 | -- nil if successfull, or an error message in case of error | 257 | -- nil if successfull, or an error message in case of error |
263 | ----------------------------------------------------------------------------- | 258 | ----------------------------------------------------------------------------- |
264 | local function send_body_bychunks(data, send_cb) | 259 | local function send_body_bychunks(data, source) |
265 | while 1 do | 260 | while 1 do |
266 | local chunk, err_or_f = send_cb() | 261 | local chunk, cb_err = source() |
267 | -- check if callback aborted | 262 | -- check if callback aborted |
268 | if not chunk then return err_or_f or "aborted by callback" end | 263 | if not chunk then return cb_err or "aborted by callback" end |
269 | -- check if callback should be replaced | ||
270 | send_cb = err_or_f or send_cb | ||
271 | -- if we are done, send last-chunk | 264 | -- if we are done, send last-chunk |
272 | if chunk == "" then return try_sending(data, "0\r\n\r\n") end | 265 | if chunk == "" then return try_sending(data, "0\r\n\r\n") end |
273 | -- else send middle chunk | 266 | -- else send middle chunk |
@@ -281,22 +274,18 @@ local function send_body_bychunks(data, send_cb) | |||
281 | end | 274 | end |
282 | 275 | ||
283 | ----------------------------------------------------------------------------- | 276 | ----------------------------------------------------------------------------- |
284 | -- Sends data comming from a callback | 277 | -- Sends the HTTP request message body |
285 | -- Input | 278 | -- Input |
286 | -- data: data connection | 279 | -- data: data connection |
287 | -- send_cb: callback to produce body contents | 280 | -- source: request message body source |
288 | -- Returns | 281 | -- Returns |
289 | -- nil if successfull, or an error message in case of error | 282 | -- nil if successfull, or an error message in case of error |
290 | ----------------------------------------------------------------------------- | 283 | ----------------------------------------------------------------------------- |
291 | local function send_body_bylength(data, send_cb) | 284 | local function send_body(data, source) |
292 | while 1 do | 285 | while 1 do |
293 | local chunk, err_or_f = send_cb() | 286 | local chunk, cb_err = source() |
294 | -- check if callback aborted | ||
295 | if not chunk then return err_or_f or "aborted by callback" end | ||
296 | -- check if callback should be replaced | ||
297 | send_cb = err_or_f or send_cb | ||
298 | -- check if callback is done | 287 | -- check if callback is done |
299 | if chunk == "" then return end | 288 | if not chunk then return cb_err end |
300 | -- send data | 289 | -- send data |
301 | local err = try_sending(data, chunk) | 290 | local err = try_sending(data, chunk) |
302 | if err then return err end | 291 | if err then return err end |
@@ -304,10 +293,10 @@ local function send_body_bylength(data, send_cb) | |||
304 | end | 293 | end |
305 | 294 | ||
306 | ----------------------------------------------------------------------------- | 295 | ----------------------------------------------------------------------------- |
307 | -- Sends mime headers | 296 | -- Sends request headers |
308 | -- Input | 297 | -- Input |
309 | -- sock: server socket | 298 | -- sock: server socket |
310 | -- headers: table with mime headers to be sent | 299 | -- headers: table with headers to be sent |
311 | -- Returns | 300 | -- Returns |
312 | -- err: error message if any | 301 | -- err: error message if any |
313 | ----------------------------------------------------------------------------- | 302 | ----------------------------------------------------------------------------- |
@@ -330,27 +319,29 @@ end | |||
330 | -- method: request method to be used | 319 | -- method: request method to be used |
331 | -- uri: request uri | 320 | -- uri: request uri |
332 | -- headers: request headers to be sent | 321 | -- headers: request headers to be sent |
333 | -- body_cb: callback to send request message body | 322 | -- source: request message body source |
334 | -- Returns | 323 | -- Returns |
335 | -- err: nil in case of success, error message otherwise | 324 | -- err: nil in case of success, error message otherwise |
336 | ----------------------------------------------------------------------------- | 325 | ----------------------------------------------------------------------------- |
337 | local function send_request(sock, method, uri, headers, body_cb) | 326 | local function send_request(sock, method, uri, headers, source) |
338 | local chunk, size, done, err | 327 | local chunk, size, done, err |
339 | -- send request line | 328 | -- send request line |
340 | err = try_sending(sock, method .. " " .. uri .. " HTTP/1.1\r\n") | 329 | err = try_sending(sock, method .. " " .. uri .. " HTTP/1.1\r\n") |
341 | if err then return err end | 330 | if err then return err end |
342 | if body_cb and not headers["content-length"] then | 331 | if source and not headers["content-length"] then |
343 | headers["transfer-encoding"] = "chunked" | 332 | headers["transfer-encoding"] = "chunked" |
344 | end | 333 | end |
345 | -- send request headers | 334 | -- send request headers |
346 | err = send_headers(sock, headers) | 335 | err = send_headers(sock, headers) |
347 | if err then return err end | 336 | if err then return err end |
348 | -- send request message body, if any | 337 | -- send request message body, if any |
349 | if body_cb then | 338 | if source then |
350 | if not headers["content-length"] then | 339 | -- make sure source is not fancy |
351 | return send_body_bychunks(sock, body_cb) | 340 | source = ltn12.source.simplify(source) |
341 | if headers["content-length"] then | ||
342 | return send_body(sock, source) | ||
352 | else | 343 | else |
353 | return send_body_bylength(sock, body_cb) | 344 | return send_body_bychunks(sock, source) |
354 | end | 345 | end |
355 | end | 346 | end |
356 | end | 347 | end |
@@ -415,23 +406,23 @@ end | |||
415 | -- Input | 406 | -- Input |
416 | -- reqt: a table with the original request information | 407 | -- reqt: a table with the original request information |
417 | -- parsed: parsed request URL | 408 | -- parsed: parsed request URL |
418 | -- respt: a table with the server response information | ||
419 | -- Returns | 409 | -- Returns |
420 | -- respt: result of target authorization | 410 | -- respt: result of target authorization |
421 | ----------------------------------------------------------------------------- | 411 | ----------------------------------------------------------------------------- |
422 | local function authorize(reqt, parsed, respt) | 412 | local function authorize(reqt, parsed) |
423 | reqt.headers["authorization"] = "Basic " .. | 413 | reqt.headers["authorization"] = "Basic " .. |
424 | (socket.mime.b64(parsed.user .. ":" .. parsed.password)) | 414 | (mime.b64(parsed.user .. ":" .. parsed.password)) |
425 | local autht = { | 415 | local autht = { |
426 | nredirects = reqt.nredirects, | 416 | nredirects = reqt.nredirects, |
427 | method = reqt.method, | 417 | method = reqt.method, |
428 | url = reqt.url, | 418 | url = reqt.url, |
429 | body_cb = reqt.body_cb, | 419 | source = reqt.source, |
420 | sink = reqt.sink, | ||
430 | headers = reqt.headers, | 421 | headers = reqt.headers, |
431 | timeout = reqt.timeout, | 422 | timeout = reqt.timeout, |
432 | proxy = reqt.proxy, | 423 | proxy = reqt.proxy, |
433 | } | 424 | } |
434 | return request_cb(autht, respt) | 425 | return request_cb(autht) |
435 | end | 426 | end |
436 | 427 | ||
437 | ----------------------------------------------------------------------------- | 428 | ----------------------------------------------------------------------------- |
@@ -443,8 +434,8 @@ end | |||
443 | -- 1 if we should redirect, nil otherwise | 434 | -- 1 if we should redirect, nil otherwise |
444 | ----------------------------------------------------------------------------- | 435 | ----------------------------------------------------------------------------- |
445 | local function should_redirect(reqt, respt) | 436 | local function should_redirect(reqt, respt) |
446 | return (reqt.redirect ~= false) and | 437 | return (reqt.redirect ~= false) and |
447 | (respt.code == 301 or respt.code == 302) and | 438 | (respt.code == 301 or respt.code == 302) and |
448 | (reqt.method == "GET" or reqt.method == "HEAD") and | 439 | (reqt.method == "GET" or reqt.method == "HEAD") and |
449 | not (reqt.nredirects and reqt.nredirects >= 5) | 440 | not (reqt.nredirects and reqt.nredirects >= 5) |
450 | end | 441 | end |
@@ -453,8 +444,7 @@ end | |||
453 | -- Returns the result of a request following a server redirect message. | 444 | -- Returns the result of a request following a server redirect message. |
454 | -- Input | 445 | -- Input |
455 | -- reqt: a table with the original request information | 446 | -- reqt: a table with the original request information |
456 | -- respt: a table with the following fields: | 447 | -- respt: response table of previous attempt |
457 | -- body_cb: response method body receive-callback | ||
458 | -- Returns | 448 | -- Returns |
459 | -- respt: result of target redirection | 449 | -- respt: result of target redirection |
460 | ----------------------------------------------------------------------------- | 450 | ----------------------------------------------------------------------------- |
@@ -467,12 +457,13 @@ local function redirect(reqt, respt) | |||
467 | -- the RFC says the redirect URL has to be absolute, but some | 457 | -- the RFC says the redirect URL has to be absolute, but some |
468 | -- servers do not respect that | 458 | -- servers do not respect that |
469 | url = socket.url.absolute(reqt.url, respt.headers["location"]), | 459 | url = socket.url.absolute(reqt.url, respt.headers["location"]), |
470 | body_cb = reqt.body_cb, | 460 | source = reqt.source, |
461 | sink = reqt.sink, | ||
471 | headers = reqt.headers, | 462 | headers = reqt.headers, |
472 | timeout = reqt.timeout, | 463 | timeout = reqt.timeout, |
473 | proxy = reqt.proxy | 464 | proxy = reqt.proxy |
474 | } | 465 | } |
475 | respt = request_cb(redirt, respt) | 466 | respt = request_cb(redirt) |
476 | -- we pass the location header as a clue we tried to redirect | 467 | -- we pass the location header as a clue we tried to redirect |
477 | if respt.headers then respt.headers.location = redirt.url end | 468 | if respt.headers then respt.headers.location = redirt.url end |
478 | return respt | 469 | return respt |
@@ -562,10 +553,9 @@ end | |||
562 | -- url: target uniform resource locator | 553 | -- url: target uniform resource locator |
563 | -- user, password: authentication information | 554 | -- user, password: authentication information |
564 | -- headers: request headers to send, or nil if none | 555 | -- headers: request headers to send, or nil if none |
565 | -- body_cb: request message body send-callback, or nil if none | 556 | -- source: request message body source, or nil if none |
557 | -- sink: response message body sink | ||
566 | -- redirect: should we refrain from following a server redirect message? | 558 | -- redirect: should we refrain from following a server redirect message? |
567 | -- respt: a table with the following fields: | ||
568 | -- body_cb: response method body receive-callback | ||
569 | -- Returns | 559 | -- Returns |
570 | -- respt: a table with the following fields: | 560 | -- respt: a table with the following fields: |
571 | -- headers: response header fields received, or nil if failed | 561 | -- headers: response header fields received, or nil if failed |
@@ -573,7 +563,7 @@ end | |||
573 | -- code: server status code, or nil if failed | 563 | -- code: server status code, or nil if failed |
574 | -- error: error message, or nil if successfull | 564 | -- error: error message, or nil if successfull |
575 | ----------------------------------------------------------------------------- | 565 | ----------------------------------------------------------------------------- |
576 | function request_cb(reqt, respt) | 566 | function request_cb(reqt) |
577 | local sock, ret | 567 | local sock, ret |
578 | local parsed = socket.url.parse(reqt.url, { | 568 | local parsed = socket.url.parse(reqt.url, { |
579 | host = "", | 569 | host = "", |
@@ -581,6 +571,7 @@ function request_cb(reqt, respt) | |||
581 | path ="/", | 571 | path ="/", |
582 | scheme = "http" | 572 | scheme = "http" |
583 | }) | 573 | }) |
574 | local respt = {} | ||
584 | if parsed.scheme ~= "http" then | 575 | if parsed.scheme ~= "http" then |
585 | respt.error = string.format("unknown scheme '%s'", parsed.scheme) | 576 | respt.error = string.format("unknown scheme '%s'", parsed.scheme) |
586 | return respt | 577 | return respt |
@@ -597,7 +588,7 @@ function request_cb(reqt, respt) | |||
597 | if not sock then return respt end | 588 | if not sock then return respt end |
598 | -- send request message | 589 | -- send request message |
599 | respt.error = send_request(sock, reqt.method, | 590 | respt.error = send_request(sock, reqt.method, |
600 | request_uri(reqt, parsed), reqt.headers, reqt.body_cb) | 591 | request_uri(reqt, parsed), reqt.headers, reqt.source) |
601 | if respt.error then | 592 | if respt.error then |
602 | sock:close() | 593 | sock:close() |
603 | return respt | 594 | return respt |
@@ -619,18 +610,18 @@ function request_cb(reqt, respt) | |||
619 | -- decide what to do based on request and response parameters | 610 | -- decide what to do based on request and response parameters |
620 | if should_redirect(reqt, respt) then | 611 | if should_redirect(reqt, respt) then |
621 | -- drop the body | 612 | -- drop the body |
622 | receive_body(sock, respt.headers, function (c, e) return 1 end) | 613 | receive_body(sock, respt.headers, ltn12.sink.null()) |
623 | -- we are done with this connection | 614 | -- we are done with this connection |
624 | sock:close() | 615 | sock:close() |
625 | return redirect(reqt, respt) | 616 | return redirect(reqt, respt) |
626 | elseif should_authorize(reqt, parsed, respt) then | 617 | elseif should_authorize(reqt, parsed, respt) then |
627 | -- drop the body | 618 | -- drop the body |
628 | receive_body(sock, respt.headers, function (c, e) return 1 end) | 619 | receive_body(sock, respt.headers, ltn12.sink.null()) |
629 | -- we are done with this connection | 620 | -- we are done with this connection |
630 | sock:close() | 621 | sock:close() |
631 | return authorize(reqt, parsed, respt) | 622 | return authorize(reqt, parsed, respt) |
632 | elseif should_receive_body(reqt, respt) then | 623 | elseif should_receive_body(reqt, respt) then |
633 | respt.error = receive_body(sock, respt.headers, respt.body_cb) | 624 | respt.error = receive_body(sock, respt.headers, reqt.sink) |
634 | if respt.error then return respt end | 625 | if respt.error then return respt end |
635 | sock:close() | 626 | sock:close() |
636 | return respt | 627 | return respt |
@@ -658,13 +649,11 @@ end | |||
658 | -- error: error message if any | 649 | -- error: error message if any |
659 | ----------------------------------------------------------------------------- | 650 | ----------------------------------------------------------------------------- |
660 | function request(reqt) | 651 | function request(reqt) |
661 | local respt = {} | 652 | reqt.source = reqt.body and ltn12.source.string(reqt.body) |
662 | reqt.body_cb = socket.callback.send.string(reqt.body) | 653 | local t = {} |
663 | local concat = socket.concat.create() | 654 | reqt.sink = ltn12.sink.table(t) |
664 | respt.body_cb = socket.callback.receive.concat(concat) | 655 | local respt = request_cb(reqt) |
665 | respt = request_cb(reqt, respt) | 656 | if table.getn(t) > 0 then respt.body = table.concat(t) end |
666 | respt.body = concat:getresult() | ||
667 | respt.body_cb = nil | ||
668 | return respt | 657 | return respt |
669 | end | 658 | end |
670 | 659 | ||
@@ -713,4 +702,4 @@ function post(url_or_request, body) | |||
713 | return respt.body, respt.headers, respt.code, respt.error | 702 | return respt.body, respt.headers, respt.code, respt.error |
714 | end | 703 | end |
715 | 704 | ||
716 | return http | 705 | return socket.http |