/src/trafficserver/include/proxy/hdrs/HTTP.h
Line | Count | Source |
1 | | /** @file |
2 | | |
3 | | A brief file description |
4 | | |
5 | | @section license License |
6 | | |
7 | | Licensed to the Apache Software Foundation (ASF) under one |
8 | | or more contributor license agreements. See the NOTICE file |
9 | | distributed with this work for additional information |
10 | | regarding copyright ownership. The ASF licenses this file |
11 | | to you under the Apache License, Version 2.0 (the |
12 | | "License"); you may not use this file except in compliance |
13 | | with the License. You may obtain a copy of the License at |
14 | | |
15 | | http://www.apache.org/licenses/LICENSE-2.0 |
16 | | |
17 | | Unless required by applicable law or agreed to in writing, software |
18 | | distributed under the License is distributed on an "AS IS" BASIS, |
19 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
20 | | See the License for the specific language governing permissions and |
21 | | limitations under the License. |
22 | | */ |
23 | | |
24 | | #pragma once |
25 | | |
26 | | #include <cassert> |
27 | | #include <string_view> |
28 | | |
29 | | using namespace std::literals; |
30 | | |
31 | | #include "tscore/Arena.h" |
32 | | #include "tscore/CryptoHash.h" |
33 | | #include "tscore/HTTPVersion.h" |
34 | | #include "proxy/hdrs/MIME.h" |
35 | | #include "proxy/hdrs/URL.h" |
36 | | |
37 | | #include "tscore/ink_apidefs.h" |
38 | | |
39 | | class Http2HeaderTable; |
40 | | |
41 | | enum class HTTPStatus { |
42 | | NONE = 0, |
43 | | |
44 | | CONTINUE = 100, |
45 | | SWITCHING_PROTOCOL = 101, |
46 | | PROCESSING = 102, |
47 | | EARLY_HINTS = 103, |
48 | | |
49 | | OK = 200, |
50 | | CREATED = 201, |
51 | | ACCEPTED = 202, |
52 | | NON_AUTHORITATIVE_INFORMATION = 203, |
53 | | NO_CONTENT = 204, |
54 | | RESET_CONTENT = 205, |
55 | | PARTIAL_CONTENT = 206, |
56 | | |
57 | | MULTIPLE_CHOICES = 300, |
58 | | MOVED_PERMANENTLY = 301, |
59 | | MOVED_TEMPORARILY = 302, |
60 | | SEE_OTHER = 303, |
61 | | NOT_MODIFIED = 304, |
62 | | USE_PROXY = 305, |
63 | | TEMPORARY_REDIRECT = 307, |
64 | | PERMANENT_REDIRECT = 308, |
65 | | |
66 | | BAD_REQUEST = 400, |
67 | | UNAUTHORIZED = 401, |
68 | | PAYMENT_REQUIRED = 402, |
69 | | FORBIDDEN = 403, |
70 | | NOT_FOUND = 404, |
71 | | METHOD_NOT_ALLOWED = 405, |
72 | | NOT_ACCEPTABLE = 406, |
73 | | PROXY_AUTHENTICATION_REQUIRED = 407, |
74 | | REQUEST_TIMEOUT = 408, |
75 | | CONFLICT = 409, |
76 | | GONE = 410, |
77 | | LENGTH_REQUIRED = 411, |
78 | | PRECONDITION_FAILED = 412, |
79 | | REQUEST_ENTITY_TOO_LARGE = 413, |
80 | | REQUEST_URI_TOO_LONG = 414, |
81 | | UNSUPPORTED_MEDIA_TYPE = 415, |
82 | | RANGE_NOT_SATISFIABLE = 416, |
83 | | TOO_EARLY = 425, |
84 | | |
85 | | INTERNAL_SERVER_ERROR = 500, |
86 | | NOT_IMPLEMENTED = 501, |
87 | | BAD_GATEWAY = 502, |
88 | | SERVICE_UNAVAILABLE = 503, |
89 | | GATEWAY_TIMEOUT = 504, |
90 | | HTTPVER_NOT_SUPPORTED = 505 |
91 | | }; |
92 | | |
93 | | enum class HTTPKeepAlive { |
94 | | UNDEFINED = 0, |
95 | | NO_KEEPALIVE, |
96 | | KEEPALIVE, |
97 | | }; |
98 | | |
99 | | enum class HTTPWarningCode { |
100 | | NONE = 0, |
101 | | |
102 | | RESPONSE_STALE = 110, |
103 | | REVALIDATION_FAILED = 111, |
104 | | DISCONNECTED_OPERATION = 112, |
105 | | HERUISTIC_EXPIRATION = 113, |
106 | | TRANSFORMATION_APPLIED = 114, |
107 | | MISC_WARNING = 199 |
108 | | }; |
109 | | |
110 | | /* squid log codes |
111 | | There is code (e.g. logstats) that depends on these errors coming at the end of this enum */ |
112 | | enum class SquidLogCode { |
113 | | EMPTY = '0', |
114 | | TCP_HIT = '1', |
115 | | TCP_DISK_HIT = '2', |
116 | | TCP_MEM_HIT = '.', // Don't want to change others codes |
117 | | TCP_MISS = '3', |
118 | | TCP_EXPIRED_MISS = '4', |
119 | | TCP_REFRESH_HIT = '5', |
120 | | TCP_REF_FAIL_HIT = '6', |
121 | | TCP_REFRESH_MISS = '7', |
122 | | TCP_CLIENT_REFRESH = '8', |
123 | | TCP_IMS_HIT = '9', |
124 | | TCP_IMS_MISS = 'a', |
125 | | TCP_SWAPFAIL = 'b', |
126 | | TCP_DENIED = 'c', |
127 | | TCP_WEBFETCH_MISS = 'd', |
128 | | TCP_FUTURE_2 = 'f', |
129 | | TCP_HIT_REDIRECT = '[', // standard redirect |
130 | | TCP_MISS_REDIRECT = ']', // standard redirect |
131 | | TCP_HIT_X_REDIRECT = '<', // extended redirect |
132 | | TCP_MISS_X_REDIRECT = '>', // extended redirect |
133 | | UDP_HIT = 'g', |
134 | | UDP_WEAK_HIT = 'h', |
135 | | UDP_HIT_OBJ = 'i', |
136 | | UDP_MISS = 'j', |
137 | | UDP_DENIED = 'k', |
138 | | UDP_INVALID = 'l', |
139 | | UDP_RELOADING = 'm', |
140 | | UDP_FUTURE_1 = 'n', |
141 | | UDP_FUTURE_2 = 'o', |
142 | | ERR_READ_TIMEOUT = 'p', |
143 | | ERR_LIFETIME_EXP = 'q', |
144 | | ERR_POST_ENTITY_TOO_LARGE = 'L', |
145 | | ERR_NO_CLIENTS_BIG_OBJ = 'r', |
146 | | ERR_READ_ERROR = 's', |
147 | | ERR_CLIENT_ABORT = 't', // Client side abort logging |
148 | | ERR_CONNECT_FAIL = 'u', |
149 | | ERR_INVALID_REQ = 'v', |
150 | | ERR_UNSUP_REQ = 'w', |
151 | | ERR_INVALID_URL = 'x', |
152 | | ERR_NO_FDS = 'y', |
153 | | ERR_DNS_FAIL = 'z', |
154 | | ERR_NOT_IMPLEMENTED = 'A', |
155 | | ERR_CANNOT_FETCH = 'B', |
156 | | ERR_NO_RELAY = 'C', |
157 | | ERR_DISK_IO = 'D', |
158 | | ERR_ZERO_SIZE_OBJECT = 'E', |
159 | | TCP_CF_HIT = 'F', // Collapsed forwarding HIT also known as Read while write hit |
160 | | ERR_PROXY_DENIED = 'G', |
161 | | ERR_WEBFETCH_DETECTED = 'H', |
162 | | ERR_FUTURE_1 = 'I', |
163 | | ERR_CLIENT_READ_ERROR = 'J', // Client side abort logging |
164 | | ERR_LOOP_DETECTED = 'K', // Loop or cycle detected, request came back to this server |
165 | | ERR_TUN_ACTIVE_TIMEOUT = 'T', // Tunnel (CONNECT) active timeout |
166 | | ERR_UNKNOWN = 'Z' |
167 | | }; |
168 | | |
169 | | // squid log subcodes |
170 | | enum class SquidSubcode { |
171 | | EMPTY = '0', |
172 | | NUM_REDIRECTIONS_EXCEEDED = '1', |
173 | | }; |
174 | | |
175 | | /* squid hierarchy codes */ |
176 | | enum class SquidHierarchyCode { |
177 | | EMPTY = '0', |
178 | | NONE = '1', |
179 | | DIRECT = '2', |
180 | | SIBLING_HIT = '3', |
181 | | PARENT_HIT = '4', |
182 | | DEFAULT_PARENT = '5', |
183 | | SINGLE_PARENT = '6', |
184 | | FIRST_UP_PARENT = '7', |
185 | | NO_PARENT_DIRECT = '8', |
186 | | FIRST_PARENT_MISS = '9', |
187 | | LOCAL_IP_DIRECT = 'a', |
188 | | FIREWALL_IP_DIRECT = 'b', |
189 | | NO_DIRECT_FAIL = 'c', |
190 | | SOURCE_FASTEST = 'd', |
191 | | SIBLING_UDP_HIT_OBJ = 'e', |
192 | | PARENT_UDP_HIT_OBJ = 'f', |
193 | | PASSTHROUGH_PARENT = 'g', |
194 | | SSL_PARENT_MISS = 'h', |
195 | | INVALID_CODE = 'i', |
196 | | TIMEOUT_DIRECT = 'j', |
197 | | TIMEOUT_SIBLING_HIT = 'k', |
198 | | TIMEOUT_PARENT_HIT = 'l', |
199 | | TIMEOUT_DEFAULT_PARENT = 'm', |
200 | | TIMEOUT_SINGLE_PARENT = 'n', |
201 | | TIMEOUT_FIRST_UP_PARENT = 'o', |
202 | | TIMEOUT_NO_PARENT_DIRECT = 'p', |
203 | | TIMEOUT_FIRST_PARENT_MISS = 'q', |
204 | | TIMEOUT_LOCAL_IP_DIRECT = 'r', |
205 | | TIMEOUT_FIREWALL_IP_DIRECT = 's', |
206 | | TIMEOUT_NO_DIRECT_FAIL = 't', |
207 | | TIMEOUT_SOURCE_FASTEST = 'u', |
208 | | TIMEOUT_SIBLING_UDP_HIT_OBJ = 'v', |
209 | | TIMEOUT_PARENT_UDP_HIT_OBJ = 'w', |
210 | | TIMEOUT_PASSTHROUGH_PARENT = 'x', |
211 | | TIMEOUT_TIMEOUT_SSL_PARENT_MISS = 'y', |
212 | | INVALID_ASSIGNED_CODE = 'z' |
213 | | }; |
214 | | |
215 | | /* squid hit/miss codes */ |
216 | | enum SquidHitMissCode { |
217 | | SQUID_HIT_RESERVED = '0', // Kinda wonky that this is '0', so skipping 'A' for now |
218 | | SQUID_HIT_LEVEL_1 = 'B', |
219 | | SQUID_HIT_LEVEL_2 = 'C', |
220 | | SQUID_HIT_LEVEL_3 = 'D', |
221 | | SQUID_HIT_LEVEL_4 = 'E', |
222 | | SQUID_HIT_LEVEL_5 = 'F', |
223 | | SQUID_HIT_LEVEL_6 = 'G', |
224 | | SQUID_HIT_LEVEL_7 = 'H', |
225 | | SQUID_HIT_LEVEL_8 = 'I', |
226 | | SQUID_HIT_LEVEl_9 = 'J', |
227 | | SQUID_MISS_NONE = '1', |
228 | | SQUID_MISS_HTTP_NON_CACHE = '3', |
229 | | SQUID_MISS_HTTP_NO_DLE = '5', |
230 | | SQUID_MISS_HTTP_NO_LE = '6', |
231 | | SQUID_MISS_HTTP_CONTENT = '7', |
232 | | SQUID_MISS_PRAGMA_NOCACHE = '8', |
233 | | SQUID_MISS_PASS = '9', |
234 | | SQUID_MISS_PRE_EXPIRED = 'a', |
235 | | SQUID_MISS_ERROR = 'b', |
236 | | SQUID_MISS_CACHE_BYPASS = 'c', |
237 | | SQUID_HIT_MISS_INVALID_ASSIGNED_CODE = 'z', |
238 | | // These are pre-allocated with special semantics, added here for convenience |
239 | | SQUID_HIT_RAM = SQUID_HIT_LEVEL_1, |
240 | | SQUID_HIT_SSD = SQUID_HIT_LEVEL_2, |
241 | | SQUID_HIT_DISK = SQUID_HIT_LEVEL_3, |
242 | | SQUID_HIT_CLUSTER = SQUID_HIT_LEVEL_4, |
243 | | SQUID_HIT_NET = SQUID_HIT_LEVEL_5, |
244 | | SQUID_HIT_RWW = SQUID_HIT_LEVEL_6 |
245 | | }; |
246 | | |
247 | | constexpr std::string_view PSEUDO_HEADER_SCHEME = ":scheme"; |
248 | | constexpr std::string_view PSEUDO_HEADER_AUTHORITY = ":authority"; |
249 | | constexpr std::string_view PSEUDO_HEADER_PATH = ":path"; |
250 | | constexpr std::string_view PSEUDO_HEADER_METHOD = ":method"; |
251 | | constexpr std::string_view PSEUDO_HEADER_STATUS = ":status"; |
252 | | |
253 | | enum class HTTPType { |
254 | | UNKNOWN, |
255 | | REQUEST, |
256 | | RESPONSE, |
257 | | }; |
258 | | |
259 | | struct HTTPHdrImpl : public HdrHeapObjImpl { |
260 | | // HdrHeapObjImpl is 4 bytes |
261 | | HTTPType m_polarity; // request or response or unknown |
262 | | HTTPVersion m_version; // cooked version number |
263 | | // 12 bytes means 4 bytes padding here on 64-bit architectures |
264 | | union { |
265 | | struct { |
266 | | URLImpl *m_url_impl; |
267 | | const char *m_ptr_method; |
268 | | uint16_t m_len_method; |
269 | | int16_t m_method_wks_idx; |
270 | | } req; |
271 | | |
272 | | struct { |
273 | | const char *m_ptr_reason; |
274 | | uint16_t m_len_reason; |
275 | | int16_t m_status; |
276 | | } resp; |
277 | | } u; |
278 | | |
279 | | MIMEHdrImpl *m_fields_impl; |
280 | | |
281 | | // Marshaling Functions |
282 | | int marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str); |
283 | | void unmarshal(intptr_t offset); |
284 | | void move_strings(HdrStrHeap *new_heap); |
285 | | size_t strings_length(); |
286 | | |
287 | | /** Rebuild everything in this header that indexes the well-known string table. |
288 | | * |
289 | | * That is the request method index, the request URL's scheme index, and the field indexes, |
290 | | * presence bits and slot accelerators of the MIME header. All of them are caches over strings |
291 | | * that are stored in the header itself, so they can always be rebuilt, and they must be after |
292 | | * the header is read back from a cached object: the object may have been written by a build |
293 | | * whose well-known string table differed from this one's, in which case the stored indexes |
294 | | * denote different strings here than they did there. |
295 | | * |
296 | | * Call this only once the header is fully unmarshalled. It walks the MIME field blocks, which |
297 | | * are separate heap objects and are not usable until their own pointers have been swizzled. |
298 | | */ |
299 | | void recompute_wks_indices(); |
300 | | |
301 | | // Sanity Check Functions |
302 | | void check_strings(HeapCheck *heaps, int num_heaps); |
303 | | }; |
304 | | |
305 | | struct HTTPValAccept { |
306 | | char *type; |
307 | | char *subtype; |
308 | | double qvalue; |
309 | | }; |
310 | | |
311 | | struct HTTPValAcceptCharset { |
312 | | char *charset; |
313 | | double qvalue; |
314 | | }; |
315 | | |
316 | | struct HTTPValAcceptEncoding { |
317 | | char *encoding; |
318 | | double qvalue; |
319 | | }; |
320 | | |
321 | | struct HTTPValAcceptLanguage { |
322 | | char *language; |
323 | | double qvalue; |
324 | | }; |
325 | | |
326 | | struct HTTPValFieldList { |
327 | | char *name; |
328 | | HTTPValFieldList *next; |
329 | | }; |
330 | | |
331 | | struct HTTPValCacheControl { |
332 | | const char *directive; |
333 | | |
334 | | union { |
335 | | int delta_seconds; |
336 | | HTTPValFieldList *field_names; |
337 | | } u; |
338 | | }; |
339 | | |
340 | | struct HTTPValRange { |
341 | | int start; |
342 | | int end; |
343 | | HTTPValRange *next; |
344 | | }; |
345 | | |
346 | | struct HTTPValTE { |
347 | | char *encoding; |
348 | | double qvalue; |
349 | | }; |
350 | | |
351 | | struct HTTPParser { |
352 | | bool m_parsing_http = false; |
353 | | MIMEParser m_mime_parser; |
354 | | }; |
355 | | |
356 | | extern c_str_view HTTP_METHOD_CONNECT; |
357 | | extern c_str_view HTTP_METHOD_DELETE; |
358 | | extern c_str_view HTTP_METHOD_GET; |
359 | | extern c_str_view HTTP_METHOD_HEAD; |
360 | | extern c_str_view HTTP_METHOD_OPTIONS; |
361 | | extern c_str_view HTTP_METHOD_POST; |
362 | | extern c_str_view HTTP_METHOD_PURGE; |
363 | | extern c_str_view HTTP_METHOD_PUT; |
364 | | extern c_str_view HTTP_METHOD_TRACE; |
365 | | extern c_str_view HTTP_METHOD_PUSH; |
366 | | |
367 | | extern int HTTP_WKSIDX_CONNECT; |
368 | | extern int HTTP_WKSIDX_DELETE; |
369 | | extern int HTTP_WKSIDX_GET; |
370 | | extern int HTTP_WKSIDX_HEAD; |
371 | | extern int HTTP_WKSIDX_OPTIONS; |
372 | | extern int HTTP_WKSIDX_POST; |
373 | | extern int HTTP_WKSIDX_PURGE; |
374 | | extern int HTTP_WKSIDX_PUT; |
375 | | extern int HTTP_WKSIDX_TRACE; |
376 | | extern int HTTP_WKSIDX_PUSH; |
377 | | extern int HTTP_WKSIDX_METHODS_CNT; |
378 | | |
379 | | extern c_str_view HTTP_VALUE_BYTES; |
380 | | extern c_str_view HTTP_VALUE_CHUNKED; |
381 | | extern c_str_view HTTP_VALUE_CLOSE; |
382 | | extern c_str_view HTTP_VALUE_COMPRESS; |
383 | | extern c_str_view HTTP_VALUE_DEFLATE; |
384 | | extern c_str_view HTTP_VALUE_GZIP; |
385 | | extern c_str_view HTTP_VALUE_BROTLI; |
386 | | extern c_str_view HTTP_VALUE_ZSTD; |
387 | | extern c_str_view HTTP_VALUE_IDENTITY; |
388 | | extern c_str_view HTTP_VALUE_KEEP_ALIVE; |
389 | | extern c_str_view HTTP_VALUE_MAX_AGE; |
390 | | extern c_str_view HTTP_VALUE_MAX_STALE; |
391 | | extern c_str_view HTTP_VALUE_MIN_FRESH; |
392 | | extern c_str_view HTTP_VALUE_MUST_REVALIDATE; |
393 | | extern c_str_view HTTP_VALUE_NONE; |
394 | | extern c_str_view HTTP_VALUE_NO_CACHE; |
395 | | extern c_str_view HTTP_VALUE_NO_STORE; |
396 | | extern c_str_view HTTP_VALUE_NO_TRANSFORM; |
397 | | extern c_str_view HTTP_VALUE_ONLY_IF_CACHED; |
398 | | extern c_str_view HTTP_VALUE_PRIVATE; |
399 | | extern c_str_view HTTP_VALUE_PROXY_REVALIDATE; |
400 | | extern c_str_view HTTP_VALUE_PUBLIC; |
401 | | extern c_str_view HTTP_VALUE_S_MAXAGE; |
402 | | extern c_str_view HTTP_VALUE_NEED_REVALIDATE_ONCE; |
403 | | extern c_str_view HTTP_VALUE_100_CONTINUE; |
404 | | |
405 | | /* Private */ |
406 | | void http_hdr_adjust(HTTPHdrImpl *hdrp, int32_t offset, int32_t length, int32_t delta); |
407 | | |
408 | | /* Public */ |
409 | | void http_init(); |
410 | | |
411 | | HTTPHdrImpl *http_hdr_create(HdrHeap *heap, HTTPType polarity, HTTPVersion version); |
412 | | void http_hdr_init(HdrHeap *heap, HTTPHdrImpl *hh, HTTPType polarity, HTTPVersion version); |
413 | | HTTPHdrImpl *http_hdr_clone(HTTPHdrImpl *s_hh, HdrHeap *s_heap, HdrHeap *d_heap); |
414 | | void http_hdr_copy_onto(HTTPHdrImpl *s_hh, HdrHeap *s_heap, HTTPHdrImpl *d_hh, HdrHeap *d_heap, bool inherit_strs); |
415 | | |
416 | | int http_hdr_print(HTTPHdrImpl const *hh, char *buf, int bufsize, int *bufindex, int *dumpoffset); |
417 | | |
418 | | void http_hdr_describe(HdrHeapObjImpl *obj, bool recurse = true); |
419 | | |
420 | | bool http_hdr_version_set(HTTPHdrImpl *hh, const HTTPVersion &ver); |
421 | | |
422 | | std::string_view http_hdr_method_get(HTTPHdrImpl *hh); |
423 | | void http_hdr_method_set(HdrHeap *heap, HTTPHdrImpl *hh, std::string_view method, int16_t method_wks_idx, bool must_copy); |
424 | | |
425 | | void http_hdr_url_set(HdrHeap *heap, HTTPHdrImpl *hh, URLImpl *url); |
426 | | |
427 | | // HTTPStatus http_hdr_status_get (HTTPHdrImpl *hh); |
428 | | void http_hdr_status_set(HTTPHdrImpl *hh, HTTPStatus status); |
429 | | std::string_view http_hdr_reason_get(HTTPHdrImpl *hh); |
430 | | void http_hdr_reason_set(HdrHeap *heap, HTTPHdrImpl *hh, std::string_view value, bool must_copy); |
431 | | const char *http_hdr_reason_lookup(HTTPStatus status); |
432 | | |
433 | | void http_parser_init(HTTPParser *parser); |
434 | | void http_parser_clear(HTTPParser *parser); |
435 | | ParseResult http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end, |
436 | | bool must_copy_strings, bool eof, int strict_uri_parsing, size_t max_request_line_size, |
437 | | size_t max_hdr_field_size); |
438 | | ParseResult validate_hdr_request_target(int method_wks_idx, URLImpl *url); |
439 | | |
440 | | // This calls http_parse_host_header internally to parse the Host field value |
441 | | // when present, so it enforces the same syntax rules and also validates the |
442 | | // port number when specified. |
443 | | ParseResult validate_hdr_host(HTTPHdrImpl *hh); |
444 | | |
445 | | // This parses and validates the Host field value. |
446 | | bool http_parse_host_header(std::string_view value, std::string_view &host, int &port, bool &has_port); |
447 | | |
448 | | ParseResult validate_hdr_content_length(HdrHeap *heap, HTTPHdrImpl *hh); |
449 | | ParseResult http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end, |
450 | | bool must_copy_strings, bool eof); |
451 | | |
452 | | HTTPStatus http_parse_status(const char *start, const char *end); |
453 | | HTTPVersion http_parse_version(const char *start, const char *end); |
454 | | |
455 | | /* |
456 | | HTTPValAccept* http_parse_accept (const char *buf, Arena *arena); |
457 | | HTTPValAcceptCharset* http_parse_accept_charset (const char *buf, Arena *arena); |
458 | | HTTPValAcceptEncoding* http_parse_accept_encoding (const char *buf, Arena *arena); |
459 | | HTTPValAcceptLanguage* http_parse_accept_language (const char *buf, Arena *arena); |
460 | | HTTPValCacheControl* http_parse_cache_control (const char *buf, Arena *arena); |
461 | | const char* http_parse_cache_directive (const char **buf); |
462 | | HTTPValRange* http_parse_range (const char *buf, Arena *arena); |
463 | | */ |
464 | | HTTPValTE *http_parse_te(const char *buf, int len, Arena *arena); |
465 | | |
466 | | bool is_http1_hdr_version_supported(const HTTPVersion &http_version); |
467 | | |
468 | | class IOBufferReader; |
469 | | |
470 | | /** HTTP Header class. |
471 | | * |
472 | | * @warning Changing the size of this class (adding/removing fields) will change |
473 | | * the on-disk cache format and cause cache incompatibility. The HTTPCacheAlt |
474 | | * structure contains embedded HTTPHdr objects, and the cache marshalling code |
475 | | * uses sizeof(HTTPCacheAlt) to read/write cache entries. Any size change will |
476 | | * cause "vector inconsistency" errors when reading cache entries written by a |
477 | | * different version. |
478 | | */ |
479 | | class HTTPHdr : public MIMEHdr |
480 | | { |
481 | | public: |
482 | | HTTPHdrImpl *m_http = nullptr; |
483 | | mutable URL m_url_cached; |
484 | | mutable MIMEField *m_host_mime = nullptr; |
485 | | mutable int m_host_length = 0; ///< Length of hostname (parsed, excludes port). |
486 | | mutable int m_port = 0; ///< Target port. |
487 | | mutable bool m_target_cached = false; ///< Whether host name and port are cached. |
488 | | mutable bool m_target_in_url = false; ///< Whether host name and port are in the URL. |
489 | | mutable bool m_100_continue_sent = false; ///< Whether ATS sent a 100 Continue optimized response. |
490 | | mutable bool m_100_continue_required = false; ///< Whether 100_continue is in the Expect header. |
491 | | /// Set if the port was effectively specified in the header. |
492 | | /// @c true if the target (in the URL or the HOST field) also specified |
493 | | /// a port. That is, @c true if whatever source had the target host |
494 | | /// also had a port, @c false otherwise. |
495 | | mutable bool m_port_in_header = false; |
496 | | |
497 | | mutable bool early_data = false; |
498 | | |
499 | 24.5k | HTTPHdr() = default; // Force the creation of the default constructor |
500 | | |
501 | | int valid() const; |
502 | | |
503 | | // destroy() and clear() name-hide HdrHeapSDKHandle's non-virtual versions |
504 | | // Dispatch is static; "override" doesn't apply |
505 | | void create(HTTPType polarity, HTTPVersion version = HTTP_INVALID, HdrHeap *heap = nullptr); |
506 | | void destroy(); |
507 | | void clear(); |
508 | | void reset(); |
509 | | void copy(const HTTPHdr *hdr); |
510 | | void copy_shallow(const HTTPHdr *hdr); |
511 | | |
512 | | int unmarshal(char *buf, int len, RefCountObj *block_ref); |
513 | | |
514 | | int print(char *buf, int bufsize, int *bufindex, int *dumpoffset) const; |
515 | | |
516 | | /** Returns the serialized byte length of the HTTP header. |
517 | | * |
518 | | * The count includes the request-line (for requests) or status-line (for |
519 | | * responses), all header fields, and the terminating blank line. The message |
520 | | * body is not included. |
521 | | * |
522 | | * @note Internal fields whose names begin with @c '@' are counted here even |
523 | | * though @c print() omits them from its output, so this length may |
524 | | * exceed the number of bytes @c print() actually writes. |
525 | | * |
526 | | * @return Serialized byte length of the header. |
527 | | * |
528 | | * @pre The header must be initialized. |
529 | | * |
530 | | * @par Thread Safety |
531 | | * Not thread-safe. |
532 | | */ |
533 | | int length_get() const; |
534 | | |
535 | | HTTPType type_get() const; |
536 | | |
537 | | HTTPVersion version_get() const; |
538 | | void version_set(HTTPVersion version); |
539 | | |
540 | | std::string_view method_get(); |
541 | | int method_get_wksidx() const; |
542 | | void method_set(std::string_view value); |
543 | | |
544 | | URL *url_create(URL *url); |
545 | | |
546 | | URL *url_get() const; |
547 | | URL *url_get(URL *url); |
548 | | /** Get a string with the effective URL in it. |
549 | | If @a length is not @c NULL then the length of the string |
550 | | is stored in the int pointed to by @a length. |
551 | | |
552 | | Note that this can be different from getting the @c URL |
553 | | and invoking @c URL::string_get if the host is in a header |
554 | | field and not explicitly in the URL. |
555 | | */ |
556 | | char *url_string_get(Arena *arena = nullptr, ///< Arena to use, or @c malloc if NULL. |
557 | | int *length = nullptr ///< Store string length here. |
558 | | ); |
559 | | /** Get a string with the effective URL in it. |
560 | | This is automatically allocated if needed in the request heap. |
561 | | |
562 | | @see url_string_get |
563 | | */ |
564 | | char *url_string_get_ref(int *length = nullptr ///< Store string length here. |
565 | | ); |
566 | | |
567 | | /** Print the URL. |
568 | | Output is not null terminated. |
569 | | @return 0 on failure, non-zero on success. |
570 | | */ |
571 | | int url_print(char *buff, ///< Output buffer |
572 | | int length, ///< Length of @a buffer |
573 | | int *offset, ///< [in,out] ??? |
574 | | int *skip, ///< [in,out] ??? |
575 | | unsigned normalization_flags = URLNormalize::NONE ///< host/scheme normalized to lower case |
576 | | ); |
577 | | |
578 | | /** Return the length of the URL that url_print() will create. |
579 | | @return -1 on failure, non-negative on success. |
580 | | */ |
581 | | int url_printed_length(unsigned normalizaion_flags = URLNormalize::NONE); |
582 | | |
583 | | /** Get the URL path. |
584 | | This is a reference, not allocated. |
585 | | @return A string_view to the path or an empty string_view if there is no valid URL. |
586 | | */ |
587 | | std::string_view path_get(); |
588 | | |
589 | | /** Get the URL query. |
590 | | This is a reference, not allocated. |
591 | | @return A string_view to the query or an empty string_view if there is no valid URL. |
592 | | */ |
593 | | std::string_view query_get(); |
594 | | |
595 | | /** Get the URL fragment. |
596 | | This is a reference, not allocated. |
597 | | @return A string_view to the fragment or an empty string_view if there is no valid URL. |
598 | | */ |
599 | | std::string_view fragment_get(); |
600 | | |
601 | | /** Get the target host name. |
602 | | The length is returned in @a length if non-NULL. |
603 | | @note The results are cached so this is fast after the first call. |
604 | | @return A string_view to the host name. |
605 | | */ |
606 | | std::string_view host_get() const; |
607 | | |
608 | | /** Get the target port. |
609 | | If the target port is not found then it is adjusted to the |
610 | | default port for the URL type. |
611 | | @note The results are cached so this is fast after the first call. |
612 | | @return The canonicalized target port. |
613 | | */ |
614 | | int port_get(); |
615 | | |
616 | | /** Get the URL scheme. |
617 | | This is a reference, not allocated. |
618 | | @return A string_view to the scheme or an empty string_view if there is no valid URL. |
619 | | */ |
620 | | std::string_view scheme_get(); |
621 | | void url_set(URL *url); |
622 | | void url_set(std::string_view value); |
623 | | |
624 | | /// Check location of target host. |
625 | | /// @return @c true if the host was in the URL, @c false otherwise. |
626 | | /// @note This returns @c false if the host is missing. |
627 | | bool is_target_in_url() const; |
628 | | |
629 | | /// Check if a port was specified in the target. |
630 | | /// @return @c true if the port was part of the target. |
631 | | bool is_port_in_header() const; |
632 | | |
633 | | /// If the target is in the fields and not the URL, copy it to the @a url. |
634 | | /// If @a url is @c NULL the cached URL in this header is used. |
635 | | /// @note In the default case the copy is avoided if the cached URL already |
636 | | /// has the target. If @a url is non @c NULL the copy is always performed. |
637 | | void set_url_target_from_host_field(URL *url = nullptr); |
638 | | |
639 | | /// Mark the target cache as invalid. |
640 | | /// @internal Ugly but too many places currently that touch the |
641 | | /// header internals, they must be able to do this. |
642 | | void mark_target_dirty() const; |
643 | | |
644 | | HTTPStatus status_get() const; |
645 | | void status_set(HTTPStatus status); |
646 | | |
647 | | std::string_view reason_get(); |
648 | | void reason_set(std::string_view value); |
649 | | |
650 | | void mark_early_data(bool flag = true) const; |
651 | | bool is_early_data() const; |
652 | | |
653 | | /** Parse an HTTP/1.x request header incrementally from a raw buffer. |
654 | | * |
655 | | * Parses input data into the header's request fields. Call repeatedly with the same @p parser |
656 | | * until a result other than @c ParseResult::CONT is returned. When @c ParseResult::DONE is |
657 | | * returned, the request method, URL, version, and header fields are set on this header. |
658 | | * |
659 | | * @param[in,out] parser Parser state. Must be the same object on each call for a given message. |
660 | | * @param[in,out] start On entry, points to the first unparsed byte; on return, |
661 | | * advanced past all consumed bytes. |
662 | | * @param[in] end One past the last available byte of input. |
663 | | * @param[in] eof @c true if no more data will follow @p end. |
664 | | * @param[in] strict_uri_parsing URI compliance level: @c 0 performs no compliance check; @c 1 rejects |
665 | | * the URI unless every character is a valid RFC 3986 URI character; @c 2 |
666 | | * is more permissive, rejecting the URI only if it contains whitespace or |
667 | | * non-printable characters. Other values behave like @c 0. |
668 | | * @param[in] max_request_line_size Maximum byte length of the request line; exceeding it returns |
669 | | * @c ParseResult::ERROR. |
670 | | * @param[in] max_hdr_field_size Maximum byte length of a single header field; exceeding it |
671 | | * returns @c ParseResult::ERROR. |
672 | | * |
673 | | * @return @c ParseResult::DONE if a complete valid request header has been parsed; |
674 | | * @c ParseResult::CONT if more data is required; |
675 | | * @c ParseResult::ERROR on a protocol error or exceeded limit. |
676 | | * |
677 | | * @pre The header must be initialized with @c HTTPType::REQUEST polarity. |
678 | | * |
679 | | * @par Thread Safety |
680 | | * Not thread-safe. |
681 | | */ |
682 | | ParseResult parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, int strict_uri_parsing = 0, |
683 | | size_t max_request_line_size = UINT16_MAX, size_t max_hdr_field_size = 131070); |
684 | | ParseResult parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof); |
685 | | |
686 | | /** Parse an HTTP/1.x request header incrementally from an @c IOBufferReader. |
687 | | * |
688 | | * Reads and consumes data from @p r, parsing it into the header's request fields. Call |
689 | | * repeatedly with the same @p parser until a result other than @c ParseResult::CONT is |
690 | | * returned. When @c ParseResult::DONE is returned, the request method, URL, version, and |
691 | | * header fields are set on this header. |
692 | | * |
693 | | * @param[in,out] parser Parser state. Must be the same object on each call for a given message. |
694 | | * @param[in,out] r Source of input data; bytes consumed by the parser are removed from |
695 | | * the reader. |
696 | | * @param[out] bytes_used Must be non-null; set to the number of bytes consumed from @p r. |
697 | | * @param[in] eof @c true if no more data will be provided after what is currently |
698 | | * available on @p r. |
699 | | * @param[in] strict_uri_parsing URI compliance level: @c 0 performs no compliance check; @c 1 rejects |
700 | | * the URI unless every character is a valid RFC 3986 URI character; @c 2 |
701 | | * is more permissive, rejecting the URI only if it contains whitespace or |
702 | | * non-printable characters. Other values behave like @c 0. |
703 | | * @param[in] max_request_line_size Maximum byte length of the request line; exceeding it returns |
704 | | * @c ParseResult::ERROR. |
705 | | * @param[in] max_hdr_field_size Maximum byte length of a single header field; exceeding it |
706 | | * returns @c ParseResult::ERROR. |
707 | | * |
708 | | * @return @c ParseResult::DONE if a complete valid request header has been parsed; |
709 | | * @c ParseResult::CONT if more data is required; |
710 | | * @c ParseResult::ERROR on a protocol error or exceeded limit. |
711 | | * |
712 | | * @pre The header must be initialized with @c HTTPType::REQUEST polarity. |
713 | | * |
714 | | * @par Thread Safety |
715 | | * Not thread-safe. |
716 | | */ |
717 | | ParseResult parse_req(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof, int strict_uri_parsing = 0, |
718 | | size_t max_request_line_size = UINT16_MAX, size_t max_hdr_field_size = UINT16_MAX); |
719 | | ParseResult parse_resp(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof); |
720 | | |
721 | | bool check_hdr_implements(); |
722 | | |
723 | | public: |
724 | | // Utility routines |
725 | | bool is_cache_control_set(const char *cc_directive_wks); |
726 | | bool is_pragma_no_cache_set(); |
727 | | bool is_keep_alive_set() const; |
728 | | bool expect_final_response() const; |
729 | | HTTPKeepAlive keep_alive_get() const; |
730 | | |
731 | | protected: |
732 | | /** Load the target cache. |
733 | | @see m_host, m_port, m_target_in_url |
734 | | */ |
735 | | void _fill_target_cache() const; |
736 | | /** Test the cache and fill it if necessary. |
737 | | @internal In contrast to @c _fill_target_cache, this method |
738 | | is inline and checks whether the cache is already filled. |
739 | | @ _fill_target_cache @b always does a cache fill. |
740 | | */ |
741 | | void _test_and_fill_target_cache() const; |
742 | | /** Null cached pointers/flags without touching the URL or heap. |
743 | | Shared between @c _reset_local_state() and @c reset(); URL and |
744 | | heap handling differ between those paths. |
745 | | */ |
746 | | void _reset_local_fields(); |
747 | | /** Null out members that reference the heap. |
748 | | Shared prologue for @c clear() and @c destroy(); ensures a reused |
749 | | HTTPHdr can't dereference a stale @c m_host_mime via @c host_get(). |
750 | | */ |
751 | | void _reset_local_state(); |
752 | | |
753 | | static Arena *const USE_HDR_HEAP_MAGIC; |
754 | | |
755 | | // No gratuitous copies! |
756 | | HTTPHdr(const HTTPHdr &m) = delete; |
757 | | HTTPHdr &operator=(const HTTPHdr &m) = delete; |
758 | | |
759 | | private: |
760 | | friend class UrlPrintHack; // don't ask. |
761 | | }; |
762 | | |
763 | | /*------------------------------------------------------------------------- |
764 | | -------------------------------------------------------------------------*/ |
765 | | |
766 | | inline int |
767 | | HTTPHdr::valid() const |
768 | 23.4k | { |
769 | 23.4k | return (m_http && m_mime && m_heap); |
770 | 23.4k | } |
771 | | |
772 | | /*------------------------------------------------------------------------- |
773 | | -------------------------------------------------------------------------*/ |
774 | | |
775 | | inline void |
776 | | HTTPHdr::create(HTTPType polarity, HTTPVersion version, HdrHeap *heap) |
777 | 24.5k | { |
778 | 24.5k | if (heap) { |
779 | 0 | m_heap = heap; |
780 | 24.5k | } else if (!m_heap) { |
781 | 24.5k | m_heap = new_HdrHeap(); |
782 | 24.5k | } |
783 | | |
784 | 24.5k | m_http = http_hdr_create(m_heap, polarity, version); |
785 | 24.5k | m_mime = m_http->m_fields_impl; |
786 | 24.5k | } |
787 | | |
788 | | inline void |
789 | | HTTPHdr::_reset_local_fields() |
790 | 24.5k | { |
791 | 24.5k | m_http = nullptr; |
792 | 24.5k | m_mime = nullptr; |
793 | 24.5k | m_host_mime = nullptr; |
794 | 24.5k | m_host_length = 0; |
795 | 24.5k | m_port = 0; |
796 | 24.5k | m_target_cached = false; |
797 | 24.5k | m_target_in_url = false; |
798 | 24.5k | m_port_in_header = false; |
799 | 24.5k | } |
800 | | |
801 | | inline void |
802 | | HTTPHdr::_reset_local_state() |
803 | 24.5k | { |
804 | 24.5k | if (m_http && m_http->m_polarity == HTTPType::REQUEST) { |
805 | 12.8k | m_url_cached.clear(); |
806 | 12.8k | } |
807 | 24.5k | _reset_local_fields(); |
808 | 24.5k | } |
809 | | |
810 | | inline void |
811 | | HTTPHdr::clear() |
812 | 0 | { |
813 | 0 | _reset_local_state(); |
814 | 0 | this->HdrHeapSDKHandle::clear(); |
815 | 0 | } |
816 | | |
817 | | inline void |
818 | | HTTPHdr::destroy() |
819 | 24.5k | { |
820 | 24.5k | _reset_local_state(); |
821 | 24.5k | this->HdrHeapSDKHandle::destroy(); |
822 | 24.5k | } |
823 | | |
824 | | inline void |
825 | | HTTPHdr::reset() |
826 | 0 | { |
827 | 0 | m_heap = nullptr; |
828 | 0 | m_url_cached.reset(); |
829 | 0 | _reset_local_fields(); |
830 | 0 | } |
831 | | |
832 | | /*------------------------------------------------------------------------- |
833 | | -------------------------------------------------------------------------*/ |
834 | | |
835 | | inline void |
836 | | HTTPHdr::copy(const HTTPHdr *hdr) |
837 | 0 | { |
838 | 0 | ink_assert(hdr->valid()); |
839 | |
|
840 | 0 | if (valid()) { |
841 | 0 | http_hdr_copy_onto(hdr->m_http, hdr->m_heap, m_http, m_heap, (m_heap != hdr->m_heap) ? true : false); |
842 | 0 | } else { |
843 | 0 | m_heap = new_HdrHeap(); |
844 | 0 | m_http = http_hdr_clone(hdr->m_http, hdr->m_heap, m_heap); |
845 | 0 | m_mime = m_http->m_fields_impl; |
846 | 0 | } |
847 | 0 | } |
848 | | |
849 | | /*------------------------------------------------------------------------- |
850 | | -------------------------------------------------------------------------*/ |
851 | | |
852 | | inline void |
853 | | HTTPHdr::copy_shallow(const HTTPHdr *hdr) |
854 | 0 | { |
855 | 0 | ink_assert(hdr->valid()); |
856 | |
|
857 | 0 | m_heap = hdr->m_heap; |
858 | 0 | m_http = hdr->m_http; |
859 | 0 | m_mime = hdr->m_mime; |
860 | |
|
861 | 0 | if (hdr->type_get() == HTTPType::REQUEST && m_url_cached.valid()) |
862 | 0 | m_url_cached.copy_shallow(&hdr->m_url_cached); |
863 | 0 | } Unexecuted instantiation: HTTPHdr::copy_shallow(HTTPHdr const*) Unexecuted instantiation: HTTPHdr::copy_shallow(HTTPHdr const*) |
864 | | |
865 | | /*------------------------------------------------------------------------- |
866 | | -------------------------------------------------------------------------*/ |
867 | | |
868 | | inline int |
869 | | HTTPHdr::print(char *buf, int bufsize, int *bufindex, int *dumpoffset) const |
870 | 0 | { |
871 | 0 | ink_assert(valid()); |
872 | 0 | return http_hdr_print(m_http, buf, bufsize, bufindex, dumpoffset); |
873 | 0 | } Unexecuted instantiation: HTTPHdr::print(char*, int, int*, int*) const Unexecuted instantiation: HTTPHdr::print(char*, int, int*, int*) const |
874 | | |
875 | | /*------------------------------------------------------------------------- |
876 | | -------------------------------------------------------------------------*/ |
877 | | |
878 | | inline void |
879 | | HTTPHdr::_test_and_fill_target_cache() const |
880 | 0 | { |
881 | 0 | if (!m_target_cached) { |
882 | 0 | this->_fill_target_cache(); |
883 | 0 | return; |
884 | 0 | } |
885 | | |
886 | | // If host came from the Host header (not URL), check for staleness by verifying |
887 | | // the current Host header value length matches what we expect from cached values. |
888 | 0 | if (!m_target_in_url && m_host_mime != nullptr) { |
889 | 0 | int expected_len = m_host_length; |
890 | 0 | if (m_port_in_header && m_port > 0) { |
891 | | // Account for ":port" suffix in the raw Host header value. |
892 | 0 | expected_len += 1; // colon |
893 | 0 | if (m_port < 10) { |
894 | 0 | expected_len += 1; |
895 | 0 | } else if (m_port < 100) { |
896 | 0 | expected_len += 2; |
897 | 0 | } else if (m_port < 1000) { |
898 | 0 | expected_len += 3; |
899 | 0 | } else if (m_port < 10000) { |
900 | 0 | expected_len += 4; |
901 | 0 | } else { |
902 | 0 | expected_len += 5; |
903 | 0 | } |
904 | 0 | } |
905 | 0 | if (m_host_mime->m_len_value != expected_len) { |
906 | 0 | this->_fill_target_cache(); |
907 | 0 | } |
908 | 0 | } |
909 | 0 | } |
910 | | |
911 | | /*------------------------------------------------------------------------- |
912 | | -------------------------------------------------------------------------*/ |
913 | | |
914 | | inline std::string_view |
915 | | HTTPHdr::host_get() const |
916 | 0 | { |
917 | 0 | this->_test_and_fill_target_cache(); |
918 | 0 | if (m_target_in_url) { |
919 | 0 | return url_get()->host_get(); |
920 | 0 | } else if (m_host_mime) { |
921 | 0 | return std::string_view{m_host_mime->m_ptr_value, static_cast<std::string_view::size_type>(m_host_length)}; |
922 | 0 | } |
923 | | |
924 | 0 | return std::string_view{}; |
925 | 0 | } |
926 | | |
927 | | /*------------------------------------------------------------------------- |
928 | | -------------------------------------------------------------------------*/ |
929 | | |
930 | | inline int |
931 | | HTTPHdr::port_get() |
932 | 0 | { |
933 | 0 | this->_test_and_fill_target_cache(); |
934 | 0 | return m_port; |
935 | 0 | } |
936 | | |
937 | | /*------------------------------------------------------------------------- |
938 | | -------------------------------------------------------------------------*/ |
939 | | |
940 | | inline bool |
941 | | HTTPHdr::is_target_in_url() const |
942 | 0 | { |
943 | 0 | this->_test_and_fill_target_cache(); |
944 | 0 | return m_target_in_url; |
945 | 0 | } |
946 | | |
947 | | /*------------------------------------------------------------------------- |
948 | | -------------------------------------------------------------------------*/ |
949 | | |
950 | | inline bool |
951 | | HTTPHdr::is_port_in_header() const |
952 | 0 | { |
953 | 0 | this->_test_and_fill_target_cache(); |
954 | 0 | return m_port_in_header; |
955 | 0 | } |
956 | | |
957 | | /*------------------------------------------------------------------------- |
958 | | -------------------------------------------------------------------------*/ |
959 | | |
960 | | inline void |
961 | | HTTPHdr::mark_target_dirty() const |
962 | 0 | { |
963 | 0 | m_target_cached = false; |
964 | 0 | } |
965 | | /*------------------------------------------------------------------------- |
966 | | -------------------------------------------------------------------------*/ |
967 | | |
968 | | inline HTTPType |
969 | | http_hdr_type_get(HTTPHdrImpl *hh) |
970 | 0 | { |
971 | 0 | return (hh->m_polarity); |
972 | 0 | } |
973 | | |
974 | | /*------------------------------------------------------------------------- |
975 | | -------------------------------------------------------------------------*/ |
976 | | |
977 | | inline HTTPType |
978 | | HTTPHdr::type_get() const |
979 | 0 | { |
980 | 0 | ink_assert(valid()); |
981 | 0 | return http_hdr_type_get(m_http); |
982 | 0 | } Unexecuted instantiation: HTTPHdr::type_get() const Unexecuted instantiation: HTTPHdr::type_get() const |
983 | | |
984 | | /*------------------------------------------------------------------------- |
985 | | -------------------------------------------------------------------------*/ |
986 | | |
987 | | inline HTTPVersion |
988 | | HTTPHdr::version_get() const |
989 | 0 | { |
990 | 0 | ink_assert(valid()); |
991 | 0 | return m_http->m_version; |
992 | 0 | } Unexecuted instantiation: HTTPHdr::version_get() const Unexecuted instantiation: HTTPHdr::version_get() const |
993 | | |
994 | | /*------------------------------------------------------------------------- |
995 | | -------------------------------------------------------------------------*/ |
996 | | |
997 | | inline static HTTPKeepAlive |
998 | | is_header_keep_alive(const HTTPVersion &http_version, const MIMEField *con_hdr) |
999 | 0 | { |
1000 | 0 | enum class ConToken { |
1001 | 0 | NONE = 0, |
1002 | 0 | KEEP_ALIVE, |
1003 | 0 | CLOSE, |
1004 | 0 | }; |
1005 | |
|
1006 | 0 | auto con_token = ConToken::NONE; |
1007 | 0 | HTTPKeepAlive keep_alive = HTTPKeepAlive::NO_KEEPALIVE; |
1008 | | // *unknown_tokens = false; |
1009 | |
|
1010 | 0 | if (con_hdr) { |
1011 | 0 | if (con_hdr->value_get_index("keep-alive"sv) >= 0) |
1012 | 0 | con_token = ConToken::KEEP_ALIVE; |
1013 | 0 | else if (con_hdr->value_get_index("close"sv) >= 0) |
1014 | 0 | con_token = ConToken::CLOSE; |
1015 | 0 | } |
1016 | |
|
1017 | 0 | if (HTTP_1_0 == http_version) { |
1018 | 0 | keep_alive = (con_token == ConToken::KEEP_ALIVE) ? (HTTPKeepAlive::KEEPALIVE) : (HTTPKeepAlive::NO_KEEPALIVE); |
1019 | 0 | } else if (HTTP_1_1 == http_version) { |
1020 | | // We deviate from the spec here. If the we got a response where |
1021 | | // where there is no Connection header and the request 1.0 was |
1022 | | // 1.0 don't treat this as keep-alive since Netscape-Enterprise/3.6 SP1 |
1023 | | // server doesn't |
1024 | 0 | keep_alive = ((con_token == ConToken::KEEP_ALIVE) || (con_token == ConToken::NONE && HTTP_1_1 == http_version)) ? |
1025 | 0 | (HTTPKeepAlive::KEEPALIVE) : |
1026 | 0 | (HTTPKeepAlive::NO_KEEPALIVE); |
1027 | 0 | } else { |
1028 | 0 | keep_alive = HTTPKeepAlive::NO_KEEPALIVE; |
1029 | 0 | } |
1030 | 0 | return (keep_alive); |
1031 | 0 | } Unexecuted instantiation: fuzz_hpack.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HTTP2.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http2Frame.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HPACK.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HTTP.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HdrHeap.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: URL.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: VersionConverter.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HeaderValidator.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: fuzz_http.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: fuzz_chunked.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpTunnel.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpConfig.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpSessionManager.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpSM.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpCacheSM.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpDebugNames.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpTransact.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpBodyFactory.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpTransactHeaders.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ConnectingEntry.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: RegressionHttpTransact.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HostDB.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheControl.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ControlBase.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ControlMatcher.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: IPAllow.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ParentSelectionStrategy.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ParentSelection.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ParentRoundRobin.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ParentConsistentHash.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ProxySession.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ProxyTransaction.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ReverseProxy.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Transform.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: VirtualHost.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: NextHopSelectionStrategy.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: NextHopHealthStatus.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: RemapProcessor.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: RemapPlugins.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: AclFiltering.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: UrlRewrite.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: NextHopStrategyFactory.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: NextHopConsistentHash.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: NextHopRoundRobin.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: RemapYamlConfig.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: RemapConfig.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Cache.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheDir.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheDisk.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheHosting.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheHttp.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheProcessor.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheRead.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheShm.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheVC.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheWrite.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpTransactCache.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: PreservationTable.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: RamCacheCLFUS.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: RamCacheLRU.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: RamCacheS3FIFO.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Stripe.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: StripeSM.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: CacheEvacuateDocVC.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Log.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: LogAccess.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: LogBuffer.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: LogConfig.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: LogField.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: LogFile.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: LogFilter.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: LogFormat.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: LogObject.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: TransactionLogData.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: YamlLogConfig.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: YamlLogConfigDecoders.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: SplitDNS.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Socks.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: OCSPStapling.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: FetchSM.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: PluginHttpConnect.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpProxyServerMain.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: ProtocolProbeSessionAccept.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpSessionAccept.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http1ClientSession.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http1ClientTransaction.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http2SessionAccept.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http2ClientSession.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http2CommonSession.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http2ConnectionState.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http2Stream.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http2DebugNames.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http1ServerSession.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http1ServerTransaction.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http2ServerSession.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http3SessionAccept.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http3App.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http3Session.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http3Transaction.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http3HeaderFramer.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: QPACK.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http3DataFramer.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http3HeaderVIOAdaptor.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http3SettingsHandler.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: Http09App.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: UnixNetProcessor.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: SNIActionPerformer.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HttpHookState.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) Unexecuted instantiation: HdrTSOnly.cc:is_header_keep_alive(HTTPVersion const&, MIMEField const*) |
1032 | | |
1033 | | inline HTTPKeepAlive |
1034 | | HTTPHdr::keep_alive_get() const |
1035 | 0 | { |
1036 | 0 | HTTPKeepAlive retval = HTTPKeepAlive::NO_KEEPALIVE; |
1037 | 0 | const MIMEField *pc = this->field_find(static_cast<std::string_view>(MIME_FIELD_PROXY_CONNECTION)); |
1038 | 0 | if (pc != nullptr) { |
1039 | 0 | retval = is_header_keep_alive(this->version_get(), pc); |
1040 | 0 | } else { |
1041 | 0 | const MIMEField *c = this->field_find(static_cast<std::string_view>(MIME_FIELD_CONNECTION)); |
1042 | 0 | retval = is_header_keep_alive(this->version_get(), c); |
1043 | 0 | } |
1044 | 0 | return retval; |
1045 | 0 | } |
1046 | | |
1047 | | inline bool |
1048 | | HTTPHdr::is_keep_alive_set() const |
1049 | 0 | { |
1050 | 0 | return this->keep_alive_get() == HTTPKeepAlive::KEEPALIVE; |
1051 | 0 | } |
1052 | | |
1053 | | /** |
1054 | | Check the status code is informational and expecting final response |
1055 | | - e.g. "100 Continue", "103 Early Hints" |
1056 | | |
1057 | | Please note that "101 Switching Protocol" is not included. |
1058 | | */ |
1059 | | inline bool |
1060 | | HTTPHdr::expect_final_response() const |
1061 | 0 | { |
1062 | 0 | switch (this->status_get()) { |
1063 | 0 | case HTTPStatus::CONTINUE: |
1064 | 0 | case HTTPStatus::EARLY_HINTS: |
1065 | 0 | return true; |
1066 | 0 | default: |
1067 | 0 | return false; |
1068 | 0 | } |
1069 | 0 | } |
1070 | | |
1071 | | /*------------------------------------------------------------------------- |
1072 | | -------------------------------------------------------------------------*/ |
1073 | | |
1074 | | inline void |
1075 | | HTTPHdr::version_set(HTTPVersion version) |
1076 | 0 | { |
1077 | 0 | ink_assert(valid()); |
1078 | 0 | http_hdr_version_set(m_http, version); |
1079 | 0 | } Unexecuted instantiation: HTTPHdr::version_set(HTTPVersion) Unexecuted instantiation: HTTPHdr::version_set(HTTPVersion) |
1080 | | |
1081 | | /*------------------------------------------------------------------------- |
1082 | | -------------------------------------------------------------------------*/ |
1083 | | |
1084 | | inline std::string_view |
1085 | | HTTPHdr::method_get() |
1086 | 0 | { |
1087 | 0 | ink_assert(valid()); |
1088 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1089 | |
|
1090 | 0 | return http_hdr_method_get(m_http); |
1091 | 0 | } Unexecuted instantiation: HTTPHdr::method_get() Unexecuted instantiation: HTTPHdr::method_get() |
1092 | | |
1093 | | inline int |
1094 | | HTTPHdr::method_get_wksidx() const |
1095 | 0 | { |
1096 | 0 | ink_assert(valid()); |
1097 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1098 | |
|
1099 | 0 | return (m_http->u.req.m_method_wks_idx); |
1100 | 0 | } Unexecuted instantiation: HTTPHdr::method_get_wksidx() const Unexecuted instantiation: HTTPHdr::method_get_wksidx() const |
1101 | | |
1102 | | /*------------------------------------------------------------------------- |
1103 | | -------------------------------------------------------------------------*/ |
1104 | | |
1105 | | inline void |
1106 | | HTTPHdr::method_set(std::string_view value) |
1107 | 0 | { |
1108 | 0 | ink_assert(valid()); |
1109 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1110 | |
|
1111 | 0 | int method_wks_idx = hdrtoken_tokenize(value.data(), static_cast<int>(value.length())); |
1112 | 0 | http_hdr_method_set(m_heap, m_http, value, method_wks_idx, true); |
1113 | 0 | } Unexecuted instantiation: HTTPHdr::method_set(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Unexecuted instantiation: HTTPHdr::method_set(std::__1::basic_string_view<char, std::__1::char_traits<char> >) |
1114 | | |
1115 | | /*------------------------------------------------------------------------- |
1116 | | -------------------------------------------------------------------------*/ |
1117 | | |
1118 | | inline URL * |
1119 | | HTTPHdr::url_create(URL *u) |
1120 | 0 | { |
1121 | 0 | ink_assert(valid()); |
1122 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1123 | |
|
1124 | 0 | u->set(this); |
1125 | 0 | u->create(m_heap); |
1126 | 0 | return (u); |
1127 | 0 | } Unexecuted instantiation: HTTPHdr::url_create(URL*) Unexecuted instantiation: HTTPHdr::url_create(URL*) |
1128 | | |
1129 | | /*------------------------------------------------------------------------- |
1130 | | -------------------------------------------------------------------------*/ |
1131 | | |
1132 | | inline URL * |
1133 | | HTTPHdr::url_get() const |
1134 | 0 | { |
1135 | 0 | ink_assert(valid()); |
1136 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1137 | | |
1138 | | // It's entirely possible that someone changed URL in our impl |
1139 | | // without updating the cached copy in the C++ layer. Check |
1140 | | // to see if this happened before handing back the url |
1141 | |
|
1142 | 0 | URLImpl *real_impl = m_http->u.req.m_url_impl; |
1143 | 0 | if (m_url_cached.m_url_impl != real_impl) { |
1144 | 0 | m_url_cached.set(this); |
1145 | 0 | m_url_cached.m_url_impl = real_impl; |
1146 | 0 | this->mark_target_dirty(); |
1147 | 0 | } |
1148 | 0 | return (&m_url_cached); |
1149 | 0 | } |
1150 | | |
1151 | | /*------------------------------------------------------------------------- |
1152 | | -------------------------------------------------------------------------*/ |
1153 | | |
1154 | | inline URL * |
1155 | | HTTPHdr::url_get(URL *url) |
1156 | 0 | { |
1157 | 0 | ink_assert(valid()); |
1158 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1159 | |
|
1160 | 0 | url->set(this); // attach refcount |
1161 | 0 | url->m_url_impl = m_http->u.req.m_url_impl; |
1162 | 0 | return (url); |
1163 | 0 | } Unexecuted instantiation: HTTPHdr::url_get(URL*) Unexecuted instantiation: HTTPHdr::url_get(URL*) |
1164 | | |
1165 | | /*------------------------------------------------------------------------- |
1166 | | -------------------------------------------------------------------------*/ |
1167 | | |
1168 | | inline void |
1169 | | HTTPHdr::url_set(URL *url) |
1170 | 0 | { |
1171 | 0 | ink_assert(valid()); |
1172 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1173 | |
|
1174 | 0 | URLImpl *url_impl = m_http->u.req.m_url_impl; |
1175 | 0 | ::url_copy_onto(url->m_url_impl, url->m_heap, url_impl, m_heap, true); |
1176 | 0 | } Unexecuted instantiation: HTTPHdr::url_set(URL*) Unexecuted instantiation: HTTPHdr::url_set(URL*) |
1177 | | |
1178 | | /*------------------------------------------------------------------------- |
1179 | | -------------------------------------------------------------------------*/ |
1180 | | |
1181 | | inline void |
1182 | | HTTPHdr::url_set(std::string_view value) |
1183 | 0 | { |
1184 | 0 | URLImpl *url_impl; |
1185 | |
|
1186 | 0 | ink_assert(valid()); |
1187 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1188 | |
|
1189 | 0 | url_impl = m_http->u.req.m_url_impl; |
1190 | 0 | ::url_clear(url_impl); |
1191 | 0 | const char *str{value.data()}; |
1192 | 0 | ::url_parse(m_heap, url_impl, &str, str + value.length(), true); |
1193 | 0 | } Unexecuted instantiation: HTTPHdr::url_set(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Unexecuted instantiation: HTTPHdr::url_set(std::__1::basic_string_view<char, std::__1::char_traits<char> >) |
1194 | | |
1195 | | /*------------------------------------------------------------------------- |
1196 | | -------------------------------------------------------------------------*/ |
1197 | | |
1198 | | inline HTTPStatus |
1199 | | http_hdr_status_get(HTTPHdrImpl const *hh) |
1200 | 0 | { |
1201 | 0 | ink_assert(hh->m_polarity == HTTPType::RESPONSE); |
1202 | 0 | return (HTTPStatus)hh->u.resp.m_status; |
1203 | 0 | } |
1204 | | |
1205 | | /*------------------------------------------------------------------------- |
1206 | | -------------------------------------------------------------------------*/ |
1207 | | |
1208 | | inline HTTPStatus |
1209 | | HTTPHdr::status_get() const |
1210 | 0 | { |
1211 | 0 | ink_assert(valid()); |
1212 | |
|
1213 | 0 | if (m_http) { |
1214 | 0 | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1215 | 0 | return http_hdr_status_get(m_http); |
1216 | 0 | } |
1217 | | |
1218 | 0 | return HTTPStatus::NONE; |
1219 | 0 | } Unexecuted instantiation: HTTPHdr::status_get() const Unexecuted instantiation: HTTPHdr::status_get() const |
1220 | | |
1221 | | /*------------------------------------------------------------------------- |
1222 | | -------------------------------------------------------------------------*/ |
1223 | | |
1224 | | inline void |
1225 | | HTTPHdr::status_set(HTTPStatus status) |
1226 | 0 | { |
1227 | 0 | ink_assert(valid()); |
1228 | 0 | ink_release_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1229 | | |
1230 | 0 | http_hdr_status_set(m_http, status); |
1231 | 0 | } Unexecuted instantiation: HTTPHdr::status_set(HTTPStatus) Unexecuted instantiation: HTTPHdr::status_set(HTTPStatus) |
1232 | | |
1233 | | /*------------------------------------------------------------------------- |
1234 | | -------------------------------------------------------------------------*/ |
1235 | | |
1236 | | inline std::string_view |
1237 | | HTTPHdr::reason_get() |
1238 | 0 | { |
1239 | 0 | ink_assert(valid()); |
1240 | 0 | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1241 | |
|
1242 | 0 | return http_hdr_reason_get(m_http); |
1243 | 0 | } Unexecuted instantiation: HTTPHdr::reason_get() Unexecuted instantiation: HTTPHdr::reason_get() |
1244 | | |
1245 | | /*------------------------------------------------------------------------- |
1246 | | -------------------------------------------------------------------------*/ |
1247 | | |
1248 | | inline void |
1249 | | HTTPHdr::reason_set(std::string_view value) |
1250 | 0 | { |
1251 | 0 | ink_assert(valid()); |
1252 | 0 | ink_release_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1253 | | |
1254 | 0 | http_hdr_reason_set(m_heap, m_http, value, true); |
1255 | 0 | } Unexecuted instantiation: HTTPHdr::reason_set(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Unexecuted instantiation: HTTPHdr::reason_set(std::__1::basic_string_view<char, std::__1::char_traits<char> >) |
1256 | | |
1257 | | /*------------------------------------------------------------------------- |
1258 | | -------------------------------------------------------------------------*/ |
1259 | | |
1260 | | inline void |
1261 | | HTTPHdr::mark_early_data(bool flag) const |
1262 | 0 | { |
1263 | 0 | ink_assert(valid()); |
1264 | 0 | early_data = flag; |
1265 | 0 | } Unexecuted instantiation: HTTPHdr::mark_early_data(bool) const Unexecuted instantiation: HTTPHdr::mark_early_data(bool) const |
1266 | | |
1267 | | /*------------------------------------------------------------------------- |
1268 | | -------------------------------------------------------------------------*/ |
1269 | | |
1270 | | inline bool |
1271 | | HTTPHdr::is_early_data() const |
1272 | 0 | { |
1273 | 0 | ink_assert(valid()); |
1274 | 0 | return early_data; |
1275 | 0 | } Unexecuted instantiation: HTTPHdr::is_early_data() const Unexecuted instantiation: HTTPHdr::is_early_data() const |
1276 | | |
1277 | | /*------------------------------------------------------------------------- |
1278 | | -------------------------------------------------------------------------*/ |
1279 | | |
1280 | | inline ParseResult |
1281 | | HTTPHdr::parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, int strict_uri_parsing, |
1282 | | size_t max_request_line_size, size_t max_hdr_field_size) |
1283 | 11.7k | { |
1284 | 11.7k | ink_assert(valid()); |
1285 | 11.7k | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1286 | | |
1287 | 11.7k | return http_parser_parse_req(parser, m_heap, m_http, start, end, true, eof, strict_uri_parsing, max_request_line_size, |
1288 | 11.7k | max_hdr_field_size); |
1289 | 11.7k | } |
1290 | | |
1291 | | /*------------------------------------------------------------------------- |
1292 | | -------------------------------------------------------------------------*/ |
1293 | | |
1294 | | inline ParseResult |
1295 | | HTTPHdr::parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof) |
1296 | 11.7k | { |
1297 | 11.7k | ink_assert(valid()); |
1298 | 11.7k | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1299 | | |
1300 | 11.7k | return http_parser_parse_resp(parser, m_heap, m_http, start, end, true, eof); |
1301 | 11.7k | } |
1302 | | |
1303 | | /*------------------------------------------------------------------------- |
1304 | | -------------------------------------------------------------------------*/ |
1305 | | |
1306 | | inline bool |
1307 | | HTTPHdr::is_cache_control_set(const char *cc_directive_wks) |
1308 | 0 | { |
1309 | 0 | ink_assert(valid()); |
1310 | 0 | ink_assert(hdrtoken_is_wks(cc_directive_wks)); |
1311 | |
|
1312 | 0 | const HdrTokenHeapPrefix *prefix = hdrtoken_wks_to_prefix(cc_directive_wks); |
1313 | 0 | ink_assert(prefix->wks_token_type == HdrTokenType::CACHE_CONTROL); |
1314 | |
|
1315 | 0 | uint32_t cc_mask = prefix->wks_type_specific.u.cache_control.cc_mask; |
1316 | 0 | if (get_cooked_cc_mask() & cc_mask) |
1317 | 0 | return (true); |
1318 | 0 | else |
1319 | 0 | return (false); |
1320 | 0 | } Unexecuted instantiation: HTTPHdr::is_cache_control_set(char const*) Unexecuted instantiation: HTTPHdr::is_cache_control_set(char const*) |
1321 | | |
1322 | | /*------------------------------------------------------------------------- |
1323 | | -------------------------------------------------------------------------*/ |
1324 | | |
1325 | | inline bool |
1326 | | HTTPHdr::is_pragma_no_cache_set() |
1327 | 0 | { |
1328 | 0 | ink_assert(valid()); |
1329 | 0 | return (get_cooked_pragma_no_cache()); |
1330 | 0 | } Unexecuted instantiation: HTTPHdr::is_pragma_no_cache_set() Unexecuted instantiation: HTTPHdr::is_pragma_no_cache_set() |
1331 | | |
1332 | | inline char * |
1333 | | HTTPHdr::url_string_get_ref(int *length) |
1334 | 0 | { |
1335 | 0 | return this->url_string_get(USE_HDR_HEAP_MAGIC, length); |
1336 | 0 | } |
1337 | | |
1338 | | inline std::string_view |
1339 | | HTTPHdr::path_get() |
1340 | 0 | { |
1341 | 0 | URL *url = this->url_get(); |
1342 | 0 | if (url) { |
1343 | 0 | return url->path_get(); |
1344 | 0 | } |
1345 | 0 | return {}; |
1346 | 0 | } |
1347 | | |
1348 | | inline std::string_view |
1349 | | HTTPHdr::query_get() |
1350 | 0 | { |
1351 | 0 | URL *url = this->url_get(); |
1352 | 0 | if (url) { |
1353 | 0 | return url->query_get(); |
1354 | 0 | } |
1355 | 0 | return std::string_view{}; |
1356 | 0 | } |
1357 | | |
1358 | | inline std::string_view |
1359 | | HTTPHdr::fragment_get() |
1360 | 0 | { |
1361 | 0 | URL *url = this->url_get(); |
1362 | 0 | if (url) { |
1363 | 0 | return url->fragment_get(); |
1364 | 0 | } |
1365 | 0 | return std::string_view{}; |
1366 | 0 | } |
1367 | | |
1368 | | inline std::string_view |
1369 | | HTTPHdr::scheme_get() |
1370 | 0 | { |
1371 | 0 | URL *url = this->url_get(); |
1372 | 0 | if (url) { |
1373 | 0 | return url->scheme_get(); |
1374 | 0 | } |
1375 | 0 | return std::string_view{}; |
1376 | 0 | } |
1377 | | |
1378 | | /*------------------------------------------------------------------------- |
1379 | | -------------------------------------------------------------------------*/ |
1380 | | |
1381 | | enum class CacheAltMagic : uint32_t { |
1382 | | ALIVE = 0xabcddeed, |
1383 | | MARSHALED = 0xdcbadeed, |
1384 | | MARSHALED_WKS = 0xdcbadeee, ///< Marshalled alternate followed by a uint64_t WKS identity. |
1385 | | DEAD = 0xdeadeed, |
1386 | | }; |
1387 | | |
1388 | | // struct HTTPCacheAlt |
1389 | | struct HTTPCacheAlt { |
1390 | | HTTPCacheAlt(); |
1391 | | void copy(HTTPCacheAlt *to_copy); |
1392 | | void copy_frag_offsets_from(HTTPCacheAlt *src); |
1393 | | void destroy(); |
1394 | | |
1395 | | CacheAltMagic m_magic = CacheAltMagic::ALIVE; |
1396 | | |
1397 | | // Writeable is set to true is we reside |
1398 | | // in a buffer owned by this structure. |
1399 | | // INVARIANT: if own the buffer this HttpCacheAlt |
1400 | | // we also own the buffers for the request & |
1401 | | // response headers |
1402 | | int32_t m_writeable = 1; |
1403 | | int32_t m_unmarshal_len = -1; |
1404 | | |
1405 | | int32_t m_id = -1; |
1406 | | int32_t m_rid = -1; |
1407 | | |
1408 | | int32_t m_object_key[sizeof(CryptoHash) / sizeof(int32_t)]; |
1409 | | int32_t m_object_size[2]; |
1410 | | |
1411 | | HTTPHdr m_request_hdr; |
1412 | | HTTPHdr m_response_hdr; |
1413 | | |
1414 | | time_t m_request_sent_time = 0; |
1415 | | time_t m_response_received_time = 0; |
1416 | | |
1417 | | /// # of fragment offsets in this alternate. |
1418 | | /// @note This is one less than the number of fragments. |
1419 | | int m_frag_offset_count = 0; |
1420 | | /// Type of offset for a fragment. |
1421 | | using FragOffset = uint64_t; |
1422 | | /// Table of fragment offsets. |
1423 | | /// @note The offsets are forward looking so that frag[0] is the |
1424 | | /// first byte past the end of fragment 0 which is also the first |
1425 | | /// byte of fragment 1. For this reason there is no fragment offset |
1426 | | /// for the last fragment. |
1427 | | FragOffset *m_frag_offsets = nullptr; |
1428 | | /// # of fragment offsets built in to object. |
1429 | | static int constexpr N_INTEGRAL_FRAG_OFFSETS = 4; |
1430 | | /// Integral fragment offset table. |
1431 | | FragOffset m_integral_frag_offsets[N_INTEGRAL_FRAG_OFFSETS]; |
1432 | | |
1433 | | // With clustering, our alt may be in cluster |
1434 | | // incoming channel buffer, when we are |
1435 | | // destroyed we decrement the refcount |
1436 | | // on that buffer so that it gets destroyed |
1437 | | // We don't want to use a ref count ptr (Ptr<>) |
1438 | | // since our ownership model requires explicit |
1439 | | // destroys and ref count pointers defeat this |
1440 | | RefCountObj *m_ext_buffer = nullptr; |
1441 | | }; |
1442 | | |
1443 | | class HTTPInfo |
1444 | | { |
1445 | | public: |
1446 | | using FragOffset = HTTPCacheAlt::FragOffset; ///< Import type. |
1447 | | |
1448 | | HTTPCacheAlt *m_alt = nullptr; |
1449 | | |
1450 | 4 | HTTPInfo() {} |
1451 | 0 | ~HTTPInfo() { clear(); } |
1452 | | void |
1453 | | clear() |
1454 | 0 | { |
1455 | 0 | m_alt = nullptr; |
1456 | 0 | } |
1457 | | bool |
1458 | | valid() const |
1459 | 0 | { |
1460 | 0 | return m_alt != nullptr; |
1461 | 0 | } |
1462 | | |
1463 | | void create(); |
1464 | | void destroy(); |
1465 | | |
1466 | | void copy(HTTPInfo *to_copy); |
1467 | | void |
1468 | | copy_shallow(HTTPInfo *info) |
1469 | 0 | { |
1470 | 0 | m_alt = info->m_alt; |
1471 | 0 | } |
1472 | | void copy_frag_offsets_from(HTTPInfo *src); |
1473 | | HTTPInfo &operator=(const HTTPInfo &m); |
1474 | | |
1475 | | int marshal_length(); |
1476 | | int marshal(char *buf, int len); |
1477 | | static int unmarshal(char *buf, int len, RefCountObj *block_ref); |
1478 | | static int unmarshal_v24_1(char *buf, int len, RefCountObj *block_ref); |
1479 | | void set_buffer_reference(RefCountObj *block_ref); |
1480 | | int get_handle(char *buf, int len); |
1481 | | |
1482 | | int32_t |
1483 | | id_get() const |
1484 | 0 | { |
1485 | 0 | return m_alt->m_id; |
1486 | 0 | } |
1487 | | int32_t |
1488 | | rid_get() |
1489 | 0 | { |
1490 | 0 | return m_alt->m_rid; |
1491 | 0 | } |
1492 | | |
1493 | | void |
1494 | | id_set(int32_t id) |
1495 | 0 | { |
1496 | 0 | m_alt->m_id = id; |
1497 | 0 | } |
1498 | | void |
1499 | | rid_set(int32_t id) |
1500 | 0 | { |
1501 | 0 | m_alt->m_rid = id; |
1502 | 0 | } |
1503 | | |
1504 | | CryptoHash object_key_get(); |
1505 | | void object_key_get(CryptoHash *); |
1506 | | bool compare_object_key(const CryptoHash *); |
1507 | | int64_t object_size_get(); |
1508 | | |
1509 | | void |
1510 | | request_get(HTTPHdr *hdr) |
1511 | 0 | { |
1512 | 0 | hdr->copy_shallow(&m_alt->m_request_hdr); |
1513 | 0 | } |
1514 | | void |
1515 | | response_get(HTTPHdr *hdr) |
1516 | 0 | { |
1517 | 0 | hdr->copy_shallow(&m_alt->m_response_hdr); |
1518 | 0 | } |
1519 | | |
1520 | | HTTPHdr * |
1521 | | request_get() |
1522 | 0 | { |
1523 | 0 | return &m_alt->m_request_hdr; |
1524 | 0 | } |
1525 | | HTTPHdr * |
1526 | | response_get() |
1527 | 0 | { |
1528 | 0 | return &m_alt->m_response_hdr; |
1529 | 0 | } |
1530 | | |
1531 | | URL * |
1532 | | request_url_get(URL *url = nullptr) |
1533 | 0 | { |
1534 | 0 | return m_alt->m_request_hdr.url_get(url); |
1535 | 0 | } |
1536 | | |
1537 | | time_t |
1538 | | request_sent_time_get() |
1539 | 0 | { |
1540 | 0 | return m_alt->m_request_sent_time; |
1541 | 0 | } |
1542 | | time_t |
1543 | | response_received_time_get() |
1544 | 0 | { |
1545 | 0 | return m_alt->m_response_received_time; |
1546 | 0 | } |
1547 | | |
1548 | | void object_key_set(CryptoHash &hash); |
1549 | | void object_size_set(int64_t size); |
1550 | | |
1551 | | void |
1552 | | request_set(const HTTPHdr *req) |
1553 | 0 | { |
1554 | 0 | m_alt->m_request_hdr.copy(req); |
1555 | 0 | } |
1556 | | void |
1557 | | response_set(const HTTPHdr *resp) |
1558 | 0 | { |
1559 | 0 | m_alt->m_response_hdr.copy(resp); |
1560 | 0 | } |
1561 | | |
1562 | | void |
1563 | | request_sent_time_set(time_t t) |
1564 | 0 | { |
1565 | 0 | m_alt->m_request_sent_time = t; |
1566 | 0 | } |
1567 | | void |
1568 | | response_received_time_set(time_t t) |
1569 | 0 | { |
1570 | 0 | m_alt->m_response_received_time = t; |
1571 | 0 | } |
1572 | | |
1573 | | /// Get the fragment table. |
1574 | | FragOffset *get_frag_table(); |
1575 | | /// Get the # of fragment offsets |
1576 | | /// @note This is the size of the fragment offset table, and one less |
1577 | | /// than the actual # of fragments. |
1578 | | int get_frag_offset_count(); |
1579 | | /// Add an @a offset to the end of the fragment offset table. |
1580 | | void push_frag_offset(FragOffset offset); |
1581 | | |
1582 | | // Sanity check functions |
1583 | | static bool check_marshalled(char *buf, int len); |
1584 | | |
1585 | | private: |
1586 | | HTTPInfo(const HTTPInfo &h); |
1587 | | }; |
1588 | | |
1589 | | inline void |
1590 | | HTTPInfo::destroy() |
1591 | 0 | { |
1592 | 0 | if (m_alt) { |
1593 | 0 | if (m_alt->m_writeable) { |
1594 | 0 | m_alt->destroy(); |
1595 | 0 | } else if (m_alt->m_ext_buffer) { |
1596 | 0 | if (m_alt->m_ext_buffer->refcount_dec() == 0) { |
1597 | 0 | m_alt->m_ext_buffer->free(); |
1598 | 0 | } |
1599 | 0 | } |
1600 | 0 | } |
1601 | 0 | clear(); |
1602 | 0 | } |
1603 | | |
1604 | | inline HTTPInfo & |
1605 | | HTTPInfo::operator=(const HTTPInfo &m) |
1606 | 0 | { |
1607 | 0 | m_alt = m.m_alt; |
1608 | 0 | return *this; |
1609 | 0 | } |
1610 | | |
1611 | | inline CryptoHash |
1612 | | HTTPInfo::object_key_get() |
1613 | 0 | { |
1614 | 0 | CryptoHash val; |
1615 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&val); |
1616 | 0 |
|
1617 | 0 | memcpy(pi, m_alt->m_object_key, sizeof(CryptoHash)); |
1618 | 0 |
|
1619 | 0 | return val; |
1620 | 0 | } |
1621 | | |
1622 | | inline void |
1623 | | HTTPInfo::object_key_get(CryptoHash *hash) |
1624 | 0 | { |
1625 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(hash); |
1626 | 0 | memcpy(pi, m_alt->m_object_key, CRYPTO_HASH_SIZE); |
1627 | 0 | } Unexecuted instantiation: HTTPInfo::object_key_get(ts::CryptoHash*) Unexecuted instantiation: HTTPInfo::object_key_get(ts::CryptoHash*) |
1628 | | |
1629 | | inline bool |
1630 | | HTTPInfo::compare_object_key(const CryptoHash *hash) |
1631 | 0 | { |
1632 | 0 | int32_t const *pi = reinterpret_cast<int32_t const *>(hash); |
1633 | 0 | return memcmp(pi, m_alt->m_object_key, CRYPTO_HASH_SIZE) == 0; |
1634 | 0 | } Unexecuted instantiation: HTTPInfo::compare_object_key(ts::CryptoHash const*) Unexecuted instantiation: HTTPInfo::compare_object_key(ts::CryptoHash const*) |
1635 | | |
1636 | | inline int64_t |
1637 | | HTTPInfo::object_size_get() |
1638 | 0 | { |
1639 | 0 | int64_t val = 0; // make gcc shut up. |
1640 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&val); |
1641 | 0 |
|
1642 | 0 | pi[0] = m_alt->m_object_size[0]; |
1643 | 0 | pi[1] = m_alt->m_object_size[1]; |
1644 | 0 | return val; |
1645 | 0 | } |
1646 | | |
1647 | | inline void |
1648 | | HTTPInfo::object_key_set(CryptoHash &hash) |
1649 | 0 | { |
1650 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&hash); |
1651 | 0 | memcpy(m_alt->m_object_key, pi, CRYPTO_HASH_SIZE); |
1652 | 0 | } Unexecuted instantiation: HTTPInfo::object_key_set(ts::CryptoHash&) Unexecuted instantiation: HTTPInfo::object_key_set(ts::CryptoHash&) |
1653 | | |
1654 | | inline void |
1655 | | HTTPInfo::object_size_set(int64_t size) |
1656 | 0 | { |
1657 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&size); |
1658 | 0 | m_alt->m_object_size[0] = pi[0]; |
1659 | 0 | m_alt->m_object_size[1] = pi[1]; |
1660 | 0 | } |
1661 | | |
1662 | | inline HTTPInfo::FragOffset * |
1663 | | HTTPInfo::get_frag_table() |
1664 | 0 | { |
1665 | 0 | return m_alt ? m_alt->m_frag_offsets : nullptr; |
1666 | 0 | } |
1667 | | |
1668 | | inline int |
1669 | | HTTPInfo::get_frag_offset_count() |
1670 | 0 | { |
1671 | 0 | return m_alt ? m_alt->m_frag_offset_count : 0; |
1672 | 0 | } |