diff options
| author | Diego Nehab <diego.nehab@gmail.com> | 2019-02-24 21:29:19 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-02-24 21:29:19 -0300 |
| commit | 9b3f7a430454dc9568dfb063fbc324b29c5134d7 (patch) | |
| tree | bd2e57f3df7a04cf02a64d575e8d6f25093e3fd2 | |
| parent | 38865fad3ac949d833bab7a02e8727a2ad336450 (diff) | |
| parent | 2a467001f6dbadf447a79dfbd036f32b6a82ce05 (diff) | |
| download | luasocket-9b3f7a430454dc9568dfb063fbc324b29c5134d7.tar.gz luasocket-9b3f7a430454dc9568dfb063fbc324b29c5134d7.tar.bz2 luasocket-9b3f7a430454dc9568dfb063fbc324b29c5134d7.zip | |
Merge pull request #268 from ewestbrook/prc-multischeme
Scheme-independent connection and redirection
| -rw-r--r-- | src/http.lua | 60 |
1 files changed, 41 insertions, 19 deletions
diff --git a/src/http.lua b/src/http.lua index 19b4dd3..2fa5a26 100644 --- a/src/http.lua +++ b/src/http.lua | |||
| @@ -26,15 +26,24 @@ _M.TIMEOUT = 60 | |||
| 26 | -- user agent field sent in request | 26 | -- user agent field sent in request |
| 27 | _M.USERAGENT = socket._VERSION | 27 | _M.USERAGENT = socket._VERSION |
| 28 | 28 | ||
| 29 | -- supported schemes | 29 | -- supported schemes and their particulars |
| 30 | local SCHEMES = { | 30 | local SCHEMES = { |
| 31 | http = { port = 80 } | 31 | http = { |
| 32 | , https = { port = 443 }} | 32 | port = 80 |
| 33 | , create = function(t) | ||
| 34 | return socket.tcp end } | ||
| 35 | , https = { | ||
| 36 | port = 443 | ||
| 37 | , create = function(t) | ||
| 38 | local https = assert( | ||
| 39 | require("ssl.https"), 'LuaSocket: LuaSec not found') | ||
| 40 | local tcp = assert( | ||
| 41 | https.tcp, 'LuaSocket: Function tcp() not available from LuaSec') | ||
| 42 | return tcp(t) end }} | ||
| 33 | 43 | ||
| 34 | -- default scheme and port for document retrieval | 44 | -- default scheme and port for document retrieval |
| 35 | local SCHEME = 'http' | 45 | local SCHEME = 'http' |
| 36 | local PORT = SCHEMES[SCHEME].port | 46 | local PORT = SCHEMES[SCHEME].port |
| 37 | |||
| 38 | ----------------------------------------------------------------------------- | 47 | ----------------------------------------------------------------------------- |
| 39 | -- Reads MIME headers from a connection, unfolding where needed | 48 | -- Reads MIME headers from a connection, unfolding where needed |
| 40 | ----------------------------------------------------------------------------- | 49 | ----------------------------------------------------------------------------- |
| @@ -115,13 +124,13 @@ local metat = { __index = {} } | |||
| 115 | 124 | ||
| 116 | function _M.open(host, port, create) | 125 | function _M.open(host, port, create) |
| 117 | -- create socket with user connect function, or with default | 126 | -- create socket with user connect function, or with default |
| 118 | local c = socket.try((create or socket.tcp)()) | 127 | local c = socket.try(create()) |
| 119 | local h = base.setmetatable({ c = c }, metat) | 128 | local h = base.setmetatable({ c = c }, metat) |
| 120 | -- create finalized try | 129 | -- create finalized try |
| 121 | h.try = socket.newtry(function() h:close() end) | 130 | h.try = socket.newtry(function() h:close() end) |
| 122 | -- set timeout before connecting | 131 | -- set timeout before connecting |
| 123 | h.try(c:settimeout(_M.TIMEOUT)) | 132 | h.try(c:settimeout(_M.TIMEOUT)) |
| 124 | h.try(c:connect(host, port or PORT)) | 133 | h.try(c:connect(host, port)) |
| 125 | -- here everything worked | 134 | -- here everything worked |
| 126 | return h | 135 | return h |
| 127 | end | 136 | end |
| @@ -221,14 +230,13 @@ end | |||
| 221 | 230 | ||
| 222 | local function adjustheaders(reqt) | 231 | local function adjustheaders(reqt) |
| 223 | -- default headers | 232 | -- default headers |
| 224 | local headhost = reqt.host | 233 | local host = reqt.host |
| 225 | local headport = tostring(reqt.port) | 234 | local port = tostring(reqt.port) |
| 226 | local schemeport = tostring(SCHEMES[reqt.scheme].port) | 235 | if port ~= tostring(SCHEMES[reqt.scheme].port) then |
| 227 | if headport ~= schemeport then | 236 | host = host .. ':' .. port end |
| 228 | headhost = headhost .. ':' .. headport end | ||
| 229 | local lower = { | 237 | local lower = { |
| 230 | ["user-agent"] = _M.USERAGENT, | 238 | ["user-agent"] = _M.USERAGENT, |
| 231 | ["host"] = headhost, | 239 | ["host"] = host, |
| 232 | ["connection"] = "close, TE", | 240 | ["connection"] = "close, TE", |
| 233 | ["te"] = "trailers" | 241 | ["te"] = "trailers" |
| 234 | } | 242 | } |
| @@ -267,8 +275,13 @@ local function adjustrequest(reqt) | |||
| 267 | local nreqt = reqt.url and url.parse(reqt.url, default) or {} | 275 | local nreqt = reqt.url and url.parse(reqt.url, default) or {} |
| 268 | -- explicit components override url | 276 | -- explicit components override url |
| 269 | for i,v in base.pairs(reqt) do nreqt[i] = v end | 277 | for i,v in base.pairs(reqt) do nreqt[i] = v end |
| 270 | if nreqt.port == "" then nreqt.port = PORT end | 278 | -- default to scheme particulars |
| 271 | if not (nreqt.host and nreqt.host ~= "") then | 279 | local schemedefs, host, port, method |
| 280 | = SCHEMES[nreqt.scheme], nreqt.host, nreqt.port, nreqt.method | ||
| 281 | if not nreqt.create then nreqt.create = schemedefs.create(nreqt) end | ||
| 282 | if not (port and port ~= '') then nreqt.port = schemedefs.port end | ||
| 283 | if not (method and method ~= '') then nreqt.method = 'GET' end | ||
| 284 | if not (host and host ~= "") then | ||
| 272 | socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'") | 285 | socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'") |
| 273 | end | 286 | end |
| 274 | -- compute uri if user hasn't overriden | 287 | -- compute uri if user hasn't overriden |
| @@ -285,8 +298,10 @@ local function shouldredirect(reqt, code, headers) | |||
| 285 | if not location then return false end | 298 | if not location then return false end |
| 286 | location = string.gsub(location, "%s", "") | 299 | location = string.gsub(location, "%s", "") |
| 287 | if location == "" then return false end | 300 | if location == "" then return false end |
| 288 | local scheme = string.match(location, "^([%w][%w%+%-%.]*)%:") | 301 | local scheme = url.parse(location).scheme |
| 289 | if scheme and not SCHEMES[scheme] then return false end | 302 | if scheme and (not SCHEMES[scheme]) then return false end |
| 303 | -- avoid https downgrades | ||
| 304 | if ('https' == reqt.scheme) and ('https' ~= scheme) then return false end | ||
| 290 | return (reqt.redirect ~= false) and | 305 | return (reqt.redirect ~= false) and |
| 291 | (code == 301 or code == 302 or code == 303 or code == 307) and | 306 | (code == 301 or code == 302 or code == 303 or code == 307) and |
| 292 | (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") | 307 | (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") |
| @@ -306,10 +321,16 @@ end | |||
| 306 | local trequest, tredirect | 321 | local trequest, tredirect |
| 307 | 322 | ||
| 308 | --[[local]] function tredirect(reqt, location) | 323 | --[[local]] function tredirect(reqt, location) |
| 324 | -- the RFC says the redirect URL has to be absolute, but some | ||
| 325 | -- servers do not respect that | ||
| 326 | local newurl = url.absolute(reqt.url, location) | ||
| 327 | -- if switching schemes, reset port and create function | ||
| 328 | if url.parse(newurl).scheme ~= reqt.scheme then | ||
| 329 | reqt.port = nil | ||
| 330 | reqt.create = nil end | ||
| 331 | -- make new request | ||
| 309 | local result, code, headers, status = trequest { | 332 | local result, code, headers, status = trequest { |
| 310 | -- the RFC says the redirect URL has to be absolute, but some | 333 | url = newurl, |
| 311 | -- servers do not respect that | ||
| 312 | url = url.absolute(reqt.url, location), | ||
| 313 | source = reqt.source, | 334 | source = reqt.source, |
| 314 | sink = reqt.sink, | 335 | sink = reqt.sink, |
| 315 | headers = reqt.headers, | 336 | headers = reqt.headers, |
| @@ -397,4 +418,5 @@ _M.request = socket.protect(function(reqt, body) | |||
| 397 | else return trequest(reqt) end | 418 | else return trequest(reqt) end |
| 398 | end) | 419 | end) |
| 399 | 420 | ||
| 421 | _M.schemes = SCHEMES | ||
| 400 | return _M | 422 | return _M |
