Repository navigation
0.12
Six new packages join the supported list, and the release also carries a security-relevant rendering fix — if you render incoming requests server-side, upgrading is worth doing now.
New adapters
Runtime dependencies stay at zero: every adapter registers only when its library is importable.
| Library | Type | Call | Notes |
|---|---|---|---|
niquests |
PreparedRequest |
to_curl |
HTTP/2 and HTTP/3 live on the transport, so no --http2 |
urllib.request (stdlib) |
Request |
to_curl |
an absent method is inferred the way urllib sends it |
aiohttp client-side |
ClientRequest |
to_curl_async |
reachable in client middlewares (aiohttp 3.12+); the body is read without consuming the payload via Payload.as_bytes() (3.12.1+) |
django |
HttpRequest |
to_curl |
the framework buffers the body, so the sync call is enough — async views included |
flask / werkzeug |
werkzeug.wrappers.Request |
to_curl |
covers Flask through its Werkzeug base |
tornado |
httpclient.HTTPRequest, httputil.HTTPServerRequest |
to_curl |
client and server |
A body or form value starting with @ or < could read a local file
curl reads a leading @ in a -d value — and @ or < in a -F value — as the name of a local file to send the contents of. A request whose body or form field started with one was rendered so that the command, pasted out of a log, read that file and sent it to the url the request was rendered for. Reachable from the wire through the server-side adapters, where the value is the caller's to choose. Such values now go through --data-raw / --form-string, which take them literally; a file part keeps -F 'field=@file', where the @ is the intended meaning.
Multipart rendering rewritten
Parts are split on the boundary from Content-Type instead of matched by regex: field values with newlines are no longer truncated, single-character field names are no longer dropped, values that do not decode as UTF-8 render as ANSI-C literals instead of raising, parts come out in the order the body carries them, and a NUL byte in a field value is rejected like one in a body.
Cookies
- A
Cookieheader held in a case-sensitive container was silently dropped — tornado's client request keeps whatever plain dict it was handed, and the value reached neither-bnor-H. The extraction now scans the lowercased header names. - An empty
Cookieheader no longer renders as-H 'cookie: '; django'sRequestFactoryputs one on every request it builds, which is how it surfaced.
Full details in CHANGELOG.md.