Stupid bug in http.lua.

This commit is contained in:
Diego Nehab 2005-06-12 22:02:21 +00:00
parent b22f6f3830
commit 8b114f3bf4
12 changed files with 78 additions and 73 deletions

3
FIX
View File

@ -7,6 +7,7 @@ get rid of a = socket.try() in the manual, except for protected cases.
get rid of "base." kludge get rid of "base." kludge
check all "require("http")" etc in the manual. check all "require("http")" etc in the manual.
make sure sock_gethostname.* only return success if the hp is not null! make sure sock_gethostname.* only return success if the hp is not null!
change 'l' prefix in C libraries to 'l-something'... change 'l' prefix in C libraries to 'c'
don't forget the declarations in luasocket.h and mime.h!!! don't forget the declarations in luasocket.h and mime.h!!!
setpeername was using udp{unconnected} setpeername was using udp{unconnected}
fixed a bug in http.lua that caused some requests to fail

View File

@ -39,7 +39,7 @@ if code == 200 then
if not data then if not data then
print(error or code) print(error or code)
else else
for i,v in data do for i,v in pairs(data) do
io.write(i, ': ', v, '\n') io.write(i, ': ', v, '\n')
end end
end end

View File

@ -27,6 +27,51 @@ PORT = 80
-- user agent field sent in request -- user agent field sent in request
USERAGENT = socket.VERSION USERAGENT = socket.VERSION
-----------------------------------------------------------------------------
-- Extra sources and sinks
-----------------------------------------------------------------------------
socket.sourcet["http-chunked"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function()
-- get chunk size, skip extention
local line, err = sock:receive()
if err then return nil, err end
local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
if not size then return nil, "invalid chunk size" end
-- was it the last chunk?
if size <= 0 then
-- skip trailer headers, if any
local line, err = sock:receive()
while not err and line ~= "" do
line, err = sock:receive()
end
return nil, err
else
-- get chunk and skip terminating CRLF
local chunk, err, part = sock:receive(size)
if chunk then sock:receive() end
return chunk, err
end
end
})
end
socket.sinkt["http-chunked"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function(self, chunk, err)
if not chunk then return sock:send("0\r\n\r\n") end
local size = string.format("%X\r\n", string.len(chunk))
return sock:send(size .. chunk .. "\r\n")
end
})
end
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Low level HTTP API -- Low level HTTP API
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
@ -70,7 +115,7 @@ function metat.__index:sendheaders(headers)
end end
function metat.__index:sendbody(headers, source, step) function metat.__index:sendbody(headers, source, step)
source = source or ltn12.source.empty() source = source or ltn12.source.empty()
step = step or ltn12.pump.step step = step or ltn12.pump.step
-- if we don't know the size in advance, send chunked and hope for the best -- if we don't know the size in advance, send chunked and hope for the best
local mode = "http-chunked" local mode = "http-chunked"
@ -155,7 +200,7 @@ end
local function adjustheaders(headers, host) local function adjustheaders(headers, host)
local lower = {} local lower = {}
-- override with user values -- override with user values
for i,v in (headers or lower) do for i,v in pairs(headers or lower) do
lower[string.lower(i)] = v lower[string.lower(i)] = v
end end
lower["user-agent"] = lower["user-agent"] or USERAGENT lower["user-agent"] = lower["user-agent"] or USERAGENT
@ -175,7 +220,7 @@ local function adjustrequest(reqt)
local nreqt = reqt.url and url.parse(reqt.url, default) or {} local nreqt = reqt.url and url.parse(reqt.url, default) or {}
local t = url.parse(reqt.url, default) local t = url.parse(reqt.url, default)
-- explicit components override url -- explicit components override url
for i,v in reqt do nreqt[i] = reqt[i] end for i,v in pairs(reqt) do nreqt[i] = v end
socket.try(nreqt.host, "invalid host '" .. base.tostring(nreqt.host) .. "'") socket.try(nreqt.host, "invalid host '" .. base.tostring(nreqt.host) .. "'")
-- compute uri if user hasn't overriden -- compute uri if user hasn't overriden
nreqt.uri = reqt.uri or adjusturi(nreqt) nreqt.uri = reqt.uri or adjusturi(nreqt)
@ -238,7 +283,7 @@ function trequest(reqt)
local h = open(reqt.host, reqt.port, reqt.connect) local h = open(reqt.host, reqt.port, reqt.connect)
h:sendrequestline(reqt.method, reqt.uri) h:sendrequestline(reqt.method, reqt.uri)
h:sendheaders(reqt.headers) h:sendheaders(reqt.headers)
h:sendbody(reqt.headers, reqt.source, reqt.step) if reqt.source then h:sendbody(reqt.headers, reqt.source, reqt.step) end
local code, headers, status local code, headers, status
code, status = h:receivestatusline() code, status = h:receivestatusline()
headers = h:receiveheaders() headers = h:receiveheaders()

