diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2001-08-07 19:50:04 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2001-08-07 19:50:04 +0000 |
commit | cb61077f7a8c71536c3ad331f041bc4ab97c719c (patch) | |
tree | d520adce2f440362ba6a8fda7a4627c28b8b34ab /src | |
parent | 3143c58e0fe839e849aca3b29e0928bd9c1df6a5 (diff) | |
download | luasocket-cb61077f7a8c71536c3ad331f041bc4ab97c719c.tar.gz luasocket-cb61077f7a8c71536c3ad331f041bc4ab97c719c.tar.bz2 luasocket-cb61077f7a8c71536c3ad331f041bc4ab97c719c.zip |
Minor documentation changes.
Constants were moved to Public table.
Updated to use new fast concatenation module (concat.lua).
Diffstat (limited to 'src')
-rw-r--r-- | src/http.lua | 104 |
1 files changed, 52 insertions, 52 deletions
diff --git a/src/http.lua b/src/http.lua index e68cf22..1e4c2cd 100644 --- a/src/http.lua +++ b/src/http.lua | |||
@@ -1,9 +1,10 @@ | |||
1 | ----------------------------------------------------------------------------- | 1 | ----------------------------------------------------------------------------- |
2 | -- Full HTTP/1.1 client support for the Lua language using the | 2 | -- HTTP/1.1 client support for the Lua language. |
3 | -- LuaSocket 1.4a toolkit. | 3 | -- LuaSocket 1.4a toolkit. |
4 | -- Author: Diego Nehab | 4 | -- Author: Diego Nehab |
5 | -- Date: 26/12/2000 | 5 | -- Date: 26/12/2000 |
6 | -- Conforming to: RFC 2068 | 6 | -- Conforming to: RFC 2616, LTN7 |
7 | -- RCS ID: $Id$ | ||
7 | ----------------------------------------------------------------------------- | 8 | ----------------------------------------------------------------------------- |
8 | 9 | ||
9 | local Public, Private = {}, {} | 10 | local Public, Private = {}, {} |
@@ -13,27 +14,27 @@ HTTP = Public | |||
13 | -- Program constants | 14 | -- Program constants |
14 | ----------------------------------------------------------------------------- | 15 | ----------------------------------------------------------------------------- |
15 | -- connection timeout in seconds | 16 | -- connection timeout in seconds |
16 | Private.TIMEOUT = 60 | 17 | Public.TIMEOUT = 60 |
17 | -- default port for document retrieval | 18 | -- default port for document retrieval |
18 | Private.PORT = 80 | 19 | Public.PORT = 80 |
19 | -- user agent field sent in request | 20 | -- user agent field sent in request |
20 | Private.USERAGENT = "LuaSocket 1.4a" | 21 | Public.USERAGENT = "LuaSocket 1.4a" |
21 | -- block size used in transfers | 22 | -- block size used in transfers |
22 | Private.BLOCKSIZE = 8192 | 23 | Public.BLOCKSIZE = 8192 |
23 | 24 | ||
24 | ----------------------------------------------------------------------------- | 25 | ----------------------------------------------------------------------------- |
25 | -- Required libraries | 26 | -- Required libraries |
26 | ----------------------------------------------------------------------------- | 27 | ----------------------------------------------------------------------------- |
27 | dofile "buffer.lua" | 28 | dofile "buffer.lua" |
28 | dofile "url.lua" | 29 | dofile "url.lua" |
29 | dofile "encode.lua" | 30 | dofile "code.lua" |
30 | 31 | ||
31 | ----------------------------------------------------------------------------- | 32 | ----------------------------------------------------------------------------- |
32 | -- Tries to get a pattern from the server and closes socket on error | 33 | -- Tries to get a pattern from the server and closes socket on error |
33 | -- sock: socket connected to the server | 34 | -- sock: socket connected to the server |
34 | -- pattern: pattern to receive | 35 | -- ...: patterns to receive |
35 | -- Returns | 36 | -- Returns |
36 | -- data: line received or nil in case of error | 37 | -- ...: received patterns |
37 | -- err: error message if any | 38 | -- err: error message if any |
38 | ----------------------------------------------------------------------------- | 39 | ----------------------------------------------------------------------------- |
39 | function Private.try_receive(...) | 40 | function Private.try_receive(...) |
@@ -60,11 +61,11 @@ function Private.try_send(sock, data) | |||
60 | end | 61 | end |
61 | 62 | ||
62 | ----------------------------------------------------------------------------- | 63 | ----------------------------------------------------------------------------- |
63 | -- Retrieves status code from http status line | 64 | -- Computes status code from HTTP status line |
64 | -- Input | 65 | -- Input |
65 | -- line: http status line | 66 | -- line: HTTP status line |
66 | -- Returns | 67 | -- Returns |
67 | -- code: integer with status code | 68 | -- code: integer with status code, or nil if malformed line |
68 | ----------------------------------------------------------------------------- | 69 | ----------------------------------------------------------------------------- |
69 | function Private.get_statuscode(line) | 70 | function Private.get_statuscode(line) |
70 | local code, _ | 71 | local code, _ |
@@ -73,12 +74,12 @@ function Private.get_statuscode(line) | |||
73 | end | 74 | end |
74 | 75 | ||
75 | ----------------------------------------------------------------------------- | 76 | ----------------------------------------------------------------------------- |
76 | -- Receive server reply messages, parsing status code | 77 | -- Receive server reply messages, parsing for status code |
77 | -- Input | 78 | -- Input |
78 | -- sock: socket connected to the server | 79 | -- sock: socket connected to the server |
79 | -- Returns | 80 | -- Returns |
80 | -- code: server status code or nil if error | 81 | -- code: server status code or nil if error |
81 | -- line: full http status line | 82 | -- line: full HTTP status line |
82 | -- err: error message if any | 83 | -- err: error message if any |
83 | ----------------------------------------------------------------------------- | 84 | ----------------------------------------------------------------------------- |
84 | function Private.receive_status(sock) | 85 | function Private.receive_status(sock) |
@@ -108,7 +109,7 @@ function Private.receive_headers(sock, headers) | |||
108 | -- headers go until a blank line is found | 109 | -- headers go until a blank line is found |
109 | while line ~= "" do | 110 | while line ~= "" do |
110 | -- get field-name and value | 111 | -- get field-name and value |
111 | _,_, name, value = strfind(line, "(.-):%s*(.*)") | 112 | _,_, name, value = strfind(line, "^(.-):%s*(.*)") |
112 | if not name or not value then | 113 | if not name or not value then |
113 | sock:close() | 114 | sock:close() |
114 | return nil, "malformed reponse headers" | 115 | return nil, "malformed reponse headers" |
@@ -145,14 +146,14 @@ function Private.receivebody_bychunks(sock, headers, receive_cb) | |||
145 | -- get chunk size, skip extention | 146 | -- get chunk size, skip extention |
146 | line, err = %Private.try_receive(sock) | 147 | line, err = %Private.try_receive(sock) |
147 | if err then | 148 | if err then |
148 | local _, uerr = receive_cb(nil, err) | 149 | local go, uerr = receive_cb(nil, err) |
149 | return uerr or err | 150 | return uerr or err |
150 | end | 151 | end |
151 | size = tonumber(gsub(line, ";.*", ""), 16) | 152 | size = tonumber(gsub(line, ";.*", ""), 16) |
152 | if not size then | 153 | if not size then |
153 | err = "invalid chunk size" | 154 | err = "invalid chunk size" |
154 | sock:close() | 155 | sock:close() |
155 | _, uerr = receive_cb(nil, err) | 156 | go, uerr = receive_cb(nil, err) |
156 | return uerr or err | 157 | return uerr or err |
157 | end | 158 | end |
158 | -- was it the last chunk? | 159 | -- was it the last chunk? |
@@ -160,7 +161,7 @@ function Private.receivebody_bychunks(sock, headers, receive_cb) | |||
160 | -- get chunk | 161 | -- get chunk |
161 | chunk, err = %Private.try_receive(sock, size) | 162 | chunk, err = %Private.try_receive(sock, size) |
162 | if err then | 163 | if err then |
163 | _, uerr = receive_cb(nil, err) | 164 | go, uerr = receive_cb(nil, err) |
164 | return uerr or err | 165 | return uerr or err |
165 | end | 166 | end |
166 | -- pass chunk to callback | 167 | -- pass chunk to callback |
@@ -172,7 +173,7 @@ function Private.receivebody_bychunks(sock, headers, receive_cb) | |||
172 | -- skip CRLF on end of chunk | 173 | -- skip CRLF on end of chunk |
173 | _, err = %Private.try_receive(sock) | 174 | _, err = %Private.try_receive(sock) |
174 | if err then | 175 | if err then |
175 | _, uerr = receive_cb(nil, err) | 176 | go, uerr = receive_cb(nil, err) |
176 | return uerr or err | 177 | return uerr or err |
177 | end | 178 | end |
178 | end | 179 | end |
@@ -181,11 +182,11 @@ function Private.receivebody_bychunks(sock, headers, receive_cb) | |||
181 | -- being caught unprepaired. | 182 | -- being caught unprepaired. |
182 | headers, err = %Private.receive_headers(sock, headers) | 183 | headers, err = %Private.receive_headers(sock, headers) |
183 | if err then | 184 | if err then |
184 | _, uerr = receive_cb(nil, err) | 185 | go, uerr = receive_cb(nil, err) |
185 | return uerr or err | 186 | return uerr or err |
186 | end | 187 | end |
187 | -- let callback know we are done | 188 | -- let callback know we are done |
188 | _, uerr = receive_cb("") | 189 | go, uerr = receive_cb("") |
189 | return uerr | 190 | return uerr |
190 | end | 191 | end |
191 | 192 | ||
@@ -193,6 +194,7 @@ end | |||
193 | -- Receives a message body by content-length | 194 | -- Receives a message body by content-length |
194 | -- Input | 195 | -- Input |
195 | -- sock: socket connected to the server | 196 | -- sock: socket connected to the server |
197 | -- length: message body length | ||
196 | -- receive_cb: function to receive chunks | 198 | -- receive_cb: function to receive chunks |
197 | -- Returns | 199 | -- Returns |
198 | -- nil if successfull or an error message in case of error | 200 | -- nil if successfull or an error message in case of error |
@@ -200,7 +202,7 @@ end | |||
200 | function Private.receivebody_bylength(sock, length, receive_cb) | 202 | function Private.receivebody_bylength(sock, length, receive_cb) |
201 | local uerr, go | 203 | local uerr, go |
202 | while length > 0 do | 204 | while length > 0 do |
203 | local size = min(%Private.BLOCKSIZE, length) | 205 | local size = min(%Public.BLOCKSIZE, length) |
204 | local chunk, err = sock:receive(size) | 206 | local chunk, err = sock:receive(size) |
205 | if err then | 207 | if err then |
206 | go, uerr = receive_cb(nil, err) | 208 | go, uerr = receive_cb(nil, err) |
@@ -228,14 +230,14 @@ end | |||
228 | function Private.receivebody_untilclosed(sock, receive_cb) | 230 | function Private.receivebody_untilclosed(sock, receive_cb) |
229 | local err, go, uerr | 231 | local err, go, uerr |
230 | while 1 do | 232 | while 1 do |
231 | local chunk, err = sock:receive(%Private.BLOCKSIZE) | 233 | local chunk, err = sock:receive(%Public.BLOCKSIZE) |
232 | if err == "closed" or not err then | 234 | if err == "closed" or not err then |
233 | go, uerr = receive_cb(chunk) | 235 | go, uerr = receive_cb(chunk) |
234 | if not go then | 236 | if not go then |
235 | sock:close() | 237 | sock:close() |
236 | return uerr or "aborted by callback" | 238 | return uerr or "aborted by callback" |
237 | end | 239 | end |
238 | if err then break end | 240 | if err == "closed" then break end |
239 | else | 241 | else |
240 | go, uerr = callback(nil, err) | 242 | go, uerr = callback(nil, err) |
241 | return uerr or err | 243 | return uerr or err |
@@ -246,7 +248,7 @@ function Private.receivebody_untilclosed(sock, receive_cb) | |||
246 | end | 248 | end |
247 | 249 | ||
248 | ----------------------------------------------------------------------------- | 250 | ----------------------------------------------------------------------------- |
249 | -- Receives http response body | 251 | -- Receives HTTP response body |
250 | -- Input | 252 | -- Input |
251 | -- sock: socket connected to the server | 253 | -- sock: socket connected to the server |
252 | -- headers: response header fields | 254 | -- headers: response header fields |
@@ -270,7 +272,7 @@ function Private.receive_body(sock, headers, receive_cb) | |||
270 | end | 272 | end |
271 | 273 | ||
272 | ----------------------------------------------------------------------------- | 274 | ----------------------------------------------------------------------------- |
273 | -- Drop http response body | 275 | -- Drop HTTP response body |
274 | -- Input | 276 | -- Input |
275 | -- sock: socket connected to the server | 277 | -- sock: socket connected to the server |
276 | -- headers: response header fields | 278 | -- headers: response header fields |
@@ -286,7 +288,7 @@ end | |||
286 | -- Input | 288 | -- Input |
287 | -- data: data connection | 289 | -- data: data connection |
288 | -- send_cb: callback to produce file contents | 290 | -- send_cb: callback to produce file contents |
289 | -- chunk, size: first callback results | 291 | -- chunk, size: first callback return values |
290 | -- Returns | 292 | -- Returns |
291 | -- nil if successfull, or an error message in case of error | 293 | -- nil if successfull, or an error message in case of error |
292 | ----------------------------------------------------------------------------- | 294 | ----------------------------------------------------------------------------- |
@@ -311,20 +313,20 @@ function Private.send_indirect(data, send_cb, chunk, size) | |||
311 | end | 313 | end |
312 | 314 | ||
313 | ----------------------------------------------------------------------------- | 315 | ----------------------------------------------------------------------------- |
314 | -- Sends a http request message through socket | 316 | -- Sends a HTTP request message through socket |
315 | -- Input | 317 | -- Input |
316 | -- sock: socket connected to the server | 318 | -- sock: socket connected to the server |
317 | -- method: request method to be used | 319 | -- method: request method to be used |
318 | -- path: url path | 320 | -- uri: request uri |
319 | -- headers: request headers to be sent | 321 | -- headers: request headers to be sent |
320 | -- body_cb: callback to send request message body | 322 | -- body_cb: callback to send request message body |
321 | -- Returns | 323 | -- Returns |
322 | -- err: nil in case of success, error message otherwise | 324 | -- err: nil in case of success, error message otherwise |
323 | ----------------------------------------------------------------------------- | 325 | ----------------------------------------------------------------------------- |
324 | function Private.send_request(sock, method, path, headers, body_cb) | 326 | function Private.send_request(sock, method, uri, headers, body_cb) |
325 | local chunk, size, done, err | 327 | local chunk, size, done, err |
326 | -- send request line | 328 | -- send request line |
327 | err = %Private.try_send(sock, method .. " " .. path .. " HTTP/1.1\r\n") | 329 | err = %Private.try_send(sock, method .. " " .. uri .. " HTTP/1.1\r\n") |
328 | if err then return err end | 330 | if err then return err end |
329 | -- if there is a request message body, add content-length header | 331 | -- if there is a request message body, add content-length header |
330 | if body_cb then | 332 | if body_cb then |
@@ -370,7 +372,7 @@ end | |||
370 | -- Converts field names to lowercase and adds a few needed headers | 372 | -- Converts field names to lowercase and adds a few needed headers |
371 | -- Input | 373 | -- Input |
372 | -- headers: request header fields | 374 | -- headers: request header fields |
373 | -- parsed: parsed url components | 375 | -- parsed: parsed request URL |
374 | -- Returns | 376 | -- Returns |
375 | -- lower: a table with the same headers, but with lowercase field names | 377 | -- lower: a table with the same headers, but with lowercase field names |
376 | ----------------------------------------------------------------------------- | 378 | ----------------------------------------------------------------------------- |
@@ -378,7 +380,7 @@ function Private.fill_headers(headers, parsed) | |||
378 | local lower = {} | 380 | local lower = {} |
379 | headers = headers or {} | 381 | headers = headers or {} |
380 | -- set default headers | 382 | -- set default headers |
381 | lower["user-agent"] = %Private.USERAGENT | 383 | lower["user-agent"] = %Public.USERAGENT |
382 | lower["host"] = parsed.host | 384 | lower["host"] = parsed.host |
383 | -- override with user values | 385 | -- override with user values |
384 | for i,v in headers do | 386 | for i,v in headers do |
@@ -393,7 +395,7 @@ end | |||
393 | -- Decides wether we should follow retry with authorization formation | 395 | -- Decides wether we should follow retry with authorization formation |
394 | -- Input | 396 | -- Input |
395 | -- request: a table with the original request information | 397 | -- request: a table with the original request information |
396 | -- parsed: parsed request url | 398 | -- parsed: parsed request URL |
397 | -- response: a table with the server response information | 399 | -- response: a table with the server response information |
398 | -- Returns | 400 | -- Returns |
399 | -- 1 if we should retry, nil otherwise | 401 | -- 1 if we should retry, nil otherwise |
@@ -410,14 +412,14 @@ end | |||
410 | -- Returns the result of retrying a request with authorization information | 412 | -- Returns the result of retrying a request with authorization information |
411 | -- Input | 413 | -- Input |
412 | -- request: a table with the original request information | 414 | -- request: a table with the original request information |
413 | -- parsed: parsed request url | 415 | -- parsed: parsed request URL |
414 | -- response: a table with the server response information | 416 | -- response: a table with the server response information |
415 | -- Returns | 417 | -- Returns |
416 | -- response: result of target redirection | 418 | -- response: result of target redirection |
417 | ----------------------------------------------------------------------------- | 419 | ----------------------------------------------------------------------------- |
418 | function Private.authorize(request, parsed, response) | 420 | function Private.authorize(request, parsed, response) |
419 | request.headers["authorization"] = "Basic " .. | 421 | request.headers["authorization"] = "Basic " .. |
420 | base64(parsed.user .. ":" .. parsed.password) | 422 | Code.base64(parsed.user .. ":" .. parsed.password) |
421 | local authorize = { | 423 | local authorize = { |
422 | redirects = request.redirects, | 424 | redirects = request.redirects, |
423 | method = request.method, | 425 | method = request.method, |
@@ -459,9 +461,9 @@ function Private.redirect(request, response) | |||
459 | local redirect = { | 461 | local redirect = { |
460 | redirects = redirects, | 462 | redirects = redirects, |
461 | method = request.method, | 463 | method = request.method, |
462 | -- the RFC says the redirect url has to be absolute, but some | 464 | -- the RFC says the redirect URL has to be absolute, but some |
463 | -- servers do not respect that | 465 | -- servers do not respect that |
464 | url = URL.build_absolute(request.url,response.headers["location"]), | 466 | url = URL.absolute_url(request.url, response.headers["location"]), |
465 | body_cb = request.body_cb, | 467 | body_cb = request.body_cb, |
466 | headers = request.headers | 468 | headers = request.headers |
467 | } | 469 | } |
@@ -469,9 +471,9 @@ function Private.redirect(request, response) | |||
469 | end | 471 | end |
470 | 472 | ||
471 | ----------------------------------------------------------------------------- | 473 | ----------------------------------------------------------------------------- |
472 | -- Computes the request URI from the given URL | 474 | -- Computes the request URI from the parsed request URL |
473 | -- Input | 475 | -- Input |
474 | -- parsed: parsed url | 476 | -- parsed: parsed URL |
475 | -- Returns | 477 | -- Returns |
476 | -- uri: request URI for parsed URL | 478 | -- uri: request URI for parsed URL |
477 | ----------------------------------------------------------------------------- | 479 | ----------------------------------------------------------------------------- |
@@ -505,9 +507,8 @@ end | |||
505 | -- error: error message, or nil if successfull | 507 | -- error: error message, or nil if successfull |
506 | ----------------------------------------------------------------------------- | 508 | ----------------------------------------------------------------------------- |
507 | function Public.request_indirect(request, response) | 509 | function Public.request_indirect(request, response) |
508 | -- get url components | 510 | local parsed = URL.parse_url(request.url, {port = %Public.PORT, path ="/"}) |
509 | local parsed = URL.parse(request.url, {port = %Private.PORT, path ="/"}) | 511 | -- explicit authentication info overrides that given by the URL |
510 | -- explicit authentication info overrides that given by the url | ||
511 | parsed.user = request.user or parsed.user | 512 | parsed.user = request.user or parsed.user |
512 | parsed.password = request.password or parsed.password | 513 | parsed.password = request.password or parsed.password |
513 | -- default method | 514 | -- default method |
@@ -519,7 +520,7 @@ function Public.request_indirect(request, response) | |||
519 | sock, response.error = connect(parsed.host, parsed.port) | 520 | sock, response.error = connect(parsed.host, parsed.port) |
520 | if not sock then return response end | 521 | if not sock then return response end |
521 | -- set connection timeout so that we do not hang forever | 522 | -- set connection timeout so that we do not hang forever |
522 | sock:timeout(%Private.TIMEOUT) | 523 | sock:timeout(%Public.TIMEOUT) |
523 | -- send request message | 524 | -- send request message |
524 | response.error = %Private.send_request(sock, request.method, | 525 | response.error = %Private.send_request(sock, request.method, |
525 | %Private.request_uri(parsed), request.headers, request.body_cb) | 526 | %Private.request_uri(parsed), request.headers, request.body_cb) |
@@ -555,7 +556,7 @@ end | |||
555 | -- Input | 556 | -- Input |
556 | -- request: a table with the following fields | 557 | -- request: a table with the following fields |
557 | -- method: "GET", "PUT", "POST" etc (defaults to "GET") | 558 | -- method: "GET", "PUT", "POST" etc (defaults to "GET") |
558 | -- url: target url, i.e. the document to be retrieved | 559 | -- url: request URL, i.e. the document to be retrieved |
559 | -- user, password: authentication information | 560 | -- user, password: authentication information |
560 | -- headers: request header fields, or nil if none | 561 | -- headers: request header fields, or nil if none |
561 | -- body: request message body as a string, or nil if none | 562 | -- body: request message body as a string, or nil if none |
@@ -572,17 +573,16 @@ function Public.request(request) | |||
572 | local response = {} | 573 | local response = {} |
573 | if request.body then | 574 | if request.body then |
574 | request.body_cb = function() | 575 | request.body_cb = function() |
575 | return %request.body, strlen(%request.body) | 576 | return %request.body, strlen(%request.body) |
576 | end | 577 | end |
577 | end | 578 | end |
578 | local auxiliar = { buf = buf_create() } | 579 | local cat = Concat.create() |
579 | response.body_cb = function(chunk, err) | 580 | response.body_cb = function(chunk, err) |
580 | if not chunk then %auxiliar.buf = nil end | 581 | %cat:addstring(chunk) |
581 | buf_addstring(%auxiliar.buf, chunk) | ||
582 | return 1 | 582 | return 1 |
583 | end | 583 | end |
584 | %Public.request_indirect(request, response) | 584 | %Public.request_indirect(request, response) |
585 | response.body = buf_getresult(auxiliar.buf) | 585 | response.body = cat:getresult() |
586 | response.body_cb = nil | 586 | response.body_cb = nil |
587 | return response | 587 | return response |
588 | end | 588 | end |
@@ -590,7 +590,7 @@ end | |||
590 | ----------------------------------------------------------------------------- | 590 | ----------------------------------------------------------------------------- |
591 | -- Retrieves a URL by the method "GET" | 591 | -- Retrieves a URL by the method "GET" |
592 | -- Input | 592 | -- Input |
593 | -- url: target url, i.e. the document to be retrieved | 593 | -- url: request URL, i.e. the document to be retrieved |
594 | -- Returns | 594 | -- Returns |
595 | -- body: response message body, or nil if failed | 595 | -- body: response message body, or nil if failed |
596 | -- headers: response header fields received, or nil if failed | 596 | -- headers: response header fields received, or nil if failed |
@@ -609,7 +609,7 @@ end | |||
609 | ----------------------------------------------------------------------------- | 609 | ----------------------------------------------------------------------------- |
610 | -- Retrieves a URL by the method "POST" | 610 | -- Retrieves a URL by the method "POST" |
611 | -- Input | 611 | -- Input |
612 | -- url: target url, i.e. the document to be retrieved | 612 | -- url: request URL, i.e. the document to be retrieved |
613 | -- body: request message body, or nil if none | 613 | -- body: request message body, or nil if none |
614 | -- Returns | 614 | -- Returns |
615 | -- body: response message body, or nil if failed | 615 | -- body: response message body, or nil if failed |