diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2005-06-17 04:04:55 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2005-06-17 04:04:55 +0000 |
| commit | 4d455c6206747ca65b14d65f75d34e16450d352b (patch) | |
| tree | 4607fc690526e4d227e5c5148025ffa9ba879843 /src/http.lua | |
| parent | 65c35845c54c7f84b1cf5b0e3d4c7bbdaf1014e3 (diff) | |
| download | luasocket-4d455c6206747ca65b14d65f75d34e16450d352b.tar.gz luasocket-4d455c6206747ca65b14d65f75d34e16450d352b.tar.bz2 luasocket-4d455c6206747ca65b14d65f75d34e16450d352b.zip | |
Using core.so instead of csocket.so and cmime.so.
Diffstat (limited to 'src/http.lua')
| -rw-r--r-- | src/http.lua | 98 |
1 files changed, 55 insertions, 43 deletions
diff --git a/src/http.lua b/src/http.lua index 1a7b101..91c52da 100644 --- a/src/http.lua +++ b/src/http.lua | |||
| @@ -28,9 +28,40 @@ PORT = 80 | |||
| 28 | USERAGENT = socket._VERSION | 28 | USERAGENT = socket._VERSION |
| 29 | 29 | ||
| 30 | ----------------------------------------------------------------------------- | 30 | ----------------------------------------------------------------------------- |
| 31 | -- Reads MIME headers from a connection, unfolding where needed | ||
| 32 | ----------------------------------------------------------------------------- | ||
| 33 | local function receiveheaders(sock, headers) | ||
| 34 | local line, name, value, err | ||
| 35 | headers = headers or {} | ||
| 36 | -- get first line | ||
| 37 | line, err = sock:receive() | ||
| 38 | if err then return nil, err end | ||
| 39 | -- headers go until a blank line is found | ||
| 40 | while line ~= "" do | ||
| 41 | -- get field-name and value | ||
| 42 | name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) | ||
| 43 | if not (name and value) then return nil, "malformed reponse headers" end | ||
| 44 | name = string.lower(name) | ||
| 45 | -- get next line (value might be folded) | ||
| 46 | line, err = sock:receive() | ||
| 47 | if err then return nil, err end | ||
| 48 | -- unfold any folded values | ||
| 49 | while string.find(line, "^%s") do | ||
| 50 | value = value .. line | ||
| 51 | line = sock:receive() | ||
| 52 | if err then return nil, err end | ||
| 53 | end | ||
| 54 | -- save pair in table | ||
| 55 | if headers[name] then headers[name] = headers[name] .. ", " .. value | ||
| 56 | else headers[name] = value end | ||
| 57 | end | ||
| 58 | return headers | ||
| 59 | end | ||
| 60 | |||
| 61 | ----------------------------------------------------------------------------- | ||
| 31 | -- Extra sources and sinks | 62 | -- Extra sources and sinks |
| 32 | ----------------------------------------------------------------------------- | 63 | ----------------------------------------------------------------------------- |
| 33 | socket.sourcet["http-chunked"] = function(sock) | 64 | socket.sourcet["http-chunked"] = function(sock, headers) |
| 34 | return base.setmetatable({ | 65 | return base.setmetatable({ |
| 35 | getfd = function() return sock:getfd() end, | 66 | getfd = function() return sock:getfd() end, |
| 36 | dirty = function() return sock:dirty() end | 67 | dirty = function() return sock:dirty() end |
| @@ -42,18 +73,15 @@ socket.sourcet["http-chunked"] = function(sock) | |||
| 42 | local size = base.tonumber(string.gsub(line, ";.*", ""), 16) | 73 | local size = base.tonumber(string.gsub(line, ";.*", ""), 16) |
| 43 | if not size then return nil, "invalid chunk size" end | 74 | if not size then return nil, "invalid chunk size" end |
| 44 | -- was it the last chunk? | 75 | -- was it the last chunk? |
| 45 | if size <= 0 then | 76 | if size > 0 then |
| 46 | -- skip trailer headers, if any | 77 | -- if not, get chunk and skip terminating CRLF |
| 47 | local line, err = sock:receive() | ||
| 48 | while not err and line ~= "" do | ||
| 49 | line, err = sock:receive() | ||
| 50 | end | ||
| 51 | return nil, err | ||
| 52 | else | ||
| 53 | -- get chunk and skip terminating CRLF | ||
| 54 | local chunk, err, part = sock:receive(size) | 78 | local chunk, err, part = sock:receive(size) |
| 55 | if chunk then sock:receive() end | 79 | if chunk then sock:receive() end |
| 56 | return chunk, err | 80 | return chunk, err |
| 81 | else | ||
| 82 | -- if it was, read trailers into headers table | ||
| 83 | headers, err = receiveheaders(sock, headers) | ||
| 84 | if not headers then return nil, err end | ||
| 57 | end | 85 | end |
| 58 | end | 86 | end |
| 59 | }) | 87 | }) |
| @@ -78,8 +106,8 @@ end | |||
| 78 | local metat = { __index = {} } | 106 | local metat = { __index = {} } |
| 79 | 107 | ||
| 80 | -- default connect function, respecting the timeout | 108 | -- default connect function, respecting the timeout |
| 81 | local function connect(host, port) | 109 | local function connect(host, port, create) |
| 82 | local c, e = socket.tcp() | 110 | local c, e = (create or socket.tcp)() |
| 83 | if not c then return nil, e end | 111 | if not c then return nil, e end |
| 84 | c:settimeout(TIMEOUT) | 112 | c:settimeout(TIMEOUT) |
| 85 | local r, e = c:connect(host, port or PORT) | 113 | local r, e = c:connect(host, port or PORT) |
| @@ -90,9 +118,9 @@ local function connect(host, port) | |||
| 90 | return c | 118 | return c |
| 91 | end | 119 | end |
| 92 | 120 | ||
| 93 | function open(host, port, user) | 121 | function open(host, port, create) |
| 94 | -- create socket with user connect function, or with default | 122 | -- create socket with user connect function, or with default |
| 95 | local c = socket.try((user or connect)(host, port)) | 123 | local c = socket.try(connect(host, port, create)) |
| 96 | -- create our http request object, pointing to the socket | 124 | -- create our http request object, pointing to the socket |
| 97 | local h = base.setmetatable({ c = c }, metat) | 125 | local h = base.setmetatable({ c = c }, metat) |
| 98 | -- make sure the object close gets called on exception | 126 | -- make sure the object close gets called on exception |
| @@ -130,37 +158,16 @@ function metat.__index:receivestatusline() | |||
| 130 | end | 158 | end |
| 131 | 159 | ||
| 132 | function metat.__index:receiveheaders() | 160 | function metat.__index:receiveheaders() |
| 133 | local line, name, value | 161 | return self.try(receiveheaders(self.c)) |
| 134 | local headers = {} | ||
| 135 | -- get first line | ||
| 136 | line = self.try(self.c:receive()) | ||
| 137 | -- headers go until a blank line is found | ||
| 138 | while line ~= "" do | ||
| 139 | -- get field-name and value | ||
| 140 | name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) | ||
| 141 | self.try(name and value, "malformed reponse headers") | ||
| 142 | name = string.lower(name) | ||
| 143 | -- get next line (value might be folded) | ||
| 144 | line = self.try(self.c:receive()) | ||
| 145 | -- unfold any folded values | ||
| 146 | while string.find(line, "^%s") do | ||
| 147 | value = value .. line | ||
| 148 | line = self.try(self.c:receive()) | ||
| 149 | end | ||
| 150 | -- save pair in table | ||
| 151 | if headers[name] then headers[name] = headers[name] .. ", " .. value | ||
| 152 | else headers[name] = value end | ||
| 153 | end | ||
| 154 | return headers | ||
| 155 | end | 162 | end |
| 156 | 163 | ||
| 157 | function metat.__index:receivebody(headers, sink, step) | 164 | function metat.__index:receivebody(headers, sink, step) |
| 158 | sink = sink or ltn12.sink.null() | 165 | sink = sink or ltn12.sink.null() |
| 159 | step = step or ltn12.pump.step | 166 | step = step or ltn12.pump.step |
| 160 | local length = base.tonumber(headers["content-length"]) | 167 | local length = base.tonumber(headers["content-length"]) |
| 161 | local TE = headers["transfer-encoding"] | 168 | local t = headers["transfer-encoding"] -- shortcut |
| 162 | local mode = "default" -- connection close | 169 | local mode = "default" -- connection close |
| 163 | if TE and TE ~= "identity" then mode = "http-chunked" | 170 | if t and t ~= "identity" then mode = "http-chunked" |
| 164 | elseif base.tonumber(headers["content-length"]) then mode = "by-length" end | 171 | elseif base.tonumber(headers["content-length"]) then mode = "by-length" end |
| 165 | return self.try(ltn12.pump.all(socket.source(mode, self.c, length), | 172 | return self.try(ltn12.pump.all(socket.source(mode, self.c, length), |
| 166 | sink, step)) | 173 | sink, step)) |
| @@ -198,16 +205,21 @@ local function adjustproxy(reqt) | |||
| 198 | end | 205 | end |
| 199 | 206 | ||
| 200 | local function adjustheaders(headers, host) | 207 | local function adjustheaders(headers, host) |
| 201 | local lower = {} | 208 | -- default headers |
| 202 | -- override with user values | 209 | local lower = { |
| 210 | ["user-agent"] = USERAGENT, | ||
| 211 | ["host"] = host, | ||
| 212 | ["connection"] = "close, TE", | ||
| 213 | ["te"] = "trailers" | ||
| 214 | } | ||
| 215 | -- override with user headers | ||
| 203 | for i,v in pairs(headers or lower) do | 216 | for i,v in pairs(headers or lower) do |
| 204 | lower[string.lower(i)] = v | 217 | lower[string.lower(i)] = v |
| 205 | end | 218 | end |
| 206 | lower["user-agent"] = lower["user-agent"] or USERAGENT | ||
| 207 | lower["host"] = lower["host"] or host | ||
| 208 | return lower | 219 | return lower |
| 209 | end | 220 | end |
| 210 | 221 | ||
| 222 | -- default url parts | ||
| 211 | local default = { | 223 | local default = { |
| 212 | host = "", | 224 | host = "", |
| 213 | port = PORT, | 225 | port = PORT, |
| @@ -280,7 +292,7 @@ end | |||
| 280 | 292 | ||
| 281 | function trequest(reqt) | 293 | function trequest(reqt) |
| 282 | reqt = adjustrequest(reqt) | 294 | reqt = adjustrequest(reqt) |
| 283 | local h = open(reqt.host, reqt.port, reqt.connect) | 295 | local h = open(reqt.host, reqt.port, reqt.create) |
| 284 | h:sendrequestline(reqt.method, reqt.uri) | 296 | h:sendrequestline(reqt.method, reqt.uri) |
| 285 | h:sendheaders(reqt.headers) | 297 | h:sendheaders(reqt.headers) |
| 286 | if reqt.source then h:sendbody(reqt.headers, reqt.source, reqt.step) end | 298 | if reqt.source then h:sendbody(reqt.headers, reqt.source, reqt.step) end |
