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 /src/tp.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 'src/tp.lua')
| -rw-r--r-- | src/tp.lua | 18 |
1 files changed, 16 insertions, 2 deletions
| @@ -19,6 +19,10 @@ local _M = socket.tp | |||
| 19 | -- Program constants | 19 | -- Program constants |
| 20 | ----------------------------------------------------------------------------- | 20 | ----------------------------------------------------------------------------- |
| 21 | _M.TIMEOUT = 60 | 21 | _M.TIMEOUT = 60 |
| 22 | -- maximum size of a single reply line | ||
| 23 | _M.MAXLINE = 8192 | ||
| 24 | -- maximum total size of a (possibly multiline) reply | ||
| 25 | _M.MAXREPLY = 65536 | ||
| 22 | 26 | ||
| 23 | ----------------------------------------------------------------------------- | 27 | ----------------------------------------------------------------------------- |
| 24 | -- Implementation | 28 | -- Implementation |
| @@ -26,14 +30,24 @@ _M.TIMEOUT = 60 | |||
| 26 | -- gets server reply (works for SMTP and FTP) | 30 | -- gets server reply (works for SMTP and FTP) |
| 27 | local function get_reply(c) | 31 | local function get_reply(c) |
| 28 | local code, current, sep | 32 | local code, current, sep |
| 29 | local line, err = c:receive() | 33 | -- bounds total bytes read across a multiline reply, on top of the |
| 34 | -- per-line MAXLINE cap, so a peer can't exhaust memory by sending many | ||
| 35 | -- lines that each individually fit under MAXLINE | ||
| 36 | local budget = _M.MAXREPLY | ||
| 37 | local function recvline() | ||
| 38 | if budget <= 0 then return nil, "oversized" end | ||
| 39 | local line, err = c:receive("*l", nil, math.min(budget, _M.MAXLINE)) | ||
| 40 | if line then budget = budget - #line end | ||
| 41 | return line, err | ||
| 42 | end | ||
| 43 | local line, err = recvline() | ||
| 30 | local reply = line | 44 | local reply = line |
| 31 | if err then return nil, err end | 45 | if err then return nil, err end |
| 32 | code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) | 46 | code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) |
| 33 | if not code then return nil, "invalid server reply" end | 47 | if not code then return nil, "invalid server reply" end |
| 34 | if sep == "-" then -- reply is multiline | 48 | if sep == "-" then -- reply is multiline |
| 35 | repeat | 49 | repeat |
| 36 | line, err = c:receive() | 50 | line, err = recvline() |
| 37 | if err then return nil, err end | 51 | if err then return nil, err end |
| 38 | current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) | 52 | current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) |
| 39 | reply = reply .. "\n" .. line | 53 | reply = reply .. "\n" .. line |
