Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions e2e/test_http_proxy_m3u_rewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,36 @@ def test_content_type_with_charset(self, shared_r2h):
finally:
upstream.stop()

def test_m3u_url_redirect_keeps_http_redirect_semantics(self, shared_r2h):
"""A redirect from an M3U URL should rewrite Location, not its HTML body."""
redirect_body = b"<html>redirecting</html>\n"
upstream = MockHTTPUpstream(
routes={
"/archive/index.m3u8": {
"status": 302,
"body": redirect_body,
"headers": {
"Content-Type": "text/html",
"Location": "http://10.0.0.1:8080/final/index.m3u8",
},
},
}
)
upstream.start()
try:
status, hdrs, body = http_get(
"127.0.0.1",
shared_r2h.port,
f"/http/127.0.0.1:{upstream.port}/archive/index.m3u8",
timeout=_TIMEOUT,
)

assert status == 302
assert get_header(hdrs, "Location") == "/http/10.0.0.1:8080/final/index.m3u8"
assert body == redirect_body
finally:
upstream.stop()


# ---------------------------------------------------------------------------
# Complex / realistic playlists
Expand Down
9 changes: 6 additions & 3 deletions src/http_proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -1133,14 +1133,17 @@ static int http_proxy_parse_response_headers(http_proxy_session_t *session) {

session->headers_received = 1;

/* Check if response body needs rewriting (M3U content). URL extension takes
* precedence; fall back to Content-Type only when the URL is not M3U-like.
/* Check if a successful response body needs rewriting (M3U content). URL
* extension takes precedence; fall back to Content-Type only when the URL
* is not M3U-like. Non-2xx responses must retain normal HTTP semantics,
* especially redirect Location rewriting and error response passthrough.
* Skip for HEAD requests — there is no body to rewrite. */
int is_m3u_response = rewrite_is_m3u_url(session->target_path);
if (!is_m3u_response)
is_m3u_response = rewrite_is_m3u_content_type(session->response_content_type);

if (is_m3u_response && strcasecmp(session->method, "HEAD") != 0) {
if (session->response_status_code >= 200 && session->response_status_code < 300 && is_m3u_response &&
strcasecmp(session->method, "HEAD") != 0) {
if (session->transfer_encoding_seen && (!session->response_is_chunked || session->unsupported_transfer_coding)) {
logger(LOG_ERROR, "HTTP Proxy: Unsupported Transfer-Encoding for M3U rewrite");
return -1;
Expand Down
Loading