Added proxy support to http.lua

Changed callback.lua module, but need more work.
Added local connect support.
This commit is contained in:
Diego Nehab 2004-01-19 00:24:41 +00:00
parent 3ea9271126
commit 6ac82d50ee
4 changed files with 125 additions and 67 deletions

7
TODO
View File

@ -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 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) in etc, modify the README.etc file and makefile.dist (eol.lua is done)

View File

@ -40,6 +40,7 @@ BLOCKSIZE = 8192
local function try_receiving(sock, pattern) local function try_receiving(sock, pattern)
local data, err = sock:receive(pattern) local data, err = sock:receive(pattern)
if not data then sock:close() end if not data then sock:close() end
--print(data)
return data, err return data, err
end end
@ -53,6 +54,7 @@ end
local function try_sending(sock, ...) local function try_sending(sock, ...)
local sent, err = sock:send(unpack(arg)) local sent, err = sock:send(unpack(arg))
if not sent then sock:close() end if not sent then sock:close() end
--io.write(unpack(arg))
return err return err
end end
@ -425,7 +427,10 @@ local function authorize(reqt, parsed, respt)
method = reqt.method, method = reqt.method,
url = reqt.url, url = reqt.url,
body_cb = reqt.body_cb, 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) return request_cb(autht, respt)
end end
@ -439,11 +444,10 @@ end
-- 1 if we should redirect, nil otherwise -- 1 if we should redirect, nil otherwise
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local function should_redirect(reqt, respt) local function should_redirect(reqt, respt)
local follow = not reqt.stay return (reqt.redirect ~= false) and
follow = follow and (respt.code == 301 or respt.code == 302) (respt.code == 301 or respt.code == 302) and
follow = follow and (reqt.method == "GET" or reqt.method == "HEAD") (reqt.method == "GET" or reqt.method == "HEAD") and
follow = follow and not (reqt.nredirects and reqt.nredirects >= 5) not (reqt.nredirects and reqt.nredirects >= 5)
return follow
end end
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@ -465,7 +469,10 @@ local function redirect(reqt, respt)
-- servers do not respect that -- servers do not respect that
url = socket.url.absolute(reqt.url, respt.headers["location"]), url = socket.url.absolute(reqt.url, respt.headers["location"]),
body_cb = reqt.body_cb, 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) respt = request_cb(redirt, respt)
-- we pass the location header as a clue we tried to redirect -- 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 -- 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 -- Input
-- parsed: parsed URL -- parsed: parsed URL
-- Returns -- Returns
-- uri: request URI for parsed URL -- uri: request URI for parsed URL
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
local function request_uri(parsed) local function request_uri(reqt, parsed)
local uri = "" local url
if parsed.path then uri = uri .. parsed.path end if not reqt.host and not reqt.port then
if parsed.params then uri = uri .. ";" .. parsed.params end url = {
if parsed.query then uri = uri .. "?" .. parsed.query end path = parsed.path,
if parsed.fragment then uri = uri .. "#" .. parsed.fragment end params = parsed.params,
return uri query = parsed.query,
fragment = parsed.fragment
}
else url = parsed end
return socket.url.build(url)
end end
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@ -519,7 +532,7 @@ end
-- user, password: authentication information -- user, password: authentication information
-- headers: request headers to send, or nil if none -- headers: request headers to send, or nil if none
-- body_cb: request message body send-callback, 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: -- respt: a table with the following fields:
-- body_cb: response method body receive-callback -- body_cb: response method body receive-callback
-- Returns -- Returns
@ -552,16 +565,17 @@ function request_cb(reqt, respt)
sock, respt.error = socket.tcp() sock, respt.error = socket.tcp()
if not sock then return respt end if not sock then return respt end
-- set connection timeout so that we do not hang forever -- set connection timeout so that we do not hang forever
sock:settimeout(TIMEOUT) sock:settimeout(reqt.timeout or TIMEOUT)
local ret 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 if not ret then
sock:close() sock:close()
return respt return respt
end end
-- send request message -- send request message
respt.error = send_request(sock, reqt.method, 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 if respt.error then
sock:close() sock:close()
return respt return respt
@ -570,7 +584,7 @@ function request_cb(reqt, respt)
respt.code, respt.status, respt.error = receive_status(sock) respt.code, respt.status, respt.error = receive_status(sock)
if respt.error then return respt end if respt.error then return respt end
-- deal with continue 100 -- 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 if respt.code == 100 then
respt.headers, respt.error = receive_headers(sock, {}) respt.headers, respt.error = receive_headers(sock, {})
if respt.error then return respt end if respt.error then return respt end
@ -612,7 +626,7 @@ end
-- user, password: authentication information -- user, password: authentication information
-- headers: request header fields, or nil if none -- headers: request header fields, or nil if none
-- body: request message body as a string, 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 -- Returns
-- respt: a table with the following fields: -- respt: a table with the following fields:
-- body: response message body, or nil if failed -- body: response message body, or nil if failed
@ -623,9 +637,9 @@ end
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
function request(reqt) function request(reqt)
local respt = {} 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() 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 = request_cb(reqt, respt)
respt.body = concat:getresult() respt.body = concat:getresult()
respt.body_cb = nil respt.body_cb = nil

View File

@ -230,15 +230,15 @@ static int meth_bind(lua_State *L)
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1);
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
unsigned short port = (unsigned short) luaL_checknumber(L, 3); 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); const char *err = inet_trybind(&tcp->sock, address, port, backlog);
if (err) { if (err) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, err); lua_pushstring(L, err);
return 2; return 2;
} }
/* turn master object into a server object */ /* turn master object into a server object if there was a listen */
aux_setclass(L, "tcp{server}", 1); if (backlog > 0) aux_setclass(L, "tcp{server}", 1);
lua_pushnumber(L, 1); lua_pushnumber(L, 1);
return 1; return 1;
} }

