fix missing headers in video get requests
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from flask import Flask, request, Response, send_from_directory, jsonify
|
||||
import os
|
||||
import re
|
||||
import requests
|
||||
from flask_cors import CORS
|
||||
import urllib.parse
|
||||
@@ -9,6 +10,44 @@ import yt_dlp
|
||||
import io
|
||||
from urllib.parse import urljoin
|
||||
|
||||
# Stream params that have dedicated meaning and must never be treated as headers.
|
||||
STREAM_RESERVED_PARAMS = {'url'}
|
||||
# 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'}
|
||||
# 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.
|
||||
HEADER_VALUE_BAD_CHARS_RE = re.compile(r'[\x00-\x08\x0a-\x1f\x7f]')
|
||||
MAX_HEADER_VALUE_LENGTH = 4096
|
||||
|
||||
|
||||
def collect_passthrough_headers(source):
|
||||
"""Treat any request param other than the reserved ones as an HTTP header to
|
||||
forward to yt-dlp/upstream. Validates names and values to prevent header
|
||||
injection (CRLF splitting) and disallows transport-level headers."""
|
||||
headers = {}
|
||||
if not source:
|
||||
return headers
|
||||
for key in source:
|
||||
if key.lower() in STREAM_RESERVED_PARAMS:
|
||||
continue
|
||||
if key.lower() in STREAM_DISALLOWED_HEADER_NAMES:
|
||||
continue
|
||||
if not HEADER_NAME_RE.match(key):
|
||||
continue
|
||||
value = source.get(key)
|
||||
if value is None:
|
||||
continue
|
||||
value = str(value)
|
||||
if not value or len(value) > MAX_HEADER_VALUE_LENGTH:
|
||||
continue
|
||||
if HEADER_VALUE_BAD_CHARS_RE.search(value):
|
||||
continue
|
||||
header_name = 'Referer' if key.lower() == 'referer' else key
|
||||
headers[header_name] = value
|
||||
return headers
|
||||
|
||||
# Serve frontend static files under `/static` to avoid colliding with API routes
|
||||
app = Flask(__name__, static_folder='../frontend', static_url_path='/static')
|
||||
app.url_map.strict_slashes = False
|
||||
@@ -503,14 +542,11 @@ def stream_video():
|
||||
},
|
||||
}
|
||||
|
||||
referer_url = ""
|
||||
if request.method == 'POST':
|
||||
referer_url = request.json.get('referer')
|
||||
else:
|
||||
referer_url = request.args.get('referer')
|
||||
if len(referer_url) > 0:
|
||||
ydl_opts['http_headers']["Referer"] = referer_url
|
||||
|
||||
passthrough_source = request.json if request.method == 'POST' else request.args
|
||||
passthrough_headers = collect_passthrough_headers(passthrough_source)
|
||||
dbg(f"passthrough_headers={list(passthrough_headers.keys())}")
|
||||
ydl_opts['http_headers'].update(passthrough_headers)
|
||||
|
||||
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
||||
# Extract the info
|
||||
info = ydl.extract_info(video_url, download=False)
|
||||
|
||||
Reference in New Issue
Block a user