View File

@ -15,9 +15,9 @@ local mime = require("cmime")
module("mime") module("mime")
-- encode, decode and wrap algorithm tables -- encode, decode and wrap algorithm tables
mime.encodet = {} encodet = {}
mime.decodet = {} decodet = {}
mime.wrapt = {} wrapt = {}
-- creates a function that chooses a filter by name from a given table -- creates a function that chooses a filter by name from a given table
local function choose(table) local function choose(table)
@ -32,21 +32,21 @@ local function choose(table)
end end
-- define the encoding filters -- define the encoding filters
mime.encodet['base64'] = function() encodet['base64'] = function()
return ltn12.filter.cycle(b64, "") return ltn12.filter.cycle(b64, "")
end end
mime.encodet['quoted-printable'] = function(mode) encodet['quoted-printable'] = function(mode)
return ltn12.filter.cycle(qp, "", return ltn12.filter.cycle(qp, "",
(mode == "binary") and "=0D=0A" or "\r\n") (mode == "binary") and "=0D=0A" or "\r\n")
end end
-- define the decoding filters -- define the decoding filters
mime.decodet['base64'] = function() decodet['base64'] = function()
return ltn12.filter.cycle(unb64, "") return ltn12.filter.cycle(unb64, "")
end end
mime.decodet['quoted-printable'] = function() decodet['quoted-printable'] = function()
return ltn12.filter.cycle(unqp, "") return ltn12.filter.cycle(unqp, "")
end end
@ -60,29 +60,29 @@ local function format(chunk)
end end
-- define the line-wrap filters -- define the line-wrap filters
mime.wrapt['text'] = function(length) wrapt['text'] = function(length)
length = length or 76 length = length or 76
return ltn12.filter.cycle(wrp, length, length) return ltn12.filter.cycle(wrp, length, length)
end end
mime.wrapt['base64'] = wrapt['text'] wrapt['base64'] = wrapt['text']
mime.wrapt['default'] = wrapt['text'] wrapt['default'] = wrapt['text']
mime.wrapt['quoted-printable'] = function() wrapt['quoted-printable'] = function()
return ltn12.filter.cycle(qpwrp, 76, 76) return ltn12.filter.cycle(qpwrp, 76, 76)
end end
-- function that choose the encoding, decoding or wrap algorithm -- function that choose the encoding, decoding or wrap algorithm
mime.encode = choose(encodet) encode = choose(encodet)
mime.decode = choose(decodet) decode = choose(decodet)
mime.wrap = choose(wrapt) wrap = choose(wrapt)
-- define the end-of-line normalization filter -- define the end-of-line normalization filter
function mime.normalize(marker) function normalize(marker)
return ltn12.filter.cycle(eol, 0, marker) return ltn12.filter.cycle(eol, 0, marker)
end end
-- high level stuffing filter -- high level stuffing filter
function mime.stuff() function stuff()
return ltn12.filter.cycle(dot, 2) return ltn12.filter.cycle(dot, 2)
end end

View File

