diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2002-07-08 21:01:18 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2002-07-08 21:01:18 +0000 |
commit | 60e7bf48b077377c11022f34e24bbbfb596397bf (patch) | |
tree | d534436cdd12f492e39a947a4b26799aa39bb24d | |
parent | 9d7f43768aaa6d9f4b604c7e837a33755078ae15 (diff) | |
download | luasocket-60e7bf48b077377c11022f34e24bbbfb596397bf.tar.gz luasocket-60e7bf48b077377c11022f34e24bbbfb596397bf.tar.bz2 luasocket-60e7bf48b077377c11022f34e24bbbfb596397bf.zip |
Updated for Lua 4.1-w3.
Dealing with 100 response codes.
-rw-r--r-- | src/http.lua | 109 |
1 files changed, 55 insertions, 54 deletions
diff --git a/src/http.lua b/src/http.lua index e4c756f..9832a6b 100644 --- a/src/http.lua +++ b/src/http.lua | |||
@@ -1,6 +1,6 @@ | |||
1 | ----------------------------------------------------------------------------- | 1 | ----------------------------------------------------------------------------- |
2 | -- HTTP/1.1 client support for the Lua language. | 2 | -- HTTP/1.1 client support for the Lua language. |
3 | -- LuaSocket 1.4 toolkit. | 3 | -- LuaSocket 1.5 toolkit. |
4 | -- Author: Diego Nehab | 4 | -- Author: Diego Nehab |
5 | -- Date: 26/12/2000 | 5 | -- Date: 26/12/2000 |
6 | -- Conforming to: RFC 2616, LTN7 | 6 | -- Conforming to: RFC 2616, LTN7 |
@@ -18,18 +18,11 @@ Public.TIMEOUT = 60 | |||
18 | -- default port for document retrieval | 18 | -- default port for document retrieval |
19 | Public.PORT = 80 | 19 | Public.PORT = 80 |
20 | -- user agent field sent in request | 20 | -- user agent field sent in request |
21 | Public.USERAGENT = "LuaSocket 1.4" | 21 | Public.USERAGENT = "LuaSocket 1.5" |
22 | -- block size used in transfers | 22 | -- block size used in transfers |
23 | Public.BLOCKSIZE = 8192 | 23 | Public.BLOCKSIZE = 8192 |
24 | 24 | ||
25 | ----------------------------------------------------------------------------- | 25 | ----------------------------------------------------------------------------- |
26 | -- Required libraries | ||
27 | ----------------------------------------------------------------------------- | ||
28 | dofile "concat.lua" | ||
29 | dofile "url.lua" | ||
30 | dofile "code.lua" | ||
31 | |||
32 | ----------------------------------------------------------------------------- | ||
33 | -- Tries to get a pattern from the server and closes socket on error | 26 | -- Tries to get a pattern from the server and closes socket on error |
34 | -- sock: socket connected to the server | 27 | -- sock: socket connected to the server |
35 | -- ...: pattern to receive | 28 | -- ...: pattern to receive |
@@ -84,8 +77,8 @@ end | |||
84 | ----------------------------------------------------------------------------- | 77 | ----------------------------------------------------------------------------- |
85 | function Private.receive_status(sock) | 78 | function Private.receive_status(sock) |
86 | local line, err | 79 | local line, err |
87 | line, err = %Private.try_receive(sock) | 80 | line, err = Private.try_receive(sock) |
88 | if not err then return %Private.get_statuscode(line), line | 81 | if not err then return Private.get_statuscode(line), line |
89 | else return nil, nil, err end | 82 | else return nil, nil, err end |
90 | end | 83 | end |
91 | 84 | ||
@@ -104,7 +97,7 @@ function Private.receive_headers(sock, headers) | |||
104 | local line, err | 97 | local line, err |
105 | local name, value, _ | 98 | local name, value, _ |
106 | -- get first line | 99 | -- get first line |
107 | line, err = %Private.try_receive(sock) | 100 | line, err = Private.try_receive(sock) |
108 | if err then return nil, err end | 101 | if err then return nil, err end |
109 | -- headers go until a blank line is found | 102 | -- headers go until a blank line is found |
110 | while line ~= "" do | 103 | while line ~= "" do |
@@ -116,12 +109,12 @@ function Private.receive_headers(sock, headers) | |||
116 | end | 109 | end |
117 | name = strlower(name) | 110 | name = strlower(name) |
118 | -- get next line (value might be folded) | 111 | -- get next line (value might be folded) |
119 | line, err = %Private.try_receive(sock) | 112 | line, err = Private.try_receive(sock) |
120 | if err then return nil, err end | 113 | if err then return nil, err end |
121 | -- unfold any folded values | 114 | -- unfold any folded values |
122 | while not err and strfind(line, "^%s") do | 115 | while not err and strfind(line, "^%s") do |
123 | value = value .. line | 116 | value = value .. line |
124 | line, err = %Private.try_receive(sock) | 117 | line, err = Private.try_receive(sock) |
125 | if err then return nil, err end | 118 | if err then return nil, err end |
126 | end | 119 | end |
127 | -- save pair in table | 120 | -- save pair in table |
@@ -144,7 +137,7 @@ function Private.receivebody_bychunks(sock, headers, receive_cb) | |||
144 | local chunk, size, line, err, go, uerr, _ | 137 | local chunk, size, line, err, go, uerr, _ |
145 | while 1 do | 138 | while 1 do |
146 | -- get chunk size, skip extention | 139 | -- get chunk size, skip extention |
147 | line, err = %Private.try_receive(sock) | 140 | line, err = Private.try_receive(sock) |
148 | if err then | 141 | if err then |
149 | local go, uerr = receive_cb(nil, err) | 142 | local go, uerr = receive_cb(nil, err) |
150 | return uerr or err | 143 | return uerr or err |
@@ -159,7 +152,7 @@ function Private.receivebody_bychunks(sock, headers, receive_cb) | |||
159 | -- was it the last chunk? | 152 | -- was it the last chunk? |
160 | if size <= 0 then break end | 153 | if size <= 0 then break end |
161 | -- get chunk | 154 | -- get chunk |
162 | chunk, err = %Private.try_receive(sock, size) | 155 | chunk, err = Private.try_receive(sock, size) |
163 | if err then | 156 | if err then |
164 | go, uerr = receive_cb(nil, err) | 157 | go, uerr = receive_cb(nil, err) |
165 | return uerr or err | 158 | return uerr or err |
@@ -171,7 +164,7 @@ function Private.receivebody_bychunks(sock, headers, receive_cb) | |||
171 | return uerr or "aborted by callback" | 164 | return uerr or "aborted by callback" |
172 | end | 165 | end |
173 | -- skip CRLF on end of chunk | 166 | -- skip CRLF on end of chunk |
174 | _, err = %Private.try_receive(sock) | 167 | _, err = Private.try_receive(sock) |
175 | if err then | 168 | if err then |
176 | go, uerr = receive_cb(nil, err) | 169 | go, uerr = receive_cb(nil, err) |
177 | return uerr or err | 170 | return uerr or err |
@@ -180,7 +173,7 @@ function Private.receivebody_bychunks(sock, headers, receive_cb) | |||
180 | -- the server should not send trailer headers because we didn't send a | 173 | -- the server should not send trailer headers because we didn't send a |
181 | -- header informing it we know how to deal with them. we do not risk | 174 | -- header informing it we know how to deal with them. we do not risk |
182 | -- being caught unprepaired. | 175 | -- being caught unprepaired. |
183 | headers, err = %Private.receive_headers(sock, headers) | 176 | headers, err = Private.receive_headers(sock, headers) |
184 | if err then | 177 | if err then |
185 | go, uerr = receive_cb(nil, err) | 178 | go, uerr = receive_cb(nil, err) |
186 | return uerr or err | 179 | return uerr or err |
@@ -202,7 +195,7 @@ end | |||
202 | function Private.receivebody_bylength(sock, length, receive_cb) | 195 | function Private.receivebody_bylength(sock, length, receive_cb) |
203 | local uerr, go | 196 | local uerr, go |
204 | while length > 0 do | 197 | while length > 0 do |
205 | local size = min(%Public.BLOCKSIZE, length) | 198 | local size = min(Public.BLOCKSIZE, length) |
206 | local chunk, err = sock:receive(size) | 199 | local chunk, err = sock:receive(size) |
207 | if err then | 200 | if err then |
208 | go, uerr = receive_cb(nil, err) | 201 | go, uerr = receive_cb(nil, err) |
@@ -230,7 +223,7 @@ end | |||
230 | function Private.receivebody_untilclosed(sock, receive_cb) | 223 | function Private.receivebody_untilclosed(sock, receive_cb) |
231 | local err, go, uerr | 224 | local err, go, uerr |
232 | while 1 do | 225 | while 1 do |
233 | local chunk, err = sock:receive(%Public.BLOCKSIZE) | 226 | local chunk, err = sock:receive(Public.BLOCKSIZE) |
234 | if err == "closed" or not err then | 227 | if err == "closed" or not err then |
235 | go, uerr = receive_cb(chunk) | 228 | go, uerr = receive_cb(chunk) |
236 | if not go then | 229 | if not go then |
@@ -260,14 +253,14 @@ function Private.receive_body(sock, headers, receive_cb) | |||
260 | local te = headers["transfer-encoding"] | 253 | local te = headers["transfer-encoding"] |
261 | if te and te ~= "identity" then | 254 | if te and te ~= "identity" then |
262 | -- get by chunked transfer-coding of message body | 255 | -- get by chunked transfer-coding of message body |
263 | return %Private.receivebody_bychunks(sock, headers, receive_cb) | 256 | return Private.receivebody_bychunks(sock, headers, receive_cb) |
264 | elseif tonumber(headers["content-length"]) then | 257 | elseif tonumber(headers["content-length"]) then |
265 | -- get by content-length | 258 | -- get by content-length |
266 | local length = tonumber(headers["content-length"]) | 259 | local length = tonumber(headers["content-length"]) |
267 | return %Private.receivebody_bylength(sock, length, receive_cb) | 260 | return Private.receivebody_bylength(sock, length, receive_cb) |
268 | else | 261 | else |
269 | -- get it all until connection closes | 262 | -- get it all until connection closes |
270 | return %Private.receivebody_untilclosed(sock, receive_cb) | 263 | return Private.receivebody_untilclosed(sock, receive_cb) |
271 | end | 264 | end |
272 | end | 265 | end |
273 | 266 | ||
@@ -280,7 +273,7 @@ end | |||
280 | -- nil if successfull or an error message in case of error | 273 | -- nil if successfull or an error message in case of error |
281 | ----------------------------------------------------------------------------- | 274 | ----------------------------------------------------------------------------- |
282 | function Private.drop_body(sock, headers) | 275 | function Private.drop_body(sock, headers) |
283 | return %Private.receive_body(sock, headers, function (c, e) return 1 end) | 276 | return Private.receive_body(sock, headers, function (c, e) return 1 end) |
284 | end | 277 | end |
285 | 278 | ||
286 | ----------------------------------------------------------------------------- | 279 | ----------------------------------------------------------------------------- |
@@ -325,11 +318,11 @@ function Private.send_headers(sock, headers) | |||
325 | headers = headers or {} | 318 | headers = headers or {} |
326 | -- send request headers | 319 | -- send request headers |
327 | for i, v in headers do | 320 | for i, v in headers do |
328 | err = %Private.try_send(sock, i .. ": " .. v .. "\r\n") | 321 | err = Private.try_send(sock, i .. ": " .. v .. "\r\n") |
329 | if err then return err end | 322 | if err then return err end |
330 | end | 323 | end |
331 | -- mark end of request headers | 324 | -- mark end of request headers |
332 | return %Private.try_send(sock, "\r\n") | 325 | return Private.try_send(sock, "\r\n") |
333 | end | 326 | end |
334 | 327 | ||
335 | ----------------------------------------------------------------------------- | 328 | ----------------------------------------------------------------------------- |
@@ -346,7 +339,7 @@ end | |||
346 | function Private.send_request(sock, method, uri, headers, body_cb) | 339 | function Private.send_request(sock, method, uri, headers, body_cb) |
347 | local chunk, size, done, err | 340 | local chunk, size, done, err |
348 | -- send request line | 341 | -- send request line |
349 | err = %Private.try_send(sock, method .. " " .. uri .. " HTTP/1.1\r\n") | 342 | err = Private.try_send(sock, method .. " " .. uri .. " HTTP/1.1\r\n") |
350 | if err then return err end | 343 | if err then return err end |
351 | -- if there is a request message body, add content-length header | 344 | -- if there is a request message body, add content-length header |
352 | if body_cb then | 345 | if body_cb then |
@@ -360,11 +353,11 @@ function Private.send_request(sock, method, uri, headers, body_cb) | |||
360 | end | 353 | end |
361 | end | 354 | end |
362 | -- send request headers | 355 | -- send request headers |
363 | err = %Private.send_headers(sock, headers) | 356 | err = Private.send_headers(sock, headers) |
364 | if err then return err end | 357 | if err then return err end |
365 | -- send request message body, if any | 358 | -- send request message body, if any |
366 | if body_cb then | 359 | if body_cb then |
367 | return %Private.send_indirect(sock, body_cb, chunk, size) | 360 | return Private.send_indirect(sock, body_cb, chunk, size) |
368 | end | 361 | end |
369 | end | 362 | end |
370 | 363 | ||
@@ -395,7 +388,7 @@ function Private.fill_headers(headers, parsed) | |||
395 | local lower = {} | 388 | local lower = {} |
396 | headers = headers or {} | 389 | headers = headers or {} |
397 | -- set default headers | 390 | -- set default headers |
398 | lower["user-agent"] = %Public.USERAGENT | 391 | lower["user-agent"] = Public.USERAGENT |
399 | -- override with user values | 392 | -- override with user values |
400 | for i,v in headers do | 393 | for i,v in headers do |
401 | lower[strlower(i)] = v | 394 | lower[strlower(i)] = v |
@@ -442,7 +435,7 @@ function Private.authorize(request, parsed, response) | |||
442 | body_cb = request.body_cb, | 435 | body_cb = request.body_cb, |
443 | headers = request.headers | 436 | headers = request.headers |
444 | } | 437 | } |
445 | return %Public.request_cb(authorize, response) | 438 | return Public.request_cb(authorize, response) |
446 | end | 439 | end |
447 | 440 | ||
448 | ----------------------------------------------------------------------------- | 441 | ----------------------------------------------------------------------------- |
@@ -482,7 +475,7 @@ function Private.redirect(request, response) | |||
482 | body_cb = request.body_cb, | 475 | body_cb = request.body_cb, |
483 | headers = request.headers | 476 | headers = request.headers |
484 | } | 477 | } |
485 | local response = %Public.request_cb(redirect, response) | 478 | local response = Public.request_cb(redirect, response) |
486 | -- we pass the location header as a clue we tried to redirect | 479 | -- we pass the location header as a clue we tried to redirect |
487 | if response.headers then response.headers.location = redirect.url end | 480 | if response.headers then response.headers.location = redirect.url end |
488 | return response | 481 | return response |
@@ -544,7 +537,7 @@ end | |||
544 | function Public.request_cb(request, response) | 537 | function Public.request_cb(request, response) |
545 | local parsed = URL.parse_url(request.url, { | 538 | local parsed = URL.parse_url(request.url, { |
546 | host = "", | 539 | host = "", |
547 | port = %Public.PORT, | 540 | port = Public.PORT, |
548 | path ="/", | 541 | path ="/", |
549 | scheme = "http" | 542 | scheme = "http" |
550 | }) | 543 | }) |
@@ -558,35 +551,43 @@ function Public.request_cb(request, response) | |||
558 | -- default method | 551 | -- default method |
559 | request.method = request.method or "GET" | 552 | request.method = request.method or "GET" |
560 | -- fill default headers | 553 | -- fill default headers |
561 | request.headers = %Private.fill_headers(request.headers, parsed) | 554 | request.headers = Private.fill_headers(request.headers, parsed) |
562 | -- try to connect to server | 555 | -- try to connect to server |
563 | local sock | 556 | local sock |
564 | sock, response.error = connect(parsed.host, parsed.port) | 557 | sock, response.error = connect(parsed.host, parsed.port) |
565 | if not sock then return response end | 558 | if not sock then return response end |
566 | -- set connection timeout so that we do not hang forever | 559 | -- set connection timeout so that we do not hang forever |
567 | sock:timeout(%Public.TIMEOUT) | 560 | sock:timeout(Public.TIMEOUT) |
568 | -- send request message | 561 | -- send request message |
569 | response.error = %Private.send_request(sock, request.method, | 562 | response.error = Private.send_request(sock, request.method, |
570 | %Private.request_uri(parsed), request.headers, request.body_cb) | 563 | Private.request_uri(parsed), request.headers, request.body_cb) |
571 | if response.error then return response end | 564 | if response.error then return response end |
572 | -- get server response message | 565 | -- get server response message |
573 | response.code, response.status, response.error = | 566 | response.code, response.status, response.error = |
574 | %Private.receive_status(sock) | 567 | Private.receive_status(sock) |
575 | if response.error then return response end | 568 | if response.error then return response end |
569 | -- deal with 1xx status | ||
570 | if response.code == 100 then | ||
571 | response.headers, response.error = Private.receive_headers(sock, {}) | ||
572 | if response.error then return response end | ||
573 | response.code, response.status, response.error = | ||
574 | Private.receive_status(sock) | ||
575 | if response.error then return response end | ||
576 | end | ||
576 | -- receive all headers | 577 | -- receive all headers |
577 | response.headers, response.error = %Private.receive_headers(sock, {}) | 578 | response.headers, response.error = Private.receive_headers(sock, {}) |
578 | if response.error then return response end | 579 | if response.error then return response end |
579 | -- decide what to do based on request and response parameters | 580 | -- decide what to do based on request and response parameters |
580 | if %Private.should_redirect(request, response) then | 581 | if Private.should_redirect(request, response) then |
581 | %Private.drop_body(sock, response.headers) | 582 | Private.drop_body(sock, response.headers) |
582 | sock:close() | 583 | sock:close() |
583 | return %Private.redirect(request, response) | 584 | return Private.redirect(request, response) |
584 | elseif %Private.should_authorize(request, parsed, response) then | 585 | elseif Private.should_authorize(request, parsed, response) then |
585 | %Private.drop_body(sock, response.headers) | 586 | Private.drop_body(sock, response.headers) |
586 | sock:close() | 587 | sock:close() |
587 | return %Private.authorize(request, parsed, response) | 588 | return Private.authorize(request, parsed, response) |
588 | elseif %Private.has_body(request, response) then | 589 | elseif Private.has_body(request, response) then |
589 | response.error = %Private.receive_body(sock, response.headers, | 590 | response.error = Private.receive_body(sock, response.headers, |
590 | response.body_cb) | 591 | response.body_cb) |
591 | if response.error then return response end | 592 | if response.error then return response end |
592 | sock:close() | 593 | sock:close() |
@@ -618,15 +619,15 @@ function Public.request(request) | |||
618 | local response = {} | 619 | local response = {} |
619 | if request.body then | 620 | if request.body then |
620 | request.body_cb = function() | 621 | request.body_cb = function() |
621 | return %request.body, strlen(%request.body) | 622 | return request.body, strlen(request.body) |
622 | end | 623 | end |
623 | end | 624 | end |
624 | local cat = Concat.create() | 625 | local cat = Concat.create() |
625 | response.body_cb = function(chunk, err) | 626 | response.body_cb = function(chunk, err) |
626 | if chunk then %cat:addstring(chunk) end | 627 | if chunk then cat:addstring(chunk) end |
627 | return 1 | 628 | return 1 |
628 | end | 629 | end |
629 | response = %Public.request_cb(request, response) | 630 | response = Public.request_cb(request, response) |
630 | response.body = cat:getresult() | 631 | response.body = cat:getresult() |
631 | response.body_cb = nil | 632 | response.body_cb = nil |
632 | return response | 633 | return response |
@@ -646,9 +647,9 @@ end | |||
646 | -- error: error message if any | 647 | -- error: error message if any |
647 | ----------------------------------------------------------------------------- | 648 | ----------------------------------------------------------------------------- |
648 | function Public.get(url_or_request) | 649 | function Public.get(url_or_request) |
649 | local request = %Private.build_request(url_or_request) | 650 | local request = Private.build_request(url_or_request) |
650 | request.method = "GET" | 651 | request.method = "GET" |
651 | local response = %Public.request(request) | 652 | local response = Public.request(request) |
652 | return response.body, response.headers, | 653 | return response.body, response.headers, |
653 | response.code, response.error | 654 | response.code, response.error |
654 | end | 655 | end |
@@ -669,10 +670,10 @@ end | |||
669 | -- error: error message, or nil if successfull | 670 | -- error: error message, or nil if successfull |
670 | ----------------------------------------------------------------------------- | 671 | ----------------------------------------------------------------------------- |
671 | function Public.post(url_or_request, body) | 672 | function Public.post(url_or_request, body) |
672 | local request = %Private.build_request(url_or_request) | 673 | local request = Private.build_request(url_or_request) |
673 | request.method = "POST" | 674 | request.method = "POST" |
674 | request.body = request.body or body | 675 | request.body = request.body or body |
675 | local response = %Public.request(request) | 676 | local response = Public.request(request) |
676 | return response.body, response.headers, | 677 | return response.body, response.headers, |
677 | response.code, response.error | 678 | response.code, response.error |
678 | end | 679 | end |