diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-06-16 21:56:23 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-06-16 21:56:23 +0000 |
| commit | 574708380f19b15bd19419bfd64ccbe422f2d924 (patch) | |
| tree | deb5030132ca370193d1d64bd57fbcce4c7ce8eb /src | |
| parent | ba2f0b8c6ba7fb3a26fa6d9676ee1aefe6d873cc (diff) | |
| download | luasocket-574708380f19b15bd19419bfd64ccbe422f2d924.tar.gz luasocket-574708380f19b15bd19419bfd64ccbe422f2d924.tar.bz2 luasocket-574708380f19b15bd19419bfd64ccbe422f2d924.zip | |
Simplified HTTP module.
Diffstat (limited to 'src')
| -rw-r--r-- | src/http.lua | 138 | ||||
| -rw-r--r-- | src/url.lua | 2 |
2 files changed, 67 insertions, 73 deletions
diff --git a/src/http.lua b/src/http.lua index 8f3fdb9..e0c4c27 100644 --- a/src/http.lua +++ b/src/http.lua | |||
| @@ -143,117 +143,111 @@ local function adjustheaders(headers, host) | |||
| 143 | return lower | 143 | return lower |
| 144 | end | 144 | end |
| 145 | 145 | ||
| 146 | local default = { | ||
| 147 | host = "", | ||
| 148 | port = PORT, | ||
| 149 | path ="/", | ||
| 150 | scheme = "http" | ||
| 151 | } | ||
| 152 | |||
| 146 | local function adjustrequest(reqt) | 153 | local function adjustrequest(reqt) |
| 147 | -- parse url with default fields | 154 | -- parse url if provided |
| 148 | local parsed = url.parse(reqt.url or "", { | 155 | if reqt.url then |
| 149 | host = "", | 156 | local parsed = url.parse(reqt.url, default) |
| 150 | port = PORT, | 157 | -- explicit components override url |
| 151 | path ="/", | 158 | for i,v in parsed do reqt[i] = reqt[i] or v end |
| 152 | scheme = "http" | 159 | end |
| 153 | }) | 160 | socket.try(reqt.host, "invalid host '" .. tostring(reqt.host) .. "'") |
| 154 | -- explicit info in reqt overrides that given by the URL | 161 | socket.try(reqt.path, "invalid path '" .. tostring(reqt.path) .. "'") |
| 155 | for i,v in reqt do parsed[i] = v end | ||
| 156 | -- compute uri if user hasn't overriden | 162 | -- compute uri if user hasn't overriden |
| 157 | parsed.uri = parsed.uri or uri(parsed) | 163 | reqt.uri = reqt.uri or uri(reqt) |
| 158 | -- adjust headers in request | 164 | -- adjust headers in request |
| 159 | parsed.headers = adjustheaders(parsed.headers, parsed.host) | 165 | reqt.headers = adjustheaders(reqt.headers, reqt.host) |
| 160 | return parsed | 166 | return reqt |
| 161 | end | 167 | end |
| 162 | 168 | ||
| 163 | local function shouldredirect(reqt, respt) | 169 | local function shouldredirect(reqt, code) |
| 164 | return (reqt.redirect ~= false) and | 170 | return (reqt.redirect ~= false) and |
| 165 | (respt.code == 301 or respt.code == 302) and | 171 | (code == 301 or code == 302) and |
| 166 | (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") | 172 | (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") |
| 167 | and (not reqt.nredirects or reqt.nredirects < 5) | 173 | and (not reqt.nredirects or reqt.nredirects < 5) |
| 168 | end | 174 | end |
| 169 | 175 | ||
| 170 | local function shouldauthorize(reqt, respt) | 176 | local function shouldauthorize(reqt, code) |
| 171 | -- if there has been an authorization attempt, it must have failed | 177 | -- if there has been an authorization attempt, it must have failed |
| 172 | if reqt.headers and reqt.headers["authorization"] then return nil end | 178 | if reqt.headers and reqt.headers["authorization"] then return nil end |
| 173 | -- if last attempt didn't fail due to lack of authentication, | 179 | -- if last attempt didn't fail due to lack of authentication, |
| 174 | -- or we don't have authorization information, we can't retry | 180 | -- or we don't have authorization information, we can't retry |
| 175 | return respt.code == 401 and reqt.user and reqt.password | 181 | return code == 401 and reqt.user and reqt.password |
| 176 | end | 182 | end |
| 177 | 183 | ||
| 178 | local function shouldreceivebody(reqt, respt) | 184 | local function shouldreceivebody(reqt, code) |
| 179 | if reqt.method == "HEAD" then return nil end | 185 | if reqt.method == "HEAD" then return nil end |
| 180 | local code = respt.code | ||
| 181 | if code == 204 or code == 304 then return nil end | 186 | if code == 204 or code == 304 then return nil end |
| 182 | if code >= 100 and code < 200 then return nil end | 187 | if code >= 100 and code < 200 then return nil end |
| 183 | return 1 | 188 | return 1 |
| 184 | end | 189 | end |
| 185 | 190 | ||
| 186 | local requestp, authorizep, redirectp | 191 | -- forward declarations |
| 187 | 192 | local trequest, tauthorize, tredirect | |
| 188 | function requestp(reqt) | ||
| 189 | local reqt = adjustrequest(reqt) | ||
| 190 | local respt = {} | ||
| 191 | local con = open(reqt.host, reqt.port) | ||
| 192 | con:sendrequestline(reqt.method, reqt.uri) | ||
| 193 | con:sendheaders(reqt.headers) | ||
| 194 | con:sendbody(reqt.headers, reqt.source, reqt.step) | ||
| 195 | respt.code, respt.status = con:receivestatusline() | ||
| 196 | respt.headers = con:receiveheaders() | ||
| 197 | if shouldredirect(reqt, respt) then | ||
| 198 | con:close() | ||
| 199 | return redirectp(reqt, respt) | ||
| 200 | elseif shouldauthorize(reqt, respt) then | ||
| 201 | con:close() | ||
| 202 | return authorizep(reqt, respt) | ||
| 203 | elseif shouldreceivebody(reqt, respt) then | ||
| 204 | con:receivebody(respt.headers, reqt.sink, reqt.step) | ||
| 205 | end | ||
| 206 | con:close() | ||
| 207 | return respt | ||
| 208 | end | ||
| 209 | 193 | ||
| 210 | function authorizep(reqt, respt) | 194 | function tauthorize(reqt) |
| 211 | local auth = "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password)) | 195 | local auth = "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password)) |
| 212 | reqt.headers["authorization"] = auth | 196 | reqt.headers["authorization"] = auth |
| 213 | return requestp(reqt) | 197 | return trequest(reqt) |
| 214 | end | 198 | end |
| 215 | 199 | ||
| 216 | function redirectp(reqt, respt) | 200 | function tredirect(reqt, headers) |
| 217 | -- we create a new table to get rid of anything we don't | 201 | -- the RFC says the redirect URL has to be absolute, but some |
| 218 | -- absolutely need, including authentication info | 202 | -- servers do not respect that |
| 219 | local redirt = { | 203 | return trequest { |
| 220 | method = reqt.method, | 204 | url = url.absolute(reqt, headers["location"]), |
| 221 | -- the RFC says the redirect URL has to be absolute, but some | ||
| 222 | -- servers do not respect that | ||
| 223 | url = url.absolute(reqt.url, respt.headers["location"]), | ||
| 224 | source = reqt.source, | 205 | source = reqt.source, |
| 225 | sink = reqt.sink, | 206 | sink = reqt.sink, |
| 226 | headers = reqt.headers, | 207 | headers = reqt.headers, |
| 227 | proxy = reqt.proxy, | 208 | proxy = reqt.proxy, |
| 228 | nredirects = (reqt.nredirects or 0) + 1 | 209 | nredirects = (reqt.nredirects or 0) + 1 |
| 229 | } | 210 | } |
| 230 | respt = requestp(redirt) | ||
| 231 | -- we pass the location header as a clue we redirected | ||
| 232 | if respt.headers then respt.headers.location = redirt.url end | ||
| 233 | return respt | ||
| 234 | end | 211 | end |
| 235 | 212 | ||
| 236 | request = socket.protect(requestp) | 213 | function trequest(reqt) |
| 214 | reqt = adjustrequest(reqt) | ||
| 215 | local con = open(reqt.host, reqt.port) | ||
| 216 | con:sendrequestline(reqt.method, reqt.uri) | ||
| 217 | con:sendheaders(reqt.headers) | ||
| 218 | con:sendbody(reqt.headers, reqt.source, reqt.step) | ||
| 219 | local code, headers, status | ||
| 220 | code, status = con:receivestatusline() | ||
| 221 | headers = con:receiveheaders() | ||
| 222 | if shouldredirect(reqt, code) then | ||
| 223 | con:close() | ||
| 224 | return tredirect(reqt, headers) | ||
| 225 | elseif shouldauthorize(reqt, code) then | ||
| 226 | con:close() | ||
| 227 | return tauthorize(reqt) | ||
| 228 | elseif shouldreceivebody(reqt, code) then | ||
| 229 | con:receivebody(headers, reqt.sink, reqt.step) | ||
| 230 | end | ||
| 231 | con:close() | ||
| 232 | return 1, code, headers, status | ||
| 233 | end | ||
| 237 | 234 | ||
| 238 | get = socket.protect(function(u) | 235 | local function srequest(u, body) |
| 239 | local t = {} | 236 | local t = {} |
| 240 | local respt = requestp { | 237 | local reqt = { |
| 241 | url = u, | 238 | url = u, |
| 242 | sink = ltn12.sink.table(t) | 239 | sink = ltn12.sink.table(t) |
| 243 | } | 240 | } |
| 244 | return (table.getn(t) > 0 or nil) and table.concat(t), respt.headers, | 241 | if body then |
| 245 | respt.code | 242 | reqt.source = ltn12.source.string(body) |
| 246 | end) | 243 | reqt.headers = { ["content-length"] = string.len(body) } |
| 244 | reqt.method = "POST" | ||
| 245 | end | ||
| 246 | local code, headers, status = socket.skip(1, trequest(reqt)) | ||
| 247 | return table.concat(t), code, headers, status | ||
| 248 | end | ||
| 247 | 249 | ||
| 248 | post = socket.protect(function(u, body) | 250 | request = socket.protect(function(reqt, body) |
| 249 | local t = {} | 251 | if type(reqt) == "string" then return srequest(reqt, body) |
| 250 | local respt = requestp { | 252 | else return trequest(reqt) end |
| 251 | url = u, | ||
| 252 | method = "POST", | ||
| 253 | source = ltn12.source.string(body), | ||
| 254 | sink = ltn12.sink.table(t), | ||
| 255 | headers = { ["content-length"] = string.len(body) } | ||
| 256 | } | ||
| 257 | return (table.getn(t) > 0 or nil) and table.concat(t), | ||
| 258 | respt.headers, respt.code | ||
| 259 | end) | 253 | end) |
diff --git a/src/url.lua b/src/url.lua index 960a248..ec26e62 100644 --- a/src/url.lua +++ b/src/url.lua | |||
| @@ -190,7 +190,7 @@ end | |||
| 190 | -- corresponding absolute url | 190 | -- corresponding absolute url |
| 191 | ----------------------------------------------------------------------------- | 191 | ----------------------------------------------------------------------------- |
| 192 | function absolute(base_url, relative_url) | 192 | function absolute(base_url, relative_url) |
| 193 | local base = parse(base_url) | 193 | local base = type(base_url) == "table" and base_url or parse(base_url) |
| 194 | local relative = parse(relative_url) | 194 | local relative = parse(relative_url) |
| 195 | if not base then return relative_url | 195 | if not base then return relative_url |
| 196 | elseif not relative then return base_url | 196 | elseif not relative then return base_url |
