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
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,14 @@ jobs:
- name: Run CPython tests
run: cargo test -p bashkit --features cpython,http_client --lib --test integration -- cpython

# bashkit's own requests/httpx (guest modules) against the upstream
# packages: same scenarios, same output.
- name: CPython requests/httpx differential
run: |
python3 -m venv /tmp/http-diff
/tmp/http-diff/bin/pip install --quiet requests==2.34.2 httpx==0.28.1
/tmp/http-diff/bin/python crates/bashkit-cpython-wasm/guest/tests/differential.py

# Same suites on the opt-in native-code build (`cpython-native`).
- name: Run CPython tests (native code)
run: cargo test -p bashkit --features cpython-native,http_client --lib --test integration -- cpython
Expand Down
4 changes: 2 additions & 2 deletions crates/bashkit-cpython-wasm/artifacts/MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ wasi_sdk=24
wasmtime_wizer=49.0.1
zlib=1.3.1
sqlite=sqlite-amalgamation-3500400
8cbd501c5b6e0f73d986be9b5bf48f4f0f28d40ef83774e666ffbb854758b0a8 python.wasm.gz
abf5df19ec01bb180672e94b816711fc03dfd92e109b94fc10e5399523bb464c python314.zip
31c43d757812151582ff3e274f0d9c65cf210064a46646a5a73a68704b83329b python.wasm.gz
7c1fec908a3c250e0591a4892f3dfbaa73e5c81798dfa33b1dc80e18931dbb74 python314.zip
Binary file modified crates/bashkit-cpython-wasm/artifacts/python.wasm.gz
Binary file not shown.
Binary file modified crates/bashkit-cpython-wasm/artifacts/python314.zip
Binary file not shown.
3 changes: 3 additions & 0 deletions crates/bashkit-cpython-wasm/guest/_bashkit_boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
"urllib.parse", "uuid", "warnings", "weakref", "zlib", "runpy",
"_bashkit", "atexit", "builtins", "importlib", "sqlite3", "zipfile",
"asyncio",
# bashkit's own HTTP clients over the host bridge: preloaded so
# `import requests` / `import httpx` cost nothing per call.
"requests", "requests.utils", "httpx", "httpx2",
)

_USAGE = """\
Expand Down
18 changes: 14 additions & 4 deletions crates/bashkit-cpython-wasm/guest/_bashkit_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
http.client writes, sends the request through the host once it is
complete, and serves the reply as an HTTP/1.1 byte stream that the real
`HTTPResponse` parses. Status line, headers, chunked uploads, keep-alive
and HEAD behave as in CPython, and host errors surface from `request()`
so urllib wraps them in `URLError` like a failed connect.
and HEAD behave as in CPython. Where errors surface matches a real
socket: a refused or denied request fails in `request()` (urllib wraps it
in `URLError`, like a failed connect), while a timeout waiting for the
reply surfaces from `getresponse()` (a read timeout, which urllib3 and
requests report as `ReadTimeout`).
- `HTTPSConnection` is defined although `ssl` is missing (context arguments
are accepted and ignored), so urllib.request registers its https handler.
- Proxies and CONNECT tunnels are not used: the bridge sends to the tunnel
Expand Down Expand Up @@ -123,7 +126,11 @@ def sendall(self, data):
return
method, target, headers, body, used = parsed
del self._out[:used]
self._replies.append(self._exchange(method, target, headers, body))
try:
reply = self._exchange(method, target, headers, body)
except TimeoutError as e:
reply = e # raised when the response is read
self._replies.append(reply)

def send(self, data):
self.sendall(data)
Expand Down Expand Up @@ -158,7 +165,10 @@ def makefile(self, mode="r", *args, **kwargs):
raise OSError("bridge socket is read-only")
if not self._replies:
raise ConnectionError("no HTTP request was sent")
return io.BytesIO(self._replies.pop(0))
reply = self._replies.pop(0)
if isinstance(reply, BaseException):
raise reply
return io.BytesIO(reply)

def settimeout(self, timeout):
self._timeout = timeout
Expand Down
Loading
Loading