Apply per-header policy shared between Python and fast parsers. Mutates ``self._expected_100_continue`` and ``self.scheme`` as needed. ``scheme_state`` is a single-element list used as a mutable sentinel so the caller can detect repeated scheme headers. Returns the
(self, name, value, scheme_state,
secure_scheme_headers, forwarder_headers,
from_trailer=False)
| 221 | return {}, [] |
| 222 | |
| 223 | def _apply_header_policy(self, name, value, scheme_state, |
| 224 | secure_scheme_headers, forwarder_headers, |
| 225 | from_trailer=False): |
| 226 | """Apply per-header policy shared between Python and fast parsers. |
| 227 | |
| 228 | Mutates ``self._expected_100_continue`` and ``self.scheme`` as needed. |
| 229 | ``scheme_state`` is a single-element list used as a mutable sentinel |
| 230 | so the caller can detect repeated scheme headers. |
| 231 | |
| 232 | Returns the (name, value) pair to retain, or ``None`` to drop the |
| 233 | header (per ``header_map='drop'``). Raises the same exceptions the |
| 234 | Python path raises so behavior is identical regardless of parser. |
| 235 | """ |
| 236 | if not from_trailer and name == "EXPECT": |
| 237 | # https://datatracker.ietf.org/doc/html/rfc9110#section-10.1.1 |
| 238 | # "The Expect field value is case-insensitive." |
| 239 | if value.lower() == "100-continue": |
| 240 | if self.version < (1, 1): |
| 241 | # https://datatracker.ietf.org/doc/html/rfc9110#section-10.1.1-12 |
| 242 | # "A server that receives a 100-continue expectation |
| 243 | # in an HTTP/1.0 request MUST ignore that expectation." |
| 244 | pass |
| 245 | else: |
| 246 | self._expected_100_continue = True |
| 247 | # N.B. understood but ignored expect header does not return 417 |
| 248 | else: |
| 249 | raise ExpectationFailed(value) |
| 250 | |
| 251 | if name in secure_scheme_headers: |
| 252 | secure = value == secure_scheme_headers[name] |
| 253 | scheme = "https" if secure else "http" |
| 254 | if scheme_state[0]: |
| 255 | if scheme != self.scheme: |
| 256 | raise InvalidSchemeHeaders() |
| 257 | else: |
| 258 | scheme_state[0] = True |
| 259 | self.scheme = scheme |
| 260 | |
| 261 | # ambiguous mapping allows fooling downstream, e.g. merging non-identical headers: |
| 262 | # X-Forwarded-For: 2001:db8::ha:cc:ed |
| 263 | # X_Forwarded_For: 127.0.0.1,::1 |
| 264 | # HTTP_X_FORWARDED_FOR = 2001:db8::ha:cc:ed,127.0.0.1,::1 |
| 265 | # Only modify after fixing *ALL* header transformations; network to wsgi env |
| 266 | if "_" in name: |
| 267 | if name in forwarder_headers or "*" in forwarder_headers: |
| 268 | # This forwarder may override our environment |
| 269 | pass |
| 270 | elif self.cfg.header_map == "dangerous": |
| 271 | # as if we did not know we cannot safely map this |
| 272 | pass |
| 273 | elif self.cfg.header_map == "drop": |
| 274 | # almost as if it never had been there |
| 275 | # but still counts against resource limits |
| 276 | return None |
| 277 | else: |
| 278 | # fail-safe fallthrough: refuse |
| 279 | raise InvalidHeaderName(name) |
| 280 |
no test coverage detected