Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Headers.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_IO_Network_HTTP_Headers_h_
5#define _Stroika_Foundation_IO_Network_HTTP_Headers_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
10#include "Stroika/Foundation/Common/Common.h"
11#include "Stroika/Foundation/Common/Property.h"
12#include "Stroika/Foundation/Containers/Association.h"
13#include "Stroika/Foundation/Containers/Collection.h"
14#include "Stroika/Foundation/Containers/Mapping.h"
15#include "Stroika/Foundation/Containers/Set.h"
18#include "Stroika/Foundation/IO/Network/HTTP/CacheControl.h"
19#include "Stroika/Foundation/IO/Network/HTTP/ContentEncoding.h"
20#include "Stroika/Foundation/IO/Network/HTTP/Cookie.h"
21#include "Stroika/Foundation/IO/Network/HTTP/ETag.h"
22#include "Stroika/Foundation/IO/Network/HTTP/IfNoneMatch.h"
23#include "Stroika/Foundation/IO/Network/HTTP/KeepAlive.h"
24#include "Stroika/Foundation/IO/Network/HTTP/TransferEncoding.h"
26
27/**
28 */
30
31 using Characters::String;
32 using Common::KeyValuePair;
33 using Containers::Association;
34 using Containers::Collection;
35 using Containers::Mapping;
36 using Containers::Set;
37 using DataExchange::InternetMediaType;
38 using Traversal::Iterable;
39
40 /**
41 * standard HTTP headers one might want to access/retrieve
42 */
43 namespace HeaderName {
44
45 constexpr string_view kAcceptEncoding = "Accept-Encoding"sv;
46 constexpr string_view kAccessControlAllowCredentials = "Access-Control-Allow-Credentials"sv;
47 constexpr string_view kAccessControlAllowOrigin = "Access-Control-Allow-Origin"sv;
48 constexpr string_view kAccessControlAllowHeaders = "Access-Control-Allow-Headers"sv;
49 constexpr string_view kAccessControlAllowMethods = "Access-Control-Allow-Methods"sv;
50 constexpr string_view kAccessControlRequestHeaders = "Access-Control-Request-Headers"sv;
51 constexpr string_view kAccessControlMaxAge = "Access-Control-Max-Age"sv;
52 constexpr string_view kAllow = "Allow"sv;
53 constexpr string_view kAuthorization = "Authorization"sv;
54 constexpr string_view kCacheControl = "Cache-Control"sv;
55 constexpr string_view kContentDisposition = "Content-Disposition"sv;
56 constexpr string_view kContentEncoding = "Content-Encoding"sv;
57 constexpr string_view kContentLength = "Content-Length"sv;
58 constexpr string_view kContentType = "Content-Type"sv;
59 constexpr string_view kConnection = "Connection"sv;
60 constexpr string_view kCookie = "Cookie"sv;
61 constexpr string_view kDate = "Date"sv;
62 constexpr string_view kETag = "ETag"sv;
63 constexpr string_view kExpect = "Expect"sv;
64 constexpr string_view kExpires = "Expires"sv;
65 constexpr string_view kHost = "Host"sv;
66 constexpr string_view kIfNoneMatch = "If-None-Match"sv;
67 constexpr string_view kIfModifiedSince = "If-Modified-Since"sv;
68 constexpr string_view kKeepAlive = "Keep-Alive"sv;
69 constexpr string_view kLastModified = "Last-Modified"sv;
70 constexpr string_view kLocation = "Location"sv;
71 constexpr string_view kOrigin = "Origin"sv;
72 constexpr string_view kReferrer = "Referer"sv; // intentionally spelled this way - misspelled in the HTTP RFC
73 constexpr string_view kServer = "Server"sv;
74 constexpr string_view kSetCookie = "Set-Cookie"sv;
75 constexpr string_view kSOAPAction = "SOAPAction"sv;
76 constexpr string_view kTransferEncoding = "Transfer-Encoding"sv;
77 constexpr string_view kUserAgent = "User-Agent"sv;
78 constexpr string_view kVary = "Vary"sv;
79
80 }
81
82 /**
83 * \note from https://www.ietf.org/rfc/rfc2616.txt
84 * The field-names given are not limited to the set of standard
85 * request-header fields defined by this specification. Field names are
86 * case-insensitive.
87 */
88 constexpr auto kHeaderNameEqualsComparer = String::EqualsComparer{Characters::eCaseInsensitive};
89 constexpr auto kHeaderNameInOrderComparer = String::LessComparer{Characters::eCaseInsensitive};
90
91 /**
92 * \brief roughly equivalent to Association<String,String>, except that the class is smart about certain
93 * keys and will automatically fold them together.
94 *
95 * \note From https://www.rfc-editor.org/rfc/rfc7230#section-3.2.2
96 *
97 * The order in which header fields with differing field names are
98 * received is not significant. However, it is good practice to send
99 * header fields that contain control data first, such as Host on
100 * requests and Date on responses, so that implementations can decide
101 * when not to handle a message as early as possible. A server MUST NOT
102 * apply a request to the target resource until the entire request
103 * header section is received, since later header fields might include
104 * conditionals, authentication credentials, or deliberately misleading
105 * duplicate header fields that would impact request processing.
106 *
107 * A sender MUST NOT generate multiple header fields with the same field
108 * name in a message unless either the entire field value for that
109 * header field is defined as a comma-separated list [i.e., #(values)]
110 * or the header field is a well-known exception (as noted below).
111 *
112 * A recipient MAY combine multiple header fields with the same field
113 * name into one "field-name: field-value" pair, without changing the
114 * semantics of the message, by appending each subsequent field value to
115 * the combined field value in order, separated by a comma. The order
116 * in which header fields with the same field name are received is
117 * therefore significant to the interpretation of the combined field
118 * value; a proxy MUST NOT change the order of these field values when
119 * forwarding a message.
120 *
121 * Note: In practice, the "Set-Cookie" header field ([RFC6265]) often
122 * appears multiple times in a response message and does not use the
123 * list syntax, violating the above requirements on multiple header
124 * fields with the same name. Since it cannot be combined into a
125 * single field-value, recipients ought to handle "Set-Cookie" as a
126 * special case while processing header fields. (See Appendix A.2.3
127 * of [Kri2001] for details.)
128 */
129 class Headers {
130 public:
131 /**
132 * ExtendableProperty allow the value of some headers to be overridden by some containing object.
133 * When copying a Header, we don't reference that external object any longer. So copying must
134 * by value, and copy that current value.
135 */
136 Headers ();
137 Headers (Headers&& src);
138 Headers (const Headers& src);
139 explicit Headers (const Iterable<pair<String, String>>& src);
140 explicit Headers (const Iterable<KeyValuePair<String, String>>& src);
141
142 public:
143 nonvirtual Headers& operator= (Headers&& rhs) noexcept;
144 nonvirtual Headers& operator= (const Headers& rhs);
145
146#if qStroika_Foundation_Debug_AssertExternallySynchronizedMutex_Enabled
147 public:
148 /**
149 * Allow users of the Headers object to have it share a 'assure externally synchronized' context.
150 */
151 void SetAssertExternallySynchronizedMutexContext (const shared_ptr<Debug::AssertExternallySynchronizedMutex::SharedContext>& sharedContext);
152#endif
153
154 public:
155 /**
156 * For now - this returns 0 or one value.
157 * @todo - this should return ALL matching if there are multiple.
158 */
159 nonvirtual optional<String> LookupOne (const String& name) const;
160
161 public:
162 /**
163 * Some HTTP headers can appear multiple times (such as Set-Cookie). Return all with the given name.
164 */
165 nonvirtual Collection<String> LookupAll (const String& name) const;
166
167 public:
168 /**
169 * Add (or sometimes replace) the given header name/value pair. Whether this replaces
170 * or adds depends on the particular headerName. Some which are recognized to appear just once
171 * are replaced (such as Cookie); Some are recognized as appearing multiple times (such as Set-Cookie)
172 * and these are appended. Use Set/Remove to avoid ambiguity.
173 */
174 nonvirtual void Add (const String& headerName, const String& value);
175 nonvirtual void Add (const KeyValuePair<String, String>& hrdAndValue);
176 nonvirtual void Add (const pair<String, String>& hrdAndValue);
177
178 public:
179 /**
180 * \brief not the same as assignment - only for headers set in argument, replace those in this header object.
181 */
182 nonvirtual void AddAll (const Headers& headers);
183
184 public:
185 /**
186 */
187 nonvirtual void operator+= (const pair<String, String>& hrdAndValue);
188 nonvirtual void operator+= (const KeyValuePair<String, String>& hrdAndValue);
189 nonvirtual void operator+= (const Headers& headers);
190
191 public:
192 /**
193 * Remove ALL occurrences of the given header name.
194 * For the two-arg overload, remove the given header with teh given value.
195 *
196 * Returns the number of items removed.
197 */
198 nonvirtual size_t Remove (const String& headerName);
199 nonvirtual size_t Remove (const String& headerName, const String& value);
200
201 public:
202 /**
203 * Set to any string value, or to nullopt to clear the option.
204 */
205 nonvirtual void Set (const String& headerName, const optional<String>& value);
206
207 public:
208 /**
209 * \see https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
210 */
212
213 public:
214 /**
215 * Property with the optional<String> value of the Access-Control-Allow-Origin header.
216 * \see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
217 *
218 * This can be nullopt (meaning not present), "*", or a hostname[:port]
219 */
221
222 public:
223 /**
224 * Property with the optional<CacheControl> value of the Allow header.
225 * \see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Allow
226 *
227 * This property automatically parses the header into an set of strings (because order here doesn't matter)
228 */
230
231 public:
232 /**
233 * \brief typically, the value will be missing, or "Bearer xxx"
234 * \see https://datatracker.ietf.org/doc/html/rfc7235 (not great reference)
235 * \note confusing name authorization due to HTTP authorization name - really refers to mix of authentication/authorization (AUTH)
236 */
238
239 public:
240 /**
241 * \brief HTTP Response header controlling how clients will cache this response.
242 *
243 * Property with the optional<CacheControl> value of the Cache-Control header.
244 *
245 * From https://tools.ietf.org/html/rfc7234#page-5
246 *
247 * Although caching is an entirely OPTIONAL feature
248 * of HTTP, it can be assumed that reusing a cached response is
249 * desirable and that such reuse is the default behavior when no
250 * requirement or local configuration prevents it. Therefore, HTTP
251 * cache requirements are focused on preventing a cache from either
252 * storing a non-reusable response or reusing a stored response
253 * inappropriately, rather than mandating that caches always store and
254 * reuse particular responses.
255 *
256 * https://tools.ietf.org/html/rfc2616#section-13.4
257 *
258 * Unless specifically constrained by a cache-control (section 14.9)
259 * directive, a caching system MAY always store a successful response
260 * (see section 13.8) as a cache entry, MAY return it without validation
261 * if it is fresh, and MAY return it after successful validation. If
262 * there is neither a cache validator nor an explicit expiration time
263 * associated with a response, we do not expect it to be cached, but
264 * certain caches MAY violate this expectation (for example, when little
265 * or no network connectivity is available).
266 *
267 * But then contradicting the above
268 * https://tools.ietf.org/html/rfc2616#section-9.5
269 * (about POST)
270 * Responses to this method are not cacheable, unless the response
271 * includes appropriate Cache-Control or Expires header fields
272 *
273 * similarly for PUT/POST/DELETE (from same document) - those appear to not be cacheable.
274 */
276
277 public:
278 /**
279 * Value of the HTTP 1.1 and earlier Connection header (connection property).
280 */
282 eKeepAlive,
283 eClose,
284 };
285
286 public:
287 /**
288 * Property with the optional<ConnectionValue> value of the Connection header.
289 *
290 * Header mostly just used for HTTP 1.1 and earlier.
291 */
293
294 public:
295 /**
296 * \see https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11
297 *
298 * \note - docs not super clear, but it appears there CAN be more than one encoding, and they are done in order, one after the other
299 */
301
302 public:
303 /**
304 * Property with the optional<uint64_t> value of the Content-Length header.
305 * \note this refers to the (possibly encoded) size in bytes of the HTTP payload body (so if zipped its the size of the zipfile not the size after unzip).
306 *
307 * \par Example Usage
308 * \code
309 * optional<uint64_t> contentLength = fHeaders_.contentLength;
310 * \endcode
311 */
313
314 public:
315 /**
316 * Property with the optional<InternetMediaType> value of the Content-Type header.
317 *
318 * \par Example Usage
319 * \code
320 * optional<InternetMediaType> contentType = fHeaders_.contentType;
321 * fHeaders_.contentType = nullopt; // remove the content-type header
322 * \endcode
323 */
325
326 public:
327 /**
328 * \brief The HTTP Content-Disposition header indicates whether content should be displayed inline in the browser as a web page or part of a web page or downloaded as an attachment locally
329 *
330 * \par Example Usage
331 * \code
332 * fHeaders_.contentDisposition = "inline"; // default value
333 * fHeaders_.contentDisposition = "attachment"; // file should be downloaded
334 * fHeaders_.contentDisposition = "attachment; filename=\"foo.jpg\"";
335 * \endcode
336 */
338
339 public:
340 /**
341 * Property with the optional<DateTime> value of the Date header.
342 *
343 * \par Example Usage
344 * \code
345 * \endcode
346 */
348
349 public:
350 /**
351 * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie
352 *
353 * if the list is empty, this corresponds to no header present
354 */
356
357 public:
358 /**
359 * Property with the optional<ETag> value of the ETag header.
360 */
362
363 public:
364 /**
365 * Property with the optional<String> value of the Host header.
366 * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host
367 * This is a request-only Header.
368 */
370
371 public:
372 /**
373 * Property with the optional<IfNoneMatch> value of the IF-None-Match header.
374 */
376
377 public:
378 /**
379 * https://tools.ietf.org/html/rfc2068#section-19.7.1.1
380 * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive
381 */
383
384 public:
385 /**
386 * Property with the optional<URI> value of the Location header.
387 * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location
388 */
390
391 public:
392 /**
393 * Property with the optional<URI> value of the Origin header.
394 * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin
395 * This is a request-only Header sent with CORS requests, as well as with POST requests
396 */
398
399 public:
400 /**
401 * Property with the optional<String> value of the Server header.
402 * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server
403 */
405
406 public:
407 /**
408 * Encoded in HTTP as a SEQUENCE of separate HTTP Headers;
409 * empty list amounts to no headers present
410 * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
411 */
413
414 public:
415 /**
416 * Property with the optional<Set<TransferEncoding>> value of the Transfer-Encoding header.
417 *
418 * This is very typically OMITTED, and when present in a Response Header, its typically value will just be TransferEncoding::kChunked
419 * because the default - TransferEncoding::eIdentity is understood when the header is missing.
420 *
421 * \note - this is generally NOT to be used for compression (though it can be).
422 *
423 * \note because a TransferEncodings object with the single entry eIdentity is the default, that state is treated as equivalent to missing (so assign of such an array to this property results in it being missing)
424 */
426
427 public:
428 /**
429 * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary
430 * This is a response-only Header.
431 */
433
434 public:
435 /**
436 * Returns the combined set of headers (list Key:Value pairs). Note this may not be returned in
437 * the same order and exactly losslessly identically to what was passed in.
438 *
439 * \note - if Mapping<String,String> is the target type, and if setCookie headers are present, some maybe omitted in the
440 * resulting Mapping<>
441 *
442 * Supported T types:
443 * o Association<String,String>
444 * o Mapping<String,String>
445 * o Collection<KeyValuePair<String,String>>
446 * o Iterable<KeyValuePair<String,String>>
447 */
448 template <Common::IAnyOf<Association<String, String>, Mapping<String, String>, Collection<KeyValuePair<String, String>>, Iterable<KeyValuePair<String, String>>> T =
449 Iterable<KeyValuePair<String, String>>>
450 nonvirtual T As () const;
451
452 public:
453 /**
454 * @see Characters::ToString ();
455 */
456 nonvirtual String ToString () const;
457
458 public:
459 /**
460 */
461 nonvirtual bool operator== (const Headers& rhs) const;
462
463 private:
464 enum class AddOrSet {
465 eAdd,
466 eSet,
467 eRemove
468 };
469 // UpdateBuiltin_ returns true iff headerName was a parsed/builtin type, and false for 'extra' headers: to find out # elts changed, use nChanges optional parameter
470 nonvirtual bool UpdateBuiltin_ (AddOrSet flag, const String& headerName, const optional<String>& value, size_t* nRemovals = nullptr);
471 nonvirtual void SetExtras_ (const String& headerName, const optional<String>& value);
472
473 private:
474 // Could have properties lookup once when loading and store here. Or could have
475 // them dynamically lookup in fExtraHeaders_. Just put the ones here in special variables
476 // that are very commonly checked for, so their check/update will be a bit quicker.
478 optional<String> fAuthorization_;
479 optional<ContentEncodings> fAcceptEncodings_; // request header only
480 optional<CacheControl> fCacheControl_;
481 optional<ContentEncodings> fContentEncoding_;
482 optional<uint64_t> fContentLength_; // must access through property to access extended property handlers (except root getter/setter)
483 optional<InternetMediaType> fContentType_;
484 optional<CookieList> fCookieList_; // store optional cuz often missing, and faster init
485 optional<Time::DateTime> fDate_;
486 optional<HTTP::ETag> fETag_; // must access through property to access extended property handlers (except root getter/setter)
487 optional<String> fHost_;
488 optional<IfNoneMatch> fIfNoneMatch_;
489 optional<CookieList> fSetCookieList_; // store optional cuz often missing, and faster init
490 optional<TransferEncodings> fTransferEncoding_; // must access through property to access extended property handlers (except root getter/setter)
491 optional<Containers::Set<String>> fVary_;
492 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
493 };
494 template <>
495 Association<String, String> Headers::As () const;
496 template <>
497 Mapping<String, String> Headers::As () const;
498 template <>
499 Collection<KeyValuePair<String, String>> Headers::As () const;
500 template <>
501 Iterable<KeyValuePair<String, String>> Headers::As () const;
502
503}
504
505/*
506 ********************************************************************************
507 ***************************** Implementation Details ***************************
508 ********************************************************************************
509 */
510#include "Headers.inl"
511
512#endif /*_Stroika_Foundation_IO_Network_HTTP_Headers_h_*/
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
ExtendableProperty is a Property which has callbacks associated with it, to be notified when it is ac...
Definition Property.h:491
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
Definition Collection.h:102
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
Definition Set.h:105
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
roughly equivalent to Association<String,String>, except that the class is smart about certain keys a...
Definition Headers.h:129
Common::Property< optional< String > > contentDisposition
The HTTP Content-Disposition header indicates whether content should be displayed inline in the brows...
Definition Headers.h:337
nonvirtual optional< String > LookupOne(const String &name) const
Definition Headers.cpp:415
Common::ExtendableProperty< optional< HTTP::ETag > > ETag
Definition Headers.h:361
Common::Property< optional< URI > > location
Definition Headers.h:389
Common::ExtendableProperty< optional< uint64_t > > contentLength
Definition Headers.h:312
Common::Property< optional< String > > accessControlAllowOrigin
Definition Headers.h:220
Common::Property< optional< InternetMediaType > > contentType
Definition Headers.h:324
Common::Property< optional< Time::DateTime > > date
Definition Headers.h:347
nonvirtual size_t Remove(const String &headerName)
Definition Headers.cpp:506
Common::Property< optional< String > > host
Definition Headers.h:369
nonvirtual void Add(const String &headerName, const String &value)
Definition Headers.cpp:528
Common::Property< optional< ContentEncodings > > contentEncoding
Definition Headers.h:300
nonvirtual Collection< String > LookupAll(const String &name) const
Definition Headers.cpp:478
Common::Property< optional< CacheControl > > cacheControl
HTTP Response header controlling how clients will cache this response.
Definition Headers.h:275
Common::Property< optional< Containers::Set< String > > > vary
Definition Headers.h:432
Common::Property< CookieList > cookie
Definition Headers.h:355
Common::Property< optional< HTTP::KeepAlive > > keepAlive
Definition Headers.h:382
Common::Property< optional< URI > > origin
Definition Headers.h:397
Common::Property< optional< ContentEncodings > > acceptEncoding
Definition Headers.h:211
Common::Property< optional< String > > authorization
typically, the value will be missing, or "Bearer xxx"
Definition Headers.h:237
Common::Property< optional< ConnectionValue > > connection
Definition Headers.h:292
Common::Property< optional< Containers::Set< String > > > allow
Definition Headers.h:229
Common::Property< CookieList > setCookie
Definition Headers.h:412
Common::Property< optional< IfNoneMatch > > ifNoneMatch
Definition Headers.h:375
Common::ExtendableProperty< optional< TransferEncodings > > transferEncoding
Definition Headers.h:425
Common::Property< optional< String > > server
Definition Headers.h:404
nonvirtual void AddAll(const Headers &headers)
not the same as assignment - only for headers set in argument, replace those in this header object.
Definition Headers.cpp:537
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
very similar to ThreeWayComparer but returns true if less
Definition String.h:1856