Metadata-Version: 2.4
Name: necko-standalone
Version: 0.8.1
Summary: Standalone NSS and Necko HTTP client with a requests-style Python API
License: MPL-2.0
Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: requests<3,>=2.32.5
Requires-Dist: urllib3<3,>=2.2.3
Requires-Dist: cryptography<51,>=45
Requires-Dist: h2<5,>=4.3
Requires-Dist: brotli<2,>=1.2
Requires-Dist: backports.zstd>=1.0; python_version < "3.14"
Requires-Dist: zstandard<1,>=0.23
Requires-Dist: publicsuffixlist<2,>=1.0
Provides-Extra: socks
Requires-Dist: PySocks!=1.5.7,>=1.5.6; extra == "socks"

# Standalone Necko HTTP Library

Version 0.8.1 exposes the Requests 2.x API through native NSS TLS and HTTP/1.1,
HTTP/2, or HTTP/3, without launching Firefox.

## Architecture

The Python package preserves Requests-style preparation, sessions, authentication,
hooks, exceptions, and response objects, with Firefox-oriented network defaults. Its default
HTTP/HTTPS adapters use the standalone C++ socket and HTTP framing APIs.
The chunked decoder is the same `Http1ChunkedDecoder.h` compiled by Firefox.
This remains a partial extraction, not Firefox's complete Necko network stack.

TLS uses our Firefox 158.0 build's NSS 3.130 and NSPR 4.40 over native socket I/O. On this
Windows build NSPR is included in `nss3.dll`. `mozglue.dll`, `softokn3.dll`, and
`freebl3.dll` are packaged alongside it. Python's `ssl` is used only for exception
types; its TLS engine is not used for requests.
HTTP/2 uses hyper-h2, with Firefox 158's SETTINGS, initial flow-control windows,
starting stream ID and pseudo-header order. ALPN advertises `h2,http/1.1` for
origins, and `http/1.1` for HTTPS proxies; selected protocols are actually used.
HTTP/2 streams share a connection and a worker serializes all NSS and protocol
operations. NSS reads and writes are nonblocking after the HTTP/2 handshake;
partial writes retain the pending TLS data and an output queue applies
backpressure. Stream cancellation stays queued without the request deadline,
including cancellation that races with stream creation. HTTP/3 uses the
checkout's Neqo 0.31.1, nss-rs 0.14.6, and neqo-udp
through `necko_quic.dll`. HTTPS Alt-Svc selects HTTP/3; a TCP backup starts after
100 ms if the QUIC handshake is still pending. The first completed authenticated
connection wins, and pending competitors are cancelled. No application request
is sent on the losing connection.
urllib3 provides response decompression and retry policy, without making HTTP
requests. Optional SOCKS negotiation uses PySocks over the same native I/O.
No Firefox process, Gecko runtime, libcurl, or urllib3 HTTP transport is required.
The legacy C APIs retain their original behavior, including WinHTTP for HTTPS;
the Python package uses the additive APIs in `necko_stream.h` and `necko_tls.h`.

Certificate chains and hostnames are verified by cryptography's X.509 verifier
against the pinned Firefox NSS server-auth roots or the supplied CA bundle.
The build extracts roots and distrust-after cutoffs from NSS `certdata.txt` and
ships the matching Firefox public suffix list. This is separate from NSS's TLS
record engine and differs from Firefox's mozpkix/CT/OCSP/CRLite policy. Custom
CA stores are isolated, including session resumption; certificates are checked
again after a resumed handshake. Client keys must be unencrypted PEM.

Default requests use Firefox 158 Windows navigation headers, ordering, User-Agent,
Accept-Language, compression and Fetch Metadata. `Session(context="fetch",
document_url="https://example.com/page")` selects script-fetch headers with an
explicit initiating page. Referer follows strict-origin-when-cross-origin.
Explicit headers still override defaults. Context is explicit, not inferred from
previous requests; the library does not execute a page or fetch its subresources.
`Session(user_activation=False)` omits `Sec-Fetch-User` for a navigation without
user activation; its default is `True`.
Cookie handling enforces host-only domains, public suffix rejection, secure
prefixes, and SameSite for the supplied context. Explicit dictionary cookies bind
to the request host. Firefox's partitioned cookie jars are not implemented.

## Install and Use

Install the platform wheel with pip so that Requests and urllib3 dependencies
are resolved. SOCKS proxies additionally require the `socks` extra.

```powershell
python -m pip install .\obj-necko\wheel-v19\necko_standalone-0.8.1-cp314-cp314-win_amd64.whl
```