View File

@ -3,6 +3,29 @@
-- needs ScriptAlias from /home/c/diego/tec/luasocket/test/cgi -- needs ScriptAlias from /home/c/diego/tec/luasocket/test/cgi
-- to "/luasocket-test-cgi" and "/luasocket-test-cgi/" -- to "/luasocket-test-cgi" and "/luasocket-test-cgi/"
-- needs "AllowOverride AuthConfig" on /home/c/diego/tec/luasocket/test/auth -- 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) local similar = function(s1, s2)
return string.lower(string.gsub(s1 or "", "%s", "")) == return string.lower(string.gsub(s1 or "", "%s", "")) ==
string.lower(string.gsub(s2 or "", "%s", "")) string.lower(string.gsub(s2 or "", "%s", ""))
@ -14,14 +37,6 @@ local fail = function(s)
os.exit() os.exit()
end 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) local check = function (v, e)
if v then print("ok") if v then print("ok")
else fail(e) end else fail(e) end
@ -48,23 +63,12 @@ local check_request = function(request, expect, ignore)
print("ok") print("ok")
end 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: ") io.write("testing request uri correctness: ")
local forth = cgiprefix .. "/request-uri?" .. "this+is+the+query+string" local forth = cgiprefix .. "/request-uri?" .. "this+is+the+query+string"
local back, h, c, e = socket.http.get("http://" .. host .. forth) local back, h, c, e = socket.http.get("http://" .. host .. forth)
if similar(back, forth) then print("ok") back = socket.url.parse(back)
else if similar(back.query, "this+is+the+query+string") then print("ok")
print(h, c, e) else fail() end
fail()
end
io.write("testing query string correctness: ") io.write("testing query string correctness: ")
forth = "this+is+the+query+string" forth = "this+is+the+query+string"
@ -86,7 +90,19 @@ ignore = {
} }
check_request(request, expect, 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: ") io.write("testing post method: ")
-- wanted to test chunked post, but apache doesn't support it... -- wanted to test chunked post, but apache doesn't support it...
@ -107,16 +123,35 @@ ignore = {
} }
check_request(request, expect, 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: ") io.write("testing simple post function: ")
body = socket.http.post("http://" .. host .. cgiprefix .. "/cat", index) back = socket.http.post("http://" .. host .. cgiprefix .. "/cat", index)
check(body == index) check(back == index)
io.write("testing simple post function with table args: ") io.write("testing simple post function with table args: ")
body = socket.http.post { back = socket.http.post {
url = "http://" .. host .. cgiprefix .. "/cat", url = "http://" .. host .. cgiprefix .. "/cat",
body = index body = index
} }
check(body == index) check(back == index)
io.write("testing http redirection: ") io.write("testing http redirection: ")
request = { request = {
@ -132,6 +167,22 @@ ignore = {
} }
check_request(request, expect, 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: ") io.write("testing automatic auth failure: ")
request = { request = {
@ -150,7 +201,7 @@ check_request(request, expect, ignore)
io.write("testing http redirection failure: ") io.write("testing http redirection failure: ")
request = { request = {
url = "http://" .. host .. prefix, url = "http://" .. host .. prefix,
stay = 1 redirect = false
} }
expect = { expect = {
code = 301 code = 301
@ -273,20 +324,6 @@ ignore = {
} }
check_request(request, expect, 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: ") io.write("testing wrong scheme: ")
request = { request = {
url = "wrong://" .. host .. cgiprefix .. "/cat", url = "wrong://" .. host .. cgiprefix .. "/cat",