-
Notifications
You must be signed in to change notification settings - Fork 169
/
chunked.lua
104 lines (88 loc) · 2.85 KB
/
chunked.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
local httpc = require "resty.resolver.http"
local _M = {
}
local cr_lf = "\r\n"
local function send(socket, data)
if not data or data == '' then
ngx.log(ngx.DEBUG, 'skipping sending nil')
return
end
return socket:send(data)
end
local function print_err(error_code, ...)
ngx.log(ngx.ERR, ...)
return ngx.exit(error_code)
end
-- write_response writes response body reader to sock in the HTTP/1.x server response format,
-- including the status line, headers, body, and optional trailer.
function _M.write_response(sock, res, chunksize)
local bytes, err
chunksize = chunksize or 65536
-- Status line
-- FIXME: should get protocol version from res?
local status = "HTTP/1.1 " .. res.status .. " " .. res.reason .. cr_lf
bytes, err = send(sock, status)
if not bytes then
print_err(503, "chunked_writer: failed to send status line, err: " .. (err or "unknown"))
end
-- Rest of header
for k, v in pairs(res.headers) do
local header = k .. ": " .. v .. cr_lf
bytes, err = send(sock, header)
if not bytes then
print_err(503, "chunked_writer: failed to send header, err: " .. (err or "unknown"))
end
end
-- End-of-header
bytes, err = send(sock, cr_lf)
if not bytes then
print_err(503, "chunked_writer: failed to send end of header, err: " .. (err or "unknown"))
end
-- Write body and trailer
-- TODO: handle trailer
if res.has_body then
local reader = res.body_reader
repeat
local chunk, read_err
chunk, read_err = reader(chunksize)
if read_err then
print_err(503, "chunked_writer: failed to read body, err: " .. (err or "unknown"))
end
if chunk then
bytes, err = send(sock, chunk)
if not bytes then
print_err(503, "chunked_writer: failed to send body, err: " .. (err or "unknown"))
end
end
until not chunk
end
end
-- chunked_reader return a body reader that translates the data read from
-- lua-resty-http client_body_reader to HTTP "chunked" format before returning it
--
-- The chunked reader return nil when the final 0-length chunk is read
function _M.chunked_reader(sock, chunksize)
chunksize = chunksize or 65536
local eof = false
local reader = httpc:get_client_body_reader(chunksize, sock)
if not reader then
return nil
end
return function()
if eof then
return nil
end
local buffer, err = reader()
if err then
return nil, err
end
if buffer then
local chunk = string.format("%x\r\n", #buffer) .. buffer .. cr_lf
return chunk
else
eof = true
return "0\r\n\r\n"
end
end
end
return _M