httpclient: handle redirects more graceful
[project/luci.git] / libs / httpclient / luasrc / httpclient.lua
index 01ef970..4f95593 100644 (file)
@@ -22,6 +22,7 @@ local http = require "luci.http.protocol"
 local date = require "luci.http.protocol.date"
 
 local type, pairs, ipairs, tonumber = type, pairs, ipairs, tonumber
+local unpack = unpack
 
 module "luci.httpclient"
 
@@ -160,11 +161,15 @@ function request_raw(uri, options)
                options.method = options.method or "POST"
        end
        
+       if type(options.body) == "function" then
+               options.method = options.method or "POST"
+       end
+
        -- Assemble message
        local message = {(options.method or "GET") .. " " .. path .. " " .. protocol}
        
        for k, v in pairs(headers) do
-               if type(v) == "string" then
+               if type(v) == "string" or type(v) == "number" then
                        message[#message+1] = k .. ": " .. v
                elseif type(v) == "table" then
                        for i, j in ipairs(v) do
@@ -194,6 +199,12 @@ function request_raw(uri, options)
        
        if type(options.body) == "string" then
                sock:sendall(options.body)
+       elseif type(options.body) == "function" then
+               local res = {options.body(sock)}
+               if not res[1] then
+                       sock:close()
+                       return unpack(res)
+               end
        end
        
        -- Create source and fetch response
@@ -201,16 +212,20 @@ function request_raw(uri, options)
        local line, code, error = linesrc()
        
        if not line then
+               sock:close()
                return nil, code, error
        end
        
-       local protocol, status, msg = line:match("^(HTTP/[0-9.]+) ([0-9]+) (.*)")
+       local protocol, status, msg = line:match("^([%w./]+) ([0-9]+) (.*)")
        
        if not protocol then
+               sock:close()
                return nil, -3, "invalid response magic: " .. line
        end
        
-       local response = {status = line, headers = {}, code = 0, cookies = {}}
+       local response = {
+               status = line, headers = {}, code = 0, cookies = {}, uri = uri
+       }
        
        line = linesrc()
        while line and line ~= "" do
@@ -228,6 +243,7 @@ function request_raw(uri, options)
        end
        
        if not line then
+               sock:close()
                return nil, -4, "protocol error"
        end
        
@@ -278,15 +294,18 @@ function request_raw(uri, options)
        if response.code and options.depth > 0 then
                if response.code == 301 or response.code == 302 or response.code == 307
                 and response.headers.Location then
-                       local nexturi = response.headers.Location
-                       if not nexturi:find("https?://") then
-                               nexturi = pr .. "://" .. host .. ":" .. port .. nexturi
+                       local nuri = response.headers.Location or response.headers.location
+                       if not nuri then
+                               return nil, -5, "invalid reference"
+                       end
+                       if not nuri:find("https?://") then
+                               nuri = pr .. "://" .. host .. ":" .. port .. nuri
                        end
                        
                        options.depth = options.depth - 1
                        sock:close()
                        
-                       return request_raw(nexturi, options)
+                       return request_raw(nuri, options)
                end
        end
        
@@ -322,4 +341,4 @@ function cookie_create(cookie)
        end
 
        return table.concat(cookiedata, "; ")
-end
\ No newline at end of file
+end