aboutsummaryrefslogtreecommitdiff
path: root/test/maxsize_http.lua
blob: 3c0dc746c855f3ef2108da0517877dab694e7edf (plain)
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