header bugfix
This commit is contained in:
@@ -33,10 +33,19 @@ def get_impersonate_session():
|
||||
return sess
|
||||
|
||||
# Stream params that have dedicated meaning and must never be treated as headers.
|
||||
STREAM_RESERVED_PARAMS = {'url'}
|
||||
# `referer` is mapped to a real Referer header by collect_passthrough_headers, but
|
||||
# `live` is purely a playback hint and must not leak upstream as a header.
|
||||
STREAM_RESERVED_PARAMS = {'url', 'live'}
|
||||
# Headers that affect the transport layer rather than the resource itself; allowing
|
||||
# these to be forwarded could enable request smuggling or vhost-routing abuse.
|
||||
STREAM_DISALLOWED_HEADER_NAMES = {'host', 'content-length', 'transfer-encoding', 'connection', 'expect'}
|
||||
# Headers curl_cffi sets coherently for the impersonated browser. Forwarding the
|
||||
# client's (or extractor's) own values for these would contradict the spoofed TLS
|
||||
# fingerprint and defeat impersonation, so they are never relayed upstream.
|
||||
STREAM_IMPERSONATION_MANAGED_HEADERS = {
|
||||
'user-agent', 'accept', 'accept-encoding', 'accept-language',
|
||||
'sec-ch-ua', 'sec-ch-ua-mobile', 'sec-ch-ua-platform',
|
||||
}
|
||||
# RFC 7230 token charset for header field-names.
|
||||
HEADER_NAME_RE = re.compile(r"^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$")
|
||||
# Reject control characters (CR/LF/NUL etc.) that could be used for header injection.
|
||||
@@ -430,6 +439,17 @@ def stream_video():
|
||||
headers['Cookie'] = request.headers['Cookie']
|
||||
dbg("forwarding cookies")
|
||||
|
||||
# Relay the per-format headers (e.g. Cookie) the frontend forwarded as
|
||||
# query params so cookie/token-authorized origins serve the media.
|
||||
# Referer is already set above, and impersonation-managed headers are left
|
||||
# to curl_cffi to keep the request coherent with the spoofed fingerprint.
|
||||
for key, value in collect_passthrough_headers(request.args).items():
|
||||
lower = key.lower()
|
||||
if lower == 'referer' or lower in STREAM_IMPERSONATION_MANAGED_HEADERS:
|
||||
continue
|
||||
if value:
|
||||
headers[key] = value
|
||||
|
||||
# Remove keys with None values
|
||||
return {k: v for k, v in headers.items() if v}
|
||||
|
||||
@@ -556,10 +576,27 @@ def stream_video():
|
||||
except LookupError:
|
||||
return body_bytes.decode("utf-8", errors="replace")
|
||||
|
||||
def passthrough_param_suffix():
|
||||
# The relayed headers (e.g. Cookie) the upstream needs for authorization,
|
||||
# encoded as &Name=value so they ride along on every proxied child URL
|
||||
# (variant playlists, segments). Referer is appended separately by each
|
||||
# rewriter; impersonation-managed headers stay with curl_cffi.
|
||||
parts = []
|
||||
for key, value in collect_passthrough_headers(request.args).items():
|
||||
lower = key.lower()
|
||||
if lower == 'referer' or lower in STREAM_IMPERSONATION_MANAGED_HEADERS:
|
||||
continue
|
||||
if not value:
|
||||
continue
|
||||
parts.append(f"&{urllib.parse.quote(key)}={urllib.parse.quote(str(value))}")
|
||||
return ''.join(parts)
|
||||
|
||||
def rewrite_hls_playlist(body_text, base_url, referer):
|
||||
extra = passthrough_param_suffix()
|
||||
|
||||
def proxied_url(target):
|
||||
absolute = urljoin(base_url, target)
|
||||
return f"/api/stream?url={urllib.parse.quote(absolute, safe='')}&referer={urllib.parse.quote(referer, safe='')}"
|
||||
return f"/api/stream?url={urllib.parse.quote(absolute, safe='')}&referer={urllib.parse.quote(referer, safe='')}{extra}"
|
||||
|
||||
lines = body_text.splitlines()
|
||||
rewritten = []
|
||||
@@ -720,9 +757,11 @@ def stream_video():
|
||||
if not video_fmts:
|
||||
return None
|
||||
|
||||
extra = passthrough_param_suffix()
|
||||
|
||||
def proxied(url):
|
||||
return (f"/api/stream?url={urllib.parse.quote(url, safe='')}"
|
||||
f"&referer={urllib.parse.quote(referer, safe='')}")
|
||||
f"&referer={urllib.parse.quote(referer, safe='')}{extra}")
|
||||
|
||||
lines = ['#EXTM3U', '#EXT-X-VERSION:3']
|
||||
|
||||
|
||||
Reference in New Issue
Block a user