mirror of
https://github.com/9001/copyparty.git
synced 2026-02-21 01:40:39 +10:00
optimize CL/TE check;
replace the heavyhanded connection:close added in b4fddbc3d
with a comparison of content-length to num bytes consumed
this approach also covers incorrectly configured servers
where the reverseproxy was not detected
also adds explicit TE/CL handling, even though most
(all?) reverseproxies already prevent such issues
also adds explicit sanchk of up2k chunk-receiver,
in case any bugs are ever added there
This commit is contained in:
@@ -374,6 +374,7 @@ class HttpCli(object):
|
||||
|
||||
return False
|
||||
|
||||
self.sr.nb = 0
|
||||
self.conn.hsrv.nreq += 1
|
||||
|
||||
self.ua = self.headers.get("user-agent", "")
|
||||
@@ -383,6 +384,19 @@ class HttpCli(object):
|
||||
self.keepalive = "close" not in zs and (
|
||||
self.http_ver != "HTTP/1.0" or zs == "keep-alive"
|
||||
)
|
||||
|
||||
if (
|
||||
"transfer-encoding" in self.headers
|
||||
and self.headers["transfer-encoding"].lower() != "identity"
|
||||
):
|
||||
self.sr.te = 1
|
||||
if "content-length" in self.headers:
|
||||
# rfc9112:6.2: ignore CL if TE
|
||||
self.keepalive = False
|
||||
self.headers.pop("content-length")
|
||||
t = "suspicious request (has both TE and CL); ignoring CL and disabling keepalive"
|
||||
self.log(t, 3)
|
||||
|
||||
self.host = self.headers.get("host") or ""
|
||||
if not self.host:
|
||||
if self.s.family == socket.AF_UNIX:
|
||||
@@ -396,7 +410,6 @@ class HttpCli(object):
|
||||
if n:
|
||||
zso = self.headers.get(self.args.xff_hdr)
|
||||
if zso:
|
||||
self.keepalive = False
|
||||
if n > 0:
|
||||
n -= 1
|
||||
|
||||
@@ -881,7 +894,11 @@ class HttpCli(object):
|
||||
self.terse_reply(b"", 500)
|
||||
return False
|
||||
|
||||
post = self.mode in ("POST", "PUT") or "content-length" in self.headers
|
||||
post = (
|
||||
self.mode in ("POST", "PUT")
|
||||
or "content-length" in self.headers
|
||||
or self.sr.te
|
||||
)
|
||||
if pex.code >= (300 if post else 400):
|
||||
self.keepalive = False
|
||||
|
||||
@@ -3200,7 +3217,7 @@ class HttpCli(object):
|
||||
t = "your chunk got corrupted somehow (received {} bytes); expected vs received hash:\n{}\n{}"
|
||||
raise Pebkac(400, t.format(post_sz, chash, sha_b64))
|
||||
|
||||
remains -= chunksize
|
||||
remains -= post_sz
|
||||
|
||||
if len(cstart) > 1 and path != os.devnull:
|
||||
t = " & ".join(unicode(x) for x in cstart[1:])
|
||||
@@ -3278,6 +3295,12 @@ class HttpCli(object):
|
||||
|
||||
spd = self._spd(postsize)
|
||||
self.log("%70s thank %r" % (spd, cinf))
|
||||
|
||||
if remains:
|
||||
t = "incorrect content-length from client"
|
||||
self.log("%s; header=%d, remains=%d" % (t, postsize, remains), 3)
|
||||
raise Pebkac(400, t)
|
||||
|
||||
self.reply(b"thank")
|
||||
return True
|
||||
|
||||
|
||||
@@ -222,6 +222,21 @@ class HttpConn(object):
|
||||
if not self.cli.run():
|
||||
return
|
||||
|
||||
if self.sr.te == 1:
|
||||
self.log("closing socket (leftover TE)", "90")
|
||||
return
|
||||
|
||||
if (
|
||||
"content-length" in self.cli.headers
|
||||
and int(self.cli.headers["content-length"]) != self.sr.nb
|
||||
):
|
||||
self.log("closing socket (CL mismatch)", "90")
|
||||
return
|
||||
|
||||
# note: proxies reject PUT sans Content-Length; illegal for HTTP/1.1
|
||||
|
||||
self.sr.nb = self.sr.te = 0
|
||||
|
||||
if self.u2idx:
|
||||
self.hsrv.put_u2idx(str(self.addr), self.u2idx)
|
||||
self.u2idx = None
|
||||
|
||||
@@ -971,6 +971,7 @@ class _Unrecv(object):
|
||||
self.log = log
|
||||
self.buf: bytes = b""
|
||||
self.nb = 0
|
||||
self.te = 0
|
||||
|
||||
def recv(self, nbytes: int, spins: int = 1) -> bytes:
|
||||
if self.buf:
|
||||
@@ -3008,6 +3009,7 @@ def read_socket_chunked(
|
||||
if chunklen == 0:
|
||||
x = sr.recv_ex(2, False)
|
||||
if x == b"\r\n":
|
||||
sr.te = 2
|
||||
return
|
||||
|
||||
t = "protocol error after final chunk: want b'\\r\\n', got {!r}"
|
||||
|
||||
Reference in New Issue
Block a user