local tonumber = tonumber;
local assert = assert;
+local url_parse = require "socket.url".parse;
+local urldecode = require "net.http".urldecode;
+
+local function preprocess_path(path)
+ path = urldecode((path:gsub("//+", "/")));
+ if path:sub(1,1) ~= "/" then
+ path = "/"..path;
+ end
+ local level = 0;
+ for component in path:gmatch("([^/]+)/") do
+ if component == ".." then
+ level = level - 1;
+ elseif component ~= "." then
+ level = level + 1;
+ end
+ if level < 0 then
+ return nil;
+ end
+ end
+ return path;
+end
local httpstream = {};
end
end
end
+ if not first_line then error = true; return error_cb("invalid-status-line"); end
len = tonumber(headers["content-length"]); -- TODO check for invalid len
if client then
-- FIXME handle '100 Continue' response (by skipping it)
responseheaders = headers;
};
else
- -- path normalization
- if path:match("^https?://") then
- headers.host, path = path:match("^https?://([^/]*)(.*)");
+ local parsed_url;
+ if path:byte() == 47 then -- starts with /
+ local _path, _query = path:match("([^?]*).?(.*)");
+ if _query == "" then _query = nil; end
+ parsed_url = { path = _path, query = _query };
+ else
+ parsed_url = url_parse(path);
+ if not(parsed_url and parsed_url.path) then error = true; return error_cb("invalid-url"); end
end
- path = path:gsub("^//+", "/"); -- TODO parse url more
+ path = preprocess_path(parsed_url.path);
+ headers.host = parsed_url.host or headers.host;
len = len or 0;
packet = {
method = method;
+ url = parsed_url;
path = path;
httpversion = httpversion;
headers = headers;
elseif #buf >= len then
packet.body, buf = buf:sub(1, len), buf:sub(len + 1);
state = nil; success_cb(packet);
+ else
+ break;
end
end
end