aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2004-03-26 06:05:20 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2004-03-26 06:05:20 +0000
commite5a090b01cd5b490f7331235b7c58c36c05bb7b6 (patch)
tree8f98ae6217650ac0b9d1c04f1ad1d3fb77af3d37 /src
parente77f1792005088f55353c6c85fe9335e60772754 (diff)
downloadluasocket-e5a090b01cd5b490f7331235b7c58c36c05bb7b6.tar.gz
luasocket-e5a090b01cd5b490f7331235b7c58c36c05bb7b6.tar.bz2
luasocket-e5a090b01cd5b490f7331235b7c58c36c05bb7b6.zip
Using socket pumps in http.lua.
Adjusted socket.try.
Diffstat (limited to 'src')
-rw-r--r--src/http.lua138
-rw-r--r--src/mime.lua22
2 files changed, 37 insertions, 123 deletions
diff --git a/src/http.lua b/src/http.lua
index 8b06184..da18aaf 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -51,7 +51,7 @@ local function receive_headers(reqt, respt, tmp)
51 while line ~= "" do 51 while line ~= "" do
52 -- get field-name and value 52 -- get field-name and value
53 _, _, name, value = string.find(line, "^(.-):%s*(.*)") 53 _, _, name, value = string.find(line, "^(.-):%s*(.*)")
54 assert(name and value, "malformed reponse headers") 54 socket.try(name and value, "malformed reponse headers")
55 name = string.lower(name) 55 name = string.lower(name)
56 -- get next line (value might be folded) 56 -- get next line (value might be folded)
57 line = socket.try(sock:receive()) 57 line = socket.try(sock:receive())
@@ -66,119 +66,32 @@ local function receive_headers(reqt, respt, tmp)
66 end 66 end
67end 67end
68 68
69local function abort(cb, err)
70 local go, cb_err = cb(nil, err)
71 error(cb_err or err)
72end
73
74local function hand(cb, chunk)
75 local go, cb_err = cb(chunk)
76 assert(go, cb_err or "aborted by callback")
77end
78
79local function receive_body_bychunks(sock, sink)
80 while 1 do
81 -- get chunk size, skip extention
82 local line, err = sock:receive()
83 if err then abort(sink, err) end
84 local size = tonumber(string.gsub(line, ";.*", ""), 16)
85 if not size then abort(sink, "invalid chunk size") end
86 -- was it the last chunk?
87 if size <= 0 then break end
88 -- get chunk
89 local chunk, err = sock:receive(size)
90 if err then abort(sink, err) end
91 -- pass chunk to callback
92 hand(sink, chunk)
93 -- skip CRLF on end of chunk
94 err = second(sock:receive())
95 if err then abort(sink, err) end
96 end
97 -- let callback know we are done
98 hand(sink, nil)
99 -- servers shouldn't send trailer headers, but who trusts them?
100 local line = socket.try(sock:receive())
101 while line ~= "" do
102 line = socket.try(sock:receive())
103 end
104end
105
106local function receive_body_bylength(sock, length, sink)
107 while length > 0 do
108 local size = math.min(BLOCKSIZE, length)
109 local chunk, err = sock:receive(size)
110 if err then abort(sink, err) end
111 length = length - string.len(chunk)
112 -- see if there was an error
113 hand(sink, chunk)
114 end
115 -- let callback know we are done
116 hand(sink, nil)
117end
118
119local function receive_body_untilclosed(sock, sink)
120 while true do
121 local chunk, err, partial = sock:receive(BLOCKSIZE)
122 -- see if we are done
123 if err == "closed" then
124 hand(sink, partial)
125 break
126 end
127 hand(sink, chunk)
128 -- see if there was an error
129 if err then abort(sink, err) end
130 end
131 -- let callback know we are done
132 hand(sink, nil)
133end
134
135local function receive_body(reqt, respt, tmp) 69local function receive_body(reqt, respt, tmp)
136 local sink = reqt.sink or ltn12.sink.null() 70 local sink = reqt.sink or ltn12.sink.null()
137 local headers = respt.headers 71 local pump = reqt.pump or ltn12.pump
138 local sock = tmp.sock 72 local source
139 local te = headers["transfer-encoding"] 73 local te = respt.headers["transfer-encoding"]
140 if te and te ~= "identity" then 74 if te and te ~= "identity" then
141 -- get by chunked transfer-coding of message body 75 -- get by chunked transfer-coding of message body
142 receive_body_bychunks(sock, sink) 76 source = socket.source("http-chunked", tmp.sock)
143 elseif tonumber(headers["content-length"]) then 77 elseif tonumber(respt.headers["content-length"]) then
144 -- get by content-length 78 -- get by content-length
145 local length = tonumber(headers["content-length"]) 79 local length = tonumber(respt.headers["content-length"])
146 receive_body_bylength(sock, length, sink) 80 source = socket.source("by-length", tmp.sock, length)
147 else 81 else
148 -- get it all until connection closes 82 -- get it all until connection closes
149 receive_body_untilclosed(sock, sink) 83 source = socket.source("until-closed", tmp.sock)
150 end
151end
152
153local function send_body_bychunks(data, source)
154 while true do
155 local chunk, err = source()
156 assert(chunk or not err, err)
157 if not chunk then break end
158 socket.try(data:send(string.format("%X\r\n", string.len(chunk))))
159 socket.try(data:send(chunk, "\r\n"))
160 end
161 socket.try(data:send("0\r\n\r\n"))
162end
163
164local function send_body(data, source)
165 while true do
166 local chunk, err = source()
167 assert(chunk or not err, err)
168 if not chunk then break end
169 socket.try(data:send(chunk))
170 end 84 end
85 socket.try(pump(source, sink))
171end 86end
172 87
173local function send_headers(sock, headers) 88local function send_headers(sock, headers)
174 -- send request headers 89 -- send request headers
175 for i, v in pairs(headers) do 90 for i, v in pairs(headers) do
176 socket.try(sock:send(i .. ": " .. v .. "\r\n")) 91 socket.try(sock:send(i .. ": " .. v .. "\r\n"))
177--io.write(i .. ": " .. v .. "\r\n")
178 end 92 end
179 -- mark end of request headers 93 -- mark end of request headers
180 socket.try(sock:send("\r\n")) 94 socket.try(sock:send("\r\n"))
181--io.write("\r\n")
182end 95end
183 96
184local function should_receive_body(reqt, respt, tmp) 97local function should_receive_body(reqt, respt, tmp)
@@ -211,22 +124,21 @@ end
211 124
212local function send_request(reqt, respt, tmp) 125local function send_request(reqt, respt, tmp)
213 local uri = request_uri(reqt, respt, tmp) 126 local uri = request_uri(reqt, respt, tmp)
214 local sock = tmp.sock
215 local headers = tmp.headers 127 local headers = tmp.headers
128 local pump = reqt.pump or ltn12.pump
216 -- send request line 129 -- send request line
217 socket.try(sock:send((reqt.method or "GET") 130 socket.try(tmp.sock:send((reqt.method or "GET")
218 .. " " .. uri .. " HTTP/1.1\r\n")) 131 .. " " .. uri .. " HTTP/1.1\r\n"))
219--io.write((reqt.method or "GET")
220 --.. " " .. uri .. " HTTP/1.1\r\n")
221 -- send request headers headeres
222 if reqt.source and not headers["content-length"] then 132 if reqt.source and not headers["content-length"] then
223 headers["transfer-encoding"] = "chunked" 133 headers["transfer-encoding"] = "chunked"
224 end 134 end
225 send_headers(sock, headers) 135 send_headers(tmp.sock, headers)
226 -- send request message body, if any 136 -- send request message body, if any
227 if reqt.source then 137 if not reqt.source then return end
228 if headers["content-length"] then send_body(sock, reqt.source) 138 if headers["content-length"] then
229 else send_body_bychunks(sock, reqt.source) end 139 socket.try(pump(reqt.source, socket.sink(tmp.sock)))
140 else
141 socket.try(pump(reqt.source, socket.sink("http-chunked", tmp.sock)))
230 end 142 end
231end 143end
232 144
@@ -235,7 +147,7 @@ local function open(reqt, respt, tmp)
235 local host, port 147 local host, port
236 if proxy then 148 if proxy then
237 local pproxy = socket.url.parse(proxy) 149 local pproxy = socket.url.parse(proxy)
238 assert(pproxy.port and pproxy.host, "invalid proxy") 150 socket.try(pproxy.port and pproxy.host, "invalid proxy")
239 host, port = pproxy.host, pproxy.port 151 host, port = pproxy.host, pproxy.port
240 else 152 else
241 host, port = tmp.parsed.host, tmp.parsed.port 153 host, port = tmp.parsed.host, tmp.parsed.port
@@ -271,9 +183,8 @@ local function parse_url(reqt, respt, tmp)
271 scheme = "http" 183 scheme = "http"
272 }) 184 })
273 -- scheme has to be http 185 -- scheme has to be http
274 if parsed.scheme ~= "http" then 186 socket.try(parsed.scheme == "http",
275 error(string.format("unknown scheme '%s'", parsed.scheme)) 187 string.format("unknown scheme '%s'", parsed.scheme))
276 end
277 -- explicit authentication info overrides that given by the URL 188 -- explicit authentication info overrides that given by the URL
278 parsed.user = reqt.user or parsed.user 189 parsed.user = reqt.user or parsed.user
279 parsed.password = reqt.password or parsed.password 190 parsed.password = reqt.password or parsed.password
@@ -342,6 +253,12 @@ local function redirect(reqt, respt, tmp)
342 if respt.headers then respt.headers.location = redirt.url end 253 if respt.headers then respt.headers.location = redirt.url end
343end 254end
344 255
256local function skip_continue(reqt, respt, tmp)
257 if respt.code == 100 then
258 receive_status(reqt, respt, tmp)
259 end
260end
261
345-- execute a request of through an exception 262-- execute a request of through an exception
346function request_p(reqt, respt, tmp) 263function request_p(reqt, respt, tmp)
347 parse_url(reqt, respt, tmp) 264 parse_url(reqt, respt, tmp)
@@ -349,6 +266,7 @@ function request_p(reqt, respt, tmp)
349 open(reqt, respt, tmp) 266 open(reqt, respt, tmp)
350 send_request(reqt, respt, tmp) 267 send_request(reqt, respt, tmp)
351 receive_status(reqt, respt, tmp) 268 receive_status(reqt, respt, tmp)
269 skip_continue(reqt, respt, tmp)
352 receive_headers(reqt, respt, tmp) 270 receive_headers(reqt, respt, tmp)
353 if should_redirect(reqt, respt, tmp) then 271 if should_redirect(reqt, respt, tmp) then
354 tmp.sock:close() 272 tmp.sock:close()
diff --git a/src/mime.lua b/src/mime.lua
index 8c2a5c0..d263d48 100644
--- a/src/mime.lua
+++ b/src/mime.lua
@@ -11,11 +11,14 @@ decodet = {}
11wrapt = {} 11wrapt = {}
12 12
13-- creates a function that chooses a filter by name from a given table 13-- creates a function that chooses a filter by name from a given table
14local function choose(table) 14function choose(table)
15 return function(name, opt) 15 return function(name, opt1, opt2)
16 if type(name) ~= "string" then
17 name, opt1, opt2 = "default", name, opt1
18 end
16 local f = table[name or "nil"] 19 local f = table[name or "nil"]
17 if not f then error("unknown filter (" .. tostring(name) .. ")", 3) 20 if not f then error("unknown key (" .. tostring(name) .. ")", 3)
18 else return f(opt) end 21 else return f(opt1, opt2) end
19 end 22 end
20end 23end
21 24
@@ -44,6 +47,7 @@ wrapt['text'] = function(length)
44 return ltn12.filter.cycle(wrp, length, length) 47 return ltn12.filter.cycle(wrp, length, length)
45end 48end
46wrapt['base64'] = wrapt['text'] 49wrapt['base64'] = wrapt['text']
50wrapt['default'] = wrapt['text']
47 51
48wrapt['quoted-printable'] = function() 52wrapt['quoted-printable'] = function()
49 return ltn12.filter.cycle(qpwrp, 76, 76) 53 return ltn12.filter.cycle(qpwrp, 76, 76)
@@ -52,15 +56,7 @@ end
52-- function that choose the encoding, decoding or wrap algorithm 56-- function that choose the encoding, decoding or wrap algorithm
53encode = choose(encodet) 57encode = choose(encodet)
54decode = choose(decodet) 58decode = choose(decodet)
55-- it's different because there is a default wrap filter 59wrap = choose(wrapt)
56local cwt = choose(wrapt)
57function wrap(mode_or_length, length)
58 if type(mode_or_length) ~= "string" then
59 length = mode_or_length
60 mode_or_length = "text"
61 end
62 return cwt(mode_or_length, length)
63end
64 60
65-- define the end-of-line normalization filter 61-- define the end-of-line normalization filter
66function normalize(marker) 62function normalize(marker)