```python
import necko as requests

with requests.Session() as session:
    session.headers.update({"User-Agent": "my-client/1.0"})
    session.cookies.set("language", "en")
    response = session.post(
        "https://example.com/api",
        params={"page": 1},
        json={"name": "Necko"},
        timeout=(3, 15),
    )
    response.raise_for_status()
    print(response.json())
    print(response.tls)
```

`from necko_requests import Session` remains supported.
Existing Requests exception handlers work because exception classes are shared.
Imports such as `from necko.auth import HTTPDigestAuth` and
`from necko.adapters import HTTPAdapter` are supported.

## Requests Compatibility

The package supports:

- All verb helpers, including OPTIONS, and positional GET params / POST JSON.
- Request, PreparedRequest, Session.prepare_request and Session.send.
- Query parameters, form data, JSON, multipart files, file bodies, and generators.
- RequestsCookieJar, per-request cookies, cookie expiry/domain/path/secure rules.
- Basic, Digest, custom auth, response hooks, and session defaults.
- Redirect history, next requests, method changes, and cross-origin auth stripping.
- Requests exception classes, response truthiness, editable encoding, JSON kwargs,
  reason, elapsed, request metadata, links, and context managers.
- Default unlimited timeout, numeric or (connect, read) timeouts, and urllib3 Timeout.
- Streaming downloads, raw reads, incremental text decoding, gzip and deflate.
- Connection pools, early-close cleanup, stale connection detection, and Retry policies.
- HTTP/HTTPS proxies, CONNECT, proxy authentication, environment proxy settings,
  NO_PROXY and trust_env. SOCKS4/4a/5/5h use the optional PySocks dependency.
- TLS verification, custom CA files/directories, client certificate/key pairs,
  environment CA configuration, and verify=False warnings.
- Session serialization and custom mounted adapters.

Duplicate response headers are available through `response.raw.headers.getlist()`.
The additional `response.headers.get_all()` and `getlist()` helpers are retained.
The optional Session constructor arguments `library_path`, `headers`, `timeout`,
`verify`, `auth`, `context`, `document_url`, and `user_activation` are extensions
to Requests. Protocol-level retries precede the caller's urllib3 retry policy.
The effective Firefox preference limits automatic attempts to ten. Safe methods
or requests on a reused connection can restart after a reset before response
bytes arrive; partial responses and read timeouts do not restart automatically.
REFUSED_STREAM and rejected GOAWAY streams are replayed only with a replayable
body. HTTP_1_1_REQUIRED downgrades the affected transaction. A 421 response on a
coalesced connection retries on a dedicated connection.
HTTP/3 REQUEST_REJECTED retains the alternate route; REQUEST_CANCELLED does not
restart automatically. VERSION_FALLBACK restricts the affected transaction to
HTTP/1.1. Other stream errors use the direct TCP route when the transaction is
restartable. STOP_SENDING with NO_ERROR ends the upload while the response remains
readable; other codes follow the same reset policy. Received response data,
including informational headers, prevents automatic replay.

```python
import necko as requests
from necko.adapters import HTTPAdapter
from urllib3.util import Retry

with requests.Session() as session:
    session.mount(
        "https://",
        HTTPAdapter(
            max_retries=Retry(total=3, status_forcelist=[429, 503]),
        ),
    )
    with session.get(
        "https://example.com/data", stream=True, timeout=(3, 30)
    ) as response:
        response.raise_for_status()
        with open("data.bin", "wb") as output:
            for chunk in response.iter_content(65536):
                output.write(chunk)
```

## Build and Export

A C++17 compiler, Rust 1.97+, Python 3.11+ for building, libclang, the package
dependencies in `pyproject.toml`, and a Firefox 158 Windows x64 NSS SDK are
required. The runtime package supports Python 3.10+. The default SDK location
is `obj-release/dist`; use `--nss-dist` to override it. A matching x64 Visual C++
runtime must be installed on the destination machine.

```sh
python -m pip install "requests>=2.32.5,<3" "urllib3>=2.2.3,<3" "cryptography>=45,<51" "h2>=4.3,<5" "brotli>=1.2,<2" "zstandard>=0.23,<1" "publicsuffixlist>=1.0,<2" PySocks
# Python < 3.14 also needs backports.zstd.
python tools/necko-standalone/build.py --export-nss-sdk obj-necko/nss-sdk-v19
python tools/necko-standalone/build.py --nss-dist obj-necko/nss-sdk-v19 --output obj-necko/nss-v19
python tools/necko-standalone/build.py --nss-dist obj-necko/nss-sdk-v19 --export obj-necko/source-v19
python obj-necko/source-v19/build.py --source-root obj-necko/source-v19 --nss-dist obj-necko/nss-sdk-v19 --output obj-necko/tmp/test-runs/export-build-v19 --work-dir obj-necko/tmp/test-runs/export-build-v19
python -m pip wheel obj-necko/nss-v19 --no-deps --wheel-dir obj-necko/wheel-v19
```

