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
105
106
107
108
109
110
|
-- Exercises the maxsize caps added to socket.http's line-based receive()
-- calls (see PLAN-RECEIVE-MAXSIZE.md). Self-contained: uses a single
-- process with a real TCP loopback connection, so it needs no paired
-- server script.
local socket = require "socket"
local http = require "socket.http"
local ltn12 = require "ltn12"
local host = "127.0.0.1"
-- connects `open_fn(host, port)` to a freshly bound loopback listener and
-- returns the client-side object it produced plus the server-side raw
-- socket accepted for that connection.
local function new_pair(open_fn)
local server = assert(socket.bind(host, 0))
local ip, port = server:getsockname()
local client = assert(open_fn(ip, port))
local srv = assert(server:accept())
server:close()
return client, srv
end
local failures = 0
local function check(ok, msg)
if ok then
print("PASS: " .. msg)
else
failures = failures + 1
print("FAIL: " .. msg)
end
end
local function http_open(ip, port)
return http.open(ip, port, socket.tcp)
end
do -- sanity: normal status line + headers still parse
http.MAXHEADERLINE, http.MAXHEADERSIZE = 8192, 65536
local h, srv = new_pair(http_open)
srv:send("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")
local code = socket.protect(function() return h:receivestatusline() end)()
local headers = socket.protect(function() return h:receiveheaders() end)()
check(code == 200 and headers and headers["content-length"] == "0",
"http: normal status line + headers parse")
h:close(); srv:close()
end
do -- status line over MAXHEADERLINE is rejected
http.MAXHEADERLINE, http.MAXHEADERSIZE = 16, 1024
local h, srv = new_pair(http_open)
srv:send("HTTP/1.1 200 " .. string.rep("x", 40) .. "\r\n")
local code, err = socket.protect(function() return h:receivestatusline() end)()
check(code == nil and err == "oversized",
"http: status line over MAXHEADERLINE -> oversized")
h:close(); srv:close()
end
do -- a single header line over MAXHEADERLINE is rejected
http.MAXHEADERLINE, http.MAXHEADERSIZE = 32, 1024
local h, srv = new_pair(http_open)
srv:send("HTTP/1.1 200 OK\r\n")
assert(socket.protect(function() return h:receivestatusline() end)() == 200)
srv:send("X-Foo: " .. string.rep("y", 60) .. "\r\n\r\n")
local headers, err = socket.protect(function() return h:receiveheaders() end)()
check(headers == nil and err == "oversized",
"http: single header line over MAXHEADERLINE -> oversized")
h:close(); srv:close()
end
do -- each header line individually fits MAXHEADERLINE, but the total exceeds MAXHEADERSIZE
http.MAXHEADERLINE, http.MAXHEADERSIZE = 32, 40
local h, srv = new_pair(http_open)
srv:send("HTTP/1.1 200 OK\r\n")
assert(socket.protect(function() return h:receivestatusline() end)() == 200)
-- each header line is ~23 bytes, individually under MAXHEADERLINE(32)
srv:send("A: 111111111111111111\r\n")
srv:send("B: 222222222222222222\r\n")
local headers, err = socket.protect(function() return h:receiveheaders() end)()
check(headers == nil and err == "oversized",
"http: total headers over MAXHEADERSIZE -> oversized (no single line over MAXHEADERLINE)")
h:close(); srv:close()
end
do -- chunk-size line over MAXHEADERLINE is rejected
http.MAXHEADERLINE, http.MAXHEADERSIZE = 32, 1024
local h, srv = new_pair(http_open)
srv:send("HTTP/1.1 200 OK\r\n")
assert(socket.protect(function() return h:receivestatusline() end)() == 200)
srv:send("Transfer-Encoding: chunked\r\n\r\n")
local headers = assert(socket.protect(function() return h:receiveheaders() end)())
srv:send(string.rep("f", 40) .. "\r\n") -- oversized chunk-size line
local t = {}
local ok, err = socket.protect(function()
return h:receivebody(headers, (ltn12.sink.table(t)))
end)()
check(ok == nil and err == "oversized",
"http: chunk-size line over MAXHEADERLINE -> oversized")
h:close(); srv:close()
end
http.MAXHEADERLINE, http.MAXHEADERSIZE = 8192, 65536
if failures == 0 then
print("All http maxsize tests passed")
os.exit(0)
else
print(failures .. " http maxsize test(s) failed")
os.exit(1)
end
|