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
|
return False
|
||||||
|
|
||||||
|
self.sr.nb = 0
|
||||||
self.conn.hsrv.nreq += 1
|
self.conn.hsrv.nreq += 1
|
||||||
|
|
||||||
self.ua = self.headers.get("user-agent", "")
|
self.ua = self.headers.get("user-agent", "")
|
||||||
@@ -383,6 +384,19 @@ class HttpCli(object):
|
|||||||
self.keepalive = "close" not in zs and (
|
self.keepalive = "close" not in zs and (
|
||||||
self.http_ver != "HTTP/1.0" or zs == "keep-alive"
|
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 ""
|
self.host = self.headers.get("host") or ""
|
||||||
if not self.host:
|
if not self.host:
|
||||||
if self.s.family == socket.AF_UNIX:
|
if self.s.family == socket.AF_UNIX:
|
||||||
@@ -396,7 +410,6 @@ class HttpCli(object):
|
|||||||
if n:
|
if n:
|
||||||
zso = self.headers.get(self.args.xff_hdr)
|
zso = self.headers.get(self.args.xff_hdr)
|
||||||
if zso:
|
if zso:
|
||||||
self.keepalive = False
|
|
||||||
if n > 0:
|
if n > 0:
|
||||||
n -= 1
|
n -= 1
|
||||||
|
|
||||||
@@ -881,7 +894,11 @@ class HttpCli(object):
|
|||||||
self.terse_reply(b"", 500)
|
self.terse_reply(b"", 500)
|
||||||
return False
|
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):
|
if pex.code >= (300 if post else 400):
|
||||||
self.keepalive = False
|
self.keepalive = False
|
||||||
|
|
||||||
@@ -3200,7 +3217,7 @@ class HttpCli(object):
|
|||||||
t = "your chunk got corrupted somehow (received {} bytes); expected vs received hash:\n{}\n{}"
|
t = "your chunk got corrupted somehow (received {} bytes); expected vs received hash:\n{}\n{}"
|
||||||
raise Pebkac(400, t.format(post_sz, chash, sha_b64))
|
raise Pebkac(400, t.format(post_sz, chash, sha_b64))
|
||||||
|
|
||||||
remains -= chunksize
|
remains -= post_sz
|
||||||
|
|
||||||
if len(cstart) > 1 and path != os.devnull:
|
if len(cstart) > 1 and path != os.devnull:
|
||||||
t = " & ".join(unicode(x) for x in cstart[1:])
|
t = " & ".join(unicode(x) for x in cstart[1:])
|
||||||
@@ -3278,6 +3295,12 @@ class HttpCli(object):
|
|||||||
|
|
||||||
spd = self._spd(postsize)
|
spd = self._spd(postsize)
|
||||||
self.log("%70s thank %r" % (spd, cinf))
|
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")
|
self.reply(b"thank")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -222,6 +222,21 @@ class HttpConn(object):
|
|||||||
if not self.cli.run():
|
if not self.cli.run():
|
||||||
return
|
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:
|
if self.u2idx:
|
||||||
self.hsrv.put_u2idx(str(self.addr), self.u2idx)
|
self.hsrv.put_u2idx(str(self.addr), self.u2idx)
|
||||||
self.u2idx = None
|
self.u2idx = None
|
||||||
|
|||||||
@@ -971,6 +971,7 @@ class _Unrecv(object):
|
|||||||
self.log = log
|
self.log = log
|
||||||
self.buf: bytes = b""
|
self.buf: bytes = b""
|
||||||
self.nb = 0
|
self.nb = 0
|
||||||
|
self.te = 0
|
||||||
|
|
||||||
def recv(self, nbytes: int, spins: int = 1) -> bytes:
|
def recv(self, nbytes: int, spins: int = 1) -> bytes:
|
||||||
if self.buf:
|
if self.buf:
|
||||||
@@ -3008,6 +3009,7 @@ def read_socket_chunked(
|
|||||||
if chunklen == 0:
|
if chunklen == 0:
|
||||||
x = sr.recv_ex(2, False)
|
x = sr.recv_ex(2, False)
|
||||||
if x == b"\r\n":
|
if x == b"\r\n":
|
||||||
|
sr.te = 2
|
||||||
return
|
return
|
||||||
|
|
||||||
t = "protocol error after final chunk: want b'\\r\\n', got {!r}"
|
t = "protocol error after final chunk: want b'\\r\\n', got {!r}"
|
||||||
|
|||||||
Reference in New Issue
Block a user