net.dns: Make sure argument to math.randomseed does not overflow a 32 bit unsigned...
[prosody.git] / net / http / parser.lua
index fdcb8ebba796b51d5edc6e8e490984a127460b0c..2545b5ac41457b88e345f5a6743650052e43ff40 100644 (file)
@@ -1,6 +1,27 @@
 
 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 = {};
 
@@ -56,6 +77,7 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb)
                                                        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)
@@ -70,15 +92,22 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb)
                                                        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;
@@ -111,6 +140,8 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb)
                                        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