diff options
| author | Caleb Maclennan <caleb@alerque.com> | 2026-08-31 11:04:37 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-31 11:04:37 +0300 |
| commit | 01162f05408ac4206be15842ef91048c63c23869 (patch) | |
| tree | 2b7c8a2916cf8083b557a897c7d258e00a9c4fa3 /test/maxsize_http.lua | |
| parent | 5afe174eeffc7f3e3b9ef80b5871237620c68415 (diff) | |
| parent | c84e79f6d1ae735bfa191694ec6a62eb8231166d (diff) | |
| download | luasocket-01162f05408ac4206be15842ef91048c63c23869.tar.gz luasocket-01162f05408ac4206be15842ef91048c63c23869.tar.bz2 luasocket-01162f05408ac4206be15842ef91048c63c23869.zip | |
Merge pull request #467 from lunarmodules/fix/http-size-protect
Fix/http size protect
Diffstat (limited to 'test/maxsize_http.lua')
| -rw-r--r-- | test/maxsize_http.lua | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/test/maxsize_http.lua b/test/maxsize_http.lua new file mode 100644 index 0000000..3c0dc74 --- /dev/null +++ b/test/maxsize_http.lua | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | -- Exercises the maxsize caps added to socket.http's line-based receive() | ||
| 2 | -- calls (see PLAN-RECEIVE-MAXSIZE.md). Self-contained: uses a single | ||
| 3 | -- process with a real TCP loopback connection, so it needs no paired | ||
| 4 | -- server script. | ||
| 5 | local socket = require "socket" | ||
| 6 | local http = require "socket.http" | ||
| 7 | local ltn12 = require "ltn12" | ||
| 8 | |||
| 9 | local host = "127.0.0.1" | ||
| 10 | |||
| 11 | -- connects `open_fn(host, port)` to a freshly bound loopback listener and | ||
| 12 | -- returns the client-side object it produced plus the server-side raw | ||
| 13 | -- socket accepted for that connection. | ||
| 14 | local function new_pair(open_fn) | ||
| 15 | local server = assert(socket.bind(host, 0)) | ||
| 16 | local ip, port = server:getsockname() | ||
| 17 | local client = assert(open_fn(ip, port)) | ||
| 18 | local srv = assert(server:accept()) | ||
| 19 | server:close() | ||
| 20 | return client, srv | ||
| 21 | end | ||
| 22 | |||
| 23 | local failures = 0 | ||
| 24 | |||
| 25 | local function check(ok, msg) | ||
| 26 | if ok then | ||
| 27 | print("PASS: " .. msg) | ||
| 28 | else | ||
| 29 | failures = failures + 1 | ||
| 30 | print("FAIL: " .. msg) | ||
| 31 | end | ||
| 32 | end | ||
| 33 | |||
| 34 | local function http_open(ip, port) | ||
| 35 | return http.open(ip, port, socket.tcp) | ||
| 36 | end | ||
| 37 | |||
| 38 | do -- sanity: normal status line + headers still parse | ||
| 39 | http.MAXHEADERLINE, http.MAXHEADERSIZE = 8192, 65536 | ||
| 40 | local h, srv = new_pair(http_open) | ||
| 41 | srv:send("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") | ||
| 42 | local code = socket.protect(function() return h:receivestatusline() end)() | ||
| 43 | local headers = socket.protect(function() return h:receiveheaders() end)() | ||
| 44 | check(code == 200 and headers and headers["content-length"] == "0", | ||
| 45 | "http: normal status line + headers parse") | ||
| 46 | h:close(); srv:close() | ||
| 47 | end | ||
| 48 | |||
| 49 | do -- status line over MAXHEADERLINE is rejected | ||
| 50 | http.MAXHEADERLINE, http.MAXHEADERSIZE = 16, 1024 | ||
| 51 | local h, srv = new_pair(http_open) | ||
| 52 | srv:send("HTTP/1.1 200 " .. string.rep("x", 40) .. "\r\n") | ||
| 53 | local code, err = socket.protect(function() return h:receivestatusline() end)() | ||
| 54 | check(code == nil and err == "oversized", | ||
| 55 | "http: status line over MAXHEADERLINE -> oversized") | ||
| 56 | h:close(); srv:close() | ||
| 57 | end | ||
| 58 | |||
| 59 | do -- a single header line over MAXHEADERLINE is rejected | ||
| 60 | http.MAXHEADERLINE, http.MAXHEADERSIZE = 32, 1024 | ||
| 61 | local h, srv = new_pair(http_open) | ||
| 62 | srv:send("HTTP/1.1 200 OK\r\n") | ||
| 63 | assert(socket.protect(function() return h:receivestatusline() end)() == 200) | ||
| 64 | srv:send("X-Foo: " .. string.rep("y", 60) .. "\r\n\r\n") | ||
| 65 | local headers, err = socket.protect(function() return h:receiveheaders() end)() | ||
| 66 | check(headers == nil and err == "oversized", | ||
| 67 | "http: single header line over MAXHEADERLINE -> oversized") | ||
| 68 | h:close(); srv:close() | ||
| 69 | end | ||
| 70 | |||
| 71 | do -- each header line individually fits MAXHEADERLINE, but the total exceeds MAXHEADERSIZE | ||
| 72 | http.MAXHEADERLINE, http.MAXHEADERSIZE = 32, 40 | ||
| 73 | local h, srv = new_pair(http_open) | ||
| 74 | srv:send("HTTP/1.1 200 OK\r\n") | ||
| 75 | assert(socket.protect(function() return h:receivestatusline() end)() == 200) | ||
| 76 | -- each header line is ~23 bytes, individually under MAXHEADERLINE(32) | ||
| 77 | srv:send("A: 111111111111111111\r\n") | ||
| 78 | srv:send("B: 222222222222222222\r\n") | ||
| 79 | local headers, err = socket.protect(function() return h:receiveheaders() end)() | ||
| 80 | check(headers == nil and err == "oversized", | ||
| 81 | "http: total headers over MAXHEADERSIZE -> oversized (no single line over MAXHEADERLINE)") | ||
| 82 | h:close(); srv:close() | ||
| 83 | end | ||
| 84 | |||
| 85 | do -- chunk-size line over MAXHEADERLINE is rejected | ||
| 86 | http.MAXHEADERLINE, http.MAXHEADERSIZE = 32, 1024 | ||
| 87 | local h, srv = new_pair(http_open) | ||
| 88 | srv:send("HTTP/1.1 200 OK\r\n") | ||
| 89 | assert(socket.protect(function() return h:receivestatusline() end)() == 200) | ||
| 90 | srv:send("Transfer-Encoding: chunked\r\n\r\n") | ||
| 91 | local headers = assert(socket.protect(function() return h:receiveheaders() end)()) | ||
| 92 | srv:send(string.rep("f", 40) .. "\r\n") -- oversized chunk-size line | ||
| 93 | local t = {} | ||
| 94 | local ok, err = socket.protect(function() | ||
| 95 | return h:receivebody(headers, (ltn12.sink.table(t))) | ||
| 96 | end)() | ||
| 97 | check(ok == nil and err == "oversized", | ||
| 98 | "http: chunk-size line over MAXHEADERLINE -> oversized") | ||
| 99 | h:close(); srv:close() | ||
| 100 | end | ||
| 101 | |||
| 102 | http.MAXHEADERLINE, http.MAXHEADERSIZE = 8192, 65536 | ||
| 103 | |||
| 104 | if failures == 0 then | ||
| 105 | print("All http maxsize tests passed") | ||
| 106 | os.exit(0) | ||
| 107 | else | ||
| 108 | print(failures .. " http maxsize test(s) failed") | ||
| 109 | os.exit(1) | ||
| 110 | end | ||
