Files
Android-pyApi/android_pyapi/java/net.py
T
shuiyu1123 bfe27fdc08 feat: Android-pyApi v1.0 - 全面翻译 Android SDK API 为 Python
52 个模块覆盖 Android + Java + org.json 标准库
2026-06-24 11:16:16 +00:00

1582 lines
47 KiB
Python

"""
Java net standard library APIs implemented in Python.
java.net package - URL, Socket, HTTP connection, and networking classes.
"""
from .._core import Stub, AndroidOnlyError, HAS_REQUESTS, HAS_HTTPX
from .io import IOException
import os as _os
import socket as _socket
import struct as _struct
import threading as _threading
from urllib.parse import (
urlparse as _urlparse,
urlunparse as _urlunparse,
quote as _quote,
unquote as _unquote,
)
from datetime import datetime as _datetime
from collections import OrderedDict as _OrderedDict
__all__ = [
"URL", "URLConnection", "HttpURLConnection",
"InetAddress", "InetSocketAddress",
"Socket", "ServerSocket", "DatagramSocket", "DatagramPacket",
"Proxy", "ProxySelector", "Authenticator", "PasswordAuthentication",
"NetworkInterface", "URI",
"CookieHandler", "CookieManager", "HttpCookie",
"URLDecoder", "URLEncoder",
"SocketException", "ConnectException", "BindException",
"NoRouteToHostException", "PortUnreachableException",
"ProtocolException", "SocketTimeoutException",
"MalformedURLException", "UnknownHostException", "UnknownServiceException",
]
# ============================================================
# Exception classes
# ============================================================
class SocketException(IOException):
pass
class ConnectException(SocketException):
pass
class BindException(SocketException):
pass
class NoRouteToHostException(SocketException):
pass
class PortUnreachableException(SocketException):
pass
class ProtocolException(IOException):
pass
class SocketTimeoutException(IOException):
pass
class MalformedURLException(IOException):
pass
class UnknownHostException(IOException):
pass
class UnknownServiceException(IOException):
pass
# ============================================================
# InetAddress
# ============================================================
class InetAddress(Stub):
def __init__(self, host, addr):
super().__init__()
self._host = host
self._addr = addr # bytes, 4 or 16
@staticmethod
def getByName(host):
try:
addr = _socket.getaddrinfo(host, None, family=_socket.AF_UNSPEC)
if addr:
raw = addr[0][4][0]
return InetAddress(host, _socket.inet_pton(_socket.AF_INET, raw) if "." in raw else _socket.inet_pton(_socket.AF_INET6, raw))
except Exception:
raise UnknownHostException(host)
@staticmethod
def getAllByName(host):
try:
addrs = _socket.getaddrinfo(host, None, family=_socket.AF_UNSPEC)
results = []
seen = set()
for a in addrs:
raw = a[4][0]
if raw not in seen:
seen.add(raw)
if "." in raw:
results.append(InetAddress(host, _socket.inet_pton(_socket.AF_INET, raw)))
else:
results.append(InetAddress(host, _socket.inet_pton(_socket.AF_INET6, raw)))
return results
except Exception:
raise UnknownHostException(host)
@staticmethod
def getLocalHost():
hostname = _socket.gethostname()
return InetAddress.getByName(hostname)
@staticmethod
def getLoopbackAddress():
return InetAddress("localhost", b"\x7f\x00\x00\x01")
@staticmethod
def getByAddress(host, addr):
return InetAddress(host, addr)
def getHostName(self):
return self._host
def getHostAddress(self):
if len(self._addr) == 4:
return _socket.inet_ntoa(self._addr)
return _socket.inet_ntop(_socket.AF_INET6, self._addr)
def getCanonicalHostName(self):
try:
name, _, _ = _socket.gethostbyaddr(self.getHostAddress())
return name
except Exception:
return self._host
def isReachable(self, timeout=5000):
try:
s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
s.settimeout(timeout / 1000.0)
result = s.connect_ex((self.getHostAddress(), 7))
s.close()
return result == 0
except Exception:
return False
def isLoopbackAddress(self):
if len(self._addr) == 4:
return self._addr[0] == 127
return self._addr == b"\x00" * 15 + b"\x01"
def isLinkLocalAddress(self):
if len(self._addr) == 4:
return self._addr[0] == 169 and self._addr[1] == 254
return (self._addr[0] & 0xFF) == 0xFE and (self._addr[1] & 0xC0) == 0x80
def isSiteLocalAddress(self):
if len(self._addr) == 4:
b0 = self._addr[0]
return b0 == 10 or (b0 == 172 and 16 <= self._addr[1] <= 31) or (b0 == 192 and self._addr[1] == 168)
return False
def isMCGlobal(self):
if len(self._addr) == 4:
return 224 <= self._addr[0] <= 239 and self._addr[0] != 224 and self._addr[0] != 239
return (self._addr[0] & 0xFF) == 0xFF and (self._addr[1] & 0x0F) == 0x0E and (self._addr[2] & 0x20) == 0
def isMCLinkLocal(self):
if len(self._addr) == 4:
return self._addr[0] == 224 and self._addr[1] == 0 and self._addr[2] == 0
return (self._addr[0] & 0xFF) == 0xFF and (self._addr[1] & 0x0F) == 0x02
def isMCNodeLocal(self):
if len(self._addr) == 4:
return self._addr[0] == 224 and self._addr[1] == 0 and self._addr[2] == 0 and self._addr[3] == 1
return (self._addr[0] & 0xFF) == 0xFF and (self._addr[1] & 0x0F) == 0x01
def isMCOrgLocal(self):
if len(self._addr) == 4:
return self._addr[0] == 239 and 192 <= self._addr[1] <= 195
return (self._addr[0] & 0xFF) == 0xFF and (self._addr[1] & 0x0F) == 0x08
def isMCSiteLocal(self):
if len(self._addr) == 4:
return self._addr[0] == 239 and 255 <= self._addr[1] <= 255
return (self._addr[0] & 0xFF) == 0xFF and (self._addr[1] & 0x0F) == 0x05
def getAddress(self):
return self._addr
def toString(self):
return f"{self._host}/{self.getHostAddress()}"
def equals(self, other):
if isinstance(other, InetAddress):
return self._addr == other._addr
return False
def hashCode(self):
return hash(bytes(self._addr)) & 0x7FFFFFFF
# ============================================================
# InetSocketAddress
# ============================================================
class InetSocketAddress(Stub):
def __init__(self, *args):
super().__init__()
if len(args) == 2 and isinstance(args[0], int):
self._addr = None
self._port = args[0] if isinstance(args[0], int) else args[1]
elif len(args) == 2:
hostname, port = args
self._addr = InetAddress.getByName(hostname) if isinstance(hostname, str) else hostname
self._port = port
elif len(args) == 1 and isinstance(args[0], int):
self._addr = None
self._port = args[0]
def getAddress(self):
return self._addr
def getPort(self):
return self._port
def getHostName(self):
return self._addr.getHostName() if self._addr else None
def getHostString(self):
return self.getHostName()
def isUnresolved(self):
return self._addr is None
def toString(self):
return f"{self.getHostName()}:{self._port}"
def equals(self, other):
if isinstance(other, InetSocketAddress):
return self._port == other._port and self._addr == other._addr
return False
def hashCode(self):
return hash((self._port, self._addr)) & 0x7FFFFFFF
# ============================================================
# URI
# ============================================================
class URI(Stub):
def __init__(self, *args):
super().__init__()
if len(args) == 1:
self._uri = args[0]
parsed = _urlparse(self._uri)
self._scheme = parsed.scheme
self._host = parsed.hostname
self._port = parsed.port
self._path = parsed.path
self._query = parsed.query
self._fragment = parsed.fragment
self._user_info = parsed.username
self._authority = parsed.netloc
elif len(args) == 5:
self._scheme = args[0]
self._authority = args[1] or ""
self._path = args[2] or ""
self._query = args[3] or ""
self._fragment = args[4] or ""
parsed = _urlparse(f"{self._scheme}://{self._authority}{self._path}")
self._host = parsed.hostname
self._port = parsed.port
self._user_info = parsed.username
self._uri = f"{self._scheme}://{self._authority}{self._path}"
if self._query:
self._uri += "?" + self._query
if self._fragment:
self._uri += "#" + self._fragment
else:
raise ValueError("URI constructor requires 1 or 5 arguments")
def getScheme(self):
return self._scheme
def getHost(self):
return self._host
def getPort(self):
return self._port if self._port else -1
def getPath(self):
return self._path
def getQuery(self):
return self._query
def getFragment(self):
return self._fragment
def getAuthority(self):
return self._authority
def getRawAuthority(self):
return self._authority
def getRawFragment(self):
return self._fragment
def getRawPath(self):
return self._path
def getRawQuery(self):
return self._query
def getRawSchemeSpecificPart(self):
return f"//{self._authority}{self._path}"
def getRawUserInfo(self):
return self._user_info or ""
def getSchemeSpecificPart(self):
return self.getRawSchemeSpecificPart()
def getUserInfo(self):
return self._user_info or ""
def isAbsolute(self):
return bool(self._scheme)
def isOpaque(self):
return not self._path and not self._authority and self._scheme
def normalize(self):
import posixpath
normalized = posixpath.normpath(self._path)
return URI(f"{self._scheme}://{self._authority}{normalized}")
def resolve(self, uri_or_str):
if isinstance(uri_or_str, URI):
other = uri_or_str
else:
other = URI(uri_or_str)
if other.isAbsolute():
return other
base_path = self._path or "/"
if base_path.endswith("/"):
new_path = base_path + other._path
else:
new_path = "/".join(base_path.rsplit("/", 1)[:-1] + [other._path]) if other._path else base_path
return URI(f"{self._scheme}://{self._authority}{new_path}")
def relativize(self, other):
if self._path and other._path and other._path.startswith(self._path):
rel = other._path[len(self._path):]
if rel.startswith("/"):
rel = rel[1:]
return URI(rel)
return other
def toASCIIString(self):
return _quote(self._uri, safe=":/?#[]@!$&'()*+,;=-._~")
def toString(self):
return self._uri
def toURL(self):
return URL(self._uri)
def compareTo(self, other):
return -1 if self._uri < other._uri else (1 if self._uri > other._uri else 0)
def equals(self, other):
if isinstance(other, URI):
return self._uri == other._uri
return False
def hashCode(self):
return hash(self._uri) & 0x7FFFFFFF
def parseServerAuthority(self):
return self
# ============================================================
# URL
# ============================================================
class URL(Stub):
def __init__(self, *args):
super().__init__()
if len(args) == 1:
spec = args[0]
parsed = _urlparse(str(spec))
self._protocol = parsed.scheme
self._host = parsed.hostname or ""
self._port = parsed.port
self._path = parsed.path or ""
self._file = parsed.path or ""
if parsed.query:
self._file += "?" + parsed.query
self._query = parsed.query or ""
self._ref = parsed.fragment or ""
self._authority = parsed.netloc or ""
self._user_info = parsed.username or ""
self._url_str = str(spec)
elif len(args) == 4:
protocol, host, port, file = args
self._protocol = protocol or ""
self._host = host or ""
self._port = port
self._path = file or ""
self._file = file or ""
self._query = ""
self._ref = ""
self._authority = f"{host}:{port}" if port and port > 0 else host
self._user_info = ""
parts = [file or ""]
self._url_str = f"{protocol}://{self._authority}{file}"
def getProtocol(self):
return self._protocol
def getHost(self):
return self._host
def getPort(self):
return self._port if self._port else -1
def getDefaultPort(self):
defaults = {
"http": 80, "https": 443, "ftp": 21, "smtp": 25,
"ssh": 22, "telnet": 23, "ldap": 389,
}
return defaults.get(self._protocol, -1)
def getPath(self):
return self._path
def getFile(self):
return self._file
def getQuery(self):
return self._query
def getRef(self):
return self._ref
def getAuthority(self):
return self._authority
def getUserInfo(self):
return self._user_info
def getContent(self, classes=None):
return self.openConnection().getContent(classes)
def openConnection(self, proxy=None):
return HttpURLConnection(self._url_str, proxy)
def openStream(self):
return self.openConnection().getInputStream()
def sameFile(self, other):
return (self._protocol == other._protocol and self._host == other._host
and self._port == other._port and self._path == other._path)
def toExternalForm(self):
return self._url_str
def toString(self):
return self._url_str
def toURI(self):
return URI(self._url_str)
def equals(self, other):
if isinstance(other, URL):
return self._url_str == other._url_str
return False
def hashCode(self):
return hash(self._url_str) & 0x7FFFFFFF
def openConnection(self, proxy=None):
return HttpURLConnection(self._url_str, proxy)
def __str__(self):
return self._url_str
# ============================================================
# URLConnection
# ============================================================
class URLConnection(Stub):
def __init__(self, url_str):
super().__init__()
self._url_str = url_str
self._connected = False
self._do_input = True
self._do_output = False
self._allow_user_interaction = False
self._use_caches = True
self._default_use_caches = True
self._if_modified_since = 0
self._read_timeout = 0
self._connect_timeout = 0
self._request_properties = _OrderedDict()
self._response_code = None
self._response_message = None
self._response_headers = _OrderedDict()
self._content = None
def connect(self):
if not self._connected:
self._connected = True
def getContent(self, classes=None):
raise UnknownServiceException("getContent not implemented")
def getContentEncoding(self):
return self._response_headers.get("Content-Encoding")
def getContentLength(self):
val = self._response_headers.get("Content-Length")
return int(val) if val else -1
def getContentLengthLong(self):
return self.getContentLength()
def getContentType(self):
return self._response_headers.get("Content-Type")
def getDate(self):
val = self._response_headers.get("Date")
if val:
try:
return int(_datetime.strptime(val, "%a, %d %b %Y %H:%M:%S %Z").timestamp() * 1000)
except Exception:
pass
return 0
def getExpiration(self):
val = self._response_headers.get("Expires")
if val:
try:
return int(_datetime.strptime(val, "%a, %d %b %Y %H:%M:%S %Z").timestamp() * 1000)
except Exception:
pass
return 0
def getHeaderField(self, name):
return self._response_headers.get(name)
def getHeaderFieldDate(self, name, default):
val = self._response_headers.get(name)
if val:
try:
return int(_datetime.strptime(val, "%a, %d %b %Y %H:%M:%S %Z").timestamp() * 1000)
except Exception:
pass
return default
def getHeaderFieldInt(self, name, default):
val = self._response_headers.get(name)
return int(val) if val and val.isdigit() else default
def getHeaderFieldKey(self, n):
keys = list(self._response_headers.keys())
return keys[n] if n < len(keys) else None
def getHeaderFields(self):
return self._response_headers
def getInputStream(self):
raise UnknownServiceException("getInputStream not implemented")
def getOutputStream(self):
raise UnknownServiceException("getOutputStream not implemented")
def getPermission(self):
return None
def getReadTimeout(self):
return self._read_timeout
def setReadTimeout(self, timeout):
self._read_timeout = timeout
def getConnectTimeout(self):
return self._connect_timeout
def setConnectTimeout(self, timeout):
self._connect_timeout = timeout
def getRequestProperty(self, key):
return self._request_properties.get(key)
def setRequestProperty(self, key, value):
self._request_properties[key] = value
def addRequestProperty(self, key, value):
if key in self._request_properties:
existing = self._request_properties[key]
if isinstance(existing, list):
existing.append(value)
else:
self._request_properties[key] = [existing, value]
else:
self._request_properties[key] = value
def getDefaultUseCaches(self):
return self._default_use_caches
def setDefaultUseCaches(self, use):
self._default_use_caches = use
def getUseCaches(self):
return self._use_caches
def setUseCaches(self, use):
self._use_caches = use
def setDoInput(self, do_input):
self._do_input = do_input
def getDoInput(self):
return self._do_input
def setDoOutput(self, do_output):
self._do_output = do_output
def getDoOutput(self):
return self._do_output
def setAllowUserInteraction(self, allow):
self._allow_user_interaction = allow
def getAllowUserInteraction(self):
return self._allow_user_interaction
def setIfModifiedSince(self, time):
self._if_modified_since = time
def getIfModifiedSince(self):
return self._if_modified_since
# ============================================================
# HttpURLConnection
# ============================================================
class HttpURLConnection(URLConnection):
HTTP_OK = 200
HTTP_CREATED = 201
HTTP_ACCEPTED = 202
HTTP_MOVED_PERM = 301
HTTP_MOVED_TEMP = 302
HTTP_NOT_MODIFIED = 304
HTTP_BAD_REQUEST = 400
HTTP_UNAUTHORIZED = 401
HTTP_FORBIDDEN = 403
HTTP_NOT_FOUND = 404
HTTP_INTERNAL_ERROR = 500
def __init__(self, url_str, proxy=None):
super().__init__(url_str)
self._request_method = "GET"
self._instance_follow_redirects = True
self._chunked = False
self._fixed_length = -1
self._input_stream = None
self._error_stream = None
self._response_code = -1
self._response_message = ""
def setRequestMethod(self, method):
method = method.upper()
valid = ["GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"]
if method not in valid:
raise ProtocolException(f"Invalid HTTP method: {method}")
self._request_method = method
def getRequestMethod(self):
return self._request_method
def getResponseCode(self):
if self._response_code == -1:
self._do_request()
return self._response_code
def getResponseMessage(self):
if self._response_code == -1:
self._do_request()
return self._response_message
def getHeaderFields(self):
if self._response_code == -1:
self._do_request()
return self._response_headers
def setInstanceFollowRedirects(self, follow):
self._instance_follow_redirects = follow
def getInstanceFollowRedirects(self):
return self._instance_follow_redirects
def getErrorStream(self):
if self._response_code == -1:
self._do_request()
if self._response_code >= 400:
return self._error_stream
return None
def setChunkedStreamingMode(self, chunklen):
self._chunked = True
self._chunk_length = chunklen
def setFixedLengthStreamingMode(self, content_length):
self._fixed_length = content_length
def setFixedLengthStreamingModeLong(self, content_length):
self._fixed_length = content_length
def disconnect(self):
self._input_stream = None
self._error_stream = None
self._connected = False
def usingProxy(self):
return False
def getInputStream(self):
if self._response_code == -1:
self._do_request()
if self._input_stream is None:
import io as _pyio_mod
self._input_stream = _pyio_mod.BytesIO(self._content.encode("utf-8") if isinstance(self._content, str) else self._content)
return self._input_stream
def _do_request(self):
if HAS_REQUESTS:
self._do_requests()
elif HAS_HTTPX:
self._do_httpx()
else:
self._do_urllib()
def _do_requests(self):
import requests
try:
kwargs = {
"headers": dict(self._request_properties),
"timeout": self._read_timeout / 1000.0 if self._read_timeout else None,
}
if self._instance_follow_redirects:
kwargs["allow_redirects"] = True
else:
kwargs["allow_redirects"] = False
method = self._request_method.lower()
if method == "get":
r = requests.get(self._url_str, **kwargs)
elif method == "post":
body = self._request_properties.pop("__body", None)
r = requests.post(self._url_str, data=body, **kwargs)
elif method == "put":
body = self._request_properties.pop("__body", None)
r = requests.put(self._url_str, data=body, **kwargs)
elif method == "delete":
r = requests.delete(self._url_str, **kwargs)
elif method == "head":
r = requests.head(self._url_str, **kwargs)
elif method == "options":
r = requests.options(self._url_str, **kwargs)
elif method == "patch":
body = self._request_properties.pop("__body", None)
r = requests.patch(self._url_str, data=body, **kwargs)
else:
r = requests.request(self._request_method, self._url_str, **kwargs)
self._response_code = r.status_code
self._response_message = r.reason
self._response_headers = dict(r.headers)
self._content = r.content
except Exception as e:
self._response_code = 0
self._response_message = str(e)
def _do_httpx(self):
import httpx
try:
client = httpx.Client(follow_redirects=self._instance_follow_redirects)
kwargs = {
"headers": dict(self._request_properties) if self._request_properties else None,
"timeout": self._read_timeout / 1000.0 if self._read_timeout else None,
}
method = self._request_method.lower()
if method == "get":
r = client.get(self._url_str, **kwargs)
elif method == "post":
body = self._request_properties.pop("__body", None)
r = client.post(self._url_str, content=body, **kwargs)
elif method == "put":
body = self._request_properties.pop("__body", None)
r = client.put(self._url_str, content=body, **kwargs)
elif method == "delete":
r = client.delete(self._url_str, **kwargs)
else:
r = client.request(self._request_method, self._url_str, **kwargs)
self._response_code = r.status_code
self._response_message = r.reason_phrase
self._response_headers = dict(r.headers)
self._content = r.content
except Exception as e:
self._response_code = 0
self._response_message = str(e)
def _do_urllib(self):
from urllib.request import urlopen, Request
from urllib.error import HTTPError
try:
req = Request(self._url_str, headers=dict(self._request_properties) if self._request_properties else {},
method=self._request_method)
resp = urlopen(req, timeout=self._read_timeout / 1000.0 if self._read_timeout else None)
self._response_code = resp.status
self._response_message = resp.reason
self._response_headers = dict(resp.headers)
self._content = resp.read()
except HTTPError as e:
self._response_code = e.code
self._response_message = e.reason
self._response_headers = dict(e.headers)
self._content = e.read()
except Exception as e:
self._response_code = 0
self._response_message = str(e)
self._content = b""
# ============================================================
# Socket
# ============================================================
class Socket(Stub):
def __init__(self, *args):
super().__init__()
self._socket = None
self._connected = False
self._bound = False
self._closed = False
self._input_shutdown = False
self._output_shutdown = False
self._input_stream = None
self._output_stream = None
self._timeout = 0
self._keep_alive = False
self._tcp_no_delay = False
self._reuse_address = False
self._send_buffer_size = 0
self._receive_buffer_size = 0
self._linger = -1
self._traffic_class = 0
if len(args) == 2:
host, port = args
self.connect(InetSocketAddress(host, port))
elif len(args) == 1 and isinstance(args[0], InetAddress):
addr, port = args[0], 0
self.connect(InetSocketAddress(addr, port))
def connect(self, endpoint, timeout=None):
if isinstance(endpoint, InetSocketAddress):
host = endpoint.getHostName()
port = endpoint.getPort()
else:
host = str(endpoint)
port = 80
self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
if self._timeout > 0:
self._socket.settimeout(self._timeout / 1000.0)
try:
self._socket.connect((host, port))
self._connected = True
except OSError as e:
raise ConnectException(str(e))
def bind(self, endpoint):
if isinstance(endpoint, InetSocketAddress):
host = endpoint.getHostName()
port = endpoint.getPort()
else:
host = "0.0.0.0"
port = 0
self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
self._socket.bind((host or "0.0.0.0", port))
self._bound = True
def close(self):
if not self._closed:
self._closed = True
if self._socket:
self._socket.close()
def getInputStream(self):
if self._input_stream is None and self._socket:
import io as _pyio_mod
fd = self._socket.fileno()
self._input_stream = _pyio_mod.FileIO(fd, closefd=False)
return self._input_stream
def getOutputStream(self):
if self._output_stream is None and self._socket:
import io as _pyio_mod
fd = self._socket.fileno()
self._output_stream = _pyio_mod.FileIO(fd, closefd=False, mode="ab")
return self._output_stream
def getInetAddress(self):
if self._socket and self._connected:
host, _ = self._socket.getpeername()
return InetAddress.getByName(host)
return None
def getPort(self):
if self._socket and self._connected:
_, port = self._socket.getpeername()
return port
return 0
def getLocalPort(self):
if self._socket:
_, port = self._socket.getsockname()
return port
return 0
def getLocalAddress(self):
if self._socket:
host, _ = self._socket.getsockname()
return InetAddress.getByName(host)
return InetAddress.getLoopbackAddress()
def getRemoteSocketAddress(self):
if self._socket and self._connected:
host, port = self._socket.getpeername()
return InetSocketAddress(host, port)
return None
def getLocalSocketAddress(self):
if self._socket:
host, port = self._socket.getsockname()
return InetSocketAddress(host, port)
return None
def getSoTimeout(self):
return self._timeout
def setSoTimeout(self, timeout):
self._timeout = timeout
if self._socket:
self._socket.settimeout(timeout / 1000.0 if timeout > 0 else None)
def getTcpNoDelay(self):
return self._tcp_no_delay
def setTcpNoDelay(self, on):
self._tcp_no_delay = on
if self._socket:
self._socket.setsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 1 if on else 0)
def getKeepAlive(self):
return self._keep_alive
def setKeepAlive(self, on):
self._keep_alive = on
if self._socket:
self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_KEEPALIVE, 1 if on else 0)
def getReuseAddress(self):
return self._reuse_address
def setReuseAddress(self, on):
self._reuse_address = on
if self._socket:
self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1 if on else 0)
def getSendBufferSize(self):
return self._send_buffer_size
def setSendBufferSize(self, size):
self._send_buffer_size = size
if self._socket:
self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_SNDBUF, size)
def getReceiveBufferSize(self):
return self._receive_buffer_size
def setReceiveBufferSize(self, size):
self._receive_buffer_size = size
if self._socket:
self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_RCVBUF, size)
def getSoLinger(self):
return self._linger
def setSoLinger(self, on, linger):
if on:
self._linger = linger
if self._socket:
self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_LINGER, _struct.pack("ii", 1, linger))
else:
self._linger = -1
def getTrafficClass(self):
return self._traffic_class
def setTrafficClass(self, tc):
self._traffic_class = tc
def shutdownInput(self):
if self._socket:
self._socket.shutdown(_socket.SHUT_RD)
self._input_shutdown = True
def shutdownOutput(self):
if self._socket:
self._socket.shutdown(_socket.SHUT_WR)
self._output_shutdown = True
def isConnected(self):
return self._connected
def isBound(self):
return self._bound
def isClosed(self):
return self._closed
def isInputShutdown(self):
return self._input_shutdown
def isOutputShutdown(self):
return self._output_shutdown
def setPerformancePreferences(self, connection_time, latency, bandwidth):
pass
# ============================================================
# ServerSocket
# ============================================================
class ServerSocket(Stub):
def __init__(self, port=0, backlog=50, bindAddr=None):
super().__init__()
self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1)
self._port = port
self._backlog = backlog
self._bind_addr = bindAddr
self._closed = False
self._timeout = 0
if port > 0 or bindAddr:
self.bind(InetSocketAddress(bindAddr or "0.0.0.0", port), backlog)
def bind(self, endpoint, backlog=50):
host = endpoint.getHostName() if isinstance(endpoint, InetSocketAddress) else str(endpoint)
port = endpoint.getPort() if isinstance(endpoint, InetSocketAddress) else 0
self._socket.bind((host or "0.0.0.0", port))
self._socket.listen(backlog)
self._port = self._socket.getsockname()[1]
def accept(self):
if self._closed:
raise SocketException("Socket closed")
if self._timeout > 0:
self._socket.settimeout(self._timeout / 1000.0)
try:
client_sock, addr = self._socket.accept()
sock = Socket()
sock._socket = client_sock
sock._connected = True
return sock
except _socket.timeout:
raise SocketTimeoutException("Accept timed out")
def close(self):
if not self._closed:
self._closed = True
self._socket.close()
def getInetAddress(self):
host, _ = self._socket.getsockname()
return InetAddress.getByName(host)
def getLocalPort(self):
return self._socket.getsockname()[1] if not self._closed else -1
def getSoTimeout(self):
return self._timeout
def setSoTimeout(self, timeout):
self._timeout = timeout
self._socket.settimeout(timeout / 1000.0 if timeout > 0 else None)
def getReceiveBufferSize(self):
return self._socket.getsockopt(_socket.SOL_SOCKET, _socket.SO_RCVBUF)
def setReceiveBufferSize(self, size):
self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_RCVBUF, size)
def getReuseAddress(self):
return bool(self._socket.getsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR))
def setReuseAddress(self, on):
self._socket.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1 if on else 0)
# ============================================================
# DatagramSocket / DatagramPacket
# ============================================================
class DatagramPacket(Stub):
def __init__(self, buf, length, address=None, port=None):
super().__init__()
if address is not None:
self._buf = bytearray(buf)
self._length = length
self._address = address
self._port = port
else:
self._buf = bytearray(buf)
self._length = length
self._address = None
self._port = -1
def getAddress(self):
return self._address
def getPort(self):
return self._port
def getData(self):
return bytes(self._buf)
def getLength(self):
return self._length
def setAddress(self, address):
self._address = address
def setPort(self, port):
self._port = port
def setData(self, buf, offset=None, length=None):
if offset is not None and length is not None:
self._buf = bytearray(buf[offset:offset+length])
self._length = length
else:
self._buf = bytearray(buf)
self._length = len(buf)
def setLength(self, length):
self._length = length
class DatagramSocket(Stub):
def __init__(self, port=None):
super().__init__()
self._socket = _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM)
self._bound = False
self._closed = False
if port is not None:
self.bind(port)
def bind(self, port):
self._socket.bind(("0.0.0.0", port))
self._bound = True
def send(self, p):
addr = p.getAddress()
port = p.getPort()
self._socket.sendto(p.getData()[:p.getLength()], (addr.getHostAddress(), port))
def receive(self, p):
data, addr = self._socket.recvfrom(p.getLength())
p.setData(data)
p.setAddress(InetAddress(addr[0], _socket.inet_pton(_socket.AF_INET, addr[0])))
p.setPort(addr[1])
def close(self):
if not self._closed:
self._closed = True
self._socket.close()
def getLocalPort(self):
return self._socket.getsockname()[1] if not self._closed else -1
def isBound(self):
return self._bound
def isClosed(self):
return self._closed
def setSoTimeout(self, timeout):
self._socket.settimeout(timeout / 1000.0 if timeout > 0 else None)
def getSoTimeout(self):
return self._socket.gettimeout() * 1000 if self._socket.gettimeout() else 0
# ============================================================
# Proxy
# ============================================================
class Proxy(Stub):
class Type:
DIRECT = "DIRECT"
HTTP = "HTTP"
SOCKS = "SOCKS"
NO_PROXY = None
def __init__(self, typ, sa=None):
super().__init__()
self._type = typ
self._address = sa
def type(self):
return self._type
def address(self):
return self._address
def toString(self):
return f"{self._type} proxy @ {self._address}"
class ProxySelector(Stub):
_default = None
@staticmethod
def getDefault():
return ProxySelector._default
@staticmethod
def setDefault(sel):
ProxySelector._default = sel
def select(self, uri):
return [Proxy.NO_PROXY]
def connectFailed(self, uri, sa, ioe):
pass
# ============================================================
# Authenticator / PasswordAuthentication
# ============================================================
class Authenticator(Stub):
_default = None
@staticmethod
def getDefault():
return Authenticator._default
@staticmethod
def setDefault(auth):
Authenticator._default = auth
def getPasswordAuthentication(self):
return self._pwd_auth
def requestPasswordAuthentication(self, addr, port, protocol, prompt, scheme):
return self._pwd_auth
class PasswordAuthentication(Stub):
def __init__(self, user, password):
super().__init__()
self._user = user
self._password = password
def getUserName(self):
return self._user
def getPassword(self):
return self._password
# ============================================================
# NetworkInterface
# ============================================================
class NetworkInterface(Stub):
_cache = {}
def __init__(self, name, display_name, addrs):
super().__init__()
self._name = name
self._display_name = display_name
self._addrs = addrs
@staticmethod
def getByName(name):
if name in NetworkInterface._cache:
return NetworkInterface._cache[name]
@staticmethod
def getByInetAddress(addr):
for ni in NetworkInterface._cache.values():
for a in ni._addrs:
if a.equals(addr):
return ni
return None
@staticmethod
def getNetworkInterfaces():
return list(NetworkInterface._cache.values())
def getName(self):
return self._name
def getDisplayName(self):
return self._display_name
def getInetAddresses(self):
return iter(self._addrs)
def getInterfaceAddresses(self):
return self._addrs
def isUp(self):
return True
def isLoopback(self):
return self._name == "lo"
def isPointToPoint(self):
return False
def supportsMulticast(self):
return True
def getHardwareAddress(self):
return None
def getMTU(self):
return 1500
def getSubInterfaces(self):
return iter([])
def getParent(self):
return None
def isVirtual(self):
return False
def toString(self):
return f"{self._display_name} ({self._name})"
@staticmethod
def _init_from_socket():
import netifaces
for iface_name in netifaces.interfaces():
addrs = []
ifaddresses = netifaces.ifaddresses(iface_name)
for family in [netifaces.AF_INET, netifaces.AF_INET6]:
if family in ifaddresses:
for addr_info in ifaddresses[family]:
try:
addr = addr_info["addr"]
if "." in addr:
addrs.append(InetAddress(addr, _socket.inet_pton(_socket.AF_INET, addr)))
else:
addrs.append(InetAddress(addr, _socket.inet_pton(_socket.AF_INET6, addr)))
except Exception:
pass
NetworkInterface._cache[iface_name] = NetworkInterface(iface_name, iface_name, addrs)
try:
NetworkInterface._init_from_socket()
except Exception:
pass
# ============================================================
# CookieHandler / CookieManager / HttpCookie
# ============================================================
class CookieHandler(Stub):
_default = None
@staticmethod
def getDefault():
return CookieHandler._default
@staticmethod
def setDefault(handler):
CookieHandler._default = handler
def get(self, uri, requestHeaders):
raise NotImplementedError
def put(self, uri, responseHeaders):
raise NotImplementedError
class HttpCookie(Stub):
def __init__(self, name, value):
super().__init__()
self._name = name
self._value = value
self._comment = None
self._comment_url = None
self._discard = False
self._domain = None
self._max_age = -1
self._path = None
self._portlist = None
self._secure = False
self._version = 0
self._http_only = False
self._creation_time = _datetime.now()
def getName(self):
return self._name
def getValue(self):
return self._value
def getComment(self):
return self._comment
def getCommentURL(self):
return self._comment_url
def getDiscard(self):
return self._discard
def getDomain(self):
return self._domain
def getMaxAge(self):
return self._max_age
def getPath(self):
return self._path
def getPortlist(self):
return self._portlist
def getSecure(self):
return self._secure
def getVersion(self):
return self._version
def getHttpOnly(self):
return self._http_only
def setComment(self, comment):
self._comment = comment
def setCommentURL(self, url):
self._comment_url = url
def setDiscard(self, discard):
self._discard = discard
def setDomain(self, domain):
self._domain = domain
def setMaxAge(self, max_age):
self._max_age = max_age
def setPath(self, path):
self._path = path
def setPortlist(self, portlist):
self._portlist = portlist
def setSecure(self, secure):
self._secure = secure
def setVersion(self, version):
self._version = version
def setHttpOnly(self, http_only):
self._http_only = http_only
def hasExpired(self):
if self._max_age < 0:
return False
elapsed = (_datetime.now() - self._creation_time).total_seconds()
return elapsed > self._max_age
def equals(self, other):
if isinstance(other, HttpCookie):
return self._name == other._name
return False
def toString(self):
return f"{self._name}={self._value}"
def validate(self, name):
if not name or name.strip() == "":
raise ValueError("Cookie name cannot be empty")
def __str__(self):
return self.toString()
class CookieManager(CookieHandler):
def __init__(self):
super().__init__()
self._cookie_store = {}
def get(self, uri, requestHeaders):
cookies = []
for domain, path, cookie in self._cookie_store.values():
if not cookie.hasExpired():
cookies.append(cookie.toString())
return {"Cookie": "; ".join(cookies)} if cookies else {}
def put(self, uri, responseHeaders):
set_cookie = responseHeaders.get("Set-Cookie")
if set_cookie:
parts = set_cookie.split(";")
name_val = parts[0].split("=", 1)
if len(name_val) == 2:
cookie = HttpCookie(name_val[0], name_val[1])
for part in parts[1:]:
part = part.strip()
if "=" in part:
k, v = part.split("=", 1)
if k.lower() == "domain":
cookie.setDomain(v)
elif k.lower() == "path":
cookie.setPath(v)
elif k.lower() == "max-age":
cookie.setMaxAge(int(v))
elif k.lower() == "version":
cookie.setVersion(int(v))
else:
if part.lower() == "secure":
cookie.setSecure(True)
elif part.lower() == "httponly":
cookie.setHttpOnly(True)
elif part.lower() == "discard":
cookie.setDiscard(True)
self._cookie_store[(cookie.getDomain(), cookie.getPath(), cookie.getName())] = (cookie.getDomain(), cookie.getPath(), cookie)
# ============================================================
# URLEncoder / URLDecoder
# ============================================================
class URLEncoder(Stub):
@staticmethod
def encode(s, charset="UTF-8"):
return _quote(str(s), safe="")
@staticmethod
def encode(s):
return _quote(str(s), safe="")
class URLDecoder(Stub):
@staticmethod
def decode(s, charset="UTF-8"):
return _unquote(str(s), encoding=charset)
@staticmethod
def decode(s):
return _unquote(str(s))
# Initialize NO_PROXY
Proxy.NO_PROXY = Proxy(Proxy.Type.DIRECT, None)