The runtime output includes both native DLLs, Python package, C headers, and SHA-256
artifact manifests. Source exports include provenance hashes and build without
the Firefox checkout. They bundle the Cargo lockfile and its dependency closure,
including optional dependencies required for offline resolution. Export
destinations must be new. `--work-dir` controls temporary object and Cargo output.
CMake builds the C++ core; `build.py` also builds and packages HTTP/3.
The SDK export resolves the checkout's header links into regular files and
retains runtime and configuration-source hashes, so the exported build needs
no Firefox checkout. It contains prebuilt NSS libraries, not an NSS source build.

## Temporary validation workspace

Validation output and cleanup staging use `obj-necko/tmp`. Test logs and
response captures go under `obj-necko/tmp/test-runs`; historical test trees,
generated bytecode, and disposable build state go under
`obj-necko/tmp/delete-queue`. The versioned runtime, SDK, source, and wheel
directories remain outside this temporary workspace. Temporary material is kept
for the user to delete manually; no automatic cleanup is performed. Historical logs and summaries
retain the paths and results from their original runs. Moved virtual environments
are disposable archives; create a fresh environment under `test-runs` for reuse.

From the checkout root, set temporary paths for validation commands:

```powershell
$neckoTmp = (Resolve-Path .\obj-necko\tmp).Path
New-Item -ItemType Directory -Force -Path "$neckoTmp\test-runs\temp" | Out-Null
$env:TEMP = "$neckoTmp\test-runs\temp"
$env:TMP = $env:TEMP
$env:PYTHONPYCACHEPREFIX = "$neckoTmp\test-runs\pycache"
```

## Scope and Upgrade Policy

Windows x64 is the validated build platform. Other platforms require their own
build and integration review before distribution. Native response headers
are limited to 64 KiB, and ambiguous Content-Length / Transfer-Encoding framing
is rejected. Streaming bodies have no fixed 64 MiB limit. DNS resolution uses
the system resolver; its blocking duration is not bounded by connect timeout.

The pinned TLS profile includes TLS 1.2/1.3, Firefox cipher and signature
preferences, ML-KEM-768/X25519 and P-256 key shares, ECH GREASE, OCSP/SCT
extensions, delegated credentials, and working zlib/Brotli/Zstandard certificate
decompression. `response.tls` reports backend/version/cipher/ALPN/resumption.

This is a measurable transport profile, not a complete browser. HTTP/2 and HTTP/3
support concurrent streams and certificate/IP-checked connection coalescing.
HTTP/2 ORIGIN entries accumulate across frames. Valid entries permit coalescing
after certificate verification without another DNS lookup; an initialized set
restricts DNS-based coalescing. Invalid stream/flag contexts are ignored.
Real ECH from DNS HTTPS records, Firefox DNS/cache, partitioned cookies, HSTS
preload and complete browser scheduling are not implemented. HTTP/3 with proxies
or client certificates currently uses TCP instead. HPACK indexing and Huffman encoding follow the
Firefox source and are compared as raw header blocks. 0-RTT is advertised as
Firefox does, but request data waits for the handshake. Redirect plumbing uses
Requests with Firefox header/context recomputation. HTTPS proxy ALPN is limited
to HTTP/1.1. CORS enforcement, DOM events, browser caches, and automatic
navigation/subresource lifecycle require a browser runtime.

On September 24, 2026, a local Firefox 156.0 comparison matched the normalized
ClientHello fields, request headers/order, and HTTP/2 frame payloads for a local
HTTPS GET with equal navigation context. Firefox opened an additional speculative
connection. Four HTTP/1 reset scenarios also matched observed attempt counts
(2, 10, 1, 1). These checks do not establish universal packet, timing, HTTP/3,
resumption, concurrency, or connection-lifecycle equivalence.

Upgrades must move the NSS SDK and Firefox TLS/HTTP2 configuration together,
review the source files listed in `necko/firefox-profile.json`, and verify a clean
wheel installation. The current
profile rejects NSS versions other than 3.130 instead of silently using changed
defaults. Native C ABI additions preserve the existing entry points. MPL-2.0
covers local code and Mozilla components; Python dependencies retain their
upstream licenses. Version 0.8.1 Python modules require the matching native DLL
with the nonblocking I/O entry points; upgrade the package and DLLs together.
