Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_net/src/http/fields.rs

71.5 KiB, 116 runs

created by r1870400018:573, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use crate::{
2 charset::Charset,
3 constant::SESSION_ID_KEY_LABEL,
4 media::{
5 ContentTypeValue,
6 MediaType,
7 Multipart,
8 },
9};
10
11use oxedyne_fe2o3_core::prelude::*;
12
13use std::{
14 collections::{
15 BTreeMap,
16 BTreeSet,
17 },
18 fmt,
19 time::Duration,
20};
21
22use strum::{
23 Display,
24};
25
26
27#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
28pub enum HeaderName {
29 AIM,
30 Accept,
31 AcceptAdditions,
32 AcceptCH,
33 AcceptCharset,
34 AcceptDatetime,
35 AcceptEncoding,
36 AcceptFeatures,
37 AcceptLanguage,
38 AcceptPatch,
39 AcceptPost,
40 AcceptRanges,
41 AcceptSignature,
42 AccessControl,
43 AccessControlAllowCredentials,
44 AccessControlAllowHeaders,
45 AccessControlAllowMethods,
46 AccessControlAllowOrigin,
47 AccessControlExposeHeaders,
48 AccessControlMaxAge,
49 AccessControlRequestHeaders,
50 AccessControlRequestMethod,
51 Age,
52 Allow,
53 ALPN,
54 AltSvc,
55 AltUsed,
56 Alternates,
57 AMPCacheTransform,
58 ApplyToRedirectRef,
59 AuthenticationControl,
60 AuthenticationInfo,
61 Authorization,
62 CExt,
63 CMan,
64 COpt,
65 CPEP,
66 CPEPInfo,
67 CacheControl,
68 CacheStatus,
69 CalManagedID,
70 CalDAVTimezones,
71 CapsuleProtocol,
72 CDNCacheControl,
73 CDNLoop,
74 CertNotAfter,
75 CertNotBefore,
76 ClearSiteData,
77 ClientCert,
78 ClientCertChain,
79 Close,
80 ConfigurationContext,
81 Connection,
82 ContentBase,
83 ContentDigest,
84 ContentDisposition,
85 ContentEncoding,
86 ContentID,
87 ContentLanguage,
88 ContentLength,
89 ContentLocation,
90 ContentMD5,
91 ContentRange,
92 ContentScriptType,
93 ContentSecurityPolicy,
94 ContentSecurityPolicyReportOnly,
95 ContentStyleType,
96 ContentType,
97 ContentVersion,
98 Cookie,
99 Cookie2,
100 CrossOriginEmbedderPolicy,
101 CrossOriginEmbedderPolicyReportOnly,
102 CrossOriginOpenerPolicy,
103 CrossOriginOpenerPolicyReportOnly,
104 CrossOriginResourcePolicy,
105 DASL,
106 Date,
107 DAV,
108 DefaultStyle,
109 DeltaBase,
110 Depth,
111 DerivedFrom,
112 Destination,
113 DifferentialID,
114 Digest,
115 DPoP,
116 DPoPNonce,
117 EarlyData,
118 EDIINTFeatures,
119 ETag,
120 Expect,
121 ExpectCT,
122 Expires,
123 Ext,
124 Forwarded,
125 From,
126 GetProfile,
127 Hobareg,
128 Host,
129 HTTP2Settings,
130 If,
131 IfMatch,
132 IfModifiedSince,
133 IfNoneMatch,
134 IfRange,
135 IfScheduleTagMatch,
136 IfUnmodifiedSince,
137 IM,
138 IncludeReferredTokenBindingID,
139 Isolation,
140 KeepAlive,
141 Label,
142 LastEventID,
143 LastModified,
144 Link,
145 Location,
146 LockToken,
147 Man,
148 MaxForwards,
149 MementoDatetime,
150 Meter,
151 MethodCheck,
152 MethodCheckExpires,
153 MIMEVersion,
154 Negotiate,
155 NEL,
156 ODataEntityId,
157 ODataIsolation,
158 ODataMaxVersion,
159 ODataVersion,
160 Opt,
161 OptionalWWWAuthenticate,
162 OrderingType,
163 Origin,
164 OriginAgentCluster,
165 OSCORE,
166 OSLCCoreVersion,
167 Overwrite,
168 P3P,
169 PEP,
170 PEPInfo,
171 PermissionsPolicy,
172 PICSLabel,
173 PingFrom,
174 PingTo,
175 Position,
176 Pragma,
177 Prefer,
178 PreferenceApplied,
179 Priority,
180 ProfileObject,
181 Protocol,
182 ProtocolInfo,
183 ProtocolQuery,
184 ProtocolRequest,
185 ProxyAuthenticate,
186 ProxyAuthenticationInfo,
187 ProxyAuthorization,
188 ProxyFeatures,
189 ProxyInstruction,
190 ProxyStatus,
191 Public,
192 PublicKeyPins,
193 PublicKeyPinsReportOnly,
194 Range,
195 RedirectRef,
196 Referer,
197 RefererRoot,
198 ReferrerPolicy,
199 Refresh,
200 RepeatabilityClientID,
201 RepeatabilityFirstSent,
202 RepeatabilityRequestID,
203 RepeatabilityResult,
204 ReplayNonce,
205 ReportingEndpoints,
206 ReprDigest,
207 RetryAfter,
208 Safe,
209 ScheduleReply,
210 ScheduleTag,
211 SecGPC,
212 SecPurpose,
213 SecTokenBinding,
214 SecWebSocketAccept,
215 SecWebSocketExtensions,
216 SecWebSocketKey,
217 SecWebSocketProtocol,
218 SecWebSocketVersion,
219 SecurityScheme,
220 Server,
221 ServerTiming,
222 SetCookie,
223 SetCookie2,
224 SetProfile,
225 Signature,
226 SignatureInput,
227 SLUG,
228 SoapAction,
229 StatusURI,
230 StrictTransportSecurity,
231 Sunset,
232 SurrogateCapability,
233 SurrogateControl,
234 TCN,
235 TE,
236 Timeout,
237 TimingAllowOrigin,
238 Topic,
239 Traceparent,
240 Tracestate,
241 Trailer,
242 TransferEncoding,
243 TTL,
244 Upgrade,
245 Urgency,
246 URI,
247 UserAgent,
248 VariantVary,
249 Vary,
250 Via,
251 WantContentDigest,
252 WantDigest,
253 WantReprDigest,
254 Warning,
255 WWWAuthenticate,
256 XContentTypeOptions,
257 XFrameOptions,
258 NonStandard(String),
259}
260
261impl fmt::Display for HeaderName {
262 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263 match self {
264 Self::AIM => write!(f, "a-im"),
265 Self::Accept => write!(f, "accept"),
266 Self::AcceptAdditions => write!(f, "accept-additions"),
267 Self::AcceptCH => write!(f, "accept-ch"),
268 Self::AcceptCharset => write!(f, "accept-charset"),
269 Self::AcceptDatetime => write!(f, "accept-datetime"),
270 Self::AcceptEncoding => write!(f, "accept-encoding"),
271 Self::AcceptFeatures => write!(f, "accept-features"),
272 Self::AcceptLanguage => write!(f, "accept-language"),
273 Self::AcceptPatch => write!(f, "accept-patch"),
274 Self::AcceptPost => write!(f, "accept-post"),
275 Self::AcceptRanges => write!(f, "accept-ranges"),
276 Self::AcceptSignature => write!(f, "accept-signature"),
277 Self::AccessControl => write!(f, "access-control"),
278 Self::AccessControlAllowCredentials => write!(f, "access-control-allow-credentials"),
279 Self::AccessControlAllowHeaders => write!(f, "access-control-allow-headers"),
280 Self::AccessControlAllowMethods => write!(f, "access-control-allow-methods"),
281 Self::AccessControlAllowOrigin => write!(f, "access-control-allow-origin"),
282 Self::AccessControlExposeHeaders => write!(f, "access-control-expose-headers"),
283 Self::AccessControlMaxAge => write!(f, "access-control-max-age"),
284 Self::AccessControlRequestHeaders => write!(f, "access-control-request-headers"),
285 Self::AccessControlRequestMethod => write!(f, "access-control-request-method"),
286 Self::Age => write!(f, "age"),
287 Self::Allow => write!(f, "allow"),
288 Self::ALPN => write!(f, "alpn"),
289 Self::AltSvc => write!(f, "alt-svc"),
290 Self::AltUsed => write!(f, "alt-used"),
291 Self::Alternates => write!(f, "alternates"),
292 Self::AMPCacheTransform => write!(f, "amp-cache-transform"),
293 Self::ApplyToRedirectRef => write!(f, "apply-to-redirect-ref"),
294 Self::AuthenticationControl => write!(f, "authentication-control"),
295 Self::AuthenticationInfo => write!(f, "authentication-info"),
296 Self::Authorization => write!(f, "authorization"),
297 Self::CExt => write!(f, "c-ext"),
298 Self::CMan => write!(f, "c-man"),
299 Self::COpt => write!(f, "c-opt"),
300 Self::CPEP => write!(f, "c-pep"),
301 Self::CPEPInfo => write!(f, "c-pep-info"),
302 Self::CacheControl => write!(f, "cache-control"),
303 Self::CacheStatus => write!(f, "cache-status"),
304 Self::CalManagedID => write!(f, "cal-managed-id"),
305 Self::CalDAVTimezones => write!(f, "caldav-timezones"),
306 Self::CapsuleProtocol => write!(f, "capsule-protocol"),
307 Self::CDNCacheControl => write!(f, "cdn-cache-control"),
308 Self::CDNLoop => write!(f, "cdn-loop"),
309 Self::CertNotAfter => write!(f, "cert-not-after"),
310 Self::CertNotBefore => write!(f, "cert-not-before"),
311 Self::ClearSiteData => write!(f, "clear-site-data"),
312 Self::ClientCert => write!(f, "client-cert"),
313 Self::ClientCertChain => write!(f, "client-cert-chain"),
314 Self::Close => write!(f, "close"),
315 Self::ConfigurationContext => write!(f, "configuration-context"),
316 Self::Connection => write!(f, "connection"),
317 Self::ContentBase => write!(f, "content-base"),
318 Self::ContentDigest => write!(f, "content-digest"),
319 Self::ContentDisposition => write!(f, "content-disposition"),
320 Self::ContentEncoding => write!(f, "content-encoding"),
321 Self::ContentID => write!(f, "content-id"),
322 Self::ContentLanguage => write!(f, "content-language"),
323 Self::ContentLength => write!(f, "content-length"),
324 Self::ContentLocation => write!(f, "content-location"),
325 Self::ContentMD5 => write!(f, "content-md5"),
326 Self::ContentRange => write!(f, "content-range"),
327 Self::ContentScriptType => write!(f, "content-script-type"),
328 Self::ContentSecurityPolicy => write!(f, "content-security-policy"),
329 Self::ContentSecurityPolicyReportOnly => write!(f, "content-security-policy-report-only"),
330 Self::ContentStyleType => write!(f, "content-style-type"),
331 Self::ContentType => write!(f, "content-type"),
332 Self::ContentVersion => write!(f, "content-version"),
333 Self::Cookie => write!(f, "cookie"),
334 Self::Cookie2 => write!(f, "cookie2"),
335 Self::CrossOriginEmbedderPolicy => write!(f, "cross-origin-embedder-policy"),
336 Self::CrossOriginEmbedderPolicyReportOnly => write!(f, "cross-origin-embedder-policy-report-only"),
337 Self::CrossOriginOpenerPolicy => write!(f, "cross-origin-opener-policy"),
338 Self::CrossOriginOpenerPolicyReportOnly => write!(f, "cross-origin-opener-policy-report-only"),
339 Self::CrossOriginResourcePolicy => write!(f, "cross-origin-resource-policy"),
340 Self::DASL => write!(f, "dasl"),
341 Self::Date => write!(f, "date"),
342 Self::DAV => write!(f, "dav"),
343 Self::DefaultStyle => write!(f, "default-style"),
344 Self::DeltaBase => write!(f, "delta-base"),
345 Self::Depth => write!(f, "depth"),
346 Self::DerivedFrom => write!(f, "derived-from"),
347 Self::Destination => write!(f, "destination"),
348 Self::DifferentialID => write!(f, "differential-id"),
349 Self::Digest => write!(f, "digest"),
350 Self::DPoP => write!(f, "dpop"),
351 Self::DPoPNonce => write!(f, "dpop-nonce"),
352 Self::EarlyData => write!(f, "early-data"),
353 Self::EDIINTFeatures => write!(f, "ediint-features"),
354 Self::ETag => write!(f, "etag"),
355 Self::Expect => write!(f, "expect"),
356 Self::ExpectCT => write!(f, "expect-ct"),
357 Self::Expires => write!(f, "expires"),
358 Self::Ext => write!(f, "ext"),
359 Self::Forwarded => write!(f, "forwarded"),
360 Self::From => write!(f, "from"),
361 Self::GetProfile => write!(f, "getprofile"),
362 Self::Hobareg => write!(f, "hobareg"),
363 Self::Host => write!(f, "host"),
364 Self::HTTP2Settings => write!(f, "http2-settings"),
365 Self::If => write!(f, "if"),
366 Self::IfMatch => write!(f, "if-match"),
367 Self::IfModifiedSince => write!(f, "if-modified-since"),
368 Self::IfNoneMatch => write!(f, "if-none-match"),
369 Self::IfRange => write!(f, "if-range"),
370 Self::IfScheduleTagMatch => write!(f, "if-schedule-tag-match"),
371 Self::IfUnmodifiedSince => write!(f, "if-unmodified-since"),
372 Self::IM => write!(f, "im"),
373 Self::IncludeReferredTokenBindingID => write!(f, "include-referred-token-binding-id"),
374 Self::Isolation => write!(f, "isolation"),
375 Self::KeepAlive => write!(f, "keep-alive"),
376 Self::Label => write!(f, "label"),
377 Self::LastEventID => write!(f, "last-event-id"),
378 Self::LastModified => write!(f, "last-modified"),
379 Self::Link => write!(f, "link"),
380 Self::Location => write!(f, "location"),
381 Self::LockToken => write!(f, "lock-token"),
382 Self::Man => write!(f, "man"),
383 Self::MaxForwards => write!(f, "max-forwards"),
384 Self::MementoDatetime => write!(f, "memento-datetime"),
385 Self::Meter => write!(f, "meter"),
386 Self::MethodCheck => write!(f, "method-check"),
387 Self::MethodCheckExpires => write!(f, "method-check-expires"),
388 Self::MIMEVersion => write!(f, "mime-version"),
389 Self::Negotiate => write!(f, "negotiate"),
390 Self::NEL => write!(f, "nel"),
391 Self::ODataEntityId => write!(f, "odata-entityid"),
392 Self::ODataIsolation => write!(f, "odata-isolation"),
393 Self::ODataMaxVersion => write!(f, "odata-maxversion"),
394 Self::ODataVersion => write!(f, "odata-version"),
395 Self::Opt => write!(f, "opt"),
396 Self::OptionalWWWAuthenticate => write!(f, "optional-www-authenticate"),
397 Self::OrderingType => write!(f, "ordering-type"),
398 Self::Origin => write!(f, "origin"),
399 Self::OriginAgentCluster => write!(f, "origin-agent-cluster"),
400 Self::OSCORE => write!(f, "oscore"),
401 Self::OSLCCoreVersion => write!(f, "oslc-core-version"),
402 Self::Overwrite => write!(f, "overwrite"),
403 Self::P3P => write!(f, "p3p"),
404 Self::PEP => write!(f, "pep"),
405 Self::PEPInfo => write!(f, "pep-info"),
406 Self::PermissionsPolicy => write!(f, "permissions-policy"),
407 Self::PICSLabel => write!(f, "pics-label"),
408 Self::PingFrom => write!(f, "ping-from"),
409 Self::PingTo => write!(f, "ping-to"),
410 Self::Position => write!(f, "position"),
411 Self::Pragma => write!(f, "pragma"),
412 Self::Prefer => write!(f, "prefer"),
413 Self::PreferenceApplied => write!(f, "preference-applied"),
414 Self::Priority => write!(f, "priority"),
415 Self::ProfileObject => write!(f, "profileobject"),
416 Self::Protocol => write!(f, "protocol"),
417 Self::ProtocolInfo => write!(f, "protocol-info"),
418 Self::ProtocolQuery => write!(f, "protocol-query"),
419 Self::ProtocolRequest => write!(f, "protocol-request"),
420 Self::ProxyAuthenticate => write!(f, "proxy-authenticate"),
421 Self::ProxyAuthenticationInfo => write!(f, "proxy-authentication-info"),
422 Self::ProxyAuthorization => write!(f, "proxy-authorization"),
423 Self::ProxyFeatures => write!(f, "proxy-features"),
424 Self::ProxyInstruction => write!(f, "proxy-instruction"),
425 Self::ProxyStatus => write!(f, "proxy-status"),
426 Self::Public => write!(f, "public"),
427 Self::PublicKeyPins => write!(f, "public-key-pins"),
428 Self::PublicKeyPinsReportOnly => write!(f, "public-key-pins-report-only"),
429 Self::Range => write!(f, "range"),
430 Self::RedirectRef => write!(f, "redirect-ref"),
431 Self::Referer => write!(f, "referer"),
432 Self::RefererRoot => write!(f, "referer-root"),
433 Self::ReferrerPolicy => write!(f, "referrer-policy"),
434 Self::Refresh => write!(f, "refresh"),
435 Self::RepeatabilityClientID => write!(f, "repeatability-client-id"),
436 Self::RepeatabilityFirstSent => write!(f, "repeatability-first-sent"),
437 Self::RepeatabilityRequestID => write!(f, "repeatability-request-id"),
438 Self::RepeatabilityResult => write!(f, "repeatability-result"),
439 Self::ReplayNonce => write!(f, "replay-nonce"),
440 Self::ReportingEndpoints => write!(f, "reporting-endpoints"),
441 Self::ReprDigest => write!(f, "repr-digest"),
442 Self::RetryAfter => write!(f, "retry-after"),
443 Self::Safe => write!(f, "safe"),
444 Self::ScheduleReply => write!(f, "schedule-reply"),
445 Self::ScheduleTag => write!(f, "schedule-tag"),
446 Self::SecGPC => write!(f, "sec-gpc"),
447 Self::SecPurpose => write!(f, "sec-purpose"),
448 Self::SecTokenBinding => write!(f, "sec-token-binding"),
449 Self::SecWebSocketAccept => write!(f, "sec-websocket-accept"),
450 Self::SecWebSocketExtensions => write!(f, "sec-websocket-extensions"),
451 Self::SecWebSocketKey => write!(f, "sec-websocket-key"),
452 Self::SecWebSocketProtocol => write!(f, "sec-websocket-protocol"),
453 Self::SecWebSocketVersion => write!(f, "sec-websocket-version"),
454 Self::SecurityScheme => write!(f, "security-scheme"),
455 Self::Server => write!(f, "server"),
456 Self::ServerTiming => write!(f, "server-timing"),
457 Self::SetCookie => write!(f, "set-cookie"),
458 Self::SetCookie2 => write!(f, "set-cookie2"),
459 Self::SetProfile => write!(f, "setprofile"),
460 Self::Signature => write!(f, "signature"),
461 Self::SignatureInput => write!(f, "signature-input"),
462 Self::SLUG => write!(f, "slug"),
463 Self::SoapAction => write!(f, "soapaction"),
464 Self::StatusURI => write!(f, "status-uri"),
465 Self::StrictTransportSecurity => write!(f, "strict-transport-security"),
466 Self::Sunset => write!(f, "sunset"),
467 Self::SurrogateCapability => write!(f, "surrogate-capability"),
468 Self::SurrogateControl => write!(f, "surrogate-control"),
469 Self::TCN => write!(f, "tcn"),
470 Self::TE => write!(f, "te"),
471 Self::Timeout => write!(f, "timeout"),
472 Self::TimingAllowOrigin => write!(f, "timing-allow-origin"),
473 Self::Topic => write!(f, "topic"),
474 Self::Traceparent => write!(f, "traceparent"),
475 Self::Tracestate => write!(f, "tracestate"),
476 Self::Trailer => write!(f, "trailer"),
477 Self::TransferEncoding => write!(f, "transfer-encoding"),
478 Self::TTL => write!(f, "ttl"),
479 Self::Upgrade => write!(f, "upgrade"),
480 Self::Urgency => write!(f, "urgency"),
481 Self::URI => write!(f, "uri"),
482 Self::UserAgent => write!(f, "user-agent"),
483 Self::VariantVary => write!(f, "variant-vary"),
484 Self::Vary => write!(f, "vary"),
485 Self::Via => write!(f, "via"),
486 Self::WantContentDigest => write!(f, "want-content-digest"),
487 Self::WantDigest => write!(f, "want-digest"),
488 Self::WantReprDigest => write!(f, "want-repr-digest"),
489 Self::Warning => write!(f, "warning"),
490 Self::WWWAuthenticate => write!(f, "www-authenticate"),
491 Self::XContentTypeOptions => write!(f, "x-content-type-options"),
492 Self::XFrameOptions => write!(f, "x-frame-options"),
493 Self::NonStandard(s) => write!(f, "{}", s),
494 }
495 }
496}
497
498impl From<&str> for HeaderName {
499 fn from(s: &str) -> Self {
500 match s {
501 "a-im" => Self::AIM,
502 "accept" => Self::Accept,
503 "accept-additions" => Self::AcceptAdditions,
504 "accept-ch" => Self::AcceptCH,
505 "accept-charset" => Self::AcceptCharset,
506 "accept-datetime" => Self::AcceptDatetime,
507 "accept-encoding" => Self::AcceptEncoding,
508 "accept-features" => Self::AcceptFeatures,
509 "accept-language" => Self::AcceptLanguage,
510 "accept-patch" => Self::AcceptPatch,
511 "accept-post" => Self::AcceptPost,
512 "accept-ranges" => Self::AcceptRanges,
513 "accept-signature" => Self::AcceptSignature,
514 "access-control" => Self::AccessControl,
515 "access-control-allow-credentials" => Self::AccessControlAllowCredentials,
516 "access-control-allow-headers" => Self::AccessControlAllowHeaders,
517 "access-control-allow-methods" => Self::AccessControlAllowMethods,
518 "access-control-allow-origin" => Self::AccessControlAllowOrigin,
519 "access-control-expose-headers" => Self::AccessControlExposeHeaders,
520 "access-control-max-age" => Self::AccessControlMaxAge,
521 "access-control-request-headers" => Self::AccessControlRequestHeaders,
522 "access-control-request-method" => Self::AccessControlRequestMethod,
523 "age" => Self::Age,
524 "allow" => Self::Allow,
525 "alpn" => Self::ALPN,
526 "alt-svc" => Self::AltSvc,
527 "alt-used" => Self::AltUsed,
528 "alternates" => Self::Alternates,
529 "amp-cache-transform" => Self::AMPCacheTransform,
530 "apply-to-redirect-ref" => Self::ApplyToRedirectRef,
531 "authentication-control" => Self::AuthenticationControl,
532 "authentication-info" => Self::AuthenticationInfo,
533 "authorization" => Self::Authorization,
534 "c-ext" => Self::CExt,
535 "c-man" => Self::CMan,
536 "c-opt" => Self::COpt,
537 "c-pep" => Self::CPEP,
538 "c-pep-info" => Self::CPEPInfo,
539 "cache-control" => Self::CacheControl,
540 "cache-status" => Self::CacheStatus,
541 "cal-managed-id" => Self::CalManagedID,
542 "caldav-timezones" => Self::CalDAVTimezones,
543 "capsule-protocol" => Self::CapsuleProtocol,
544 "cdn-cache-control" => Self::CDNCacheControl,
545 "cdn-loop" => Self::CDNLoop,
546 "cert-not-after" => Self::CertNotAfter,
547 "cert-not-before" => Self::CertNotBefore,
548 "clear-site-data" => Self::ClearSiteData,
549 "client-cert" => Self::ClientCert,
550 "client-cert-chain" => Self::ClientCertChain,
551 "close" => Self::Close,
552 "configuration-context" => Self::ConfigurationContext,
553 "connection" => Self::Connection,
554 "content-base" => Self::ContentBase,
555 "content-digest" => Self::ContentDigest,
556 "content-disposition" => Self::ContentDisposition,
557 "content-encoding" => Self::ContentEncoding,
558 "content-id" => Self::ContentID,
559 "content-language" => Self::ContentLanguage,
560 "content-length" => Self::ContentLength,
561 "content-location" => Self::ContentLocation,
562 "content-md5" => Self::ContentMD5,
563 "content-range" => Self::ContentRange,
564 "content-script-type" => Self::ContentScriptType,
565 "content-security-policy" => Self::ContentSecurityPolicy,
566 "content-security-policy-report-only" => Self::ContentSecurityPolicyReportOnly,
567 "content-style-type" => Self::ContentStyleType,
568 "content-type" => Self::ContentType,
569 "content-version" => Self::ContentVersion,
570 "cookie" => Self::Cookie,
571 "cookie2" => Self::Cookie2,
572 "cross-origin-embedder-policy" => Self::CrossOriginEmbedderPolicy,
573 "cross-origin-embedder-policy-report-only" => Self::CrossOriginEmbedderPolicyReportOnly,
574 "cross-origin-opener-policy" => Self::CrossOriginOpenerPolicy,
575 "cross-origin-opener-policy-report-only" => Self::CrossOriginOpenerPolicyReportOnly,
576 "cross-origin-resource-policy" => Self::CrossOriginResourcePolicy,
577 "dasl" => Self::DASL,
578 "date" => Self::Date,
579 "dav" => Self::DAV,
580 "default-style" => Self::DefaultStyle,
581 "delta-base" => Self::DeltaBase,
582 "depth" => Self::Depth,
583 "derived-from" => Self::DerivedFrom,
584 "destination" => Self::Destination,
585 "differential-id" => Self::DifferentialID,
586 "digest" => Self::Digest,
587 "dpop" => Self::DPoP,
588 "dpop-nonce" => Self::DPoPNonce,
589 "early-data" => Self::EarlyData,
590 "ediint-features" => Self::EDIINTFeatures,
591 "etag" => Self::ETag,
592 "expect" => Self::Expect,
593 "expect-ct" => Self::ExpectCT,
594 "expires" => Self::Expires,
595 "ext" => Self::Ext,
596 "forwarded" => Self::Forwarded,
597 "from" => Self::From,
598 "getprofile" => Self::GetProfile,
599 "hobareg" => Self::Hobareg,
600 "host" => Self::Host,
601 "http2-settings" => Self::HTTP2Settings,
602 "if" => Self::If,
603 "if-match" => Self::IfMatch,
604 "if-modified-since" => Self::IfModifiedSince,
605 "if-none-match" => Self::IfNoneMatch,
606 "if-range" => Self::IfRange,
607 "if-schedule-tag-match" => Self::IfScheduleTagMatch,
608 "if-unmodified-since" => Self::IfUnmodifiedSince,
609 "im" => Self::IM,
610 "include-referred-token-binding-id" => Self::IncludeReferredTokenBindingID,
611 "isolation" => Self::Isolation,
612 "keep-alive" => Self::KeepAlive,
613 "label" => Self::Label,
614 "last-event-id" => Self::LastEventID,
615 "last-modified" => Self::LastModified,
616 "link" => Self::Link,
617 "location" => Self::Location,
618 "lock-token" => Self::LockToken,
619 "man" => Self::Man,
620 "max-forwards" => Self::MaxForwards,
621 "memento-datetime" => Self::MementoDatetime,
622 "meter" => Self::Meter,
623 "method-check" => Self::MethodCheck,
624 "method-check-expires" => Self::MethodCheckExpires,
625 "mime-version" => Self::MIMEVersion,
626 "negotiate" => Self::Negotiate,
627 "nel" => Self::NEL,
628 "odata-entityid" => Self::ODataEntityId,
629 "odata-isolation" => Self::ODataIsolation,
630 "odata-maxversion" => Self::ODataMaxVersion,
631 "odata-version" => Self::ODataVersion,
632 "opt" => Self::Opt,
633 "optional-www-authenticate" => Self::OptionalWWWAuthenticate,
634 "ordering-type" => Self::OrderingType,
635 "origin" => Self::Origin,
636 "origin-agent-cluster" => Self::OriginAgentCluster,
637 "oscore" => Self::OSCORE,
638 "oslc-core-version" => Self::OSLCCoreVersion,
639 "overwrite" => Self::Overwrite,
640 "p3p" => Self::P3P,
641 "pep" => Self::PEP,
642 "pep-info" => Self::PEPInfo,
643 "permissions-policy" => Self::PermissionsPolicy,
644 "pics-label" => Self::PICSLabel,
645 "ping-from" => Self::PingFrom,
646 "ping-to" => Self::PingTo,
647 "position" => Self::Position,
648 "pragma" => Self::Pragma,
649 "prefer" => Self::Prefer,
650 "preference-applied" => Self::PreferenceApplied,
651 "priority" => Self::Priority,
652 "profileobject" => Self::ProfileObject,
653 "protocol" => Self::Protocol,
654 "protocol-info" => Self::ProtocolInfo,
655 "protocol-query" => Self::ProtocolQuery,
656 "protocol-request" => Self::ProtocolRequest,
657 "proxy-authenticate" => Self::ProxyAuthenticate,
658 "proxy-authentication-info" => Self::ProxyAuthenticationInfo,
659 "proxy-authorization" => Self::ProxyAuthorization,
660 "proxy-features" => Self::ProxyFeatures,
661 "proxy-instruction" => Self::ProxyInstruction,
662 "proxy-status" => Self::ProxyStatus,
663 "public" => Self::Public,
664 "public-key-pins" => Self::PublicKeyPins,
665 "public-key-pins-report-only" => Self::PublicKeyPinsReportOnly,
666 "range" => Self::Range,
667 "redirect-ref" => Self::RedirectRef,
668 "referer" => Self::Referer,
669 "referer-root" => Self::RefererRoot,
670 "referrer-policy" => Self::ReferrerPolicy,
671 "refresh" => Self::Refresh,
672 "repeatability-client-id" => Self::RepeatabilityClientID,
673 "repeatability-first-sent" => Self::RepeatabilityFirstSent,
674 "repeatability-request-id" => Self::RepeatabilityRequestID,
675 "repeatability-result" => Self::RepeatabilityResult,
676 "replay-nonce" => Self::ReplayNonce,
677 "reporting-endpoints" => Self::ReportingEndpoints,
678 "repr-digest" => Self::ReprDigest,
679 "retry-after" => Self::RetryAfter,
680 "safe" => Self::Safe,
681 "schedule-reply" => Self::ScheduleReply,
682 "schedule-tag" => Self::ScheduleTag,
683 "sec-gpc" => Self::SecGPC,
684 "sec-purpose" => Self::SecPurpose,
685 "sec-token-binding" => Self::SecTokenBinding,
686 "sec-websocket-accept" => Self::SecWebSocketAccept,
687 "sec-websocket-extensions" => Self::SecWebSocketExtensions,
688 "sec-websocket-key" => Self::SecWebSocketKey,
689 "sec-websocket-protocol" => Self::SecWebSocketProtocol,
690 "sec-websocket-version" => Self::SecWebSocketVersion,
691 "security-scheme" => Self::SecurityScheme,
692 "server" => Self::Server,
693 "server-timing" => Self::ServerTiming,
694 "set-cookie" => Self::SetCookie,
695 "set-cookie2" => Self::SetCookie2,
696 "setprofile" => Self::SetProfile,
697 "signature" => Self::Signature,
698 "signature-input" => Self::SignatureInput,
699 "slug" => Self::SLUG,
700 "soapaction" => Self::SoapAction,
701 "status-uri" => Self::StatusURI,
702 "strict-transport-security" => Self::StrictTransportSecurity,
703 "sunset" => Self::Sunset,
704 "surrogate-capability" => Self::SurrogateCapability,
705 "surrogate-control" => Self::SurrogateControl,
706 "tcn" => Self::TCN,
707 "te" => Self::TE,
708 "timeout" => Self::Timeout,
709 "timing-allow-origin" => Self::TimingAllowOrigin,
710 "topic" => Self::Topic,
711 "traceparent" => Self::Traceparent,
712 "tracestate" => Self::Tracestate,
713 "trailer" => Self::Trailer,
714 "transfer-encoding" => Self::TransferEncoding,
715 "ttl" => Self::TTL,
716 "upgrade" => Self::Upgrade,
717 "urgency" => Self::Urgency,
718 "uri" => Self::URI,
719 "user-agent" => Self::UserAgent,
720 "variant-vary" => Self::VariantVary,
721 "vary" => Self::Vary,
722 "via" => Self::Via,
723 "want-content-digest" => Self::WantContentDigest,
724 "want-digest" => Self::WantDigest,
725 "want-repr-digest" => Self::WantReprDigest,
726 "warning" => Self::Warning,
727 "www-authenticate" => Self::WWWAuthenticate,
728 "x-content-type-options" => Self::XContentTypeOptions,
729 "x-frame-options" => Self::XFrameOptions,
730 _ => Self::NonStandard(s.to_string()),
731 }
732 }
733}
734impl From<&String> for HeaderName {
735 fn from(s: &String) -> Self {
736 Self::from(s.as_str())
737 }
738}
739
740impl From<String> for HeaderName {
741 fn from(s: String) -> Self {
742 Self::from(s.as_str())
743 }
744}
745
746impl HeaderName {
747 /// Whether at most one line of this field may appear in a message.
748 ///
749 /// Two groups qualify. The first is the fields whose grammar is a single
750 /// value rather than a comma-separated list, which RFC 9110 §5.3 says a
751 /// sender must not repeat. The second is the list fields whose whole list
752 /// this crate encapsulates in one `HeaderFieldValue`, so a second insertion
753 /// carries the full replacement list rather than an addition to it. Fields
754 /// outside both groups, `set-cookie` above all, may legitimately repeat.
755 pub fn is_singleton(&self) -> bool {
756 match self {
757 // Single-valued fields (RFC 9110 §5.3).
758 Self::Age |
759 Self::Authorization |
760 Self::ContentLength |
761 Self::ContentLocation |
762 Self::ContentRange |
763 Self::ContentType |
764 Self::Date |
765 Self::ETag |
766 Self::Expires |
767 Self::From |
768 Self::Host |
769 Self::LastModified |
770 Self::Location |
771 Self::MaxForwards |
772 Self::ProxyAuthorization |
773 Self::Referer |
774 Self::RetryAfter |
775 Self::Server |
776 Self::UserAgent |
777 // List fields held whole in a single `HeaderFieldValue`.
778 Self::Connection |
779 Self::Cookie |
780 Self::TransferEncoding |
781 Self::Upgrade => true,
782 _ => false,
783 }
784 }
785
786 /// Categorise `HeaderNames`s mainly for ordering.
787 pub fn category(&self) -> HeaderFieldCategory {
788 match self {
789 Self::CacheControl |
790 Self::Connection |
791 Self::Date |
792 Self::Pragma |
793 Self::Trailer |
794 Self::TransferEncoding |
795 Self::Upgrade |
796 Self::Via |
797 Self::Warning => HeaderFieldCategory::General,
798 Self::Accept |
799 Self::AcceptCharset |
800 Self::AcceptEncoding |
801 Self::AcceptLanguage |
802 Self::Authorization |
803 Self::Expect |
804 Self::From |
805 Self::Host |
806 Self::IfMatch |
807 Self::IfModifiedSince |
808 Self::IfNoneMatch |
809 Self::IfRange |
810 Self::IfUnmodifiedSince |
811 Self::MaxForwards |
812 Self::ProxyAuthorization |
813 Self::Range |
814 Self::Referer |
815 Self::TE |
816 Self::UserAgent => HeaderFieldCategory::Request,
817 Self::AcceptRanges |
818 Self::Age |
819 Self::ETag |
820 Self::Location |
821 Self::ProxyAuthenticate |
822 Self::RetryAfter |
823 Self::Server |
824 Self::Vary |
825 Self::WWWAuthenticate => HeaderFieldCategory::Response,
826 Self::Allow |
827 Self::ContentEncoding |
828 Self::ContentLanguage |
829 Self::ContentLength |
830 Self::ContentLocation |
831 Self::ContentMD5 |
832 Self::ContentRange |
833 Self::ContentType |
834 Self::Expires |
835 Self::LastModified => HeaderFieldCategory::Entity,
836 _ => HeaderFieldCategory::Other,
837 }
838 }
839}
840
841#[derive(Clone, Debug, Default)]
842pub struct Cookie {
843 pub key: String,
844 pub val: String,
845 pub attrs: Option<BTreeSet<SetCookieAttributes>>,
846}
847
848#[derive(Clone, Debug, Display, Eq, Ord, PartialEq, PartialOrd)]
849pub enum SameSite {
850 Strict,
851 Lax,
852 None,
853}
854
855#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
856pub enum SetCookieAttributes {
857 Domain(String),
858 Expires((Duration, String)),
859 HttpOnly,
860 MaxAge(u32),
861 Partitioned,
862 Path(String),
863 SameSite(SameSite),
864 Secure,
865}
866
867impl fmt::Display for SetCookieAttributes {
868 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
869 match self {
870 Self::Domain(s) => write!(f, "Domain={}", s),
871 Self::Expires((_dt, s)) => write!(f, "Expires={}", s),
872 Self::HttpOnly => write!(f, "HttpOnly"),
873 Self::MaxAge(n) => write!(f, "Max-Age={}", n),
874 Self::Partitioned => write!(f, "Partitioned"),
875 Self::Path(s) => write!(f, "Path={}", s),
876 Self::SameSite(same_site) => match same_site {
877 SameSite::None => write!(f, "SameSite={}; Secure", same_site),
878 _ => write!(f, "SameSite={}", same_site),
879 },
880 Self::Secure => write!(f, "Secure"),
881 }
882 }
883}
884
885#[derive(Clone, Debug, Eq, PartialEq)]
886pub enum ConnectionType {
887 Close,
888 KeepAlive,
889}
890
891impl fmt::Display for ConnectionType {
892 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
893 match self {
894 Self::Close => write!(f, "close"),
895 Self::KeepAlive => write!(f, "keep-alive"),
896 }
897 }
898}
899
900impl FromStr for ConnectionType {
901 type Err = Error<ErrTag>;
902
903 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
904 Ok(match s {
905 "close" => Self::Close,
906 "keep-alive" => Self::KeepAlive,
907 _ => return Err(err!(
908 "Unrecognised connection type '{}'.", s;
909 IO, Network, Unknown, Input)),
910 })
911 }
912}
913
914impl ConnectionType {
915 pub fn new(close: bool) -> Self {
916 match close {
917 true => Self::Close,
918 _ => Self::KeepAlive,
919 }
920 }
921}
922
923#[derive(Clone, Debug)]
924pub enum HeaderFieldValue {
925 Generic(String),
926 // Encapsulated:
927 Connection(Option<ConnectionType>, Vec<String>),
928 Cookie(Vec<Cookie>),
929 ContentLength(usize),
930 ContentType(ContentTypeValue),
931 SecWebSocketKey(String),
932 SetCookie(Cookie),
933 Upgrade(Vec<String>),
934}
935
936impl fmt::Display for HeaderFieldValue {
937 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
938 match self {
939 // RFC 9110 §7.6.1: a comma-separated list of connection-option
940 // tokens, and nothing else. A `Debug` rendering of the optional
941 // connection type once put `Some(Close)` on the wire, whose
942 // parentheses are delimiters, so the peer never saw the `close` it
943 // needed to expect the teardown that followed.
944 Self::Connection(ct_opt, list) => {
945 let mut toks = Vec::new();
946 if let Some(ct) = ct_opt {
947 toks.push(fmt!("{}", ct));
948 }
949 for opt in list {
950 toks.push(opt.clone());
951 }
952 write!(f, "{}", toks.join(", "))
953 }
954 Self::Cookie(list) => {
955 let s = list.iter()
956 .map(|cookie| fmt!("{}={}", cookie.key, cookie.val))
957 .collect::<Vec<_>>()
958 .join("; ");
959 write!(f, "{}", s)
960 }
961 Self::ContentLength(n) => write!(f, "{}", n),
962 Self::ContentType(ctv) => write!(f, "{}", ctv),
963 Self::Generic(s) => write!(f, "{}", s),
964 Self::SecWebSocketKey(s) => write!(f, "{}", s),
965 Self::SetCookie(Cookie { key, val, attrs }) => {
966 if let Some(attrs_set) = attrs {
967 if attrs_set.len() > 0 {
968 let s = attrs_set.iter()
969 .map(|attr| fmt!("{}", attr))
970 .collect::<Vec<_>>()
971 .join("; ");
972 write!(f, "{}={}; {}", key, val, s)
973 } else {
974 write!(f, "{}={}", key, val)
975 }
976 } else {
977 write!(f, "{}={}", key, val)
978 }
979 }
980 Self::Upgrade(list) => write!(f, "{}", list.join(", ")),
981 }
982 }
983}
984
985impl HeaderFieldValue {
986
987 /// Whether the value renders to an empty field value, in which case the
988 /// field says nothing and is better left off the wire than sent as a bare
989 /// name. A `Connection` field holding neither a connection type nor an
990 /// option is the case that arises in practice.
991 pub fn is_wire_empty(&self) -> bool {
992 match self {
993 Self::Connection(None, list) => list.is_empty(),
994 Self::Cookie(list) => list.is_empty(),
995 Self::Upgrade(list) => list.is_empty(),
996 _ => false,
997 }
998 }
999
1000 pub fn new(name: &HeaderName, value: &str) -> Outcome<Self> {
1001 Ok(match name {
1002 HeaderName::Connection => {
1003 let parts = value.split(',').map(str::trim).map(|w| w.to_lowercase());
1004 let mut contyp_opt = None;
1005 let mut list = Vec::new();
1006 for part in parts {
1007 match ConnectionType::from_str(&part) {
1008 Ok(ct) => if contyp_opt.is_some() {
1009 return Err(err!(
1010 "Connection type '{:?}' already defined, '{}' is redundant.",
1011 contyp_opt, ct;
1012 Invalid, Input, Conflict));
1013 } else {
1014 contyp_opt = Some(ct);
1015 },
1016 Err(_) => list.push(part),
1017 }
1018 }
1019 Self::Connection(contyp_opt, list)
1020 },
1021 HeaderName::Cookie => {
1022 let mut list = Vec::new();
1023 for pair in value.split(';').map(str::trim) {
1024 let mut parts = pair.split('=').map(str::trim);
1025 let k = parts.next();
1026 let v = parts.next();
1027 match (k, v) {
1028 (Some(k), Some(v)) => {
1029 list.push(Cookie {
1030 key: k.to_string(),
1031 val: v.to_string(),
1032 attrs: None,
1033 });
1034 },
1035 (Some(k), None) => return Err(err!(
1036 "Missing value for key '{}' in header field line '{}", k, value;
1037 Invalid, Input, Missing)),
1038 (None, Some(v)) => return Err(err!(
1039 "Missing key for value '{}' in header field line '{}", v, value;
1040 Invalid, Input, Missing)),
1041 _ => (),
1042 }
1043 }
1044 Self::Cookie(list)
1045 },
1046 HeaderName::ContentLength => match value.parse() {
1047 Ok(n) => Self::ContentLength(n),
1048 Err(e) => return Err(err!(e,
1049 "Could not parse the content length '{}'.", value;
1050 Invalid, Input, String, Decode)),
1051 },
1052 HeaderName::ContentType => { // A; B=C
1053 // The media type and the parameter NAME are matched case
1054 // insensitively, but the parameter VALUE is not lowercased: a
1055 // multipart boundary is case sensitive (RFC 2046 s5.1.1), and
1056 // lowercasing `----WebKitFormBoundaryAbC` yields a delimiter
1057 // that matches nothing in the body it is meant to divide.
1058 let mut parts = value.split(';').map(str::trim);
1059 match parts.next() { // A
1060 Some(first) => {
1061 let media_type = res!(MediaType::from_str(&first.to_lowercase()));
1062 let is_multipart = match media_type {
1063 MediaType::Multipart(Multipart::FormData) => true,
1064 _ => false,
1065 };
1066 match parts.next() { // B=C
1067 Some(second) => {
1068 let mut parts2 = second.split('=').map(str::trim);
1069 match parts2.next() { // B
1070 Some(left) => match is_multipart {
1071 true => if left.to_lowercase() != "boundary" {
1072 return Err(err!(
1073 "Expected 'boundary' found '{}'.", left;
1074 Invalid, Input, String, Decode));
1075 },
1076 false => if left.to_lowercase() != "charset" {
1077 return Err(err!(
1078 "Expected 'charset' found '{}'.", left;
1079 Invalid, Input, String, Decode));
1080 },
1081 },
1082 None => (),
1083 }
1084 match parts2.next() { // C
1085 Some(right) => match is_multipart {
1086 true => Self::ContentType(ContentTypeValue::Multipart((
1087 Multipart::FormData,
1088 right.to_string(),
1089 ))),
1090 false => Self::ContentType(ContentTypeValue::MediaType((
1091 media_type,
1092 Some(res!(Charset::from_str(&right.to_lowercase()))),
1093 ))),
1094 },
1095 None => return Err(err!("Missing {} value in '{}'.",
1096 if is_multipart { "boundary" } else { "charset" }, value;
1097 Invalid, Input, String, Decode, Missing)),
1098 }
1099 },
1100 None => match is_multipart {
1101 true => return Err(err!(
1102 "A 'boundary=string' is required but is missing in {}'.", value;
1103 Invalid, Input, String, Decode, Missing)),
1104 false => Self::ContentType(ContentTypeValue::MediaType((
1105 media_type,
1106 None,
1107 ))),
1108 },
1109 }
1110 },
1111 None => return Err(err!(
1112 "Missing header field value for Content-Type.";
1113 Invalid, Input, String, Decode, Missing)),
1114 }
1115 },
1116 HeaderName::SecWebSocketKey |
1117 HeaderName::SecWebSocketAccept => Self::SecWebSocketKey(value.to_string()),
1118 HeaderName::Upgrade => {
1119 let list: Vec<_> = value
1120 .split(',').map(str::trim).map(|w| w.to_lowercase()).collect();
1121 Self::Upgrade(list)
1122 },
1123 // TODO encapsulate more header field types
1124 _ => {
1125 trace!("Header field '{}' not encapsulated.", name);
1126 Self::Generic(value.to_string())
1127 }
1128 })
1129 }
1130}
1131
1132#[derive(Clone, Debug)]
1133pub struct HeaderField {
1134 pub name: HeaderName,
1135 pub value: HeaderFieldValue,
1136}
1137
1138impl HeaderField {
1139
1140 pub fn new(line: &str, line_num: Option<u16>) -> Outcome<Self> {
1141 let mut parts = line.splitn(2, ':').map(str::trim);
1142 let line_msg = match line_num {
1143 Some(n) => fmt!(" at HTTP message line number {}.", n),
1144 None => ".".to_string(),
1145 };
1146 let name = match parts.next() {
1147 Some(name) => HeaderName::from(&name.to_lowercase()),
1148 None => return Err(err!(
1149 "A name was not found for the HTTP header field in the header line '{}'{}",
1150 line, line_msg;
1151 Invalid, Input, Missing)),
1152 };
1153 let value = match parts.next() {
1154 Some(value) => res!(HeaderFieldValue::new(&name, value)),
1155 None => return Err(err!(
1156 "A value must be present for header field name '{}' in the header line '{}'{}",
1157 name, line, line_msg;
1158 Invalid, Input, Missing)),
1159 };
1160
1161 Ok(Self {
1162 name,
1163 value,
1164 })
1165 }
1166
1167}
1168
1169#[derive(Clone, Copy, Debug)]
1170#[repr(u16)]
1171pub enum HeaderFieldCategory {
1172 General = 0,
1173 Request = 1_000,
1174 Response = 2_000,
1175 Entity = 3_000,
1176 Other = 5_000,
1177}
1178
1179impl HeaderFieldCategory {
1180 pub fn order(&self) -> u16 {
1181 *self as u16
1182 }
1183}
1184
1185#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
1186struct OrderedHeaderName {
1187 ord: u16,
1188 name: HeaderName,
1189}
1190
1191impl OrderedHeaderName {
1192 fn new(ord: u16, name: HeaderName) -> Self {
1193 Self {
1194 ord,
1195 name,
1196 }
1197 }
1198}
1199
1200/// In HTTP, each header field is just a pair of strings (k, v), but multiple fields can exist with
1201/// the same key, while order is somewhat important in that we want the most general fields
1202/// appearing first. Returns whether the header field name was present.
1203#[derive(Clone, Debug, Default)]
1204pub struct HeaderFields {
1205 fields: BTreeMap<HeaderName, (Vec<HeaderFieldValue>, u16)>,
1206 order: BTreeMap<OrderedHeaderName, HeaderName>,
1207}
1208
1209impl HeaderFields {
1210
1211 /// Insert a header field value, returning whether the field name was already
1212 /// present.
1213 ///
1214 /// A singleton field (see `HeaderName::is_singleton`) is replaced rather than
1215 /// added to, because a second line of it on the wire is either meaningless or,
1216 /// for the framing fields, dangerous. Every other field accumulates its
1217 /// values, so `set-cookie` and the like still emit one line each.
1218 ///
1219 /// `Content-Length` and `Transfer-Encoding` are mutually exclusive here by
1220 /// construction: RFC 9112 §6.1 forbids a sender from emitting both, and
1221 /// §6.3 treats the pair as the request-smuggling signal it is. Whichever
1222 /// order they arrive in, the transfer encoding wins, since it is the framing
1223 /// the peer actually applied; so inserting a `Transfer-Encoding` drops any
1224 /// `Content-Length`, and inserting a `Content-Length` while a
1225 /// `Transfer-Encoding` stands is refused.
1226 pub fn insert(
1227 &mut self,
1228 nam: HeaderName,
1229 val: HeaderFieldValue,
1230 ord: Option<u16>,
1231 )
1232 -> bool
1233 {
1234 let new_ord = match ord {
1235 Some(ord) => ord,
1236 None => nam.category().order(),
1237 };
1238
1239 match nam {
1240 HeaderName::TransferEncoding => {
1241 self.remove(&HeaderName::ContentLength);
1242 },
1243 HeaderName::ContentLength => {
1244 if self.fields.contains_key(&HeaderName::TransferEncoding) {
1245 return false;
1246 }
1247 },
1248 _ => (),
1249 }
1250
1251 match self.fields.get_mut(&nam) {
1252 Some((prev_val_list, prev_ord)) => {
1253 // The name may already sit in the order map under a different
1254 // ordinal, and a stale entry there would emit the field twice.
1255 let stale = OrderedHeaderName::new(*prev_ord, nam.clone());
1256 if nam.is_singleton() {
1257 prev_val_list.clear();
1258 }
1259 prev_val_list.push(val);
1260 *prev_ord = new_ord;
1261 if stale.ord != new_ord {
1262 self.order.remove(&stale);
1263 }
1264 self.order.insert(OrderedHeaderName::new(new_ord, nam.clone()), nam);
1265 true
1266 },
1267 None => {
1268 self.fields.insert(nam.clone(), (vec![val], new_ord));
1269 self.order.insert(OrderedHeaderName::new(new_ord, nam.clone()), nam);
1270 false
1271 },
1272 }
1273 }
1274
1275 /// Remove every value for the given field name, returning whether it was
1276 /// present.
1277 pub fn remove(&mut self, nam: &HeaderName) -> bool {
1278 let was_present = self.fields.remove(nam).is_some();
1279 self.order.retain(|_, held| held != nam);
1280 was_present
1281 }
1282
1283 pub fn get_all(
1284 &self,
1285 nam: &HeaderName,
1286 )
1287 -> Option<&(Vec<HeaderFieldValue>, u16)>
1288 {
1289 self.fields.get(nam)
1290 }
1291
1292 pub fn get_list(
1293 &self,
1294 nam: &HeaderName,
1295 )
1296 -> Option<&Vec<HeaderFieldValue>>
1297 {
1298 match self.fields.get(nam) {
1299 Some((list, _)) => Some(list),
1300 None => None,
1301 }
1302 }
1303
1304 /// The first value of the given field, or `None` if the field is absent or empty.
1305 ///
1306 /// Correct when the sender of the field is its authority and the field carries one value: a
1307 /// singleton (see [`HeaderName::is_singleton`]), where `insert` replaces rather than
1308 /// accumulates so first and last are the same value, or a field like `Cookie`, `Content-Type`
1309 /// or `Authorization` whose only meaningful value is the one the client sent.
1310 ///
1311 /// **Wrong for any field that each hop appends to.** `X-Forwarded-For`, `X-Forwarded-Proto`,
1312 /// `X-Forwarded-Host`, RFC 7239 `Forwarded` and `Via` accumulate left to right, so `list[0]` is
1313 /// the value the *caller* supplied -- the one part of the chain nothing verified. Use
1314 /// [`get_last`](Self::get_last) for those.
1315 pub fn get_one(
1316 &self,
1317 nam: &HeaderName,
1318 )
1319 -> Option<&HeaderFieldValue>
1320 {
1321 match self.fields.get(nam) {
1322 Some((list, _)) => {
1323 if list.len() > 0 {
1324 Some(&list[0])
1325 } else {
1326 None
1327 }
1328 },
1329 _ => None,
1330 }
1331 }
1332
1333 /// The last value of the given field, or `None` if the field is absent or empty.
1334 ///
1335 /// Correct for every field a proxy chain appends to: `X-Forwarded-For`, `X-Forwarded-Proto`,
1336 /// `X-Forwarded-Host`, RFC 7239 `Forwarded` and `Via`. Each hop adds its own account of the
1337 /// request after whatever it received, so the last value is the nearest hop's -- the only one
1338 /// written by something the reader is behind rather than by something in front of it.
1339 ///
1340 /// This method exists because its absence is what makes [`get_one`](Self::get_one) get reached
1341 /// for, and `get_one` returns `list[0]`. For a forwarded header `list[0]` is the value the
1342 /// *caller* supplied, and nothing stops a caller supplying one. A downstream service that
1343 /// rate-limits by the first `X-Forwarded-For` therefore keys its limit on an address the
1344 /// attacker chose, and grants a fresh allowance for every fresh invented address: not a weaker
1345 /// limit but no limit at all, while looking configured. Read the same way,
1346 /// `X-Forwarded-Proto: http` tells a service that a TLS request arrived in plaintext, and a
1347 /// service that redirects plaintext to HTTPS on that basis loops.
1348 ///
1349 /// Two caveats. The last value is only as trustworthy as the hop that wrote it, so this is the
1350 /// right reader on the assumption that the immediate hop is one the reader trusts -- see
1351 /// [`crate::http::fwd::ForwardedPolicy`] for the writing side of that bargain. And a value here
1352 /// is one *line*: a hop that wrote `X-Forwarded-For: a, b` on one line leaves one value holding
1353 /// both, so this returns the last line rather than the last comma-separated element.
1354 pub fn get_last(
1355 &self,
1356 nam: &HeaderName,
1357 )
1358 -> Option<&HeaderFieldValue>
1359 {
1360 match self.fields.get(nam) {
1361 Some((list, _)) => list.last(),
1362 None => None,
1363 }
1364 }
1365
1366 /// Get the value for the given name. The value list must exist, and must have a length of one.
1367 pub fn get_the_one(
1368 &self,
1369 nam: &HeaderName,
1370 )
1371 -> Outcome<&HeaderFieldValue>
1372 {
1373 match self.fields.get(nam) {
1374 Some((list, _)) => {
1375 if list.len() == 1 {
1376 Ok(&list[0])
1377 } else {
1378 Err(err!(
1379 "Number of values for header field '{}', {} is not one.",
1380 nam, list.len();
1381 IO, Network, Invalid, Input))
1382 }
1383 },
1384 None => Err(err!(
1385 "Value list for header field '{}' does not exist.", nam;
1386 IO, Network, Invalid, Input)),
1387 }
1388 }
1389
1390 pub fn get_session_id(&self) -> Option<String> {
1391 if let Some(HeaderFieldValue::Cookie(cookies)) = self.get_one(&HeaderName::Cookie) {
1392 for cookie in cookies {
1393 if cookie.key == SESSION_ID_KEY_LABEL {
1394 return Some(cookie.val.clone());
1395 }
1396 }
1397 }
1398 None
1399 }
1400
1401 /// Iterate over the header fields according to the `order` map.
1402 pub fn iter(&self) -> impl Iterator<Item = (HeaderName, Vec<HeaderFieldValue>)> + '_ {
1403 self.order.iter().filter_map(move |(_, key)| {
1404 self.fields.get(key).map(|(value, _)| (key.clone(), value.clone()))
1405 })
1406 }
1407
1408}
1409
1410
1411#[cfg(test)]
1412mod wire_tests {
1413 use super::*;
1414 use crate::{
1415 http::{
1416 header::{
1417 HttpHeader,
1418 HttpHeadline,
1419 HttpVersion,
1420 },
1421 status::HttpStatus,
1422 },
1423 media::MEDIA_PLAIN_TEXT,
1424 };
1425
1426 /// A 200 response carrying just the given fields, so a test can compare the
1427 /// bytes it puts on the wire against a literal from the RFC.
1428 fn response(fields: HeaderFields) -> HttpHeader {
1429 HttpHeader {
1430 version: HttpVersion::Http1_1,
1431 headline: HttpHeadline::Response { status: HttpStatus::OK },
1432 fields,
1433 }
1434 }
1435
1436 fn with_connection(ct_opt: Option<ConnectionType>, list: Vec<String>) -> HeaderFields {
1437 let mut fields = HeaderFields::default();
1438 fields.insert(
1439 HeaderName::Connection,
1440 HeaderFieldValue::Connection(ct_opt, list),
1441 Some(HeaderFieldCategory::General as u16),
1442 );
1443 fields
1444 }
1445
1446 /// RFC 9110 §7.6.1 wants a token. A `Debug` rendering once wrote
1447 /// `connection: Some(Close)`, whose parentheses are delimiters, so the peer
1448 /// never saw the `close` that explained the teardown it was about to get.
1449 #[test]
1450 fn test_a_connection_close_is_written_as_a_token() {
1451 assert_eq!(
1452 response(with_connection(Some(ConnectionType::Close), Vec::new())).as_vec(),
1453 b"HTTP/1.1 200 OK\r\nconnection: close\r\n\r\n".to_vec(),
1454 );
1455 }
1456
1457 #[test]
1458 fn test_a_connection_type_and_its_options_are_one_comma_separated_list() {
1459 assert_eq!(
1460 response(with_connection(
1461 Some(ConnectionType::KeepAlive),
1462 vec!["upgrade".to_string()],
1463 )).as_vec(),
1464 b"HTTP/1.1 200 OK\r\nconnection: keep-alive, upgrade\r\n\r\n".to_vec(),
1465 );
1466 }
1467
1468 #[test]
1469 fn test_connection_options_stand_without_a_connection_type() {
1470 assert_eq!(
1471 response(with_connection(None, vec!["upgrade".to_string()])).as_vec(),
1472 b"HTTP/1.1 200 OK\r\nconnection: upgrade\r\n\r\n".to_vec(),
1473 );
1474 }
1475
1476 /// A `Connection` field with neither a type nor an option says nothing, so it
1477 /// is left off the wire rather than sent as `connection: None`, or as a bare
1478 /// name with an empty value.
1479 #[test]
1480 fn test_an_empty_connection_field_is_not_written_at_all() {
1481 assert_eq!(
1482 response(with_connection(None, Vec::new())).as_vec(),
1483 b"HTTP/1.1 200 OK\r\n\r\n".to_vec(),
1484 );
1485 }
1486
1487 /// A singleton field is replaced, not repeated: RFC 9110 §5.3 forbids sending
1488 /// a second line of a field whose grammar is a single value. Setting a
1489 /// content type on a response that already had one once emitted both.
1490 #[test]
1491 fn test_a_second_content_type_replaces_the_first() {
1492 let mut fields = HeaderFields::default();
1493 fields.insert(
1494 HeaderName::ContentType,
1495 HeaderFieldValue::ContentType(MEDIA_PLAIN_TEXT),
1496 Some(HeaderFieldCategory::Entity as u16),
1497 );
1498 fields.insert(
1499 HeaderName::ContentType,
1500 HeaderFieldValue::Generic("text/css".to_string()),
1501 None,
1502 );
1503 assert_eq!(
1504 response(fields).as_vec(),
1505 b"HTTP/1.1 200 OK\r\ncontent-type: text/css\r\n\r\n".to_vec(),
1506 );
1507 }
1508
1509 /// The same, where the two insertions carry different ordinals, as they do
1510 /// when a parsed message (ordinal by line number) is later amended. A stale
1511 /// entry in the order map emitted the field a second time.
1512 #[test]
1513 fn test_a_replaced_field_leaves_no_stale_ordering_entry() {
1514 let mut fields = HeaderFields::default();
1515 fields.insert(
1516 HeaderName::ContentType,
1517 HeaderFieldValue::Generic("text/plain".to_string()),
1518 Some(1), // As `HttpHeader::parse` numbers the lines it reads.
1519 );
1520 fields.insert(
1521 HeaderName::ContentType,
1522 HeaderFieldValue::Generic("text/html".to_string()),
1523 Some(HeaderFieldCategory::Entity as u16),
1524 );
1525 assert_eq!(
1526 response(fields).as_vec(),
1527 b"HTTP/1.1 200 OK\r\ncontent-type: text/html\r\n\r\n".to_vec(),
1528 );
1529 }
1530
1531 /// Replacement is for singletons only. A cookie jar is set one line at a
1532 /// time (RFC 6265 §3.1), and must still be.
1533 #[test]
1534 fn test_set_cookie_still_repeats() {
1535 let mut fields = HeaderFields::default();
1536 for (key, val) in [("a", "1"), ("b", "2")] {
1537 fields.insert(
1538 HeaderName::SetCookie,
1539 HeaderFieldValue::SetCookie(Cookie {
1540 key: key.to_string(),
1541 val: val.to_string(),
1542 attrs: None,
1543 }),
1544 None,
1545 );
1546 }
1547 assert_eq!(
1548 response(fields).as_vec(),
1549 b"HTTP/1.1 200 OK\r\nset-cookie: a=1\r\nset-cookie: b=2\r\n\r\n".to_vec(),
1550 );
1551 }
1552
1553 /// RFC 9112 §6.1: a sender must not put both framing fields in one message.
1554 /// The transfer encoding wins, whichever order they arrive in, because it is
1555 /// the framing the peer actually applied.
1556 #[test]
1557 fn test_a_content_length_cannot_join_a_transfer_encoding() {
1558 let mut fields = HeaderFields::default();
1559 fields.insert(
1560 HeaderName::TransferEncoding,
1561 HeaderFieldValue::Generic("chunked".to_string()),
1562 Some(2),
1563 );
1564 fields.insert(
1565 HeaderName::ContentLength,
1566 HeaderFieldValue::ContentLength(15),
1567 Some(HeaderFieldCategory::Entity as u16),
1568 );
1569 assert_eq!(
1570 response(fields).as_vec(),
1571 b"HTTP/1.1 200 OK\r\ntransfer-encoding: chunked\r\n\r\n".to_vec(),
1572 );
1573 }
1574
1575 #[test]
1576 fn test_a_transfer_encoding_evicts_a_content_length() {
1577 let mut fields = HeaderFields::default();
1578 fields.insert(
1579 HeaderName::ContentLength,
1580 HeaderFieldValue::ContentLength(15),
1581 Some(HeaderFieldCategory::Entity as u16),
1582 );
1583 fields.insert(
1584 HeaderName::TransferEncoding,
1585 HeaderFieldValue::Generic("chunked".to_string()),
1586 Some(2),
1587 );
1588 assert_eq!(
1589 response(fields).as_vec(),
1590 b"HTTP/1.1 200 OK\r\ntransfer-encoding: chunked\r\n\r\n".to_vec(),
1591 );
1592 }
1593}
1594
1595
1596/// Which of a repeated field's values a reader should take.
1597#[cfg(test)]
1598mod value_choice_tests {
1599 use super::*;
1600
1601 /// The name a proxy chain appends to, as the wire parser produces it.
1602 fn xff() -> HeaderName {
1603 HeaderName::from("x-forwarded-for")
1604 }
1605
1606 /// A field holding the given values, in the order given.
1607 fn with_values(nam: HeaderName, values: &[&str]) -> HeaderFields {
1608 let mut fields = HeaderFields::default();
1609 for value in values {
1610 fields.insert(nam.clone(), HeaderFieldValue::Generic(value.to_string()), None);
1611 }
1612 fields
1613 }
1614
1615 /// The case the whole method is for: two values, the caller's first and this hop's second.
1616 ///
1617 /// `get_one` returns the caller's, which is an address the attacker chose. `get_last` returns
1618 /// the one the proxy appended, which is the address the proxy actually accepted the connection
1619 /// from. A rate limiter keyed on the first grants a fresh allowance per invented address.
1620 #[test]
1621 fn test_get_last_returns_the_value_this_hop_appended_00() -> Outcome<()> {
1622 let fields = with_values(xff(), &["9.9.9.9", "203.0.113.7:51000"]);
1623
1624 let first = res!(fields.get_one(&xff()).ok_or_else(|| err!(
1625 "The field was inserted, so a first value must exist."; Test, Missing)));
1626 assert_eq!(fmt!("{}", first), "9.9.9.9",
1627 "get_one returns list[0], which is whatever the caller supplied");
1628
1629 let last = res!(fields.get_last(&xff()).ok_or_else(|| err!(
1630 "The field was inserted, so a last value must exist."; Test, Missing)));
1631 assert_eq!(fmt!("{}", last), "203.0.113.7:51000",
1632 "get_last returns the value the nearest hop appended");
1633 Ok(())
1634 }
1635
1636 /// A longer chain: still the last, not the second, and not the first.
1637 ///
1638 /// A reader that took `list[1]` on the assumption of one proxy would be right for exactly one
1639 /// deployment and wrong the day a second hop appeared, which is the kind of correctness that
1640 /// stops being correct without anybody editing it.
1641 #[test]
1642 fn test_get_last_takes_the_end_of_any_chain_00() -> Outcome<()> {
1643 let fields = with_values(xff(), &["9.9.9.9", "198.51.100.34", "203.0.113.7:51000"]);
1644 let last = res!(fields.get_last(&xff()).ok_or_else(|| err!(
1645 "The field was inserted, so a last value must exist."; Test, Missing)));
1646 assert_eq!(fmt!("{}", last), "203.0.113.7:51000");
1647 Ok(())
1648 }
1649
1650 /// One value, and the two readers agree. An absent field is `None` from both.
1651 #[test]
1652 fn test_get_last_matches_get_one_for_a_single_value_00() -> Outcome<()> {
1653 let fields = with_values(xff(), &["203.0.113.7:51000"]);
1654 let one = res!(fields.get_one(&xff()).ok_or_else(|| err!(
1655 "The field was inserted."; Test, Missing)));
1656 let last = res!(fields.get_last(&xff()).ok_or_else(|| err!(
1657 "The field was inserted."; Test, Missing)));
1658 assert_eq!(fmt!("{}", one), fmt!("{}", last));
1659
1660 let empty = HeaderFields::default();
1661 assert!(empty.get_one(&xff()).is_none());
1662 assert!(empty.get_last(&xff()).is_none(),
1663 "an absent field has no last value, rather than some default one");
1664 Ok(())
1665 }
1666
1667 /// A singleton field is replaced rather than accumulated, so both readers see the replacement.
1668 ///
1669 /// Without this, `get_last` would look like a way to reach a superseded `Host` -- and a reader
1670 /// that could reach one would eventually be written to.
1671 #[test]
1672 fn test_get_last_on_a_singleton_is_the_surviving_value_00() -> Outcome<()> {
1673 let fields = with_values(HeaderName::Host, &["app.example", "upstream.internal"]);
1674 let one = res!(fields.get_one(&HeaderName::Host).ok_or_else(|| err!(
1675 "The field was inserted."; Test, Missing)));
1676 let last = res!(fields.get_last(&HeaderName::Host).ok_or_else(|| err!(
1677 "The field was inserted."; Test, Missing)));
1678 assert_eq!(fmt!("{}", one), "upstream.internal");
1679 assert_eq!(fmt!("{}", last), "upstream.internal");
1680 Ok(())
1681 }
1682
1683 /// One line is one value, comma-separated list or not.
1684 ///
1685 /// The documented caveat, asserted so that a later change to how a line is stored is caught
1686 /// here rather than by a reader who believed `get_last` returned the last address.
1687 #[test]
1688 fn test_get_last_returns_the_last_line_not_the_last_element_00() -> Outcome<()> {
1689 let fields = with_values(xff(), &["8.8.8.8, 7.7.7.7"]);
1690 let last = res!(fields.get_last(&xff()).ok_or_else(|| err!(
1691 "The field was inserted."; Test, Missing)));
1692 assert_eq!(fmt!("{}", last), "8.8.8.8, 7.7.7.7");
1693 Ok(())
1694 }
1695}