]>
Commit | Line | Data |
---|---|---|
1 | // | |
2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // Official repository: https://github.com/boostorg/beast | |
8 | // | |
9 | ||
10 | #ifndef BOOST_BEAST_HTTP_IMPL_FIELD_IPP | |
11 | #define BOOST_BEAST_HTTP_IMPL_FIELD_IPP | |
12 | ||
13 | #include <boost/beast/http/field.hpp> | |
14 | #include <algorithm> | |
15 | #include <array> | |
16 | #include <cstring> | |
17 | #include <boost/assert.hpp> | |
18 | ||
19 | namespace boost { | |
20 | namespace beast { | |
21 | namespace http { | |
22 | ||
23 | namespace detail { | |
24 | ||
25 | struct field_table | |
26 | { | |
27 | using array_type = | |
28 | std::array<string_view, 353>; | |
29 | ||
30 | // Strings are converted to lowercase | |
31 | static | |
32 | std::uint32_t | |
33 | digest(string_view s) | |
34 | { | |
35 | std::uint32_t r = 0; | |
36 | std::size_t n = s.size(); | |
37 | unsigned char const* p =reinterpret_cast< | |
38 | unsigned char const*>(s.data()); | |
39 | while(n >= 4) | |
40 | { | |
41 | std::uint32_t v; | |
42 | std::memcpy(&v, p, 4); | |
43 | r = r * 5 + ( v | 0x20202020 ); | |
44 | p += 4; | |
45 | n -= 4; | |
46 | } | |
47 | while( n > 0 ) | |
48 | { | |
49 | r = r * 5 + ( *p | 0x20 ); | |
50 | ++p; | |
51 | --n; | |
52 | } | |
53 | return r; | |
54 | } | |
55 | ||
56 | // This comparison is case-insensitive, and the | |
57 | // strings must contain only valid http field characters. | |
58 | static | |
59 | bool | |
60 | equals(string_view lhs, string_view rhs) | |
61 | { | |
62 | using Int = std::uint32_t; // or std::size_t | |
63 | auto n = lhs.size(); | |
64 | if(n != rhs.size()) | |
65 | return false; | |
66 | auto p1 = lhs.data(); | |
67 | auto p2 = rhs.data(); | |
68 | auto constexpr S = sizeof(Int); | |
69 | auto constexpr Mask = static_cast<Int>( | |
70 | 0xDFDFDFDFDFDFDFDF & ~Int{0}); | |
71 | for(; n >= S; p1 += S, p2 += S, n -= S) | |
72 | { | |
73 | Int v1, v2; | |
74 | std::memcpy( &v1, p1, S ); | |
75 | std::memcpy( &v2, p2, S ); | |
76 | if((v1 ^ v2) & Mask) | |
77 | return false; | |
78 | } | |
79 | for(; n; ++p1, ++p2, --n) | |
80 | if(( *p1 ^ *p2) & 0xDF) | |
81 | return false; | |
82 | return true; | |
83 | } | |
84 | ||
85 | array_type by_name_; | |
86 | ||
87 | enum { N = 5155 }; | |
88 | unsigned char map_[ N ][ 2 ] = {}; | |
89 | ||
90 | /* | |
91 | From: | |
92 | ||
93 | https://www.iana.org/assignments/message-headers/message-headers.xhtml | |
94 | */ | |
95 | field_table() | |
96 | : by_name_({{ | |
97 | "<unknown-field>", | |
98 | "A-IM", | |
99 | "Accept", | |
100 | "Accept-Additions", | |
101 | "Accept-Charset", | |
102 | "Accept-Datetime", | |
103 | "Accept-Encoding", | |
104 | "Accept-Features", | |
105 | "Accept-Language", | |
106 | "Accept-Patch", | |
107 | "Accept-Post", | |
108 | "Accept-Ranges", | |
109 | "Access-Control", | |
110 | "Access-Control-Allow-Credentials", | |
111 | "Access-Control-Allow-Headers", | |
112 | "Access-Control-Allow-Methods", | |
113 | "Access-Control-Allow-Origin", | |
114 | "Access-Control-Expose-Headers", | |
115 | "Access-Control-Max-Age", | |
116 | "Access-Control-Request-Headers", | |
117 | "Access-Control-Request-Method", | |
118 | "Age", | |
119 | "Allow", | |
120 | "ALPN", | |
121 | "Also-Control", | |
122 | "Alt-Svc", | |
123 | "Alt-Used", | |
124 | "Alternate-Recipient", | |
125 | "Alternates", | |
126 | "Apparently-To", | |
127 | "Apply-To-Redirect-Ref", | |
128 | "Approved", | |
129 | "Archive", | |
130 | "Archived-At", | |
131 | "Article-Names", | |
132 | "Article-Updates", | |
133 | "Authentication-Control", | |
134 | "Authentication-Info", | |
135 | "Authentication-Results", | |
136 | "Authorization", | |
137 | "Auto-Submitted", | |
138 | "Autoforwarded", | |
139 | "Autosubmitted", | |
140 | "Base", | |
141 | "Bcc", | |
142 | "Body", | |
143 | "C-Ext", | |
144 | "C-Man", | |
145 | "C-Opt", | |
146 | "C-PEP", | |
147 | "C-PEP-Info", | |
148 | "Cache-Control", | |
149 | "CalDAV-Timezones", | |
150 | "Cancel-Key", | |
151 | "Cancel-Lock", | |
152 | "Cc", | |
153 | "Close", | |
154 | "Comments", | |
155 | "Compliance", | |
156 | "Connection", | |
157 | "Content-Alternative", | |
158 | "Content-Base", | |
159 | "Content-Description", | |
160 | "Content-Disposition", | |
161 | "Content-Duration", | |
162 | "Content-Encoding", | |
163 | "Content-features", | |
164 | "Content-ID", | |
165 | "Content-Identifier", | |
166 | "Content-Language", | |
167 | "Content-Length", | |
168 | "Content-Location", | |
169 | "Content-MD5", | |
170 | "Content-Range", | |
171 | "Content-Return", | |
172 | "Content-Script-Type", | |
173 | "Content-Style-Type", | |
174 | "Content-Transfer-Encoding", | |
175 | "Content-Type", | |
176 | "Content-Version", | |
177 | "Control", | |
178 | "Conversion", | |
179 | "Conversion-With-Loss", | |
180 | "Cookie", | |
181 | "Cookie2", | |
182 | "Cost", | |
183 | "DASL", | |
184 | "Date", | |
185 | "Date-Received", | |
186 | "DAV", | |
187 | "Default-Style", | |
188 | "Deferred-Delivery", | |
189 | "Delivery-Date", | |
190 | "Delta-Base", | |
191 | "Depth", | |
192 | "Derived-From", | |
193 | "Destination", | |
194 | "Differential-ID", | |
195 | "Digest", | |
196 | "Discarded-X400-IPMS-Extensions", | |
197 | "Discarded-X400-MTS-Extensions", | |
198 | "Disclose-Recipients", | |
199 | "Disposition-Notification-Options", | |
200 | "Disposition-Notification-To", | |
201 | "Distribution", | |
202 | "DKIM-Signature", | |
203 | "DL-Expansion-History", | |
204 | "Downgraded-Bcc", | |
205 | "Downgraded-Cc", | |
206 | "Downgraded-Disposition-Notification-To", | |
207 | "Downgraded-Final-Recipient", | |
208 | "Downgraded-From", | |
209 | "Downgraded-In-Reply-To", | |
210 | "Downgraded-Mail-From", | |
211 | "Downgraded-Message-Id", | |
212 | "Downgraded-Original-Recipient", | |
213 | "Downgraded-Rcpt-To", | |
214 | "Downgraded-References", | |
215 | "Downgraded-Reply-To", | |
216 | "Downgraded-Resent-Bcc", | |
217 | "Downgraded-Resent-Cc", | |
218 | "Downgraded-Resent-From", | |
219 | "Downgraded-Resent-Reply-To", | |
220 | "Downgraded-Resent-Sender", | |
221 | "Downgraded-Resent-To", | |
222 | "Downgraded-Return-Path", | |
223 | "Downgraded-Sender", | |
224 | "Downgraded-To", | |
225 | "EDIINT-Features", | |
226 | "Eesst-Version", | |
227 | "Encoding", | |
228 | "Encrypted", | |
229 | "Errors-To", | |
230 | "ETag", | |
231 | "Expect", | |
232 | "Expires", | |
233 | "Expiry-Date", | |
234 | "Ext", | |
235 | "Followup-To", | |
236 | "Forwarded", | |
237 | "From", | |
238 | "Generate-Delivery-Report", | |
239 | "GetProfile", | |
240 | "Hobareg", | |
241 | "Host", | |
242 | "HTTP2-Settings", | |
243 | "If", | |
244 | "If-Match", | |
245 | "If-Modified-Since", | |
246 | "If-None-Match", | |
247 | "If-Range", | |
248 | "If-Schedule-Tag-Match", | |
249 | "If-Unmodified-Since", | |
250 | "IM", | |
251 | "Importance", | |
252 | "In-Reply-To", | |
253 | "Incomplete-Copy", | |
254 | "Injection-Date", | |
255 | "Injection-Info", | |
256 | "Jabber-ID", | |
257 | "Keep-Alive", | |
258 | "Keywords", | |
259 | "Label", | |
260 | "Language", | |
261 | "Last-Modified", | |
262 | "Latest-Delivery-Time", | |
263 | "Lines", | |
264 | "Link", | |
265 | "List-Archive", | |
266 | "List-Help", | |
267 | "List-ID", | |
268 | "List-Owner", | |
269 | "List-Post", | |
270 | "List-Subscribe", | |
271 | "List-Unsubscribe", | |
272 | "List-Unsubscribe-Post", | |
273 | "Location", | |
274 | "Lock-Token", | |
275 | "Man", | |
276 | "Max-Forwards", | |
277 | "Memento-Datetime", | |
278 | "Message-Context", | |
279 | "Message-ID", | |
280 | "Message-Type", | |
281 | "Meter", | |
282 | "Method-Check", | |
283 | "Method-Check-Expires", | |
284 | "MIME-Version", | |
285 | "MMHS-Acp127-Message-Identifier", | |
286 | "MMHS-Authorizing-Users", | |
287 | "MMHS-Codress-Message-Indicator", | |
288 | "MMHS-Copy-Precedence", | |
289 | "MMHS-Exempted-Address", | |
290 | "MMHS-Extended-Authorisation-Info", | |
291 | "MMHS-Handling-Instructions", | |
292 | "MMHS-Message-Instructions", | |
293 | "MMHS-Message-Type", | |
294 | "MMHS-Originator-PLAD", | |
295 | "MMHS-Originator-Reference", | |
296 | "MMHS-Other-Recipients-Indicator-CC", | |
297 | "MMHS-Other-Recipients-Indicator-To", | |
298 | "MMHS-Primary-Precedence", | |
299 | "MMHS-Subject-Indicator-Codes", | |
300 | "MT-Priority", | |
301 | "Negotiate", | |
302 | "Newsgroups", | |
303 | "NNTP-Posting-Date", | |
304 | "NNTP-Posting-Host", | |
305 | "Non-Compliance", | |
306 | "Obsoletes", | |
307 | "Opt", | |
308 | "Optional", | |
309 | "Optional-WWW-Authenticate", | |
310 | "Ordering-Type", | |
311 | "Organization", | |
312 | "Origin", | |
313 | "Original-Encoded-Information-Types", | |
314 | "Original-From", | |
315 | "Original-Message-ID", | |
316 | "Original-Recipient", | |
317 | "Original-Sender", | |
318 | "Original-Subject", | |
319 | "Originator-Return-Address", | |
320 | "Overwrite", | |
321 | "P3P", | |
322 | "Path", | |
323 | "PEP", | |
324 | "Pep-Info", | |
325 | "PICS-Label", | |
326 | "Position", | |
327 | "Posting-Version", | |
328 | "Pragma", | |
329 | "Prefer", | |
330 | "Preference-Applied", | |
331 | "Prevent-NonDelivery-Report", | |
332 | "Priority", | |
333 | "Privicon", | |
334 | "ProfileObject", | |
335 | "Protocol", | |
336 | "Protocol-Info", | |
337 | "Protocol-Query", | |
338 | "Protocol-Request", | |
339 | "Proxy-Authenticate", | |
340 | "Proxy-Authentication-Info", | |
341 | "Proxy-Authorization", | |
342 | "Proxy-Connection", | |
343 | "Proxy-Features", | |
344 | "Proxy-Instruction", | |
345 | "Public", | |
346 | "Public-Key-Pins", | |
347 | "Public-Key-Pins-Report-Only", | |
348 | "Range", | |
349 | "Received", | |
350 | "Received-SPF", | |
351 | "Redirect-Ref", | |
352 | "References", | |
353 | "Referer", | |
354 | "Referer-Root", | |
355 | "Relay-Version", | |
356 | "Reply-By", | |
357 | "Reply-To", | |
358 | "Require-Recipient-Valid-Since", | |
359 | "Resent-Bcc", | |
360 | "Resent-Cc", | |
361 | "Resent-Date", | |
362 | "Resent-From", | |
363 | "Resent-Message-ID", | |
364 | "Resent-Reply-To", | |
365 | "Resent-Sender", | |
366 | "Resent-To", | |
367 | "Resolution-Hint", | |
368 | "Resolver-Location", | |
369 | "Retry-After", | |
370 | "Return-Path", | |
371 | "Safe", | |
372 | "Schedule-Reply", | |
373 | "Schedule-Tag", | |
374 | "Sec-WebSocket-Accept", | |
375 | "Sec-WebSocket-Extensions", | |
376 | "Sec-WebSocket-Key", | |
377 | "Sec-WebSocket-Protocol", | |
378 | "Sec-WebSocket-Version", | |
379 | "Security-Scheme", | |
380 | "See-Also", | |
381 | "Sender", | |
382 | "Sensitivity", | |
383 | "Server", | |
384 | "Set-Cookie", | |
385 | "Set-Cookie2", | |
386 | "SetProfile", | |
387 | "SIO-Label", | |
388 | "SIO-Label-History", | |
389 | "SLUG", | |
390 | "SoapAction", | |
391 | "Solicitation", | |
392 | "Status-URI", | |
393 | "Strict-Transport-Security", | |
394 | "Subject", | |
395 | "SubOK", | |
396 | "Subst", | |
397 | "Summary", | |
398 | "Supersedes", | |
399 | "Surrogate-Capability", | |
400 | "Surrogate-Control", | |
401 | "TCN", | |
402 | "TE", | |
403 | "Timeout", | |
404 | "Title", | |
405 | "To", | |
406 | "Topic", | |
407 | "Trailer", | |
408 | "Transfer-Encoding", | |
409 | "TTL", | |
410 | "UA-Color", | |
411 | "UA-Media", | |
412 | "UA-Pixels", | |
413 | "UA-Resolution", | |
414 | "UA-Windowpixels", | |
415 | "Upgrade", | |
416 | "Urgency", | |
417 | "URI", | |
418 | "User-Agent", | |
419 | "Variant-Vary", | |
420 | "Vary", | |
421 | "VBR-Info", | |
422 | "Version", | |
423 | "Via", | |
424 | "Want-Digest", | |
425 | "Warning", | |
426 | "WWW-Authenticate", | |
427 | "X-Archived-At", | |
428 | "X-Device-Accept", | |
429 | "X-Device-Accept-Charset", | |
430 | "X-Device-Accept-Encoding", | |
431 | "X-Device-Accept-Language", | |
432 | "X-Device-User-Agent", | |
433 | "X-Frame-Options", | |
434 | "X-Mittente", | |
435 | "X-PGP-Sig", | |
436 | "X-Ricevuta", | |
437 | "X-Riferimento-Message-ID", | |
438 | "X-TipoRicevuta", | |
439 | "X-Trasporto", | |
440 | "X-VerificaSicurezza", | |
441 | "X400-Content-Identifier", | |
442 | "X400-Content-Return", | |
443 | "X400-Content-Type", | |
444 | "X400-MTS-Identifier", | |
445 | "X400-Originator", | |
446 | "X400-Received", | |
447 | "X400-Recipients", | |
448 | "X400-Trace", | |
449 | "Xref" | |
450 | }}) | |
451 | { | |
452 | for(std::size_t i = 1, n = 256; i < n; ++i) | |
453 | { | |
454 | auto sv = by_name_[ i ]; | |
455 | auto h = digest(sv); | |
456 | auto j = h % N; | |
457 | BOOST_ASSERT(map_[j][0] == 0); | |
458 | map_[j][0] = static_cast<unsigned char>(i); | |
459 | } | |
460 | ||
461 | for(std::size_t i = 256, n = by_name_.size(); i < n; ++i) | |
462 | { | |
463 | auto sv = by_name_[i]; | |
464 | auto h = digest(sv); | |
465 | auto j = h % N; | |
466 | BOOST_ASSERT(map_[j][1] == 0); | |
467 | map_[j][1] = static_cast<unsigned char>(i - 255); | |
468 | } | |
469 | } | |
470 | ||
471 | field | |
472 | string_to_field(string_view s) const | |
473 | { | |
474 | auto h = digest(s); | |
475 | auto j = h % N; | |
476 | int i = map_[j][0]; | |
477 | string_view s2 = by_name_[i]; | |
478 | if(i != 0 && equals(s, s2)) | |
479 | return static_cast<field>(i); | |
480 | i = map_[j][1]; | |
481 | if(i == 0) | |
482 | return field::unknown; | |
483 | i += 255; | |
484 | s2 = by_name_[i]; | |
485 | ||
486 | if(equals(s, s2)) | |
487 | return static_cast<field>(i); | |
488 | return field::unknown; | |
489 | } | |
490 | ||
491 | // | |
492 | // Deprecated | |
493 | // | |
494 | ||
495 | using const_iterator = | |
496 | array_type::const_iterator; | |
497 | ||
498 | std::size_t | |
499 | size() const | |
500 | { | |
501 | return by_name_.size(); | |
502 | } | |
503 | ||
504 | const_iterator | |
505 | begin() const | |
506 | { | |
507 | return by_name_.begin(); | |
508 | } | |
509 | ||
510 | const_iterator | |
511 | end() const | |
512 | { | |
513 | return by_name_.end(); | |
514 | } | |
515 | }; | |
516 | ||
517 | BOOST_BEAST_DECL | |
518 | field_table const& | |
519 | get_field_table() | |
520 | { | |
521 | static field_table const tab; | |
522 | return tab; | |
523 | } | |
524 | ||
525 | BOOST_BEAST_DECL | |
526 | string_view | |
527 | to_string(field f) | |
528 | { | |
529 | auto const& v = get_field_table(); | |
530 | BOOST_ASSERT(static_cast<unsigned>(f) < v.size()); | |
531 | return v.begin()[static_cast<unsigned>(f)]; | |
532 | } | |
533 | ||
534 | } // detail | |
535 | ||
536 | string_view | |
537 | to_string(field f) | |
538 | { | |
539 | return detail::to_string(f); | |
540 | } | |
541 | ||
542 | field | |
543 | string_to_field(string_view s) | |
544 | { | |
545 | return detail::get_field_table().string_to_field(s); | |
546 | } | |
547 | ||
548 | } // http | |
549 | } // beast | |
550 | } // boost | |
551 | ||
552 | #endif |