MCPcopy
hub / github.com/benoitc/gunicorn / _apply_header_policy

Method _apply_header_policy

gunicorn/http/message.py:223–281  ·  view source on GitHub ↗

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)

Source from the content-addressed store, hash-verified

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

Callers 2

parse_headersMethod · 0.95
_parse_fastMethod · 0.80

Calls 3

ExpectationFailedClass · 0.90
InvalidHeaderNameClass · 0.90

Tested by

no test coverage detected