diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-19 00:24:41 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-19 00:24:41 +0000 |
| commit | 6ac82d50eecdf9bf55f4234ed3a5449afd7a2992 (patch) | |
| tree | 8cd27e814359d60543428a89b104a8528d0e6bf2 | |
| parent | 3ea92711269153916990d6cd7999bf436775e647 (diff) | |
| download | luasocket-6ac82d50eecdf9bf55f4234ed3a5449afd7a2992.tar.gz luasocket-6ac82d50eecdf9bf55f4234ed3a5449afd7a2992.tar.bz2 luasocket-6ac82d50eecdf9bf55f4234ed3a5449afd7a2992.zip | |
Added proxy support to http.lua
Changed callback.lua module, but need more work.
Added local connect support.
| -rw-r--r-- | TODO | 7 | ||||
| -rw-r--r-- | src/http.lua | 58 | ||||
| -rw-r--r-- | src/tcp.c | 6 | ||||
| -rw-r--r-- | test/httptest.lua | 121 |
4 files changed, 125 insertions, 67 deletions
| @@ -1,3 +1,10 @@ | |||
| 1 | add callback module to manual | ||
| 2 | change stay to redirect in http.lua and in manual | ||
| 3 | add timeout to request table | ||
| 4 | |||
| 5 | change code to mime | ||
| 6 | change *all* modules to be namespace independent | ||
| 7 | |||
| 1 | write some utilities that use the code.lua module and put them | 8 | write some utilities that use the code.lua module and put them |
| 2 | in etc, modify the README.etc file and makefile.dist (eol.lua is done) | 9 | in etc, modify the README.etc file and makefile.dist (eol.lua is done) |
| 3 | 10 | ||
diff --git a/src/http.lua b/src/http.lua index f51da25..fb13d99 100644 --- a/src/http.lua +++ b/src/http.lua | |||
| @@ -40,6 +40,7 @@ BLOCKSIZE = 8192 | |||
| 40 | local function try_receiving(sock, pattern) | 40 | local function try_receiving(sock, pattern) |
| 41 | local data, err = sock:receive(pattern) | 41 | local data, err = sock:receive(pattern) |
| 42 | if not data then sock:close() end | 42 | if not data then sock:close() end |
| 43 | --print(data) | ||
| 43 | return data, err | 44 | return data, err |
| 44 | end | 45 | end |
| 45 | 46 | ||
| @@ -53,6 +54,7 @@ end | |||
| 53 | local function try_sending(sock, ...) | 54 | local function try_sending(sock, ...) |
| 54 | local sent, err = sock:send(unpack(arg)) | 55 | local sent, err = sock:send(unpack(arg)) |
| 55 | if not sent then sock:close() end | 56 | if not sent then sock:close() end |
| 57 | --io.write(unpack(arg)) | ||
| 56 | return err | 58 | return err |
| 57 | end | 59 | end |
| 58 | 60 | ||
| @@ -425,7 +427,10 @@ local function authorize(reqt, parsed, respt) | |||
| 425 | method = reqt.method, | 427 | method = reqt.method, |
| 426 | url = reqt.url, | 428 | url = reqt.url, |
| 427 | body_cb = reqt.body_cb, | 429 | body_cb = reqt.body_cb, |
| 428 | headers = reqt.headers | 430 | headers = reqt.headers, |
| 431 | timeout = reqt.timeout, | ||
| 432 | host = reqt.host, | ||
| 433 | port = reqt.port | ||
| 429 | } | 434 | } |
| 430 | return request_cb(autht, respt) | 435 | return request_cb(autht, respt) |
| 431 | end | 436 | end |
| @@ -439,11 +444,10 @@ end | |||
| 439 | -- 1 if we should redirect, nil otherwise | 444 | -- 1 if we should redirect, nil otherwise |
| 440 | ----------------------------------------------------------------------------- | 445 | ----------------------------------------------------------------------------- |
| 441 | local function should_redirect(reqt, respt) | 446 | local function should_redirect(reqt, respt) |
| 442 | local follow = not reqt.stay | 447 | return (reqt.redirect ~= false) and |
| 443 | follow = follow and (respt.code == 301 or respt.code == 302) | 448 | (respt.code == 301 or respt.code == 302) and |
| 444 | follow = follow and (reqt.method == "GET" or reqt.method == "HEAD") | 449 | (reqt.method == "GET" or reqt.method == "HEAD") and |
| 445 | follow = follow and not (reqt.nredirects and reqt.nredirects >= 5) | 450 | not (reqt.nredirects and reqt.nredirects >= 5) |
| 446 | return follow | ||
| 447 | end | 451 | end |
| 448 | 452 | ||
| 449 | ----------------------------------------------------------------------------- | 453 | ----------------------------------------------------------------------------- |
| @@ -465,7 +469,10 @@ local function redirect(reqt, respt) | |||
| 465 | -- servers do not respect that | 469 | -- servers do not respect that |
| 466 | url = socket.url.absolute(reqt.url, respt.headers["location"]), | 470 | url = socket.url.absolute(reqt.url, respt.headers["location"]), |
| 467 | body_cb = reqt.body_cb, | 471 | body_cb = reqt.body_cb, |
| 468 | headers = reqt.headers | 472 | headers = reqt.headers, |
| 473 | timeout = reqt.timeout, | ||
| 474 | host = reqt.host, | ||
| 475 | port = reqt.port | ||
| 469 | } | 476 | } |
| 470 | respt = request_cb(redirt, respt) | 477 | respt = request_cb(redirt, respt) |
| 471 | -- we pass the location header as a clue we tried to redirect | 478 | -- we pass the location header as a clue we tried to redirect |
| @@ -475,18 +482,24 @@ end | |||
| 475 | 482 | ||
| 476 | ----------------------------------------------------------------------------- | 483 | ----------------------------------------------------------------------------- |
| 477 | -- Computes the request URI from the parsed request URL | 484 | -- Computes the request URI from the parsed request URL |
| 485 | -- If host and port are given in the request table, we use he | ||
| 486 | -- absoluteURI format. Otherwise, we use the abs_path format. | ||
| 478 | -- Input | 487 | -- Input |
| 479 | -- parsed: parsed URL | 488 | -- parsed: parsed URL |
| 480 | -- Returns | 489 | -- Returns |
| 481 | -- uri: request URI for parsed URL | 490 | -- uri: request URI for parsed URL |
| 482 | ----------------------------------------------------------------------------- | 491 | ----------------------------------------------------------------------------- |
| 483 | local function request_uri(parsed) | 492 | local function request_uri(reqt, parsed) |
| 484 | local uri = "" | 493 | local url |
| 485 | if parsed.path then uri = uri .. parsed.path end | 494 | if not reqt.host and not reqt.port then |
| 486 | if parsed.params then uri = uri .. ";" .. parsed.params end | 495 | url = { |
| 487 | if parsed.query then uri = uri .. "?" .. parsed.query end | 496 | path = parsed.path, |
| 488 | if parsed.fragment then uri = uri .. "#" .. parsed.fragment end | 497 | params = parsed.params, |
| 489 | return uri | 498 | query = parsed.query, |
| 499 | fragment = parsed.fragment | ||
| 500 | } | ||
| 501 | else url = parsed end | ||
| 502 | return socket.url.build(url) | ||
| 490 | end | 503 | end |
| 491 | 504 | ||
| 492 | ----------------------------------------------------------------------------- | 505 | ----------------------------------------------------------------------------- |
| @@ -519,7 +532,7 @@ end | |||
| 519 | -- user, password: authentication information | 532 | -- user, password: authentication information |
| 520 | -- headers: request headers to send, or nil if none | 533 | -- headers: request headers to send, or nil if none |
| 521 | -- body_cb: request message body send-callback, or nil if none | 534 | -- body_cb: request message body send-callback, or nil if none |
| 522 | -- stay: should we refrain from following a server redirect message? | 535 | -- redirect: should we refrain from following a server redirect message? |
| 523 | -- respt: a table with the following fields: | 536 | -- respt: a table with the following fields: |
| 524 | -- body_cb: response method body receive-callback | 537 | -- body_cb: response method body receive-callback |
| 525 | -- Returns | 538 | -- Returns |
| @@ -552,16 +565,17 @@ function request_cb(reqt, respt) | |||
| 552 | sock, respt.error = socket.tcp() | 565 | sock, respt.error = socket.tcp() |
| 553 | if not sock then return respt end | 566 | if not sock then return respt end |
| 554 | -- set connection timeout so that we do not hang forever | 567 | -- set connection timeout so that we do not hang forever |
| 555 | sock:settimeout(TIMEOUT) | 568 | sock:settimeout(reqt.timeout or TIMEOUT) |
| 556 | local ret | 569 | local ret |
| 557 | ret, respt.error = sock:connect(parsed.host, parsed.port) | 570 | ret, respt.error = sock:connect(reqt.host or parsed.host, |
| 571 | reqt.port or parsed.port) | ||
| 558 | if not ret then | 572 | if not ret then |
| 559 | sock:close() | 573 | sock:close() |
| 560 | return respt | 574 | return respt |
| 561 | end | 575 | end |
| 562 | -- send request message | 576 | -- send request message |
| 563 | respt.error = send_request(sock, reqt.method, | 577 | respt.error = send_request(sock, reqt.method, |
| 564 | request_uri(parsed), reqt.headers, reqt.body_cb) | 578 | request_uri(reqt, parsed), reqt.headers, reqt.body_cb) |
| 565 | if respt.error then | 579 | if respt.error then |
| 566 | sock:close() | 580 | sock:close() |
| 567 | return respt | 581 | return respt |
| @@ -570,7 +584,7 @@ function request_cb(reqt, respt) | |||
| 570 | respt.code, respt.status, respt.error = receive_status(sock) | 584 | respt.code, respt.status, respt.error = receive_status(sock) |
| 571 | if respt.error then return respt end | 585 | if respt.error then return respt end |
| 572 | -- deal with continue 100 | 586 | -- deal with continue 100 |
| 573 | -- servers should not send them, but they might | 587 | -- servers should not send them, but some do! |
| 574 | if respt.code == 100 then | 588 | if respt.code == 100 then |
| 575 | respt.headers, respt.error = receive_headers(sock, {}) | 589 | respt.headers, respt.error = receive_headers(sock, {}) |
| 576 | if respt.error then return respt end | 590 | if respt.error then return respt end |
| @@ -612,7 +626,7 @@ end | |||
| 612 | -- user, password: authentication information | 626 | -- user, password: authentication information |
| 613 | -- headers: request header fields, or nil if none | 627 | -- headers: request header fields, or nil if none |
| 614 | -- body: request message body as a string, or nil if none | 628 | -- body: request message body as a string, or nil if none |
| 615 | -- stay: should we refrain from following a server redirect message? | 629 | -- redirect: should we refrain from following a server redirect message? |
| 616 | -- Returns | 630 | -- Returns |
| 617 | -- respt: a table with the following fields: | 631 | -- respt: a table with the following fields: |
| 618 | -- body: response message body, or nil if failed | 632 | -- body: response message body, or nil if failed |
| @@ -623,9 +637,9 @@ end | |||
| 623 | ----------------------------------------------------------------------------- | 637 | ----------------------------------------------------------------------------- |
| 624 | function request(reqt) | 638 | function request(reqt) |
| 625 | local respt = {} | 639 | local respt = {} |
| 626 | reqt.body_cb = socket.callback.send_string(reqt.body) | 640 | reqt.body_cb = socket.callback.send.string(reqt.body) |
| 627 | local concat = socket.concat.create() | 641 | local concat = socket.concat.create() |
| 628 | respt.body_cb = socket.callback.receive_concat(concat) | 642 | respt.body_cb = socket.callback.receive.concat(concat) |
| 629 | respt = request_cb(reqt, respt) | 643 | respt = request_cb(reqt, respt) |
| 630 | respt.body = concat:getresult() | 644 | respt.body = concat:getresult() |
| 631 | respt.body_cb = nil | 645 | respt.body_cb = nil |
| @@ -230,15 +230,15 @@ static int meth_bind(lua_State *L) | |||
| 230 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); | 230 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); |
| 231 | const char *address = luaL_checkstring(L, 2); | 231 | const char *address = luaL_checkstring(L, 2); |
| 232 | unsigned short port = (unsigned short) luaL_checknumber(L, 3); | 232 | unsigned short port = (unsigned short) luaL_checknumber(L, 3); |
| 233 | int backlog = (int) luaL_optnumber(L, 4, 0); | 233 | int backlog = (int) luaL_optnumber(L, 4, 1); |
| 234 | const char *err = inet_trybind(&tcp->sock, address, port, backlog); | 234 | const char *err = inet_trybind(&tcp->sock, address, port, backlog); |
| 235 | if (err) { | 235 | if (err) { |
| 236 | lua_pushnil(L); | 236 | lua_pushnil(L); |
| 237 | lua_pushstring(L, err); | 237 | lua_pushstring(L, err); |
| 238 | return 2; | 238 | return 2; |
| 239 | } | 239 | } |
| 240 | /* turn master object into a server object */ | 240 | /* turn master object into a server object if there was a listen */ |
| 241 | aux_setclass(L, "tcp{server}", 1); | 241 | if (backlog > 0) aux_setclass(L, "tcp{server}", 1); |
| 242 | lua_pushnumber(L, 1); | 242 | lua_pushnumber(L, 1); |
| 243 | return 1; | 243 | return 1; |
| 244 | } | 244 | } |
diff --git a/test/httptest.lua b/test/httptest.lua index 96c9378..3d0db87 100644 --- a/test/httptest.lua +++ b/test/httptest.lua | |||
| @@ -3,6 +3,29 @@ | |||
| 3 | -- needs ScriptAlias from /home/c/diego/tec/luasocket/test/cgi | 3 | -- needs ScriptAlias from /home/c/diego/tec/luasocket/test/cgi |
| 4 | -- to "/luasocket-test-cgi" and "/luasocket-test-cgi/" | 4 | -- to "/luasocket-test-cgi" and "/luasocket-test-cgi/" |
| 5 | -- needs "AllowOverride AuthConfig" on /home/c/diego/tec/luasocket/test/auth | 5 | -- needs "AllowOverride AuthConfig" on /home/c/diego/tec/luasocket/test/auth |
| 6 | dofile("noglobals.lua") | ||
| 7 | |||
| 8 | local host, proxyh, proxyp, request, response | ||
| 9 | local ignore, expect, index, prefix, cgiprefix | ||
| 10 | |||
| 11 | local t = socket.time() | ||
| 12 | |||
| 13 | host = host or "diego.princeton.edu" | ||
| 14 | proxyh = proxyh or "localhost" | ||
| 15 | proxyp = proxyp or 3128 | ||
| 16 | prefix = prefix or "/luasocket-test" | ||
| 17 | cgiprefix = cgiprefix or "/luasocket-test-cgi" | ||
| 18 | |||
| 19 | local readfile = function(name) | ||
| 20 | local f = io.open(name, "r") | ||
| 21 | if not f then return nil end | ||
| 22 | local s = f:read("*a") | ||
| 23 | f:close() | ||
| 24 | return s | ||
| 25 | end | ||
| 26 | |||
| 27 | index = readfile("test/index.html") | ||
| 28 | |||
| 6 | local similar = function(s1, s2) | 29 | local similar = function(s1, s2) |
| 7 | return string.lower(string.gsub(s1 or "", "%s", "")) == | 30 | return string.lower(string.gsub(s1 or "", "%s", "")) == |
| 8 | string.lower(string.gsub(s2 or "", "%s", "")) | 31 | string.lower(string.gsub(s2 or "", "%s", "")) |
| @@ -14,14 +37,6 @@ local fail = function(s) | |||
| 14 | os.exit() | 37 | os.exit() |
| 15 | end | 38 | end |
| 16 | 39 | ||
| 17 | local readfile = function(name) | ||
| 18 | local f = io.open(name, "r") | ||
| 19 | if not f then return nil end | ||
| 20 | local s = f:read("*a") | ||
| 21 | f:close() | ||
| 22 | return s | ||
| 23 | end | ||
| 24 | |||
| 25 | local check = function (v, e) | 40 | local check = function (v, e) |
| 26 | if v then print("ok") | 41 | if v then print("ok") |
| 27 | else fail(e) end | 42 | else fail(e) end |
| @@ -48,23 +63,12 @@ local check_request = function(request, expect, ignore) | |||
| 48 | print("ok") | 63 | print("ok") |
| 49 | end | 64 | end |
| 50 | 65 | ||
| 51 | local host, request, response, ignore, expect, index, prefix, cgiprefix | ||
| 52 | |||
| 53 | local t = socket.time() | ||
| 54 | |||
| 55 | host = host or "localhost" | ||
| 56 | prefix = prefix or "/luasocket-test" | ||
| 57 | cgiprefix = cgiprefix or "/luasocket-test-cgi" | ||
| 58 | index = readfile("test/index.html") | ||
| 59 | |||
| 60 | io.write("testing request uri correctness: ") | 66 | io.write("testing request uri correctness: ") |
| 61 | local forth = cgiprefix .. "/request-uri?" .. "this+is+the+query+string" | 67 | local forth = cgiprefix .. "/request-uri?" .. "this+is+the+query+string" |
| 62 | local back, h, c, e = socket.http.get("http://" .. host .. forth) | 68 | local back, h, c, e = socket.http.get("http://" .. host .. forth) |
| 63 | if similar(back, forth) then print("ok") | 69 | back = socket.url.parse(back) |
| 64 | else | 70 | if similar(back.query, "this+is+the+query+string") then print("ok") |
| 65 | print(h, c, e) | 71 | else fail() end |
| 66 | fail() | ||
| 67 | end | ||
| 68 | 72 | ||
| 69 | io.write("testing query string correctness: ") | 73 | io.write("testing query string correctness: ") |
| 70 | forth = "this+is+the+query+string" | 74 | forth = "this+is+the+query+string" |
| @@ -86,7 +90,19 @@ ignore = { | |||
| 86 | } | 90 | } |
| 87 | check_request(request, expect, ignore) | 91 | check_request(request, expect, ignore) |
| 88 | 92 | ||
| 89 | socket.http.get("http://" .. host .. prefix .. "/lixo.html") | 93 | io.write("testing redirect loop: ") |
| 94 | request = { | ||
| 95 | url = "http://" .. host .. cgiprefix .. "/redirect-loop" | ||
| 96 | } | ||
| 97 | expect = { | ||
| 98 | code = 302 | ||
| 99 | } | ||
| 100 | ignore = { | ||
| 101 | status = 1, | ||
| 102 | headers = 1, | ||
| 103 | body = 1 | ||
| 104 | } | ||
| 105 | check_request(request, expect, ignore) | ||
| 90 | 106 | ||
| 91 | io.write("testing post method: ") | 107 | io.write("testing post method: ") |
| 92 | -- wanted to test chunked post, but apache doesn't support it... | 108 | -- wanted to test chunked post, but apache doesn't support it... |
| @@ -107,16 +123,35 @@ ignore = { | |||
| 107 | } | 123 | } |
| 108 | check_request(request, expect, ignore) | 124 | check_request(request, expect, ignore) |
| 109 | 125 | ||
| 126 | io.write("testing proxy with post method: ") | ||
| 127 | request = { | ||
| 128 | url = "http://" .. host .. cgiprefix .. "/cat", | ||
| 129 | method = "POST", | ||
| 130 | body = index, | ||
| 131 | headers = { ["content-length"] = string.len(index) }, | ||
| 132 | port = proxyp, | ||
| 133 | host = proxyh | ||
| 134 | } | ||
| 135 | expect = { | ||
| 136 | body = index, | ||
| 137 | code = 200 | ||
| 138 | } | ||
| 139 | ignore = { | ||
| 140 | status = 1, | ||
| 141 | headers = 1 | ||
| 142 | } | ||
| 143 | check_request(request, expect, ignore) | ||
| 144 | |||
| 110 | io.write("testing simple post function: ") | 145 | io.write("testing simple post function: ") |
| 111 | body = socket.http.post("http://" .. host .. cgiprefix .. "/cat", index) | 146 | back = socket.http.post("http://" .. host .. cgiprefix .. "/cat", index) |
| 112 | check(body == index) | 147 | check(back == index) |
| 113 | 148 | ||
| 114 | io.write("testing simple post function with table args: ") | 149 | io.write("testing simple post function with table args: ") |
| 115 | body = socket.http.post { | 150 | back = socket.http.post { |
| 116 | url = "http://" .. host .. cgiprefix .. "/cat", | 151 | url = "http://" .. host .. cgiprefix .. "/cat", |
| 117 | body = index | 152 | body = index |
| 118 | } | 153 | } |
| 119 | check(body == index) | 154 | check(back == index) |
| 120 | 155 | ||
| 121 | io.write("testing http redirection: ") | 156 | io.write("testing http redirection: ") |
| 122 | request = { | 157 | request = { |
| @@ -132,6 +167,22 @@ ignore = { | |||
| 132 | } | 167 | } |
| 133 | check_request(request, expect, ignore) | 168 | check_request(request, expect, ignore) |
| 134 | 169 | ||
| 170 | io.write("testing proxy with redirection: ") | ||
| 171 | request = { | ||
| 172 | url = "http://" .. host .. prefix, | ||
| 173 | host = proxyh, | ||
| 174 | port = proxyp | ||
| 175 | } | ||
| 176 | expect = { | ||
| 177 | body = index, | ||
| 178 | code = 200 | ||
| 179 | } | ||
| 180 | ignore = { | ||
| 181 | status = 1, | ||
| 182 | headers = 1 | ||
| 183 | } | ||
| 184 | check_request(request, expect, ignore) | ||
| 185 | |||
| 135 | 186 | ||
| 136 | io.write("testing automatic auth failure: ") | 187 | io.write("testing automatic auth failure: ") |
| 137 | request = { | 188 | request = { |
| @@ -150,7 +201,7 @@ check_request(request, expect, ignore) | |||
| 150 | io.write("testing http redirection failure: ") | 201 | io.write("testing http redirection failure: ") |
| 151 | request = { | 202 | request = { |
| 152 | url = "http://" .. host .. prefix, | 203 | url = "http://" .. host .. prefix, |
| 153 | stay = 1 | 204 | redirect = false |
| 154 | } | 205 | } |
| 155 | expect = { | 206 | expect = { |
| 156 | code = 301 | 207 | code = 301 |
| @@ -273,20 +324,6 @@ ignore = { | |||
| 273 | } | 324 | } |
| 274 | check_request(request, expect, ignore) | 325 | check_request(request, expect, ignore) |
| 275 | 326 | ||
| 276 | io.write("testing redirect loop: ") | ||
| 277 | request = { | ||
| 278 | url = "http://" .. host .. cgiprefix .. "/redirect-loop" | ||
| 279 | } | ||
| 280 | expect = { | ||
| 281 | code = 302 | ||
| 282 | } | ||
| 283 | ignore = { | ||
| 284 | status = 1, | ||
| 285 | headers = 1, | ||
| 286 | body = 1 | ||
| 287 | } | ||
| 288 | check_request(request, expect, ignore) | ||
| 289 | |||
| 290 | io.write("testing wrong scheme: ") | 327 | io.write("testing wrong scheme: ") |
| 291 | request = { | 328 | request = { |
| 292 | url = "wrong://" .. host .. cgiprefix .. "/cat", | 329 | url = "wrong://" .. host .. cgiprefix .. "/cat", |
