HTTP
HTTP goes through a native client: urllib.request and urllib.error compile to urlopen calls served by ps_http.c, with no subprocess and no host curl.
This page shows what compiles, the caveats that remain, and the curl escape hatch for the cases the client does not cover.
What compiles
urlopen(url) returns an HttpResponse with status, headers and body (bytes), plus getcode(), info() and read().
data sends a POST, timeout bounds the whole request and raises TimeoutError on expiry.
import json
import urllib.request
def fetch(url: str) -> str:
resp: urllib.request.HTTPResponse = urllib.request.urlopen(url)
body: bytes = resp.read()
return body.decode("utf-8")
def status(body: str) -> str:
doc: dict[str, str] = json.loads(body)
return doc["status"]
json.loads needs the result annotation (dict[str, str] above), and the decoded string must be UTF-8, since bytes.decode compiles the utf-8 encoding only.
Request(url, data=..., headers=..., method=...) builds the request record that urlopen consumes, for methods beyond GET and POST and for custom headers.
Redirects (301, 302, 303, 307, 308) follow CPython’s method rules, relative Location resolution included, with a 10-hop cap.
Chunked transfer-encoding is decoded.
Divergences from CPython
- TLS is not there yet: an
https://URL raisesOSError.
TLS via mbedTLS is #235. urlopentakesurl,dataandtimeout; other keywords are unsupported.
Headers go on theRequest, as a dict display with constant string keys and values; a header dict built at run time stops the compile.- 4xx and 5xx raise
HTTPErrorcarryingstatus,headersand a readable body; malformed URLs and connection failures raiseURLError.
Both catch through theOSErrorchain like CPython, but the error types are synthetic records, not the fullurllib.errorclass surface. - Only
urlopenandRequestcompile; the rest ofurllib.request(urlretrieve, openers, proxies) is unsupported, andhttp.clientis not supported (#237). - No streaming: the whole body arrives as one
bytesvalue. - These are the numbered divergences 27 and 28 in the divergence list.
The curl escape hatch
For the cases the native client does not cover, such as an unusual TLS configuration or a proxy setup, the curl bridge still works by running the call through embedded CPython (fallback mode):
import subprocess
def fetch(url: str) -> str:
out: bytes = subprocess.check_output(["curl", "-s", url])
return out.decode("utf-8")
It needs curl on PATH at run time and the libpython-linked binary shape; see divergence 15 in the divergence list.