mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-06-10 03:02:09 +00:00
fix(session): proxy auth on http targets and string params support
Drop the manually-set Proxy-Authorization header in the Service base class. It was malformed (base64 of user:pass with no "Basic" scheme) and redundant: both rnet (Proxy.all) and requests authenticate from the credentials embedded in the proxy URL. The broken header was tunnelled harmlessly on HTTPS (CONNECT) but handed to the proxy on plaintext-http forward requests, causing HTTP 407 (e.g. http MPD/segment URLs behind an authenticated geofence proxy). Also make RnetSession._build_url accept the same params shapes as requests (mapping, sequence of pairs, or a pre-built str/bytes query). urlencode() previously raised TypeError on a string params value.
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
import base64
|
|
||||||
import logging
|
import logging
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from collections.abc import Callable, Generator
|
from collections.abc import Callable, Generator
|
||||||
@@ -213,15 +212,10 @@ class Service(metaclass=ABCMeta):
|
|||||||
|
|
||||||
if proxy:
|
if proxy:
|
||||||
self.session.proxies.update({"all": proxy})
|
self.session.proxies.update({"all": proxy})
|
||||||
proxy_parse = urlparse(proxy)
|
# Don't set Proxy-Authorization manually: both rnet (Proxy.all) and
|
||||||
if proxy_parse.username and proxy_parse.password:
|
# requests authenticate from the credentials embedded in the proxy URL.
|
||||||
self.session.headers.update(
|
# A manual header here was malformed (no "Basic " scheme) and broke
|
||||||
{
|
# plaintext-http forward-proxy requests with HTTP 407.
|
||||||
"Proxy-Authorization": base64.b64encode(
|
|
||||||
f"{proxy_parse.username}:{proxy_parse.password}".encode("utf8")
|
|
||||||
).decode()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
# Always verify proxy IP - proxies can change exit nodes
|
# Always verify proxy IP - proxies can change exit nodes
|
||||||
try:
|
try:
|
||||||
proxy_ip_info = get_ip_info(self.session)
|
proxy_ip_info = get_ip_info(self.session)
|
||||||
|
|||||||
@@ -523,15 +523,24 @@ class RnetSession:
|
|||||||
self.cookies._flush_to_client()
|
self.cookies._flush_to_client()
|
||||||
return self._client
|
return self._client
|
||||||
|
|
||||||
def _build_url(self, url: str, params: Optional[dict] = None) -> str:
|
def _build_url(self, url: str, params: Optional[Any] = None) -> str:
|
||||||
"""URL-encode params dict into the URL (rnet ignores params kwarg)."""
|
"""Encode params into the URL (rnet ignores the params kwarg).
|
||||||
|
|
||||||
|
Accepts the same shapes as requests: a mapping, a sequence of pairs, or a
|
||||||
|
pre-built query string/bytes. A string is appended verbatim (already encoded);
|
||||||
|
urlencode() would raise TypeError on it.
|
||||||
|
"""
|
||||||
if not params:
|
if not params:
|
||||||
return url
|
return url
|
||||||
|
if isinstance(params, bytes):
|
||||||
|
extra = params.decode("utf-8")
|
||||||
|
elif isinstance(params, str):
|
||||||
|
extra = params
|
||||||
|
else:
|
||||||
|
extra = urlencode(params, doseq=True)
|
||||||
parsed = urlparse(url)
|
parsed = urlparse(url)
|
||||||
separator = "&" if parsed.query else ""
|
separator = "&" if parsed.query else ""
|
||||||
query = (
|
query = parsed.query + separator + extra if parsed.query else extra
|
||||||
parsed.query + separator + urlencode(params, doseq=True) if parsed.query else urlencode(params, doseq=True)
|
|
||||||
)
|
|
||||||
return urlunparse(parsed._replace(query=query))
|
return urlunparse(parsed._replace(query=query))
|
||||||
|
|
||||||
def get_sleep_time(self, response: Optional[RnetResponse], attempt: int) -> Optional[float]:
|
def get_sleep_time(self, response: Optional[RnetResponse], attempt: int) -> Optional[float]:
|
||||||
|
|||||||
Reference in New Issue
Block a user