diff --git a/TODO b/TODO index 91b8830..ab88dbd 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,10 @@ +add callback module to manual +change stay to redirect in http.lua and in manual +add timeout to request table + +change code to mime +change *all* modules to be namespace independent + write some utilities that use the code.lua module and put them in etc, modify the README.etc file and makefile.dist (eol.lua is done) 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 local function try_receiving(sock, pattern) local data, err = sock:receive(pattern) if not data then sock:close() end +--print(data) return data, err end @@ -53,6 +54,7 @@ end local function try_sending(sock, ...) local sent, err = sock:send(unpack(arg)) if not sent then sock:close() end +--io.write(unpack(arg)) return err end @@ -425,7 +427,10 @@ local function authorize(reqt, parsed, respt) method = reqt.method, url = reqt.url, body_cb = reqt.body_cb, - headers = reqt.headers + headers = reqt.headers, + timeout = reqt.timeout, + host = reqt.host, + port = reqt.port } return request_cb(autht, respt) end @@ -439,11 +444,10 @@ end -- 1 if we should redirect, nil otherwise ----------------------------------------------------------------------------- local function should_redirect(reqt, respt) - local follow = not reqt.stay - follow = follow and (respt.code == 301 or respt.code == 302) - follow = follow and (reqt.method == "GET" or reqt.method == "HEAD") - follow = follow and not (reqt.nredirects and reqt.nredirects >= 5) - return follow + return (reqt.redirect ~= false) and + (respt.code == 301 or respt.code == 302) and + (reqt.method == "GET" or reqt.method == "HEAD") and + not (reqt.nredirects and reqt.nredirects >= 5) end ----------------------------------------------------------------------------- @@ -465,7 +469,10 @@ local function redirect(reqt, respt) -- servers do not respect that url = socket.url.absolute(reqt.url, respt.headers["location"]), body_cb = reqt.body_cb, - headers = reqt.headers + headers = reqt.headers, + timeout = reqt.timeout, + host = reqt.host, + port = reqt.port } respt = request_cb(redirt, respt) -- we pass the location header as a clue we tried to redirect @@ -475,18 +482,24 @@ end ----------------------------------------------------------------------------- -- Computes the request URI from the parsed request URL +-- If host and port are given in the request table, we use he +-- absoluteURI format. Otherwise, we use the abs_path format. -- Input -- parsed: parsed URL -- Returns -- uri: request URI for parsed URL ----------------------------------------------------------------------------- -local function request_uri(parsed) - local uri = "" - if parsed.path then uri = uri .. parsed.path end - if parsed.params then uri = uri .. ";" .. parsed.params end - if parsed.query then uri = uri .. "?" .. parsed.query end - if parsed.fragment then uri = uri .. "#" .. parsed.fragment end - return uri +local function request_uri(reqt, parsed) + local url + if not reqt.host and not reqt.port then + url = { + path = parsed.path, + params = parsed.params, + query = parsed.query, + fragment = parsed.fragment + } + else url = parsed end + return socket.url.build(url) end ----------------------------------------------------------------------------- @@ -519,7 +532,7 @@ end -- user, password: authentication information -- headers: request headers to send, or nil if none -- body_cb: request message body send-callback, or nil if none --- stay: should we refrain from following a server redirect message? +-- redirect: should we refrain from following a server redirect message? -- respt: a table with the following fields: -- body_cb: response method body receive-callback -- Returns @@ -552,16 +565,17 @@ function request_cb(reqt, respt) sock, respt.error = socket.tcp() if not sock then return respt end -- set connection timeout so that we do not hang forever - sock:settimeout(TIMEOUT) + sock:settimeout(reqt.timeout or TIMEOUT) local ret - ret, respt.error = sock:connect(parsed.host, parsed.port) + ret, respt.error = sock:connect(reqt.host or parsed.host, + reqt.port or parsed.port) if not ret then sock:close() return respt end -- send request message respt.error = send_request(sock, reqt.method, - request_uri(parsed), reqt.headers, reqt.body_cb) + request_uri(reqt, parsed), reqt.headers, reqt.body_cb) if respt.error then sock:close() return respt @@ -570,7 +584,7 @@ function request_cb(reqt, respt) respt.code, respt.status, respt.error = receive_status(sock) if respt.error then return respt end -- deal with continue 100 - -- servers should not send them, but they might + -- servers should not send them, but some do! if respt.code == 100 then respt.headers, respt.error = receive_headers(sock, {}) if respt.error then return respt end @@ -612,7 +626,7 @@ end -- user, password: authentication information -- headers: request header fields, or nil if none -- body: request message body as a string, or nil if none --- stay: should we refrain from following a server redirect message? +-- redirect: should we refrain from following a server redirect message? -- Returns -- respt: a table with the following fields: -- body: response message body, or nil if failed @@ -623,9 +637,9 @@ end ----------------------------------------------------------------------------- function request(reqt) local respt = {} - reqt.body_cb = socket.callback.send_string(reqt.body) + reqt.body_cb = socket.callback.send.string(reqt.body) local concat = socket.concat.create() - respt.body_cb = socket.callback.receive_concat(concat) + respt.body_cb = socket.callback.receive.concat(concat) respt = request_cb(reqt, respt) respt.body = concat:getresult() respt.body_cb = nil diff --git a/src/tcp.c b/src/tcp.c index 34dd71c..ce2ae17 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -230,15 +230,15 @@ static int meth_bind(lua_State *L) p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); const char *address = luaL_checkstring(L, 2); unsigned short port = (unsigned short) luaL_checknumber(L, 3); - int backlog = (int) luaL_optnumber(L, 4, 0); + int backlog = (int) luaL_optnumber(L, 4, 1); const char *err = inet_trybind(&tcp->sock, address, port, backlog); if (err) { lua_pushnil(L); lua_pushstring(L, err); return 2; } - /* turn master object into a server object */ - aux_setclass(L, "tcp{server}", 1); + /* turn master object into a server object if there was a listen */ + if (backlog > 0) aux_setclass(L, "tcp{server}", 1); lua_pushnumber(L, 1); return 1; } 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 @@ -- needs ScriptAlias from /home/c/diego/tec/luasocket/test/cgi -- to "/luasocket-test-cgi" and "/luasocket-test-cgi/" -- needs "AllowOverride AuthConfig" on /home/c/diego/tec/luasocket/test/auth +dofile("noglobals.lua") + +local host, proxyh, proxyp, request, response +local ignore, expect, index, prefix, cgiprefix + +local t = socket.time() + +host = host or "diego.princeton.edu" +proxyh = proxyh or "localhost" +proxyp = proxyp or 3128 +prefix = prefix or "/luasocket-test" +cgiprefix = cgiprefix or "/luasocket-test-cgi" + +local readfile = function(name) + local f = io.open(name, "r") + if not f then return nil end + local s = f:read("*a") + f:close() + return s +end + +index = readfile("test/index.html") + local similar = function(s1, s2) return string.lower(string.gsub(s1 or "", "%s", "")) == string.lower(string.gsub(s2 or "", "%s", "")) @@ -14,14 +37,6 @@ local fail = function(s) os.exit() end -local readfile = function(name) - local f = io.open(name, "r") - if not f then return nil end - local s = f:read("*a") - f:close() - return s -end - local check = function (v, e) if v then print("ok") else fail(e) end @@ -48,23 +63,12 @@ local check_request = function(request, expect, ignore) print("ok") end -local host, request, response, ignore, expect, index, prefix, cgiprefix - -local t = socket.time() - -host = host or "localhost" -prefix = prefix or "/luasocket-test" -cgiprefix = cgiprefix or "/luasocket-test-cgi" -index = readfile("test/index.html") - io.write("testing request uri correctness: ") local forth = cgiprefix .. "/request-uri?" .. "this+is+the+query+string" local back, h, c, e = socket.http.get("http://" .. host .. forth) -if similar(back, forth) then print("ok") -else -print(h, c, e) -fail() -end +back = socket.url.parse(back) +if similar(back.query, "this+is+the+query+string") then print("ok") +else fail() end io.write("testing query string correctness: ") forth = "this+is+the+query+string" @@ -86,7 +90,19 @@ ignore = { } check_request(request, expect, ignore) -socket.http.get("http://" .. host .. prefix .. "/lixo.html") +io.write("testing redirect loop: ") +request = { + url = "http://" .. host .. cgiprefix .. "/redirect-loop" +} +expect = { + code = 302 +} +ignore = { + status = 1, + headers = 1, + body = 1 +} +check_request(request, expect, ignore) io.write("testing post method: ") -- wanted to test chunked post, but apache doesn't support it... @@ -107,16 +123,35 @@ ignore = { } check_request(request, expect, ignore) +io.write("testing proxy with post method: ") +request = { + url = "http://" .. host .. cgiprefix .. "/cat", + method = "POST", + body = index, + headers = { ["content-length"] = string.len(index) }, + port = proxyp, + host = proxyh +} +expect = { + body = index, + code = 200 +} +ignore = { + status = 1, + headers = 1 +} +check_request(request, expect, ignore) + io.write("testing simple post function: ") -body = socket.http.post("http://" .. host .. cgiprefix .. "/cat", index) -check(body == index) +back = socket.http.post("http://" .. host .. cgiprefix .. "/cat", index) +check(back == index) io.write("testing simple post function with table args: ") -body = socket.http.post { +back = socket.http.post { url = "http://" .. host .. cgiprefix .. "/cat", body = index } -check(body == index) +check(back == index) io.write("testing http redirection: ") request = { @@ -132,6 +167,22 @@ ignore = { } check_request(request, expect, ignore) +io.write("testing proxy with redirection: ") +request = { + url = "http://" .. host .. prefix, + host = proxyh, + port = proxyp +} +expect = { + body = index, + code = 200 +} +ignore = { + status = 1, + headers = 1 +} +check_request(request, expect, ignore) + io.write("testing automatic auth failure: ") request = { @@ -150,7 +201,7 @@ check_request(request, expect, ignore) io.write("testing http redirection failure: ") request = { url = "http://" .. host .. prefix, - stay = 1 + redirect = false } expect = { code = 301 @@ -273,20 +324,6 @@ ignore = { } check_request(request, expect, ignore) -io.write("testing redirect loop: ") -request = { - url = "http://" .. host .. cgiprefix .. "/redirect-loop" -} -expect = { - code = 302 -} -ignore = { - status = 1, - headers = 1, - body = 1 -} -check_request(request, expect, ignore) - io.write("testing wrong scheme: ") request = { url = "wrong://" .. host .. cgiprefix .. "/cat",