# Data flow — psf/requests

> Canonical page: https://codevetter.com/unpack/requests/data-flow

# Data flow — psf/requests

Scanned commit 611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60 (2026-09-21). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Input arrives as loosely-typed Python kwargs at `api.request()` or `Session.request()`, is funnelled into a `Request` value object, then normalised into a fully-serialised `PreparedRequest` (bytes body, `CaseInsensitiveDict` headers, percent-encoded URL string) by `Session.prepare_request()`. Session-level and environment-level settings are merged in at two distinct points — `merge_setting`/`merge_hooks` during preparation, and `merge_environment_settings` for proxies/verify/cert/stream just before send. The `PreparedRequest` crosses the adapter boundary into urllib3, and the urllib3 response crosses back through `HTTPAdapter.build_response()`, which is the sole constructor of `Response` objects. State ownership is clean: `Session` owns cookies, adapters and defaults; `PreparedRequest` owns the wire representation; `Response` owns `_content`/`_content_consumed` and lazily pulls bytes off `raw`. Output boundaries are the `Response` accessors and the environment mutations in `should_bypass_proxies` (via `set_environ`) and `extract_zipped_paths` (via `tempfile.mkstemp`).
- Settings precedence is implemented by `merge_setting(request_setting, session_setting)`: non-Mapping request values win outright, Mappings are merged with request keys overriding, and any key explicitly set to `None` is deleted from the merged result — that is how callers suppress a session default header. — [src/requests/sessions.py#L75-L104](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/sessions.py#L75-L104)
- Hooks need special merging because `{'response': []}` would otherwise wipe session hooks; `merge_hooks` short-circuits when either side has an empty response list. — [src/requests/sessions.py#L107-L123](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/sessions.py#L107-L123)
- Cookies flow through a three-way merge in `prepare_request`: `merge_cookies(merge_cookies(RequestsCookieJar(), self.cookies), request.cookies)`, so per-request cookies layer over session cookies into a fresh jar rather than mutating the session's. — [src/requests/sessions.py#L511-L556](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/sessions.py#L511-L556) [src/requests/cookies.py#L604-L625](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/cookies.py#L604-L625)
- `PreparedRequest.prepare()` runs a fixed six-step pipeline — method, url, headers, cookies, body, auth — then hooks; the ordering comment states auth must be last so schemes like OAuth can sign a fully-formed request and still register hooks. — [src/requests/models.py#L424-L452](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/models.py#L424-L452)
- `prepare_auth` mutates the prepared request by `self.__dict__.update(r.__dict__)` from whatever the auth callable returns, then recomputes Content-Length — so an auth handler can legitimately rewrite body and headers. — [src/requests/models.py#L670-L697](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/models.py#L670-L697)
- Credentials embedded in the URL are extracted into auth during preparation: `prepare_auth` calls `get_auth_from_url(self.url)` when no explicit auth was supplied, and `prepare_url` reassembles netloc with the `auth@` prefix preserved. — [src/requests/models.py#L672-L676](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/models.py#L672-L676) [src/requests/utils.py#L1070](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/utils.py#L1070) [src/requests/models.py#L536-L541](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/models.py#L536-L541)
- Environment enters the flow at `merge_environment_settings`, which (only when `trust_env`) seeds proxies from `getproxies()` and overrides `verify` from `REQUESTS_CA_BUNDLE` or `CURL_CA_BUNDLE` — explicitly to be cURL-compatible. — [src/requests/sessions.py#L831-L868](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/sessions.py#L831-L868)
- Proxy selection is layered: `resolve_proxies` consults `should_bypass_proxies` (NO_PROXY, CIDR matching, platform `proxy_bypass`), then `select_proxy` picks by the key precedence `scheme://host` → `scheme` → `all://host` → `all`. — [src/requests/utils.py#L810-L871](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/utils.py#L810-L871) [src/requests/utils.py#L885-L940](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/utils.py#L885-L940)
- Body length determination flows through `super_len()`, which probes `__len__`, `.len`, `fileno()`+`os.fstat`, and `seek/tell`, subtracting the current file position so partially-read files report the remaining bytes. — [src/requests/utils.py#L160-L228](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/utils.py#L160-L228) [src/requests/models.py#L654-L668](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/models.py#L654-L668)
- Header values are validated at the input boundary by `check_header_validity`, which regex-matches against `HEADER_VALIDATORS` to reject CR/LF and leading-whitespace — the CRLF-injection guard. — [src/requests/models.py#L565-L574](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/models.py#L565-L574) [src/requests/utils.py#L1087-L1120](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/utils.py#L1087-L1120) [src/requests/_internal_utils.py#L13-L24](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/_internal_utils.py#L13-L24)
- The response side is constructed exclusively in `HTTPAdapter.build_response()`, which lifts status, `CaseInsensitiveDict` headers, encoding from `get_encoding_from_headers`, `raw`, reason, url, extracts server cookies into `response.cookies`, and back-links `request` and `connection`. — [src/requests/adapters.py#L365-L402](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/adapters.py#L365-L402)
- Cookies persist onto the Session after the fact: `Session.send` calls `extract_cookies_to_jar(self.cookies, request, r.raw)` for the final response and separately for every entry in `r.history`. — [src/requests/sessions.py#L791-L800](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/sessions.py#L791-L800) [src/requests/cookies.py#L135-L152](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/cookies.py#L135-L152)
- Response bytes are pulled lazily: `content` joins `iter_content(CONTENT_CHUNK_SIZE)` (10 KiB) once and caches into `_content`, flipping `_content_consumed`; `Session.send` forces this by touching `r.content` whenever `stream` is falsy. — [src/requests/models.py#L1035-L1052](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/models.py#L1035-L1052) [src/requests/models.py#L104](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/models.py#L104) [src/requests/sessions.py#L826-L829](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/sessions.py#L826-L829)
- urllib3 exceptions are translated into the requests hierarchy at exactly one place — the `try/except` ladder in `HTTPAdapter.send` mapping `MaxRetryError` reasons to `ConnectTimeout`/`RetryError`/`ProxyError`/`SSLError` and `ProtocolError`/`OSError` to `ConnectionError`. — [src/requests/adapters.py#L703-L747](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/adapters.py#L703-L747) [src/requests/exceptions.py#L66-L150](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/exceptions.py#L66-L150)
- `should_bypass_proxies` temporarily mutates process environment via the `set_environ('no_proxy', ...)` context manager before calling the stdlib `proxy_bypass`, restoring the prior value in a `finally` block. — [src/requests/utils.py#L787-L808](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/utils.py#L787-L808) [src/requests/utils.py#L860-L868](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/utils.py#L860-L868)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
