Fix project isolation: Make loadChatHistory respect active project sessions
- Modified loadChatHistory() to check for active project before fetching all sessions - When active project exists, use project.sessions instead of fetching from API - Added detailed console logging to debug session filtering - This prevents ALL sessions from appearing in every project's sidebar Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
150
.venv/lib/python3.11/site-packages/websockets/proxy.py
Normal file
150
.venv/lib/python3.11/site-packages/websockets/proxy.py
Normal file
@@ -0,0 +1,150 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
from .datastructures import Headers
|
||||
from .exceptions import InvalidProxy
|
||||
from .headers import build_authorization_basic, build_host
|
||||
from .http11 import USER_AGENT
|
||||
from .uri import DELIMS, WebSocketURI
|
||||
|
||||
|
||||
__all__ = ["get_proxy", "parse_proxy", "Proxy"]
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Proxy:
|
||||
"""
|
||||
Proxy address.
|
||||
|
||||
Attributes:
|
||||
scheme: ``"socks5h"``, ``"socks5"``, ``"socks4a"``, ``"socks4"``,
|
||||
``"https"``, or ``"http"``.
|
||||
host: Normalized to lower case.
|
||||
port: Always set even if it's the default.
|
||||
username: Available when the proxy address contains `User Information`_.
|
||||
password: Available when the proxy address contains `User Information`_.
|
||||
|
||||
.. _User Information: https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1
|
||||
|
||||
"""
|
||||
|
||||
scheme: str
|
||||
host: str
|
||||
port: int
|
||||
username: str | None = None
|
||||
password: str | None = None
|
||||
|
||||
@property
|
||||
def user_info(self) -> tuple[str, str] | None:
|
||||
if self.username is None:
|
||||
return None
|
||||
assert self.password is not None
|
||||
return (self.username, self.password)
|
||||
|
||||
|
||||
def parse_proxy(proxy: str) -> Proxy:
|
||||
"""
|
||||
Parse and validate a proxy.
|
||||
|
||||
Args:
|
||||
proxy: proxy.
|
||||
|
||||
Returns:
|
||||
Parsed proxy.
|
||||
|
||||
Raises:
|
||||
InvalidProxy: If ``proxy`` isn't a valid proxy.
|
||||
|
||||
"""
|
||||
parsed = urllib.parse.urlparse(proxy)
|
||||
if parsed.scheme not in ["socks5h", "socks5", "socks4a", "socks4", "https", "http"]:
|
||||
raise InvalidProxy(proxy, f"scheme {parsed.scheme} isn't supported")
|
||||
if parsed.hostname is None:
|
||||
raise InvalidProxy(proxy, "hostname isn't provided")
|
||||
if parsed.path not in ["", "/"]:
|
||||
raise InvalidProxy(proxy, "path is meaningless")
|
||||
if parsed.query != "":
|
||||
raise InvalidProxy(proxy, "query is meaningless")
|
||||
if parsed.fragment != "":
|
||||
raise InvalidProxy(proxy, "fragment is meaningless")
|
||||
|
||||
scheme = parsed.scheme
|
||||
host = parsed.hostname
|
||||
port = parsed.port or (443 if parsed.scheme == "https" else 80)
|
||||
username = parsed.username
|
||||
password = parsed.password
|
||||
# urllib.parse.urlparse accepts URLs with a username but without a
|
||||
# password. This doesn't make sense for HTTP Basic Auth credentials.
|
||||
if username is not None and password is None:
|
||||
raise InvalidProxy(proxy, "username provided without password")
|
||||
|
||||
try:
|
||||
proxy.encode("ascii")
|
||||
except UnicodeEncodeError:
|
||||
# Input contains non-ASCII characters.
|
||||
# It must be an IRI. Convert it to a URI.
|
||||
host = host.encode("idna").decode()
|
||||
if username is not None:
|
||||
assert password is not None
|
||||
username = urllib.parse.quote(username, safe=DELIMS)
|
||||
password = urllib.parse.quote(password, safe=DELIMS)
|
||||
|
||||
return Proxy(scheme, host, port, username, password)
|
||||
|
||||
|
||||
def get_proxy(uri: WebSocketURI) -> str | None:
|
||||
"""
|
||||
Return the proxy to use for connecting to the given WebSocket URI, if any.
|
||||
|
||||
"""
|
||||
if urllib.request.proxy_bypass(f"{uri.host}:{uri.port}"):
|
||||
return None
|
||||
|
||||
# According to the _Proxy Usage_ section of RFC 6455, use a SOCKS5 proxy if
|
||||
# available, else favor the proxy for HTTPS connections over the proxy for
|
||||
# HTTP connections.
|
||||
|
||||
# The priority of a proxy for WebSocket connections is unspecified. We give
|
||||
# it the highest priority. This makes it easy to configure a specific proxy
|
||||
# for websockets.
|
||||
|
||||
# getproxies() may return SOCKS proxies as {"socks": "http://host:port"} or
|
||||
# as {"https": "socks5h://host:port"} depending on whether they're declared
|
||||
# in the operating system or in environment variables.
|
||||
|
||||
proxies = urllib.request.getproxies()
|
||||
if uri.secure:
|
||||
schemes = ["wss", "socks", "https"]
|
||||
else:
|
||||
schemes = ["ws", "socks", "https", "http"]
|
||||
|
||||
for scheme in schemes:
|
||||
proxy = proxies.get(scheme)
|
||||
if proxy is not None:
|
||||
if scheme == "socks" and proxy.startswith("http://"):
|
||||
proxy = "socks5h://" + proxy[7:]
|
||||
return proxy
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def prepare_connect_request(
|
||||
proxy: Proxy,
|
||||
ws_uri: WebSocketURI,
|
||||
user_agent_header: str | None = USER_AGENT,
|
||||
) -> bytes:
|
||||
host = build_host(ws_uri.host, ws_uri.port, ws_uri.secure, always_include_port=True)
|
||||
headers = Headers()
|
||||
headers["Host"] = build_host(ws_uri.host, ws_uri.port, ws_uri.secure)
|
||||
if user_agent_header is not None:
|
||||
headers["User-Agent"] = user_agent_header
|
||||
if proxy.username is not None:
|
||||
assert proxy.password is not None # enforced by parse_proxy()
|
||||
headers["Proxy-Authorization"] = build_authorization_basic(
|
||||
proxy.username, proxy.password
|
||||
)
|
||||
# We cannot use the Request class because it supports only GET requests.
|
||||
return f"CONNECT {host} HTTP/1.1\r\n".encode() + headers.serialize()
|
||||
Reference in New Issue
Block a user