Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Headers.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
7#include "Stroika/Foundation/Characters/String2Int.h"
9#include "Stroika/Foundation/Containers/Set.h"
10
11#include "Headers.h"
12
13using namespace Stroika::Foundation;
16using namespace Stroika::Foundation::IO;
19using namespace Stroika::Foundation::Streams;
20
22
23namespace {
24 constexpr string_view kKeepAlive_ = "Keep-Alive"sv;
25 constexpr string_view kClose_ = "close"sv;
26}
27
28/*
29 ********************************************************************************
30 ******************************** HTTP::Headers *********************************
31 ********************************************************************************
32 */
34 : acceptEncoding{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<ContentEncodings> {
35 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::acceptEncoding);
36 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
37 return thisObj->fAcceptEncodings_;
38 },
39 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& newAcceptEncodings) {
40 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::acceptEncoding);
41 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
42 thisObj->fAcceptEncodings_ = newAcceptEncodings;
43 }}
44 , accessControlAllowOrigin{
45 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<String> {
46 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::accessControlAllowOrigin);
47 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
48 return thisObj->LookupOne (HeaderName::kAccessControlAllowOrigin);
49 },
50 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& accessControlAllowOrigin) {
51 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::accessControlAllowOrigin);
52 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
53 thisObj->SetExtras_ (HeaderName::kAccessControlAllowOrigin, accessControlAllowOrigin);
54 }}
55 , allow{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<Containers::Set<String>> {
56 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::allow);
57 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
58 if (auto hdr = thisObj->LookupOne (HeaderName::kAllow)) {
59 return Containers::Set<String>{hdr->Tokenize ({','})};
60 }
61 return nullopt;
62 },
63 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& allowed) {
64 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::allow);
65 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
66 thisObj->SetExtras_ (HeaderName::kAllow, allowed ? String::Join (*allowed) : optional<String>{});
67 }}
68 , authorization{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<String> {
69 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::authorization);
70 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
71 return thisObj->fAuthorization_;
72 },
73 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& newAuth) {
74 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::authorization);
75 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
76 thisObj->fAuthorization_ = newAuth;
77 }}
78 , cacheControl{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<CacheControl> {
79 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::cacheControl);
80 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
81 return thisObj->fCacheControl_;
82 },
83 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& cacheControl) {
84 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::cacheControl);
85 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
86 thisObj->fCacheControl_ = cacheControl;
87 }}
88 , connection{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<ConnectionValue> {
89 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::connection);
90 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
91 if (auto connectionHdr = thisObj->LookupOne (HeaderName::kConnection)) {
92 if (kHeaderNameEqualsComparer (*connectionHdr, kKeepAlive_)) {
93 return eKeepAlive;
94 }
95 else if (kHeaderNameEqualsComparer (*connectionHdr, kClose_)) {
96 return eClose;
97 }
98 }
99 return nullopt;
100 },
101 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& connectionValue) {
102 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::connection);
103 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
104 optional<String> v;
105 if (connectionValue) {
106 switch (*connectionValue) {
107 case ConnectionValue::eKeepAlive:
108 v = kKeepAlive_;
109 break;
110 case ConnectionValue::eClose:
111 v = kClose_;
112 break;
113 }
114 }
115 thisObj->SetExtras_ (HeaderName::kConnection, v);
116 }}
117 , contentEncoding{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<ContentEncodings> {
118 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::contentEncoding);
119 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
120 return thisObj->fContentEncoding_;
121 },
122 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, auto newContentEncoding) {
123 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::contentEncoding);
124 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
125 thisObj->fContentEncoding_ = newContentEncoding;
126 }}
127 , contentLength{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<uint64_t> {
128 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::contentLength);
129 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
130 return thisObj->fContentLength_;
131 },
132 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, auto contentLength) {
133 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::contentLength);
134 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
135 thisObj->fContentLength_ = contentLength;
136 }}
137 , contentType{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
138 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::contentType);
139 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
140 return thisObj->fContentType_;
141 },
142 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& contentType) {
143 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::contentType);
144 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
145 thisObj->fContentType_ = contentType;
146 }}
147 , contentDisposition{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<String> {
148 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::contentDisposition);
149 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
150 return thisObj->LookupOne (HeaderName::kContentDisposition);
151 },
152 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& hdrVal) {
153 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::contentDisposition);
154 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
155 thisObj->SetExtras_ (HeaderName::kContentDisposition, hdrVal);
156 }}
157 , date{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
158 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::date);
159 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
160 return thisObj->fDate_;
161 },
162 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& d) {
163 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::date);
164 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
165 thisObj->fDate_ = d ? d->AsUTC () : d;
166 }}
167 , cookie{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
168 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::cookie);
169 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
170 return Memory::NullCoalesce (thisObj->fCookieList_);
171 },
172 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& cookies) {
173 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::cookie);
174 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
175 thisObj->fCookieList_ = cookies.cookieDetails ().empty () ? optional<CookieList>{} : cookies;
176 }}
177 , ETag{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
178 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::ETag);
179 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
180 return thisObj->fETag_;
181 },
182 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& etag) {
183 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::ETag);
184 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
185 thisObj->fETag_ = etag;
186 }}
187 , host{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
188 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::host);
189 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
190 return thisObj->fHost_;
191 },
192 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& host) {
193 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::host);
194 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
195 thisObj->fHost_ = host;
196 }}
197 , ifNoneMatch{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
198 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::ifNoneMatch);
199 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
200 return thisObj->fIfNoneMatch_;
201 },
202 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& ifNoneMatch) {
203 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::ifNoneMatch);
204 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
205 thisObj->fIfNoneMatch_ = ifNoneMatch;
206 }}
207 , keepAlive{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<HTTP::KeepAlive> {
208 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::keepAlive);
209 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
210 if (auto hdrValue = thisObj->LookupOne (HeaderName::kKeepAlive)) {
211 return HTTP::KeepAlive::Parse (*hdrValue);
212 }
213 return nullopt;
214 },
215 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& keepAliveValue) {
216 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::keepAlive);
217 optional<String> v;
218 if (keepAliveValue) {
219 v = keepAliveValue->AsValue ();
220 }
221 thisObj->SetExtras_ (HeaderName::kKeepAlive, v);
222 }}
223 , location{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<URI> {
224 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::location);
225 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
226 if (auto hdr = thisObj->LookupOne (HeaderName::kLocation)) {
227 return URI::Parse (*hdr);
228 }
229 return nullopt;
230 },
231 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const optional<URI>& location) {
232 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::location);
233 thisObj->SetExtras_ (HeaderName::kLocation, location ? location->As<String> () : optional<String>{});
234 }}
235 , origin{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<URI> {
236 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::origin);
237 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
238 if (auto hdr = thisObj->LookupOne (HeaderName::kOrigin)) {
239 return URI::Parse (*hdr);
240 }
241 return nullopt;
242 },
243 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const optional<URI>& origin) {
244 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::origin);
245 thisObj->SetExtras_ (HeaderName::kOrigin, origin ? origin->As<String> () : optional<String>{});
246 }}
247 , server{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<String> {
248 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::server);
249 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
250 return thisObj->LookupOne (HeaderName::kServer);
251 },
252 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const optional<String>& server) {
253 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::server);
254 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
255 thisObj->SetExtras_ (HeaderName::kServer, server);
256 }}
257 , setCookie{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
258 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::setCookie);
259 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
260 return Memory::NullCoalesce (thisObj->fSetCookieList_);
261 },
262 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& cookies) {
263 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::setCookie);
264 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
265 thisObj->fSetCookieList_ = cookies.cookieDetails ().empty () ? optional<CookieList>{} : cookies;
266 }}
267 , transferEncoding{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) {
268 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::transferEncoding);
269 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
270 return thisObj->fTransferEncoding_;
271 },
272 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const auto& newTransferEncodings) {
273 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::transferEncoding);
274 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
275 if (newTransferEncodings && newTransferEncodings->length () == 1 &&
276 newTransferEncodings->Contains (TransferEncoding::kIdentity)) {
277 thisObj->fTransferEncoding_ = nullopt;
278 }
279 else {
280 thisObj->fTransferEncoding_ = newTransferEncodings;
281 }
282 }}
283 , vary{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> optional<Containers::Set<String>> {
284 const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::vary);
285 AssertExternallySynchronizedMutex::ReadContext declareContext{thisObj->fThisAssertExternallySynchronized_};
286 return thisObj->fVary_;
287 },
288 [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] auto* property, const optional<Containers::Set<String>>& vary) {
289 Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::vary);
290 AssertExternallySynchronizedMutex::WriteContext declareContext{thisObj->fThisAssertExternallySynchronized_};
291 thisObj->fVary_ = vary;
292 }}
293{
294}
295
296Headers::Headers (const Headers& src)
297 : Headers{}
298{
299 AssertExternallySynchronizedMutex::ReadContext declareContext{src.fThisAssertExternallySynchronized_};
300 // NOTE properties and fields refer to the same thing. COULD copy properties, but cheaper to just 'initialize' the fields
301 // However, cannot mix initialize with calling delegated CTOR, so do the slightly more inefficient way to avoid duplicative code
302 fExtraHeaders_ = src.fExtraHeaders_;
303 fAcceptEncodings_ = src.fAcceptEncodings_;
304 fAuthorization_ = src.fAuthorization_;
305 fCacheControl_ = src.fCacheControl_;
306 fContentEncoding_ = src.fContentEncoding_;
307 fContentType_ = src.fContentType_;
308 fCookieList_ = src.fCookieList_;
309 fDate_ = src.fDate_;
310 fHost_ = src.fHost_;
311 fIfNoneMatch_ = src.fIfNoneMatch_;
312 fSetCookieList_ = src.fSetCookieList_;
313 fTransferEncoding_ = src.fTransferEncoding_;
314 fVary_ = src.fVary_;
315 // for extended properties, we must call the property function to get the callbacks called
316 fContentLength_ = src.contentLength ();
317 fETag_ = src.ETag ();
318}
319
321 : Headers{}
322{
323 AssertExternallySynchronizedMutex::WriteContext declareContext{src.fThisAssertExternallySynchronized_};
324 // NOTE properties and fields refer to the same thing. COULD copy properties, but cheaper to just 'initialize' the fields
325 // However, cannot mix initialize with calling delegated CTOR, so do the slightly more inefficent way to avoid duplicative code
326 fExtraHeaders_ = move (src.fExtraHeaders_);
327 fAcceptEncodings_ = move (src.fAcceptEncodings_);
328 fAuthorization_ = move (src.fAuthorization_);
329 fCacheControl_ = move (src.fCacheControl_);
330 fContentEncoding_ = move (src.fContentEncoding_);
331 fContentType_ = move (src.fContentType_);
332 fCookieList_ = move (src.fCookieList_);
333 fDate_ = move (src.fDate_);
334 fHost_ = move (src.fHost_);
335 fIfNoneMatch_ = move (src.fIfNoneMatch_);
336 fSetCookieList_ = move (src.fSetCookieList_);
337 fTransferEncoding_ = move (src.fTransferEncoding_);
338 fVary_ = move (src.fVary_);
339 // for extended properties, we must call the property function to get the callbacks called
340 fContentLength_ = src.contentLength ();
341 fETag_ = src.ETag ();
342}
343
344Headers::Headers (const Iterable<pair<String, String>>& src)
345 : Headers{}
346{
347 for (const auto& kv : src) {
348 Set (kv.first, kv.second);
349 }
350}
351
353 : Headers{}
354{
355 for (const auto& kv : src) {
356 Set (kv.fKey, kv.fValue);
357 }
358}
359
360Headers& Headers::operator= (const Headers& rhs)
361{
362 AssertExternallySynchronizedMutex::ReadContext critSec1{rhs.fThisAssertExternallySynchronized_};
363 AssertExternallySynchronizedMutex::WriteContext critSec2{fThisAssertExternallySynchronized_};
364 if (this != &rhs) {
365 fExtraHeaders_ = rhs.fExtraHeaders_;
366 fAcceptEncodings_ = rhs.fAcceptEncodings_;
367 fAuthorization_ = rhs.fAuthorization_;
368 fCacheControl_ = rhs.fCacheControl_;
369 fContentLength_ = rhs.fContentLength_;
370 fContentEncoding_ = rhs.fContentEncoding_;
371 fContentType_ = rhs.fContentType_;
372 fCookieList_ = rhs.fCookieList_;
373 fDate_ = rhs.fDate_;
374 fETag_ = rhs.fETag_;
375 fHost_ = rhs.fHost_;
376 fIfNoneMatch_ = rhs.fIfNoneMatch_;
377 fSetCookieList_ = rhs.fSetCookieList_;
378 fTransferEncoding_ = rhs.fTransferEncoding_;
379 fVary_ = rhs.fVary_;
380 }
381 return *this;
382}
383
384Headers& Headers::operator= (Headers&& rhs) noexcept
385{
386 AssertExternallySynchronizedMutex::WriteContext critSec1{rhs.fThisAssertExternallySynchronized_};
387 AssertExternallySynchronizedMutex::WriteContext critSec2{fThisAssertExternallySynchronized_};
388 if (this != &rhs) {
389 fExtraHeaders_ = move (rhs.fExtraHeaders_);
390 fAcceptEncodings_ = move (rhs.fAcceptEncodings_);
391 fAuthorization_ = move (rhs.fAuthorization_);
392 fCacheControl_ = move (rhs.fCacheControl_);
393 fContentLength_ = move (rhs.fContentLength_);
394 fContentEncoding_ = move (rhs.fContentEncoding_);
395 fContentType_ = move (rhs.fContentType_);
396 fCookieList_ = move (rhs.fCookieList_);
397 fDate_ = move (rhs.fDate_);
398 fETag_ = move (rhs.fETag_);
399 fHost_ = move (rhs.fHost_);
400 fIfNoneMatch_ = move (rhs.fIfNoneMatch_);
401 fSetCookieList_ = move (rhs.fSetCookieList_);
402 fTransferEncoding_ = move (rhs.fTransferEncoding_);
403 fVary_ = move (rhs.fVary_);
404 }
405 return *this;
406}
407
408#if qStroika_Foundation_Debug_AssertExternallySynchronizedMutex_Enabled
409void Headers::SetAssertExternallySynchronizedMutexContext (const shared_ptr<AssertExternallySynchronizedMutex::SharedContext>& sharedContext)
410{
411 fThisAssertExternallySynchronized_.SetAssertExternallySynchronizedMutexContext (sharedContext);
412}
413#endif
414
415optional<String> Headers::LookupOne (const String& name) const
416{
417 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
418 if (kHeaderNameEqualsComparer (name, HeaderName::kAcceptEncoding)) {
419 return fAcceptEncodings_ ? fAcceptEncodings_->As<String> () : optional<String>{};
420 }
421 else if (kHeaderNameEqualsComparer (name, HeaderName::kAuthorization)) {
422 return fAuthorization_;
423 }
424 else if (kHeaderNameEqualsComparer (name, HeaderName::kCacheControl)) {
425 return fCacheControl_ ? fCacheControl_->As<String> () : optional<String>{};
426 }
427 else if (kHeaderNameEqualsComparer (name, HeaderName::kContentLength)) {
428 auto cl = this->contentLength ();
429 return cl ? "{}"_f(*cl) : optional<String>{};
430 }
431 else if (kHeaderNameEqualsComparer (name, HeaderName::kContentEncoding)) {
432 return fContentEncoding_ ? fContentEncoding_->As<String> () : optional<String>{};
433 }
434 else if (kHeaderNameEqualsComparer (name, HeaderName::kContentType)) {
435 return fContentType_ ? fContentType_->As<String> () : optional<String>{};
436 }
437 else if (kHeaderNameEqualsComparer (name, HeaderName::kCookie)) {
438 return fCookieList_ ? fCookieList_->EncodeForCookieHeader () : optional<String>{};
439 }
440 else if (kHeaderNameEqualsComparer (name, HeaderName::kDate)) {
441 return fDate_ ? fDate_->Format (Time::DateTime::kRFC1123Format) : optional<String>{};
442 }
443 else if (kHeaderNameEqualsComparer (name, HeaderName::kETag)) {
444 auto e = this->ETag ();
445 return e ? e->As<String> () : optional<String>{};
446 }
447 else if (kHeaderNameEqualsComparer (name, HeaderName::kHost)) {
448 return fHost_;
449 }
450 else if (kHeaderNameEqualsComparer (name, HeaderName::kIfNoneMatch)) {
451 return fIfNoneMatch_ ? fIfNoneMatch_->As<String> () : optional<String>{};
452 }
453 else if (kHeaderNameEqualsComparer (name, HeaderName::kSetCookie)) {
454 // we can only return the first setCookie here... (see LookupAll)
455 if (fSetCookieList_.has_value ()) {
456 if (auto i = fSetCookieList_->cookieDetails ().First ()) {
457 return i->As<String> ();
458 }
459 }
460 return optional<String>{};
461 }
462 else if (kHeaderNameEqualsComparer (name, HeaderName::kTransferEncoding)) {
463 auto tc = this->transferEncoding ();
464 return tc ? tc->As<String> () : optional<String>{};
465 }
466 else if (kHeaderNameEqualsComparer (name, HeaderName::kVary)) {
467 return fVary_ ? String::Join (*fVary_) : optional<String>{};
468 }
469 else {
470 // should switch to new non-existent class Association here - and use that...more efficient -
471 if (auto ri = fExtraHeaders_.Find ([&] (const auto& i) { return kHeaderNameEqualsComparer (name, i.fKey); })) {
472 return ri->fValue;
473 }
474 return nullopt;
475 }
476}
477
479{
480 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
481 if (kHeaderNameEqualsComparer (name, HeaderName::kCacheControl) or kHeaderNameEqualsComparer (name, HeaderName::kContentLength) or
482 kHeaderNameEqualsComparer (name, HeaderName::kContentType) or kHeaderNameEqualsComparer (name, HeaderName::kCookie) or
483 kHeaderNameEqualsComparer (name, HeaderName::kETag) or kHeaderNameEqualsComparer (name, HeaderName::kHost) or
484 kHeaderNameEqualsComparer (name, HeaderName::kIfNoneMatch) or kHeaderNameEqualsComparer (name, HeaderName::kTransferEncoding) or
485 kHeaderNameEqualsComparer (name, HeaderName::kVary)) {
486 auto o = this->LookupOne (name);
487 return o ? Collection<String>{*o} : Collection<String>{};
488 }
489 else if (kHeaderNameEqualsComparer (name, HeaderName::kSetCookie)) {
490 // return each 'set' cookie as a separate header value
491 if (fSetCookieList_.has_value ()) {
492 return fSetCookieList_->cookieDetails ().Map<Iterable<String>> ([] (const Cookie& i) { return i.As<String> (); });
493 }
494 return Collection<String>{};
495 }
496 else {
497 Collection<String> result;
498 // should switch to new non-existent class Association here - and use that...more efficient -
499 if (auto ri = fExtraHeaders_.Find ([&] (const auto& i) { return kHeaderNameEqualsComparer (name, i.fKey); })) {
500 result += ri->fValue;
501 }
502 return result;
503 }
504}
505
506size_t Headers::Remove (const String& headerName)
507{
508 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
509 size_t nRemovals{};
510 if (UpdateBuiltin_ (AddOrSet::eRemove, headerName, nullopt, &nRemovals)) {
511 return nRemovals; // could be zero if its builtin, but this doesn't change anything
512 }
513 // currently removes all, but later add variant that removes one/all (in fact rename this)
514 return fExtraHeaders_.RemoveAll ([=] (const auto& i) { return kHeaderNameEqualsComparer (i.fKey, headerName); });
515}
516
517size_t Headers::Remove (const String& headerName, const String& value)
518{
519 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
520 size_t nRemovals{};
521 if (UpdateBuiltin_ (AddOrSet::eRemove, headerName, value, &nRemovals)) {
522 return nRemovals;
523 }
524 // currently removes all, but later add variant that removes one/all (in fact rename this)
525 return fExtraHeaders_.RemoveAll ([=] (const auto& i) { return kHeaderNameEqualsComparer (i.fKey, headerName) and value == i.fValue; });
526}
527
528void Headers::Add (const String& headerName, const String& value)
529{
530 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
531 if (UpdateBuiltin_ (AddOrSet::eAdd, headerName, value)) {
532 return;
533 }
534 fExtraHeaders_.Add ({headerName, value});
535}
536
537void Headers::AddAll (const Headers& headers)
538{
539 // more efficient to add each fields than converting arg to collection and then applying each mappnig back
540 fExtraHeaders_ += headers.fExtraHeaders_;
541 if (headers.fAcceptEncodings_) {
542 fAcceptEncodings_ = *headers.fAcceptEncodings_;
543 }
544 if (headers.fCacheControl_) {
545 fCacheControl_ = *headers.fCacheControl_;
546 }
547 if (auto cl = headers.contentLength ()) {
548 this->contentLength = *cl;
549 }
550 if (headers.fContentEncoding_) {
551 fContentEncoding_ = *headers.fContentEncoding_;
552 }
553 if (headers.fContentType_) {
554 fContentType_ = *headers.fContentType_;
555 }
556 if (headers.fCookieList_) {
557 fCookieList_ = *headers.fCookieList_;
558 }
559 if (headers.fDate_) {
560 fDate_ = *headers.fDate_;
561 }
562 if (auto et = headers.ETag ()) {
563 fETag_ = *et;
564 }
565 if (headers.fHost_) {
566 fHost_ = *headers.fHost_;
567 }
568 if (headers.fIfNoneMatch_) {
569 fIfNoneMatch_ = *headers.fIfNoneMatch_;
570 }
571 if (headers.fSetCookieList_) {
572 fSetCookieList_ = *headers.fSetCookieList_;
573 }
574 if (auto tc = headers.transferEncoding ()) {
575 fTransferEncoding_ = *tc;
576 }
577 if (headers.fVary_) {
578 fVary_ = *headers.fVary_;
579 }
580}
581
582bool Headers::UpdateBuiltin_ (AddOrSet flag, const String& headerName, const optional<String>& value, size_t* nRemovals)
583{
584 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
586 if (value == nullopt) {
587 Require (flag == AddOrSet::eRemove or flag == AddOrSet::eSet);
588 }
589 if (flag == AddOrSet::eRemove) {
590 // GENERALLY value will be none, but for some cases (like Set-Cookie) with multiple values, it can be the value you want removed
591 }
592 if (flag == AddOrSet::eAdd) {
593 Require (value.has_value ());
594 }
595 if (flag == AddOrSet::eSet) {
596 // nullopt means remove, and value is what we replace with
597 }
598 }
599 if (kHeaderNameEqualsComparer (headerName, HeaderName::kAcceptEncoding)) {
600 if (nRemovals != nullptr) {
601 *nRemovals = (value == nullopt and fAcceptEncodings_ != nullopt) ? 1 : 0;
602 }
603 fAcceptEncodings_ = value ? ContentEncodings::Parse (*value) : optional<ContentEncodings>{};
604 return true;
605 }
606 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kAuthorization)) {
607 if (nRemovals != nullptr) {
608 *nRemovals = (value == nullopt and fAuthorization_ != nullopt) ? 1 : 0;
609 }
610 fAuthorization_ = value;
611 return true;
612 }
613 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kCacheControl)) {
614 if (nRemovals != nullptr) {
615 *nRemovals = (value == nullopt and fCacheControl_ != nullopt) ? 1 : 0;
616 }
617 fCacheControl_ = value ? CacheControl::Parse (*value) : optional<CacheControl>{};
618 return true;
619 }
620 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kContentEncoding)) {
621 if (nRemovals != nullptr) {
622 *nRemovals = (value == nullopt and fContentEncoding_ != nullopt) ? 1 : 0;
623 }
624 this->contentEncoding = value ? ContentEncoding{*value} : optional<ContentEncoding>{};
625 return true;
626 }
627 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kContentLength)) {
628 if (nRemovals != nullptr) {
629 *nRemovals = (value == nullopt and fContentLength_ != nullopt) ? 1 : 0;
630 }
631 this->contentLength = value ? String2Int<uint64_t> (*value) : optional<uint64_t>{};
632 return true;
633 }
634 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kContentType)) {
635 if (nRemovals != nullptr) {
636 *nRemovals = (value == nullopt and fContentType_ != nullopt) ? 1 : 0;
637 }
638 fContentType_ = value ? InternetMediaType{*value} : optional<InternetMediaType>{};
639 return true;
640 }
641 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kCookie)) {
642 if (nRemovals != nullptr) {
643 *nRemovals = (value == nullopt and fCookieList_ != nullopt) ? 1 : 0;
644 }
645 fCookieList_ = value ? CookieList::Parse (*value) : optional<CookieList>{};
646 }
647 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kDate)) {
648 optional<Time::DateTime> useDT;
649 // see http://stroika-bugs.sophists.com/browse/STK-731 - should support parsing (not writing) older formats too
650 try {
651 if (value) {
652 useDT = Time::DateTime::Parse (*value, Time::DateTime::kRFC1123Format).AsUTC ();
653 }
654 }
655 catch (...) {
656 DbgTrace ("Treating ill-formatted date as missing date header"_f);
657 }
658 if (nRemovals != nullptr) {
659 *nRemovals = (useDT == nullopt and fDate_ != nullopt) ? 1 : 0;
660 }
661 fDate_ = useDT ? useDT : optional<Time::DateTime>{};
662 return true;
663 }
664 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kETag)) {
665 if (nRemovals != nullptr) {
666 *nRemovals = (value == nullopt and fETag_ != nullopt) ? 1 : 0;
667 }
668 fETag_ = value ? ETag::Parse (*value) : optional<HTTP::ETag>{};
669 return true;
670 }
671 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kHost)) {
672 if (nRemovals != nullptr) {
673 *nRemovals = (value == nullopt and fHost_ != nullopt) ? 1 : 0;
674 }
675 fHost_ = value;
676 return true;
677 }
678 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kIfNoneMatch)) {
679 if (nRemovals != nullptr) {
680 *nRemovals = (value == nullopt and fIfNoneMatch_ != nullopt) ? 1 : 0;
681 }
682 fIfNoneMatch_ = value ? IfNoneMatch::Parse (*value) : optional<IfNoneMatch>{};
683 return true;
684 }
685 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kSetCookie)) {
686 if (nRemovals != nullptr) {
687 *nRemovals = (value == nullopt and fSetCookieList_ != nullopt) ? 1 : 0;
688 }
689 switch (flag) {
690 case AddOrSet::eRemove: {
691 if (fSetCookieList_ != nullopt) {
692 if (value) {
693 // then remove a specific one
694 Collection<Cookie> cookieDetails = fSetCookieList_->cookieDetails ();
695 auto removeMe = Cookie::Parse (*value);
696 bool r = cookieDetails.RemoveIf (removeMe);
697 if (nRemovals != nullptr) {
698 *nRemovals = r ? 1 : 0;
699 }
700 }
701 else {
702 fSetCookieList_ = nullopt; // then remove all
703 }
704 }
705 } break;
706 case AddOrSet::eAdd: {
707 Collection<Cookie> cookieDetails = fSetCookieList_ ? fSetCookieList_->cookieDetails () : Collection<Cookie>{};
708 cookieDetails += Cookie::Parse (*value);
709 fSetCookieList_ = cookieDetails;
710 } break;
711 case AddOrSet::eSet: {
712 fSetCookieList_ = value ? CookieList::Parse (*value) : optional<CookieList>{};
713 } break;
714 }
715 return true;
716 }
717 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kTransferEncoding)) {
718 if (nRemovals != nullptr) {
719 *nRemovals = (value == nullopt and fTransferEncoding_ != nullopt) ? 1 : 0;
720 }
721 this->transferEncoding = value ? TransferEncodings::Parse (*value) : optional<TransferEncodings>{};
722 return true;
723 }
724 else if (kHeaderNameEqualsComparer (headerName, HeaderName::kVary)) {
725 if (nRemovals != nullptr) {
726 *nRemovals = (value == nullopt and fVary_ != nullopt) ? 1 : 0;
727 }
728 fVary_ = value ? Containers::Set<String>{value->Tokenize ({','})} : optional<Containers::Set<String>>{};
729 return true;
730 }
731 return false;
732}
733
734void Headers::SetExtras_ (const String& headerName, const optional<String>& value)
735{
736 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
737 fExtraHeaders_.RemoveIf ([=] (const auto& i) { return kHeaderNameEqualsComparer (i.fKey, headerName); });
738 if (value) {
739 fExtraHeaders_.Add ({headerName, *value});
740 }
741}
742
743void Headers::Set (const String& headerName, const optional<String>& value)
744{
745 if (UpdateBuiltin_ (AddOrSet::eSet, headerName, value)) {
746 return;
747 }
748 SetExtras_ (headerName, value);
749}
750
751template <>
753{
754 return As<Collection<KeyValuePair<String, String>>> ().As<Association<String, String>> (kHeaderNameEqualsComparer);
755}
756
757template <>
759{
760 // NOTE - CAN be lossy conversion to Mapping, losing Set-Cookie's
761 return As<Collection<KeyValuePair<String, String>>> ().As<Mapping<String, String>> (kHeaderNameEqualsComparer);
762}
763
764template <>
766{
767 AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
768 Collection<KeyValuePair<String, String>> results = fExtraHeaders_;
769 if (fAcceptEncodings_) {
770 results.Add ({HeaderName::kAcceptEncoding, fAcceptEncodings_->As<String> ()});
771 }
772 if (fAuthorization_) {
773 results.Add ({HeaderName::kAuthorization, *fAuthorization_});
774 }
775 if (fCacheControl_) {
776 results.Add ({HeaderName::kCacheControl, fCacheControl_->As<String> ()});
777 }
778 if (auto cl = this->contentLength ()) {
779 results.Add ({HeaderName::kContentLength, "{}"_f(static_cast<long long> (*cl))});
780 }
781 if (fContentEncoding_) {
782 results.Add ({HeaderName::kContentEncoding, fContentEncoding_->As<String> ()});
783 }
784 if (fContentType_) {
785 results.Add ({HeaderName::kContentType, fContentType_->As<String> ()});
786 }
787 if (fCookieList_) {
788 results.Add ({HeaderName::kCookie, fCookieList_->EncodeForCookieHeader ()});
789 }
790 if (fDate_) {
791 results.Add ({HeaderName::kDate, fDate_->Format (Time::DateTime::kRFC1123Format)});
792 }
793 if (auto et = ETag ()) {
794 results.Add ({HeaderName::kETag, et->As<String> ()});
795 }
796 if (fHost_) {
797 results.Add ({HeaderName::kHost, *fHost_});
798 }
799 if (fIfNoneMatch_) {
800 results.Add ({HeaderName::kIfNoneMatch, fIfNoneMatch_->As<String> ()});
801 }
802 if (fSetCookieList_) {
803 // fSetCookieList_ produces multiple set-headers
804 for (const auto& i : fSetCookieList_->cookieDetails ()) {
805 results.Add ({HeaderName::kSetCookie, i.As<String> ()});
806 }
807 }
808 if (auto tc = this->transferEncoding ()) {
809 results.Add ({HeaderName::kTransferEncoding, tc->As<String> ()});
810 }
811 if (fVary_) {
812 results.Add ({HeaderName::kVary, String::Join (*fVary_)});
813 }
814 return results;
815}
816
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:48
#define DbgTrace
Definition Trace.h:309
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
static String Join(const Iterable< String > &list, const String &separator=", "sv)
Definition String.cpp:1692
An Association pairs key values with (possibly multiple or none) mapped_type values....
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
Definition Collection.h:102
nonvirtual bool RemoveIf(ArgByValueType< value_type > item, EQUALS_COMPARER &&equalsComparer={})
RemoveIf () the (the first matching) argument value, if present. Returns true if item removed.
nonvirtual void Add(ArgByValueType< value_type > item)
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
Definition Set.h:105
nonvirtual bool RemoveIf(ArgByValueType< value_type > item)
Definition Set.inl:194
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
nonvirtual void Set(const String &headerName, const optional< String > &value)
Definition Headers.cpp:743
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
static URI Parse(const String &rawURL)
Definition URI.cpp:119
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
String ToString(T &&t, ARGS... args)
Return a debug-friendly, display version of the argument: not guaranteed parsable or usable except fo...
Definition ToString.inl:465
static CacheControl Parse(const Characters::String &headerValue)
Content coding values indicate an encoding transformation that has been or can be applied to an entit...
static optional< ETag > Parse(const String &wireFormat)
Definition ETag.inl:17
static optional< IfNoneMatch > Parse(const String &wireFormat)