@ -124,7 +124,7 @@ static int collect_fd(lua_State *L, int tab, int max_fd,
break; break;
} }
fd = getfd(L); fd = getfd(L);
if (fd > 0) { if (fd >= 0) {
FD_SET(fd, set); FD_SET(fd, set);
if (max_fd < fd) max_fd = fd; if (max_fd < fd) max_fd = fd;
lua_pushnumber(L, fd); lua_pushnumber(L, fd);
@ -150,7 +150,7 @@ static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
break; break;
} }
fd = getfd(L); fd = getfd(L);
if (fd > 0 && dirty(L)) { if (fd >= 0 && dirty(L)) {
lua_pushnumber(L, ++ndirty); lua_pushnumber(L, ++ndirty);
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
lua_settable(L, dtab); lua_settable(L, dtab);

View File

@ -211,7 +211,7 @@ end
-- set defaul headers -- set defaul headers
local function adjust_headers(mesgt) local function adjust_headers(mesgt)
local lower = {} local lower = {}
for i,v in (mesgt.headers or lower) do for i,v in base.pairs(mesgt.headers or lower) do
lower[string.lower(i)] = v lower[string.lower(i)] = v
end end
lower["date"] = lower["date"] or lower["date"] = lower["date"] or

View File

@ -62,19 +62,6 @@ socket.sinkt = {}
socket.BLOCKSIZE = 2048 socket.BLOCKSIZE = 2048
socket.sinkt["http-chunked"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function(self, chunk, err)
if not chunk then return sock:send("0\r\n\r\n") end
local size = string.format("%X\r\n", string.len(chunk))
return sock:send(size .. chunk .. "\r\n")
end
})
end
socket.sinkt["close-when-done"] = function(sock) socket.sinkt["close-when-done"] = function(sock)
return base.setmetatable({ return base.setmetatable({
getfd = function() return sock:getfd() end, getfd = function() return sock:getfd() end,
@ -140,34 +127,6 @@ socket.sourcet["until-closed"] = function(sock)
}) })
end end
socket.sourcet["http-chunked"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function()
-- get chunk size, skip extention
local line, err = sock:receive()
if err then return nil, err end
local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
if not size then return nil, "invalid chunk size" end
-- was it the last chunk?
if size <= 0 then
-- skip trailer headers, if any
local line, err = sock:receive()
while not err and line ~= "" do
line, err = sock:receive()
end
return nil, err
else
-- get chunk and skip terminating CRLF
local chunk, err = sock:receive(size)
if chunk then sock:receive() end
return chunk, err
end
end
})
end
socket.sourcet["default"] = socket.sourcet["until-closed"] socket.sourcet["default"] = socket.sourcet["until-closed"]

View File

@ -119,7 +119,7 @@ end
function parse(url, default) function parse(url, default)
-- initialize default parameters -- initialize default parameters
local parsed = {} local parsed = {}
for i,v in (default or parsed) do parsed[i] = v end for i,v in base.pairs(default or parsed) do parsed[i] = v end
-- empty url is parsed to nil -- empty url is parsed to nil
if not url or url == "" then return nil, "invalid url" end if not url or url == "" then return nil, "invalid url" end
-- remove whitespace -- remove whitespace

View File

@ -1,3 +1,3 @@
local dict = require"socket.dict" local dict = require"socket.dict"
for i,v in dict.get("dict://localhost/d:teste") do print(v) end for i,v in pairs(dict.get("dict://localhost/d:teste")) do print(v) end

View File

@ -32,7 +32,7 @@ index_file = "test/index.html"
index = readfile(index_file) index = readfile(index_file)
local check_result = function(response, expect, ignore) local check_result = function(response, expect, ignore)
for i,v in response do for i,v in pairs(response) do
if not ignore[i] then if not ignore[i] then
if v ~= expect[i] then if v ~= expect[i] then
local f = io.open("err", "w") local f = io.open("err", "w")
@ -42,7 +42,7 @@ local check_result = function(response, expect, ignore)
end end
end end
end end
for i,v in expect do for i,v in pairs(expect) do
if not ignore[i] then if not ignore[i] then
if v ~= response[i] then if v ~= response[i] then
local f = io.open("err", "w") local f = io.open("err", "w")

View File

@ -70,7 +70,7 @@ end
local check_headers = function(sent, got) local check_headers = function(sent, got)
sent = sent or {} sent = sent or {}
got = got or {} got = got or {}
for i,v in sent do for i,v in pairs(sent) do
if not similar(v, got[i]) then fail("header " .. v .. "failed!") end if not similar(v, got[i]) then fail("header " .. v .. "failed!") end
end end
end end

View File

@ -75,7 +75,7 @@ local check_parse_url = function(gaba)
if v ~= parsed[i] then if v ~= parsed[i] then
io.write("parse: In test for '", url, "' expected ", i, " = '", io.write("parse: In test for '", url, "' expected ", i, " = '",
v, "' but got '", tostring(parsed[i]), "'\n") v, "' but got '", tostring(parsed[i]), "'\n")
for i,v in parsed do print(i,v) end for i,v in pairs(parsed) do print(i,v) end
exit() exit()
end end
end end
@ -83,7 +83,7 @@ local check_parse_url = function(gaba)
if v ~= gaba[i] then if v ~= gaba[i] then
io.write("parse: In test for '", url, "' expected ", i, " = '", io.write("parse: In test for '", url, "' expected ", i, " = '",
tostring(gaba[i]), "' but got '", v, "'\n") tostring(gaba[i]), "' but got '", v, "'\n")
for i,v in parsed do print(i,v) end for i,v in pairs(parsed) do print(i,v) end
exit() exit()
end end
end end