/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_UNKNOWN = 'Z' |
166 | | }; |
167 | | |
168 | | // squid log subcodes |
169 | | enum class SquidSubcode { |
170 | | EMPTY = '0', |
171 | | NUM_REDIRECTIONS_EXCEEDED = '1', |
172 | | }; |
173 | | |
174 | | /* squid hierarchy codes */ |
175 | | enum class SquidHierarchyCode { |
176 | | EMPTY = '0', |
177 | | NONE = '1', |
178 | | DIRECT = '2', |
179 | | SIBLING_HIT = '3', |
180 | | PARENT_HIT = '4', |
181 | | DEFAULT_PARENT = '5', |
182 | | SINGLE_PARENT = '6', |
183 | | FIRST_UP_PARENT = '7', |
184 | | NO_PARENT_DIRECT = '8', |
185 | | FIRST_PARENT_MISS = '9', |
186 | | LOCAL_IP_DIRECT = 'a', |
187 | | FIREWALL_IP_DIRECT = 'b', |
188 | | NO_DIRECT_FAIL = 'c', |
189 | | SOURCE_FASTEST = 'd', |
190 | | SIBLING_UDP_HIT_OBJ = 'e', |
191 | | PARENT_UDP_HIT_OBJ = 'f', |
192 | | PASSTHROUGH_PARENT = 'g', |
193 | | SSL_PARENT_MISS = 'h', |
194 | | INVALID_CODE = 'i', |
195 | | TIMEOUT_DIRECT = 'j', |
196 | | TIMEOUT_SIBLING_HIT = 'k', |
197 | | TIMEOUT_PARENT_HIT = 'l', |
198 | | TIMEOUT_DEFAULT_PARENT = 'm', |
199 | | TIMEOUT_SINGLE_PARENT = 'n', |
200 | | TIMEOUT_FIRST_UP_PARENT = 'o', |
201 | | TIMEOUT_NO_PARENT_DIRECT = 'p', |
202 | | TIMEOUT_FIRST_PARENT_MISS = 'q', |
203 | | TIMEOUT_LOCAL_IP_DIRECT = 'r', |
204 | | TIMEOUT_FIREWALL_IP_DIRECT = 's', |
205 | | TIMEOUT_NO_DIRECT_FAIL = 't', |
206 | | TIMEOUT_SOURCE_FASTEST = 'u', |
207 | | TIMEOUT_SIBLING_UDP_HIT_OBJ = 'v', |
208 | | TIMEOUT_PARENT_UDP_HIT_OBJ = 'w', |
209 | | TIMEOUT_PASSTHROUGH_PARENT = 'x', |
210 | | TIMEOUT_TIMEOUT_SSL_PARENT_MISS = 'y', |
211 | | INVALID_ASSIGNED_CODE = 'z' |
212 | | }; |
213 | | |
214 | | /* squid hit/miss codes */ |
215 | | enum SquidHitMissCode { |
216 | | SQUID_HIT_RESERVED = '0', // Kinda wonky that this is '0', so skipping 'A' for now |
217 | | SQUID_HIT_LEVEL_1 = 'B', |
218 | | SQUID_HIT_LEVEL_2 = 'C', |
219 | | SQUID_HIT_LEVEL_3 = 'D', |
220 | | SQUID_HIT_LEVEL_4 = 'E', |
221 | | SQUID_HIT_LEVEL_5 = 'F', |
222 | | SQUID_HIT_LEVEL_6 = 'G', |
223 | | SQUID_HIT_LEVEL_7 = 'H', |
224 | | SQUID_HIT_LEVEL_8 = 'I', |
225 | | SQUID_HIT_LEVEl_9 = 'J', |
226 | | SQUID_MISS_NONE = '1', |
227 | | SQUID_MISS_HTTP_NON_CACHE = '3', |
228 | | SQUID_MISS_HTTP_NO_DLE = '5', |
229 | | SQUID_MISS_HTTP_NO_LE = '6', |
230 | | SQUID_MISS_HTTP_CONTENT = '7', |
231 | | SQUID_MISS_PRAGMA_NOCACHE = '8', |
232 | | SQUID_MISS_PASS = '9', |
233 | | SQUID_MISS_PRE_EXPIRED = 'a', |
234 | | SQUID_MISS_ERROR = 'b', |
235 | | SQUID_MISS_CACHE_BYPASS = 'c', |
236 | | SQUID_HIT_MISS_INVALID_ASSIGNED_CODE = 'z', |
237 | | // These are pre-allocated with special semantics, added here for convenience |
238 | | SQUID_HIT_RAM = SQUID_HIT_LEVEL_1, |
239 | | SQUID_HIT_SSD = SQUID_HIT_LEVEL_2, |
240 | | SQUID_HIT_DISK = SQUID_HIT_LEVEL_3, |
241 | | SQUID_HIT_CLUSTER = SQUID_HIT_LEVEL_4, |
242 | | SQUID_HIT_NET = SQUID_HIT_LEVEL_5, |
243 | | SQUID_HIT_RWW = SQUID_HIT_LEVEL_6 |
244 | | }; |
245 | | |
246 | | constexpr std::string_view PSEUDO_HEADER_SCHEME = ":scheme"; |
247 | | constexpr std::string_view PSEUDO_HEADER_AUTHORITY = ":authority"; |
248 | | constexpr std::string_view PSEUDO_HEADER_PATH = ":path"; |
249 | | constexpr std::string_view PSEUDO_HEADER_METHOD = ":method"; |
250 | | constexpr std::string_view PSEUDO_HEADER_STATUS = ":status"; |
251 | | |
252 | | enum class HTTPType { |
253 | | UNKNOWN, |
254 | | REQUEST, |
255 | | RESPONSE, |
256 | | }; |
257 | | |
258 | | struct HTTPHdrImpl : public HdrHeapObjImpl { |
259 | | // HdrHeapObjImpl is 4 bytes |
260 | | HTTPType m_polarity; // request or response or unknown |
261 | | HTTPVersion m_version; // cooked version number |
262 | | // 12 bytes means 4 bytes padding here on 64-bit architectures |
263 | | union { |
264 | | struct { |
265 | | URLImpl *m_url_impl; |
266 | | const char *m_ptr_method; |
267 | | uint16_t m_len_method; |
268 | | int16_t m_method_wks_idx; |
269 | | } req; |
270 | | |
271 | | struct { |
272 | | const char *m_ptr_reason; |
273 | | uint16_t m_len_reason; |
274 | | int16_t m_status; |
275 | | } resp; |
276 | | } u; |
277 | | |
278 | | MIMEHdrImpl *m_fields_impl; |
279 | | |
280 | | // Marshaling Functions |
281 | | int marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str); |
282 | | void unmarshal(intptr_t offset); |
283 | | void move_strings(HdrStrHeap *new_heap); |
284 | | size_t strings_length(); |
285 | | |
286 | | // Sanity Check Functions |
287 | | void check_strings(HeapCheck *heaps, int num_heaps); |
288 | | }; |
289 | | |
290 | | struct HTTPValAccept { |
291 | | char *type; |
292 | | char *subtype; |
293 | | double qvalue; |
294 | | }; |
295 | | |
296 | | struct HTTPValAcceptCharset { |
297 | | char *charset; |
298 | | double qvalue; |
299 | | }; |
300 | | |
301 | | struct HTTPValAcceptEncoding { |
302 | | char *encoding; |
303 | | double qvalue; |
304 | | }; |
305 | | |
306 | | struct HTTPValAcceptLanguage { |
307 | | char *language; |
308 | | double qvalue; |
309 | | }; |
310 | | |
311 | | struct HTTPValFieldList { |
312 | | char *name; |
313 | | HTTPValFieldList *next; |
314 | | }; |
315 | | |
316 | | struct HTTPValCacheControl { |
317 | | const char *directive; |
318 | | |
319 | | union { |
320 | | int delta_seconds; |
321 | | HTTPValFieldList *field_names; |
322 | | } u; |
323 | | }; |
324 | | |
325 | | struct HTTPValRange { |
326 | | int start; |
327 | | int end; |
328 | | HTTPValRange *next; |
329 | | }; |
330 | | |
331 | | struct HTTPValTE { |
332 | | char *encoding; |
333 | | double qvalue; |
334 | | }; |
335 | | |
336 | | struct HTTPParser { |
337 | | bool m_parsing_http = false; |
338 | | MIMEParser m_mime_parser; |
339 | | }; |
340 | | |
341 | | extern c_str_view HTTP_METHOD_CONNECT; |
342 | | extern c_str_view HTTP_METHOD_DELETE; |
343 | | extern c_str_view HTTP_METHOD_GET; |
344 | | extern c_str_view HTTP_METHOD_HEAD; |
345 | | extern c_str_view HTTP_METHOD_OPTIONS; |
346 | | extern c_str_view HTTP_METHOD_POST; |
347 | | extern c_str_view HTTP_METHOD_PURGE; |
348 | | extern c_str_view HTTP_METHOD_PUT; |
349 | | extern c_str_view HTTP_METHOD_TRACE; |
350 | | extern c_str_view HTTP_METHOD_PUSH; |
351 | | |
352 | | extern int HTTP_WKSIDX_CONNECT; |
353 | | extern int HTTP_WKSIDX_DELETE; |
354 | | extern int HTTP_WKSIDX_GET; |
355 | | extern int HTTP_WKSIDX_HEAD; |
356 | | extern int HTTP_WKSIDX_OPTIONS; |
357 | | extern int HTTP_WKSIDX_POST; |
358 | | extern int HTTP_WKSIDX_PURGE; |
359 | | extern int HTTP_WKSIDX_PUT; |
360 | | extern int HTTP_WKSIDX_TRACE; |
361 | | extern int HTTP_WKSIDX_PUSH; |
362 | | extern int HTTP_WKSIDX_METHODS_CNT; |
363 | | |
364 | | extern c_str_view HTTP_VALUE_BYTES; |
365 | | extern c_str_view HTTP_VALUE_CHUNKED; |
366 | | extern c_str_view HTTP_VALUE_CLOSE; |
367 | | extern c_str_view HTTP_VALUE_COMPRESS; |
368 | | extern c_str_view HTTP_VALUE_DEFLATE; |
369 | | extern c_str_view HTTP_VALUE_GZIP; |
370 | | extern c_str_view HTTP_VALUE_BROTLI; |
371 | | extern c_str_view HTTP_VALUE_ZSTD; |
372 | | extern c_str_view HTTP_VALUE_IDENTITY; |
373 | | extern c_str_view HTTP_VALUE_KEEP_ALIVE; |
374 | | extern c_str_view HTTP_VALUE_MAX_AGE; |
375 | | extern c_str_view HTTP_VALUE_MAX_STALE; |
376 | | extern c_str_view HTTP_VALUE_MIN_FRESH; |
377 | | extern c_str_view HTTP_VALUE_MUST_REVALIDATE; |
378 | | extern c_str_view HTTP_VALUE_NONE; |
379 | | extern c_str_view HTTP_VALUE_NO_CACHE; |
380 | | extern c_str_view HTTP_VALUE_NO_STORE; |
381 | | extern c_str_view HTTP_VALUE_NO_TRANSFORM; |
382 | | extern c_str_view HTTP_VALUE_ONLY_IF_CACHED; |
383 | | extern c_str_view HTTP_VALUE_PRIVATE; |
384 | | extern c_str_view HTTP_VALUE_PROXY_REVALIDATE; |
385 | | extern c_str_view HTTP_VALUE_PUBLIC; |
386 | | extern c_str_view HTTP_VALUE_S_MAXAGE; |
387 | | extern c_str_view HTTP_VALUE_NEED_REVALIDATE_ONCE; |
388 | | extern c_str_view HTTP_VALUE_100_CONTINUE; |
389 | | |
390 | | /* Private */ |
391 | | void http_hdr_adjust(HTTPHdrImpl *hdrp, int32_t offset, int32_t length, int32_t delta); |
392 | | |
393 | | /* Public */ |
394 | | void http_init(); |
395 | | |
396 | | HTTPHdrImpl *http_hdr_create(HdrHeap *heap, HTTPType polarity, HTTPVersion version); |
397 | | void http_hdr_init(HdrHeap *heap, HTTPHdrImpl *hh, HTTPType polarity, HTTPVersion version); |
398 | | HTTPHdrImpl *http_hdr_clone(HTTPHdrImpl *s_hh, HdrHeap *s_heap, HdrHeap *d_heap); |
399 | | void http_hdr_copy_onto(HTTPHdrImpl *s_hh, HdrHeap *s_heap, HTTPHdrImpl *d_hh, HdrHeap *d_heap, bool inherit_strs); |
400 | | |
401 | | int http_hdr_print(HTTPHdrImpl const *hh, char *buf, int bufsize, int *bufindex, int *dumpoffset); |
402 | | |
403 | | void http_hdr_describe(HdrHeapObjImpl *obj, bool recurse = true); |
404 | | |
405 | | bool http_hdr_version_set(HTTPHdrImpl *hh, const HTTPVersion &ver); |
406 | | |
407 | | std::string_view http_hdr_method_get(HTTPHdrImpl *hh); |
408 | | void http_hdr_method_set(HdrHeap *heap, HTTPHdrImpl *hh, std::string_view method, int16_t method_wks_idx, bool must_copy); |
409 | | |
410 | | void http_hdr_url_set(HdrHeap *heap, HTTPHdrImpl *hh, URLImpl *url); |
411 | | |
412 | | // HTTPStatus http_hdr_status_get (HTTPHdrImpl *hh); |
413 | | void http_hdr_status_set(HTTPHdrImpl *hh, HTTPStatus status); |
414 | | std::string_view http_hdr_reason_get(HTTPHdrImpl *hh); |
415 | | void http_hdr_reason_set(HdrHeap *heap, HTTPHdrImpl *hh, std::string_view value, bool must_copy); |
416 | | const char *http_hdr_reason_lookup(HTTPStatus status); |
417 | | |
418 | | void http_parser_init(HTTPParser *parser); |
419 | | void http_parser_clear(HTTPParser *parser); |
420 | | ParseResult http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end, |
421 | | bool must_copy_strings, bool eof, int strict_uri_parsing, size_t max_request_line_size, |
422 | | size_t max_hdr_field_size); |
423 | | ParseResult validate_hdr_request_target(int method_wks_idx, URLImpl *url); |
424 | | ParseResult validate_hdr_host(HTTPHdrImpl *hh); |
425 | | ParseResult validate_hdr_content_length(HdrHeap *heap, HTTPHdrImpl *hh); |
426 | | ParseResult http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end, |
427 | | bool must_copy_strings, bool eof); |
428 | | |
429 | | HTTPStatus http_parse_status(const char *start, const char *end); |
430 | | HTTPVersion http_parse_version(const char *start, const char *end); |
431 | | |
432 | | /* |
433 | | HTTPValAccept* http_parse_accept (const char *buf, Arena *arena); |
434 | | HTTPValAcceptCharset* http_parse_accept_charset (const char *buf, Arena *arena); |
435 | | HTTPValAcceptEncoding* http_parse_accept_encoding (const char *buf, Arena *arena); |
436 | | HTTPValAcceptLanguage* http_parse_accept_language (const char *buf, Arena *arena); |
437 | | HTTPValCacheControl* http_parse_cache_control (const char *buf, Arena *arena); |
438 | | const char* http_parse_cache_directive (const char **buf); |
439 | | HTTPValRange* http_parse_range (const char *buf, Arena *arena); |
440 | | */ |
441 | | HTTPValTE *http_parse_te(const char *buf, int len, Arena *arena); |
442 | | |
443 | | bool is_http1_hdr_version_supported(const HTTPVersion &http_version); |
444 | | |
445 | | class IOBufferReader; |
446 | | |
447 | | /** HTTP Header class. |
448 | | * |
449 | | * @warning Changing the size of this class (adding/removing fields) will change |
450 | | * the on-disk cache format and cause cache incompatibility. The HTTPCacheAlt |
451 | | * structure contains embedded HTTPHdr objects, and the cache marshalling code |
452 | | * uses sizeof(HTTPCacheAlt) to read/write cache entries. Any size change will |
453 | | * cause "vector inconsistency" errors when reading cache entries written by a |
454 | | * different version. |
455 | | */ |
456 | | class HTTPHdr : public MIMEHdr |
457 | | { |
458 | | public: |
459 | | HTTPHdrImpl *m_http = nullptr; |
460 | | mutable URL m_url_cached; |
461 | | mutable MIMEField *m_host_mime = nullptr; |
462 | | mutable int m_host_length = 0; ///< Length of hostname (parsed, excludes port). |
463 | | mutable int m_port = 0; ///< Target port. |
464 | | mutable bool m_target_cached = false; ///< Whether host name and port are cached. |
465 | | mutable bool m_target_in_url = false; ///< Whether host name and port are in the URL. |
466 | | mutable bool m_100_continue_sent = false; ///< Whether ATS sent a 100 Continue optimized response. |
467 | | mutable bool m_100_continue_required = false; ///< Whether 100_continue is in the Expect header. |
468 | | /// Set if the port was effectively specified in the header. |
469 | | /// @c true if the target (in the URL or the HOST field) also specified |
470 | | /// a port. That is, @c true if whatever source had the target host |
471 | | /// also had a port, @c false otherwise. |
472 | | mutable bool m_port_in_header = false; |
473 | | |
474 | | mutable bool early_data = false; |
475 | | |
476 | 18.7k | HTTPHdr() = default; // Force the creation of the default constructor |
477 | | |
478 | | int valid() const; |
479 | | |
480 | | void create(HTTPType polarity, HTTPVersion version = HTTP_INVALID, HdrHeap *heap = nullptr); |
481 | | void clear(); |
482 | | void reset(); |
483 | | void copy(const HTTPHdr *hdr); |
484 | | void copy_shallow(const HTTPHdr *hdr); |
485 | | |
486 | | int unmarshal(char *buf, int len, RefCountObj *block_ref); |
487 | | |
488 | | int print(char *buf, int bufsize, int *bufindex, int *dumpoffset) const; |
489 | | |
490 | | int length_get() const; |
491 | | |
492 | | HTTPType type_get() const; |
493 | | |
494 | | HTTPVersion version_get() const; |
495 | | void version_set(HTTPVersion version); |
496 | | |
497 | | std::string_view method_get(); |
498 | | int method_get_wksidx() const; |
499 | | void method_set(std::string_view value); |
500 | | |
501 | | URL *url_create(URL *url); |
502 | | |
503 | | URL *url_get() const; |
504 | | URL *url_get(URL *url); |
505 | | /** Get a string with the effective URL in it. |
506 | | If @a length is not @c NULL then the length of the string |
507 | | is stored in the int pointed to by @a length. |
508 | | |
509 | | Note that this can be different from getting the @c URL |
510 | | and invoking @c URL::string_get if the host is in a header |
511 | | field and not explicitly in the URL. |
512 | | */ |
513 | | char *url_string_get(Arena *arena = nullptr, ///< Arena to use, or @c malloc if NULL. |
514 | | int *length = nullptr ///< Store string length here. |
515 | | ); |
516 | | /** Get a string with the effective URL in it. |
517 | | This is automatically allocated if needed in the request heap. |
518 | | |
519 | | @see url_string_get |
520 | | */ |
521 | | char *url_string_get_ref(int *length = nullptr ///< Store string length here. |
522 | | ); |
523 | | |
524 | | /** Print the URL. |
525 | | Output is not null terminated. |
526 | | @return 0 on failure, non-zero on success. |
527 | | */ |
528 | | int url_print(char *buff, ///< Output buffer |
529 | | int length, ///< Length of @a buffer |
530 | | int *offset, ///< [in,out] ??? |
531 | | int *skip, ///< [in,out] ??? |
532 | | unsigned normalization_flags = URLNormalize::NONE ///< host/scheme normalized to lower case |
533 | | ); |
534 | | |
535 | | /** Return the length of the URL that url_print() will create. |
536 | | @return -1 on failure, non-negative on success. |
537 | | */ |
538 | | int url_printed_length(unsigned normalizaion_flags = URLNormalize::NONE); |
539 | | |
540 | | /** Get the URL path. |
541 | | This is a reference, not allocated. |
542 | | @return A string_view to the path or an empty string_view if there is no valid URL. |
543 | | */ |
544 | | std::string_view path_get(); |
545 | | |
546 | | /** Get the URL query. |
547 | | This is a reference, not allocated. |
548 | | @return A string_view to the query or an empty string_view if there is no valid URL. |
549 | | */ |
550 | | std::string_view query_get(); |
551 | | |
552 | | /** Get the URL fragment. |
553 | | This is a reference, not allocated. |
554 | | @return A string_view to the fragment or an empty string_view if there is no valid URL. |
555 | | */ |
556 | | std::string_view fragment_get(); |
557 | | |
558 | | /** Get the target host name. |
559 | | The length is returned in @a length if non-NULL. |
560 | | @note The results are cached so this is fast after the first call. |
561 | | @return A string_view to the host name. |
562 | | */ |
563 | | std::string_view host_get() const; |
564 | | |
565 | | /** Get the target port. |
566 | | If the target port is not found then it is adjusted to the |
567 | | default port for the URL type. |
568 | | @note The results are cached so this is fast after the first call. |
569 | | @return The canonicalized target port. |
570 | | */ |
571 | | int port_get(); |
572 | | |
573 | | /** Get the URL scheme. |
574 | | This is a reference, not allocated. |
575 | | @return A string_view to the scheme or an empty string_view if there is no valid URL. |
576 | | */ |
577 | | std::string_view scheme_get(); |
578 | | void url_set(URL *url); |
579 | | void url_set(std::string_view value); |
580 | | |
581 | | /// Check location of target host. |
582 | | /// @return @c true if the host was in the URL, @c false otherwise. |
583 | | /// @note This returns @c false if the host is missing. |
584 | | bool is_target_in_url() const; |
585 | | |
586 | | /// Check if a port was specified in the target. |
587 | | /// @return @c true if the port was part of the target. |
588 | | bool is_port_in_header() const; |
589 | | |
590 | | /// If the target is in the fields and not the URL, copy it to the @a url. |
591 | | /// If @a url is @c NULL the cached URL in this header is used. |
592 | | /// @note In the default case the copy is avoided if the cached URL already |
593 | | /// has the target. If @a url is non @c NULL the copy is always performed. |
594 | | void set_url_target_from_host_field(URL *url = nullptr); |
595 | | |
596 | | /// Mark the target cache as invalid. |
597 | | /// @internal Ugly but too many places currently that touch the |
598 | | /// header internals, they must be able to do this. |
599 | | void mark_target_dirty() const; |
600 | | |
601 | | HTTPStatus status_get() const; |
602 | | void status_set(HTTPStatus status); |
603 | | |
604 | | std::string_view reason_get(); |
605 | | void reason_set(std::string_view value); |
606 | | |
607 | | void mark_early_data(bool flag = true) const; |
608 | | bool is_early_data() const; |
609 | | |
610 | | ParseResult parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, int strict_uri_parsing = 0, |
611 | | size_t max_request_line_size = UINT16_MAX, size_t max_hdr_field_size = 131070); |
612 | | ParseResult parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof); |
613 | | |
614 | | ParseResult parse_req(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof, int strict_uri_parsing = 0, |
615 | | size_t max_request_line_size = UINT16_MAX, size_t max_hdr_field_size = UINT16_MAX); |
616 | | ParseResult parse_resp(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof); |
617 | | |
618 | | bool check_hdr_implements(); |
619 | | |
620 | | public: |
621 | | // Utility routines |
622 | | bool is_cache_control_set(const char *cc_directive_wks); |
623 | | bool is_pragma_no_cache_set(); |
624 | | bool is_keep_alive_set() const; |
625 | | bool expect_final_response() const; |
626 | | HTTPKeepAlive keep_alive_get() const; |
627 | | |
628 | | protected: |
629 | | /** Load the target cache. |
630 | | @see m_host, m_port, m_target_in_url |
631 | | */ |
632 | | void _fill_target_cache() const; |
633 | | /** Test the cache and fill it if necessary. |
634 | | @internal In contrast to @c _fill_target_cache, this method |
635 | | is inline and checks whether the cache is already filled. |
636 | | @ _fill_target_cache @b always does a cache fill. |
637 | | */ |
638 | | void _test_and_fill_target_cache() const; |
639 | | |
640 | | static Arena *const USE_HDR_HEAP_MAGIC; |
641 | | |
642 | | // No gratuitous copies! |
643 | | HTTPHdr(const HTTPHdr &m) = delete; |
644 | | HTTPHdr &operator=(const HTTPHdr &m) = delete; |
645 | | |
646 | | private: |
647 | | friend class UrlPrintHack; // don't ask. |
648 | | }; |
649 | | |
650 | | /*------------------------------------------------------------------------- |
651 | | -------------------------------------------------------------------------*/ |
652 | | |
653 | | inline int |
654 | | HTTPHdr::valid() const |
655 | 18.7k | { |
656 | 18.7k | return (m_http && m_mime && m_heap); |
657 | 18.7k | } |
658 | | |
659 | | /*------------------------------------------------------------------------- |
660 | | -------------------------------------------------------------------------*/ |
661 | | |
662 | | inline void |
663 | | HTTPHdr::create(HTTPType polarity, HTTPVersion version, HdrHeap *heap) |
664 | 18.7k | { |
665 | 18.7k | if (heap) { |
666 | 0 | m_heap = heap; |
667 | 18.7k | } else if (!m_heap) { |
668 | 18.7k | m_heap = new_HdrHeap(); |
669 | 18.7k | } |
670 | | |
671 | 18.7k | m_http = http_hdr_create(m_heap, polarity, version); |
672 | 18.7k | m_mime = m_http->m_fields_impl; |
673 | 18.7k | } |
674 | | |
675 | | inline void |
676 | | HTTPHdr::clear() |
677 | 0 | { |
678 | 0 | if (m_http && m_http->m_polarity == HTTPType::REQUEST) { |
679 | 0 | m_url_cached.clear(); |
680 | 0 | } |
681 | 0 | this->HdrHeapSDKHandle::clear(); |
682 | 0 | m_http = nullptr; |
683 | 0 | m_mime = nullptr; |
684 | 0 | } |
685 | | |
686 | | inline void |
687 | | HTTPHdr::reset() |
688 | 0 | { |
689 | 0 | m_heap = nullptr; |
690 | 0 | m_http = nullptr; |
691 | 0 | m_mime = nullptr; |
692 | 0 | m_url_cached.reset(); |
693 | 0 | } |
694 | | |
695 | | /*------------------------------------------------------------------------- |
696 | | -------------------------------------------------------------------------*/ |
697 | | |
698 | | inline void |
699 | | HTTPHdr::copy(const HTTPHdr *hdr) |
700 | 0 | { |
701 | 0 | ink_assert(hdr->valid()); |
702 | |
|
703 | 0 | if (valid()) { |
704 | 0 | http_hdr_copy_onto(hdr->m_http, hdr->m_heap, m_http, m_heap, (m_heap != hdr->m_heap) ? true : false); |
705 | 0 | } else { |
706 | 0 | m_heap = new_HdrHeap(); |
707 | 0 | m_http = http_hdr_clone(hdr->m_http, hdr->m_heap, m_heap); |
708 | 0 | m_mime = m_http->m_fields_impl; |
709 | 0 | } |
710 | 0 | } |
711 | | |
712 | | /*------------------------------------------------------------------------- |
713 | | -------------------------------------------------------------------------*/ |
714 | | |
715 | | inline void |
716 | | HTTPHdr::copy_shallow(const HTTPHdr *hdr) |
717 | 0 | { |
718 | 0 | ink_assert(hdr->valid()); |
719 | 0 |
|
720 | 0 | m_heap = hdr->m_heap; |
721 | 0 | m_http = hdr->m_http; |
722 | 0 | m_mime = hdr->m_mime; |
723 | 0 |
|
724 | 0 | if (hdr->type_get() == HTTPType::REQUEST && m_url_cached.valid()) |
725 | 0 | m_url_cached.copy_shallow(&hdr->m_url_cached); |
726 | 0 | } |
727 | | |
728 | | /*------------------------------------------------------------------------- |
729 | | -------------------------------------------------------------------------*/ |
730 | | |
731 | | inline int |
732 | | HTTPHdr::print(char *buf, int bufsize, int *bufindex, int *dumpoffset) const |
733 | 0 | { |
734 | 0 | ink_assert(valid()); |
735 | 0 | return http_hdr_print(m_http, buf, bufsize, bufindex, dumpoffset); |
736 | 0 | } |
737 | | |
738 | | /*------------------------------------------------------------------------- |
739 | | -------------------------------------------------------------------------*/ |
740 | | |
741 | | inline void |
742 | | HTTPHdr::_test_and_fill_target_cache() const |
743 | 0 | { |
744 | 0 | if (!m_target_cached) { |
745 | 0 | this->_fill_target_cache(); |
746 | 0 | return; |
747 | 0 | } |
748 | | |
749 | | // If host came from the Host header (not URL), check for staleness by verifying |
750 | | // the current Host header value length matches what we expect from cached values. |
751 | 0 | if (!m_target_in_url && m_host_mime != nullptr) { |
752 | 0 | int expected_len = m_host_length; |
753 | 0 | if (m_port_in_header && m_port > 0) { |
754 | | // Account for ":port" suffix in the raw Host header value. |
755 | 0 | expected_len += 1; // colon |
756 | 0 | if (m_port < 10) { |
757 | 0 | expected_len += 1; |
758 | 0 | } else if (m_port < 100) { |
759 | 0 | expected_len += 2; |
760 | 0 | } else if (m_port < 1000) { |
761 | 0 | expected_len += 3; |
762 | 0 | } else if (m_port < 10000) { |
763 | 0 | expected_len += 4; |
764 | 0 | } else { |
765 | 0 | expected_len += 5; |
766 | 0 | } |
767 | 0 | } |
768 | 0 | if (m_host_mime->m_len_value != expected_len) { |
769 | 0 | this->_fill_target_cache(); |
770 | 0 | } |
771 | 0 | } |
772 | 0 | } |
773 | | |
774 | | /*------------------------------------------------------------------------- |
775 | | -------------------------------------------------------------------------*/ |
776 | | |
777 | | inline std::string_view |
778 | | HTTPHdr::host_get() const |
779 | 0 | { |
780 | 0 | this->_test_and_fill_target_cache(); |
781 | 0 | if (m_target_in_url) { |
782 | 0 | return url_get()->host_get(); |
783 | 0 | } else if (m_host_mime) { |
784 | 0 | return std::string_view{m_host_mime->m_ptr_value, static_cast<std::string_view::size_type>(m_host_length)}; |
785 | 0 | } |
786 | | |
787 | 0 | return std::string_view{}; |
788 | 0 | } |
789 | | |
790 | | /*------------------------------------------------------------------------- |
791 | | -------------------------------------------------------------------------*/ |
792 | | |
793 | | inline int |
794 | | HTTPHdr::port_get() |
795 | 0 | { |
796 | 0 | this->_test_and_fill_target_cache(); |
797 | 0 | return m_port; |
798 | 0 | } |
799 | | |
800 | | /*------------------------------------------------------------------------- |
801 | | -------------------------------------------------------------------------*/ |
802 | | |
803 | | inline bool |
804 | | HTTPHdr::is_target_in_url() const |
805 | 0 | { |
806 | 0 | this->_test_and_fill_target_cache(); |
807 | 0 | return m_target_in_url; |
808 | 0 | } |
809 | | |
810 | | /*------------------------------------------------------------------------- |
811 | | -------------------------------------------------------------------------*/ |
812 | | |
813 | | inline bool |
814 | | HTTPHdr::is_port_in_header() const |
815 | 0 | { |
816 | 0 | this->_test_and_fill_target_cache(); |
817 | 0 | return m_port_in_header; |
818 | 0 | } |
819 | | |
820 | | /*------------------------------------------------------------------------- |
821 | | -------------------------------------------------------------------------*/ |
822 | | |
823 | | inline void |
824 | | HTTPHdr::mark_target_dirty() const |
825 | 0 | { |
826 | 0 | m_target_cached = false; |
827 | 0 | } |
828 | | /*------------------------------------------------------------------------- |
829 | | -------------------------------------------------------------------------*/ |
830 | | |
831 | | inline HTTPType |
832 | | http_hdr_type_get(HTTPHdrImpl *hh) |
833 | 0 | { |
834 | 0 | return (hh->m_polarity); |
835 | 0 | } |
836 | | |
837 | | /*------------------------------------------------------------------------- |
838 | | -------------------------------------------------------------------------*/ |
839 | | |
840 | | inline HTTPType |
841 | | HTTPHdr::type_get() const |
842 | 0 | { |
843 | 0 | ink_assert(valid()); |
844 | 0 | return http_hdr_type_get(m_http); |
845 | 0 | } |
846 | | |
847 | | /*------------------------------------------------------------------------- |
848 | | -------------------------------------------------------------------------*/ |
849 | | |
850 | | inline HTTPVersion |
851 | | HTTPHdr::version_get() const |
852 | 0 | { |
853 | 0 | ink_assert(valid()); |
854 | 0 | return m_http->m_version; |
855 | 0 | } |
856 | | |
857 | | /*------------------------------------------------------------------------- |
858 | | -------------------------------------------------------------------------*/ |
859 | | |
860 | | inline static HTTPKeepAlive |
861 | | is_header_keep_alive(const HTTPVersion &http_version, const MIMEField *con_hdr) |
862 | 0 | { |
863 | 0 | enum class ConToken { |
864 | 0 | NONE = 0, |
865 | 0 | KEEP_ALIVE, |
866 | 0 | CLOSE, |
867 | 0 | }; |
868 | 0 |
|
869 | 0 | auto con_token = ConToken::NONE; |
870 | 0 | HTTPKeepAlive keep_alive = HTTPKeepAlive::NO_KEEPALIVE; |
871 | 0 | // *unknown_tokens = false; |
872 | 0 |
|
873 | 0 | if (con_hdr) { |
874 | 0 | if (con_hdr->value_get_index("keep-alive"sv) >= 0) |
875 | 0 | con_token = ConToken::KEEP_ALIVE; |
876 | 0 | else if (con_hdr->value_get_index("close"sv) >= 0) |
877 | 0 | con_token = ConToken::CLOSE; |
878 | 0 | } |
879 | 0 |
|
880 | 0 | if (HTTP_1_0 == http_version) { |
881 | 0 | keep_alive = (con_token == ConToken::KEEP_ALIVE) ? (HTTPKeepAlive::KEEPALIVE) : (HTTPKeepAlive::NO_KEEPALIVE); |
882 | 0 | } else if (HTTP_1_1 == http_version) { |
883 | 0 | // We deviate from the spec here. If the we got a response where |
884 | 0 | // where there is no Connection header and the request 1.0 was |
885 | 0 | // 1.0 don't treat this as keep-alive since Netscape-Enterprise/3.6 SP1 |
886 | 0 | // server doesn't |
887 | 0 | keep_alive = ((con_token == ConToken::KEEP_ALIVE) || (con_token == ConToken::NONE && HTTP_1_1 == http_version)) ? |
888 | 0 | (HTTPKeepAlive::KEEPALIVE) : |
889 | 0 | (HTTPKeepAlive::NO_KEEPALIVE); |
890 | 0 | } else { |
891 | 0 | keep_alive = HTTPKeepAlive::NO_KEEPALIVE; |
892 | 0 | } |
893 | 0 | return (keep_alive); |
894 | 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: HdrToken.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*) |
895 | | |
896 | | inline HTTPKeepAlive |
897 | | HTTPHdr::keep_alive_get() const |
898 | 0 | { |
899 | 0 | HTTPKeepAlive retval = HTTPKeepAlive::NO_KEEPALIVE; |
900 | 0 | const MIMEField *pc = this->field_find(static_cast<std::string_view>(MIME_FIELD_PROXY_CONNECTION)); |
901 | 0 | if (pc != nullptr) { |
902 | 0 | retval = is_header_keep_alive(this->version_get(), pc); |
903 | 0 | } else { |
904 | 0 | const MIMEField *c = this->field_find(static_cast<std::string_view>(MIME_FIELD_CONNECTION)); |
905 | 0 | retval = is_header_keep_alive(this->version_get(), c); |
906 | 0 | } |
907 | 0 | return retval; |
908 | 0 | } |
909 | | |
910 | | inline bool |
911 | | HTTPHdr::is_keep_alive_set() const |
912 | 0 | { |
913 | 0 | return this->keep_alive_get() == HTTPKeepAlive::KEEPALIVE; |
914 | 0 | } |
915 | | |
916 | | /** |
917 | | Check the status code is informational and expecting final response |
918 | | - e.g. "100 Continue", "103 Early Hints" |
919 | | |
920 | | Please note that "101 Switching Protocol" is not included. |
921 | | */ |
922 | | inline bool |
923 | | HTTPHdr::expect_final_response() const |
924 | 0 | { |
925 | 0 | switch (this->status_get()) { |
926 | 0 | case HTTPStatus::CONTINUE: |
927 | 0 | case HTTPStatus::EARLY_HINTS: |
928 | 0 | return true; |
929 | 0 | default: |
930 | 0 | return false; |
931 | 0 | } |
932 | 0 | } |
933 | | |
934 | | /*------------------------------------------------------------------------- |
935 | | -------------------------------------------------------------------------*/ |
936 | | |
937 | | inline void |
938 | | HTTPHdr::version_set(HTTPVersion version) |
939 | 0 | { |
940 | 0 | ink_assert(valid()); |
941 | 0 | http_hdr_version_set(m_http, version); |
942 | 0 | } Unexecuted instantiation: HTTPHdr::version_set(HTTPVersion) Unexecuted instantiation: HTTPHdr::version_set(HTTPVersion) |
943 | | |
944 | | /*------------------------------------------------------------------------- |
945 | | -------------------------------------------------------------------------*/ |
946 | | |
947 | | inline std::string_view |
948 | | HTTPHdr::method_get() |
949 | 0 | { |
950 | 0 | ink_assert(valid()); |
951 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
952 | |
|
953 | 0 | return http_hdr_method_get(m_http); |
954 | 0 | } Unexecuted instantiation: HTTPHdr::method_get() Unexecuted instantiation: HTTPHdr::method_get() |
955 | | |
956 | | inline int |
957 | | HTTPHdr::method_get_wksidx() const |
958 | 0 | { |
959 | 0 | ink_assert(valid()); |
960 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
961 | 0 |
|
962 | 0 | return (m_http->u.req.m_method_wks_idx); |
963 | 0 | } |
964 | | |
965 | | /*------------------------------------------------------------------------- |
966 | | -------------------------------------------------------------------------*/ |
967 | | |
968 | | inline void |
969 | | HTTPHdr::method_set(std::string_view value) |
970 | 0 | { |
971 | 0 | ink_assert(valid()); |
972 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
973 | |
|
974 | 0 | int method_wks_idx = hdrtoken_tokenize(value.data(), static_cast<int>(value.length())); |
975 | 0 | http_hdr_method_set(m_heap, m_http, value, method_wks_idx, true); |
976 | 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> >) |
977 | | |
978 | | /*------------------------------------------------------------------------- |
979 | | -------------------------------------------------------------------------*/ |
980 | | |
981 | | inline URL * |
982 | | HTTPHdr::url_create(URL *u) |
983 | 0 | { |
984 | 0 | ink_assert(valid()); |
985 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
986 | 0 |
|
987 | 0 | u->set(this); |
988 | 0 | u->create(m_heap); |
989 | 0 | return (u); |
990 | 0 | } |
991 | | |
992 | | /*------------------------------------------------------------------------- |
993 | | -------------------------------------------------------------------------*/ |
994 | | |
995 | | inline URL * |
996 | | HTTPHdr::url_get() const |
997 | 0 | { |
998 | 0 | ink_assert(valid()); |
999 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1000 | | |
1001 | | // It's entirely possible that someone changed URL in our impl |
1002 | | // without updating the cached copy in the C++ layer. Check |
1003 | | // to see if this happened before handing back the url |
1004 | |
|
1005 | 0 | URLImpl *real_impl = m_http->u.req.m_url_impl; |
1006 | 0 | if (m_url_cached.m_url_impl != real_impl) { |
1007 | 0 | m_url_cached.set(this); |
1008 | 0 | m_url_cached.m_url_impl = real_impl; |
1009 | 0 | this->mark_target_dirty(); |
1010 | 0 | } |
1011 | 0 | return (&m_url_cached); |
1012 | 0 | } |
1013 | | |
1014 | | /*------------------------------------------------------------------------- |
1015 | | -------------------------------------------------------------------------*/ |
1016 | | |
1017 | | inline URL * |
1018 | | HTTPHdr::url_get(URL *url) |
1019 | 0 | { |
1020 | 0 | ink_assert(valid()); |
1021 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1022 | 0 |
|
1023 | 0 | url->set(this); // attach refcount |
1024 | 0 | url->m_url_impl = m_http->u.req.m_url_impl; |
1025 | 0 | return (url); |
1026 | 0 | } |
1027 | | |
1028 | | /*------------------------------------------------------------------------- |
1029 | | -------------------------------------------------------------------------*/ |
1030 | | |
1031 | | inline void |
1032 | | HTTPHdr::url_set(URL *url) |
1033 | 0 | { |
1034 | 0 | ink_assert(valid()); |
1035 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1036 | 0 |
|
1037 | 0 | URLImpl *url_impl = m_http->u.req.m_url_impl; |
1038 | 0 | ::url_copy_onto(url->m_url_impl, url->m_heap, url_impl, m_heap, true); |
1039 | 0 | } |
1040 | | |
1041 | | /*------------------------------------------------------------------------- |
1042 | | -------------------------------------------------------------------------*/ |
1043 | | |
1044 | | inline void |
1045 | | HTTPHdr::url_set(std::string_view value) |
1046 | 0 | { |
1047 | 0 | URLImpl *url_impl; |
1048 | 0 |
|
1049 | 0 | ink_assert(valid()); |
1050 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1051 | 0 |
|
1052 | 0 | url_impl = m_http->u.req.m_url_impl; |
1053 | 0 | ::url_clear(url_impl); |
1054 | 0 | const char *str{value.data()}; |
1055 | 0 | ::url_parse(m_heap, url_impl, &str, str + value.length(), true); |
1056 | 0 | } |
1057 | | |
1058 | | /*------------------------------------------------------------------------- |
1059 | | -------------------------------------------------------------------------*/ |
1060 | | |
1061 | | inline HTTPStatus |
1062 | | http_hdr_status_get(HTTPHdrImpl const *hh) |
1063 | 0 | { |
1064 | 0 | ink_assert(hh->m_polarity == HTTPType::RESPONSE); |
1065 | 0 | return (HTTPStatus)hh->u.resp.m_status; |
1066 | 0 | } |
1067 | | |
1068 | | /*------------------------------------------------------------------------- |
1069 | | -------------------------------------------------------------------------*/ |
1070 | | |
1071 | | inline HTTPStatus |
1072 | | HTTPHdr::status_get() const |
1073 | 0 | { |
1074 | 0 | ink_assert(valid()); |
1075 | |
|
1076 | 0 | if (m_http) { |
1077 | 0 | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1078 | 0 | return http_hdr_status_get(m_http); |
1079 | 0 | } |
1080 | | |
1081 | 0 | return HTTPStatus::NONE; |
1082 | 0 | } Unexecuted instantiation: HTTPHdr::status_get() const Unexecuted instantiation: HTTPHdr::status_get() const |
1083 | | |
1084 | | /*------------------------------------------------------------------------- |
1085 | | -------------------------------------------------------------------------*/ |
1086 | | |
1087 | | inline void |
1088 | | HTTPHdr::status_set(HTTPStatus status) |
1089 | 0 | { |
1090 | 0 | ink_assert(valid()); |
1091 | 0 | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1092 | |
|
1093 | 0 | http_hdr_status_set(m_http, status); |
1094 | 0 | } Unexecuted instantiation: HTTPHdr::status_set(HTTPStatus) Unexecuted instantiation: HTTPHdr::status_set(HTTPStatus) |
1095 | | |
1096 | | /*------------------------------------------------------------------------- |
1097 | | -------------------------------------------------------------------------*/ |
1098 | | |
1099 | | inline std::string_view |
1100 | | HTTPHdr::reason_get() |
1101 | 0 | { |
1102 | 0 | ink_assert(valid()); |
1103 | 0 | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1104 | 0 |
|
1105 | 0 | return http_hdr_reason_get(m_http); |
1106 | 0 | } |
1107 | | |
1108 | | /*------------------------------------------------------------------------- |
1109 | | -------------------------------------------------------------------------*/ |
1110 | | |
1111 | | inline void |
1112 | | HTTPHdr::reason_set(std::string_view value) |
1113 | 0 | { |
1114 | 0 | ink_assert(valid()); |
1115 | 0 | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1116 | 0 |
|
1117 | 0 | http_hdr_reason_set(m_heap, m_http, value, true); |
1118 | 0 | } |
1119 | | |
1120 | | /*------------------------------------------------------------------------- |
1121 | | -------------------------------------------------------------------------*/ |
1122 | | |
1123 | | inline void |
1124 | | HTTPHdr::mark_early_data(bool flag) const |
1125 | 0 | { |
1126 | 0 | ink_assert(valid()); |
1127 | 0 | early_data = flag; |
1128 | 0 | } |
1129 | | |
1130 | | /*------------------------------------------------------------------------- |
1131 | | -------------------------------------------------------------------------*/ |
1132 | | |
1133 | | inline bool |
1134 | | HTTPHdr::is_early_data() const |
1135 | 0 | { |
1136 | 0 | ink_assert(valid()); |
1137 | 0 | return early_data; |
1138 | 0 | } |
1139 | | |
1140 | | /*------------------------------------------------------------------------- |
1141 | | -------------------------------------------------------------------------*/ |
1142 | | |
1143 | | inline ParseResult |
1144 | | HTTPHdr::parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, int strict_uri_parsing, |
1145 | | size_t max_request_line_size, size_t max_hdr_field_size) |
1146 | 9.36k | { |
1147 | 9.36k | ink_assert(valid()); |
1148 | 9.36k | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1149 | | |
1150 | 9.36k | return http_parser_parse_req(parser, m_heap, m_http, start, end, true, eof, strict_uri_parsing, max_request_line_size, |
1151 | 9.36k | max_hdr_field_size); |
1152 | 9.36k | } |
1153 | | |
1154 | | /*------------------------------------------------------------------------- |
1155 | | -------------------------------------------------------------------------*/ |
1156 | | |
1157 | | inline ParseResult |
1158 | | HTTPHdr::parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof) |
1159 | 9.36k | { |
1160 | 9.36k | ink_assert(valid()); |
1161 | 9.36k | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1162 | | |
1163 | 9.36k | return http_parser_parse_resp(parser, m_heap, m_http, start, end, true, eof); |
1164 | 9.36k | } |
1165 | | |
1166 | | /*------------------------------------------------------------------------- |
1167 | | -------------------------------------------------------------------------*/ |
1168 | | |
1169 | | inline bool |
1170 | | HTTPHdr::is_cache_control_set(const char *cc_directive_wks) |
1171 | 0 | { |
1172 | 0 | ink_assert(valid()); |
1173 | 0 | ink_assert(hdrtoken_is_wks(cc_directive_wks)); |
1174 | 0 |
|
1175 | 0 | const HdrTokenHeapPrefix *prefix = hdrtoken_wks_to_prefix(cc_directive_wks); |
1176 | 0 | ink_assert(prefix->wks_token_type == HdrTokenType::CACHE_CONTROL); |
1177 | 0 |
|
1178 | 0 | uint32_t cc_mask = prefix->wks_type_specific.u.cache_control.cc_mask; |
1179 | 0 | if (get_cooked_cc_mask() & cc_mask) |
1180 | 0 | return (true); |
1181 | 0 | else |
1182 | 0 | return (false); |
1183 | 0 | } |
1184 | | |
1185 | | /*------------------------------------------------------------------------- |
1186 | | -------------------------------------------------------------------------*/ |
1187 | | |
1188 | | inline bool |
1189 | | HTTPHdr::is_pragma_no_cache_set() |
1190 | 0 | { |
1191 | 0 | ink_assert(valid()); |
1192 | 0 | return (get_cooked_pragma_no_cache()); |
1193 | 0 | } |
1194 | | |
1195 | | inline char * |
1196 | | HTTPHdr::url_string_get_ref(int *length) |
1197 | 0 | { |
1198 | 0 | return this->url_string_get(USE_HDR_HEAP_MAGIC, length); |
1199 | 0 | } |
1200 | | |
1201 | | inline std::string_view |
1202 | | HTTPHdr::path_get() |
1203 | 0 | { |
1204 | 0 | URL *url = this->url_get(); |
1205 | 0 | if (url) { |
1206 | 0 | return url->path_get(); |
1207 | 0 | } |
1208 | 0 | return {}; |
1209 | 0 | } |
1210 | | |
1211 | | inline std::string_view |
1212 | | HTTPHdr::query_get() |
1213 | 0 | { |
1214 | 0 | URL *url = this->url_get(); |
1215 | 0 | if (url) { |
1216 | 0 | return url->query_get(); |
1217 | 0 | } |
1218 | 0 | return std::string_view{}; |
1219 | 0 | } |
1220 | | |
1221 | | inline std::string_view |
1222 | | HTTPHdr::fragment_get() |
1223 | 0 | { |
1224 | 0 | URL *url = this->url_get(); |
1225 | 0 | if (url) { |
1226 | 0 | return url->fragment_get(); |
1227 | 0 | } |
1228 | 0 | return std::string_view{}; |
1229 | 0 | } |
1230 | | |
1231 | | inline std::string_view |
1232 | | HTTPHdr::scheme_get() |
1233 | 0 | { |
1234 | 0 | URL *url = this->url_get(); |
1235 | 0 | if (url) { |
1236 | 0 | return url->scheme_get(); |
1237 | 0 | } |
1238 | 0 | return std::string_view{}; |
1239 | 0 | } |
1240 | | |
1241 | | /*------------------------------------------------------------------------- |
1242 | | -------------------------------------------------------------------------*/ |
1243 | | |
1244 | | enum class CacheAltMagic : uint32_t { |
1245 | | ALIVE = 0xabcddeed, |
1246 | | MARSHALED = 0xdcbadeed, |
1247 | | DEAD = 0xdeadeed, |
1248 | | }; |
1249 | | |
1250 | | // struct HTTPCacheAlt |
1251 | | struct HTTPCacheAlt { |
1252 | | HTTPCacheAlt(); |
1253 | | void copy(HTTPCacheAlt *to_copy); |
1254 | | void copy_frag_offsets_from(HTTPCacheAlt *src); |
1255 | | void destroy(); |
1256 | | |
1257 | | CacheAltMagic m_magic = CacheAltMagic::ALIVE; |
1258 | | |
1259 | | // Writeable is set to true is we reside |
1260 | | // in a buffer owned by this structure. |
1261 | | // INVARIANT: if own the buffer this HttpCacheAlt |
1262 | | // we also own the buffers for the request & |
1263 | | // response headers |
1264 | | int32_t m_writeable = 1; |
1265 | | int32_t m_unmarshal_len = -1; |
1266 | | |
1267 | | int32_t m_id = -1; |
1268 | | int32_t m_rid = -1; |
1269 | | |
1270 | | int32_t m_object_key[sizeof(CryptoHash) / sizeof(int32_t)]; |
1271 | | int32_t m_object_size[2]; |
1272 | | |
1273 | | HTTPHdr m_request_hdr; |
1274 | | HTTPHdr m_response_hdr; |
1275 | | |
1276 | | time_t m_request_sent_time = 0; |
1277 | | time_t m_response_received_time = 0; |
1278 | | |
1279 | | /// # of fragment offsets in this alternate. |
1280 | | /// @note This is one less than the number of fragments. |
1281 | | int m_frag_offset_count = 0; |
1282 | | /// Type of offset for a fragment. |
1283 | | using FragOffset = uint64_t; |
1284 | | /// Table of fragment offsets. |
1285 | | /// @note The offsets are forward looking so that frag[0] is the |
1286 | | /// first byte past the end of fragment 0 which is also the first |
1287 | | /// byte of fragment 1. For this reason there is no fragment offset |
1288 | | /// for the last fragment. |
1289 | | FragOffset *m_frag_offsets = nullptr; |
1290 | | /// # of fragment offsets built in to object. |
1291 | | static int constexpr N_INTEGRAL_FRAG_OFFSETS = 4; |
1292 | | /// Integral fragment offset table. |
1293 | | FragOffset m_integral_frag_offsets[N_INTEGRAL_FRAG_OFFSETS]; |
1294 | | |
1295 | | // With clustering, our alt may be in cluster |
1296 | | // incoming channel buffer, when we are |
1297 | | // destroyed we decrement the refcount |
1298 | | // on that buffer so that it gets destroyed |
1299 | | // We don't want to use a ref count ptr (Ptr<>) |
1300 | | // since our ownership model requires explicit |
1301 | | // destroys and ref count pointers defeat this |
1302 | | RefCountObj *m_ext_buffer = nullptr; |
1303 | | }; |
1304 | | |
1305 | | class HTTPInfo |
1306 | | { |
1307 | | public: |
1308 | | using FragOffset = HTTPCacheAlt::FragOffset; ///< Import type. |
1309 | | |
1310 | | HTTPCacheAlt *m_alt = nullptr; |
1311 | | |
1312 | 0 | HTTPInfo() {} |
1313 | 0 | ~HTTPInfo() { clear(); } |
1314 | | void |
1315 | | clear() |
1316 | 0 | { |
1317 | 0 | m_alt = nullptr; |
1318 | 0 | } |
1319 | | bool |
1320 | | valid() const |
1321 | 0 | { |
1322 | 0 | return m_alt != nullptr; |
1323 | 0 | } |
1324 | | |
1325 | | void create(); |
1326 | | void destroy(); |
1327 | | |
1328 | | void copy(HTTPInfo *to_copy); |
1329 | | void |
1330 | | copy_shallow(HTTPInfo *info) |
1331 | 0 | { |
1332 | 0 | m_alt = info->m_alt; |
1333 | 0 | } |
1334 | | void copy_frag_offsets_from(HTTPInfo *src); |
1335 | | HTTPInfo &operator=(const HTTPInfo &m); |
1336 | | |
1337 | | int marshal_length(); |
1338 | | int marshal(char *buf, int len); |
1339 | | static int unmarshal(char *buf, int len, RefCountObj *block_ref); |
1340 | | static int unmarshal_v24_1(char *buf, int len, RefCountObj *block_ref); |
1341 | | void set_buffer_reference(RefCountObj *block_ref); |
1342 | | int get_handle(char *buf, int len); |
1343 | | |
1344 | | int32_t |
1345 | | id_get() const |
1346 | 0 | { |
1347 | 0 | return m_alt->m_id; |
1348 | 0 | } |
1349 | | int32_t |
1350 | | rid_get() |
1351 | 0 | { |
1352 | 0 | return m_alt->m_rid; |
1353 | 0 | } |
1354 | | |
1355 | | void |
1356 | | id_set(int32_t id) |
1357 | 0 | { |
1358 | 0 | m_alt->m_id = id; |
1359 | 0 | } |
1360 | | void |
1361 | | rid_set(int32_t id) |
1362 | 0 | { |
1363 | 0 | m_alt->m_rid = id; |
1364 | 0 | } |
1365 | | |
1366 | | CryptoHash object_key_get(); |
1367 | | void object_key_get(CryptoHash *); |
1368 | | bool compare_object_key(const CryptoHash *); |
1369 | | int64_t object_size_get(); |
1370 | | |
1371 | | void |
1372 | | request_get(HTTPHdr *hdr) |
1373 | 0 | { |
1374 | 0 | hdr->copy_shallow(&m_alt->m_request_hdr); |
1375 | 0 | } |
1376 | | void |
1377 | | response_get(HTTPHdr *hdr) |
1378 | 0 | { |
1379 | 0 | hdr->copy_shallow(&m_alt->m_response_hdr); |
1380 | 0 | } |
1381 | | |
1382 | | HTTPHdr * |
1383 | | request_get() |
1384 | 0 | { |
1385 | 0 | return &m_alt->m_request_hdr; |
1386 | 0 | } |
1387 | | HTTPHdr * |
1388 | | response_get() |
1389 | 0 | { |
1390 | 0 | return &m_alt->m_response_hdr; |
1391 | 0 | } |
1392 | | |
1393 | | URL * |
1394 | | request_url_get(URL *url = nullptr) |
1395 | 0 | { |
1396 | 0 | return m_alt->m_request_hdr.url_get(url); |
1397 | 0 | } |
1398 | | |
1399 | | time_t |
1400 | | request_sent_time_get() |
1401 | 0 | { |
1402 | 0 | return m_alt->m_request_sent_time; |
1403 | 0 | } |
1404 | | time_t |
1405 | | response_received_time_get() |
1406 | 0 | { |
1407 | 0 | return m_alt->m_response_received_time; |
1408 | 0 | } |
1409 | | |
1410 | | void object_key_set(CryptoHash &hash); |
1411 | | void object_size_set(int64_t size); |
1412 | | |
1413 | | void |
1414 | | request_set(const HTTPHdr *req) |
1415 | 0 | { |
1416 | 0 | m_alt->m_request_hdr.copy(req); |
1417 | 0 | } |
1418 | | void |
1419 | | response_set(const HTTPHdr *resp) |
1420 | 0 | { |
1421 | 0 | m_alt->m_response_hdr.copy(resp); |
1422 | 0 | } |
1423 | | |
1424 | | void |
1425 | | request_sent_time_set(time_t t) |
1426 | 0 | { |
1427 | 0 | m_alt->m_request_sent_time = t; |
1428 | 0 | } |
1429 | | void |
1430 | | response_received_time_set(time_t t) |
1431 | 0 | { |
1432 | 0 | m_alt->m_response_received_time = t; |
1433 | 0 | } |
1434 | | |
1435 | | /// Get the fragment table. |
1436 | | FragOffset *get_frag_table(); |
1437 | | /// Get the # of fragment offsets |
1438 | | /// @note This is the size of the fragment offset table, and one less |
1439 | | /// than the actual # of fragments. |
1440 | | int get_frag_offset_count(); |
1441 | | /// Add an @a offset to the end of the fragment offset table. |
1442 | | void push_frag_offset(FragOffset offset); |
1443 | | |
1444 | | // Sanity check functions |
1445 | | static bool check_marshalled(char *buf, int len); |
1446 | | |
1447 | | private: |
1448 | | HTTPInfo(const HTTPInfo &h); |
1449 | | }; |
1450 | | |
1451 | | inline void |
1452 | | HTTPInfo::destroy() |
1453 | 0 | { |
1454 | 0 | if (m_alt) { |
1455 | 0 | if (m_alt->m_writeable) { |
1456 | 0 | m_alt->destroy(); |
1457 | 0 | } else if (m_alt->m_ext_buffer) { |
1458 | 0 | if (m_alt->m_ext_buffer->refcount_dec() == 0) { |
1459 | 0 | m_alt->m_ext_buffer->free(); |
1460 | 0 | } |
1461 | 0 | } |
1462 | 0 | } |
1463 | 0 | clear(); |
1464 | 0 | } |
1465 | | |
1466 | | inline HTTPInfo & |
1467 | | HTTPInfo::operator=(const HTTPInfo &m) |
1468 | 0 | { |
1469 | 0 | m_alt = m.m_alt; |
1470 | 0 | return *this; |
1471 | 0 | } |
1472 | | |
1473 | | inline CryptoHash |
1474 | | HTTPInfo::object_key_get() |
1475 | 0 | { |
1476 | 0 | CryptoHash val; |
1477 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&val); |
1478 | 0 |
|
1479 | 0 | memcpy(pi, m_alt->m_object_key, sizeof(CryptoHash)); |
1480 | 0 |
|
1481 | 0 | return val; |
1482 | 0 | } |
1483 | | |
1484 | | inline void |
1485 | | HTTPInfo::object_key_get(CryptoHash *hash) |
1486 | 0 | { |
1487 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(hash); |
1488 | 0 | memcpy(pi, m_alt->m_object_key, CRYPTO_HASH_SIZE); |
1489 | 0 | } |
1490 | | |
1491 | | inline bool |
1492 | | HTTPInfo::compare_object_key(const CryptoHash *hash) |
1493 | 0 | { |
1494 | 0 | int32_t const *pi = reinterpret_cast<int32_t const *>(hash); |
1495 | 0 | return memcmp(pi, m_alt->m_object_key, CRYPTO_HASH_SIZE) == 0; |
1496 | 0 | } |
1497 | | |
1498 | | inline int64_t |
1499 | | HTTPInfo::object_size_get() |
1500 | 0 | { |
1501 | 0 | int64_t val = 0; // make gcc shut up. |
1502 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&val); |
1503 | 0 |
|
1504 | 0 | pi[0] = m_alt->m_object_size[0]; |
1505 | 0 | pi[1] = m_alt->m_object_size[1]; |
1506 | 0 | return val; |
1507 | 0 | } |
1508 | | |
1509 | | inline void |
1510 | | HTTPInfo::object_key_set(CryptoHash &hash) |
1511 | 0 | { |
1512 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&hash); |
1513 | 0 | memcpy(m_alt->m_object_key, pi, CRYPTO_HASH_SIZE); |
1514 | 0 | } |
1515 | | |
1516 | | inline void |
1517 | | HTTPInfo::object_size_set(int64_t size) |
1518 | 0 | { |
1519 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&size); |
1520 | 0 | m_alt->m_object_size[0] = pi[0]; |
1521 | 0 | m_alt->m_object_size[1] = pi[1]; |
1522 | 0 | } |
1523 | | |
1524 | | inline HTTPInfo::FragOffset * |
1525 | | HTTPInfo::get_frag_table() |
1526 | 0 | { |
1527 | 0 | return m_alt ? m_alt->m_frag_offsets : nullptr; |
1528 | 0 | } |
1529 | | |
1530 | | inline int |
1531 | | HTTPInfo::get_frag_offset_count() |
1532 | 0 | { |
1533 | 0 | return m_alt ? m_alt->m_frag_offset_count : 0; |
1534 | 0 | } |