/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 | | |
425 | | // This calls http_parse_host_header internally to parse the Host field value |
426 | | // when present, so it enforces the same syntax rules and also validates the |
427 | | // port number when specified. |
428 | | ParseResult validate_hdr_host(HTTPHdrImpl *hh); |
429 | | |
430 | | // This parses and validates the Host field value. |
431 | | bool http_parse_host_header(std::string_view value, std::string_view &host, int &port, bool &has_port); |
432 | | |
433 | | ParseResult validate_hdr_content_length(HdrHeap *heap, HTTPHdrImpl *hh); |
434 | | ParseResult http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end, |
435 | | bool must_copy_strings, bool eof); |
436 | | |
437 | | HTTPStatus http_parse_status(const char *start, const char *end); |
438 | | HTTPVersion http_parse_version(const char *start, const char *end); |
439 | | |
440 | | /* |
441 | | HTTPValAccept* http_parse_accept (const char *buf, Arena *arena); |
442 | | HTTPValAcceptCharset* http_parse_accept_charset (const char *buf, Arena *arena); |
443 | | HTTPValAcceptEncoding* http_parse_accept_encoding (const char *buf, Arena *arena); |
444 | | HTTPValAcceptLanguage* http_parse_accept_language (const char *buf, Arena *arena); |
445 | | HTTPValCacheControl* http_parse_cache_control (const char *buf, Arena *arena); |
446 | | const char* http_parse_cache_directive (const char **buf); |
447 | | HTTPValRange* http_parse_range (const char *buf, Arena *arena); |
448 | | */ |
449 | | HTTPValTE *http_parse_te(const char *buf, int len, Arena *arena); |
450 | | |
451 | | bool is_http1_hdr_version_supported(const HTTPVersion &http_version); |
452 | | |
453 | | class IOBufferReader; |
454 | | |
455 | | /** HTTP Header class. |
456 | | * |
457 | | * @warning Changing the size of this class (adding/removing fields) will change |
458 | | * the on-disk cache format and cause cache incompatibility. The HTTPCacheAlt |
459 | | * structure contains embedded HTTPHdr objects, and the cache marshalling code |
460 | | * uses sizeof(HTTPCacheAlt) to read/write cache entries. Any size change will |
461 | | * cause "vector inconsistency" errors when reading cache entries written by a |
462 | | * different version. |
463 | | */ |
464 | | class HTTPHdr : public MIMEHdr |
465 | | { |
466 | | public: |
467 | | HTTPHdrImpl *m_http = nullptr; |
468 | | mutable URL m_url_cached; |
469 | | mutable MIMEField *m_host_mime = nullptr; |
470 | | mutable int m_host_length = 0; ///< Length of hostname (parsed, excludes port). |
471 | | mutable int m_port = 0; ///< Target port. |
472 | | mutable bool m_target_cached = false; ///< Whether host name and port are cached. |
473 | | mutable bool m_target_in_url = false; ///< Whether host name and port are in the URL. |
474 | | mutable bool m_100_continue_sent = false; ///< Whether ATS sent a 100 Continue optimized response. |
475 | | mutable bool m_100_continue_required = false; ///< Whether 100_continue is in the Expect header. |
476 | | /// Set if the port was effectively specified in the header. |
477 | | /// @c true if the target (in the URL or the HOST field) also specified |
478 | | /// a port. That is, @c true if whatever source had the target host |
479 | | /// also had a port, @c false otherwise. |
480 | | mutable bool m_port_in_header = false; |
481 | | |
482 | | mutable bool early_data = false; |
483 | | |
484 | 18.7k | HTTPHdr() = default; // Force the creation of the default constructor |
485 | | |
486 | | int valid() const; |
487 | | |
488 | | void create(HTTPType polarity, HTTPVersion version = HTTP_INVALID, HdrHeap *heap = nullptr); |
489 | | void clear(); |
490 | | void reset(); |
491 | | void copy(const HTTPHdr *hdr); |
492 | | void copy_shallow(const HTTPHdr *hdr); |
493 | | |
494 | | int unmarshal(char *buf, int len, RefCountObj *block_ref); |
495 | | |
496 | | int print(char *buf, int bufsize, int *bufindex, int *dumpoffset) const; |
497 | | |
498 | | int length_get() const; |
499 | | |
500 | | HTTPType type_get() const; |
501 | | |
502 | | HTTPVersion version_get() const; |
503 | | void version_set(HTTPVersion version); |
504 | | |
505 | | std::string_view method_get(); |
506 | | int method_get_wksidx() const; |
507 | | void method_set(std::string_view value); |
508 | | |
509 | | URL *url_create(URL *url); |
510 | | |
511 | | URL *url_get() const; |
512 | | URL *url_get(URL *url); |
513 | | /** Get a string with the effective URL in it. |
514 | | If @a length is not @c NULL then the length of the string |
515 | | is stored in the int pointed to by @a length. |
516 | | |
517 | | Note that this can be different from getting the @c URL |
518 | | and invoking @c URL::string_get if the host is in a header |
519 | | field and not explicitly in the URL. |
520 | | */ |
521 | | char *url_string_get(Arena *arena = nullptr, ///< Arena to use, or @c malloc if NULL. |
522 | | int *length = nullptr ///< Store string length here. |
523 | | ); |
524 | | /** Get a string with the effective URL in it. |
525 | | This is automatically allocated if needed in the request heap. |
526 | | |
527 | | @see url_string_get |
528 | | */ |
529 | | char *url_string_get_ref(int *length = nullptr ///< Store string length here. |
530 | | ); |
531 | | |
532 | | /** Print the URL. |
533 | | Output is not null terminated. |
534 | | @return 0 on failure, non-zero on success. |
535 | | */ |
536 | | int url_print(char *buff, ///< Output buffer |
537 | | int length, ///< Length of @a buffer |
538 | | int *offset, ///< [in,out] ??? |
539 | | int *skip, ///< [in,out] ??? |
540 | | unsigned normalization_flags = URLNormalize::NONE ///< host/scheme normalized to lower case |
541 | | ); |
542 | | |
543 | | /** Return the length of the URL that url_print() will create. |
544 | | @return -1 on failure, non-negative on success. |
545 | | */ |
546 | | int url_printed_length(unsigned normalizaion_flags = URLNormalize::NONE); |
547 | | |
548 | | /** Get the URL path. |
549 | | This is a reference, not allocated. |
550 | | @return A string_view to the path or an empty string_view if there is no valid URL. |
551 | | */ |
552 | | std::string_view path_get(); |
553 | | |
554 | | /** Get the URL query. |
555 | | This is a reference, not allocated. |
556 | | @return A string_view to the query or an empty string_view if there is no valid URL. |
557 | | */ |
558 | | std::string_view query_get(); |
559 | | |
560 | | /** Get the URL fragment. |
561 | | This is a reference, not allocated. |
562 | | @return A string_view to the fragment or an empty string_view if there is no valid URL. |
563 | | */ |
564 | | std::string_view fragment_get(); |
565 | | |
566 | | /** Get the target host name. |
567 | | The length is returned in @a length if non-NULL. |
568 | | @note The results are cached so this is fast after the first call. |
569 | | @return A string_view to the host name. |
570 | | */ |
571 | | std::string_view host_get() const; |
572 | | |
573 | | /** Get the target port. |
574 | | If the target port is not found then it is adjusted to the |
575 | | default port for the URL type. |
576 | | @note The results are cached so this is fast after the first call. |
577 | | @return The canonicalized target port. |
578 | | */ |
579 | | int port_get(); |
580 | | |
581 | | /** Get the URL scheme. |
582 | | This is a reference, not allocated. |
583 | | @return A string_view to the scheme or an empty string_view if there is no valid URL. |
584 | | */ |
585 | | std::string_view scheme_get(); |
586 | | void url_set(URL *url); |
587 | | void url_set(std::string_view value); |
588 | | |
589 | | /// Check location of target host. |
590 | | /// @return @c true if the host was in the URL, @c false otherwise. |
591 | | /// @note This returns @c false if the host is missing. |
592 | | bool is_target_in_url() const; |
593 | | |
594 | | /// Check if a port was specified in the target. |
595 | | /// @return @c true if the port was part of the target. |
596 | | bool is_port_in_header() const; |
597 | | |
598 | | /// If the target is in the fields and not the URL, copy it to the @a url. |
599 | | /// If @a url is @c NULL the cached URL in this header is used. |
600 | | /// @note In the default case the copy is avoided if the cached URL already |
601 | | /// has the target. If @a url is non @c NULL the copy is always performed. |
602 | | void set_url_target_from_host_field(URL *url = nullptr); |
603 | | |
604 | | /// Mark the target cache as invalid. |
605 | | /// @internal Ugly but too many places currently that touch the |
606 | | /// header internals, they must be able to do this. |
607 | | void mark_target_dirty() const; |
608 | | |
609 | | HTTPStatus status_get() const; |
610 | | void status_set(HTTPStatus status); |
611 | | |
612 | | std::string_view reason_get(); |
613 | | void reason_set(std::string_view value); |
614 | | |
615 | | void mark_early_data(bool flag = true) const; |
616 | | bool is_early_data() const; |
617 | | |
618 | | ParseResult parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, int strict_uri_parsing = 0, |
619 | | size_t max_request_line_size = UINT16_MAX, size_t max_hdr_field_size = 131070); |
620 | | ParseResult parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof); |
621 | | |
622 | | ParseResult parse_req(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof, int strict_uri_parsing = 0, |
623 | | size_t max_request_line_size = UINT16_MAX, size_t max_hdr_field_size = UINT16_MAX); |
624 | | ParseResult parse_resp(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof); |
625 | | |
626 | | bool check_hdr_implements(); |
627 | | |
628 | | public: |
629 | | // Utility routines |
630 | | bool is_cache_control_set(const char *cc_directive_wks); |
631 | | bool is_pragma_no_cache_set(); |
632 | | bool is_keep_alive_set() const; |
633 | | bool expect_final_response() const; |
634 | | HTTPKeepAlive keep_alive_get() const; |
635 | | |
636 | | protected: |
637 | | /** Load the target cache. |
638 | | @see m_host, m_port, m_target_in_url |
639 | | */ |
640 | | void _fill_target_cache() const; |
641 | | /** Test the cache and fill it if necessary. |
642 | | @internal In contrast to @c _fill_target_cache, this method |
643 | | is inline and checks whether the cache is already filled. |
644 | | @ _fill_target_cache @b always does a cache fill. |
645 | | */ |
646 | | void _test_and_fill_target_cache() const; |
647 | | |
648 | | static Arena *const USE_HDR_HEAP_MAGIC; |
649 | | |
650 | | // No gratuitous copies! |
651 | | HTTPHdr(const HTTPHdr &m) = delete; |
652 | | HTTPHdr &operator=(const HTTPHdr &m) = delete; |
653 | | |
654 | | private: |
655 | | friend class UrlPrintHack; // don't ask. |
656 | | }; |
657 | | |
658 | | /*------------------------------------------------------------------------- |
659 | | -------------------------------------------------------------------------*/ |
660 | | |
661 | | inline int |
662 | | HTTPHdr::valid() const |
663 | 18.7k | { |
664 | 18.7k | return (m_http && m_mime && m_heap); |
665 | 18.7k | } |
666 | | |
667 | | /*------------------------------------------------------------------------- |
668 | | -------------------------------------------------------------------------*/ |
669 | | |
670 | | inline void |
671 | | HTTPHdr::create(HTTPType polarity, HTTPVersion version, HdrHeap *heap) |
672 | 18.7k | { |
673 | 18.7k | if (heap) { |
674 | 0 | m_heap = heap; |
675 | 18.7k | } else if (!m_heap) { |
676 | 18.7k | m_heap = new_HdrHeap(); |
677 | 18.7k | } |
678 | | |
679 | 18.7k | m_http = http_hdr_create(m_heap, polarity, version); |
680 | 18.7k | m_mime = m_http->m_fields_impl; |
681 | 18.7k | } |
682 | | |
683 | | inline void |
684 | | HTTPHdr::clear() |
685 | 0 | { |
686 | 0 | if (m_http && m_http->m_polarity == HTTPType::REQUEST) { |
687 | 0 | m_url_cached.clear(); |
688 | 0 | } |
689 | 0 | this->HdrHeapSDKHandle::clear(); |
690 | 0 | m_http = nullptr; |
691 | 0 | m_mime = nullptr; |
692 | 0 | } |
693 | | |
694 | | inline void |
695 | | HTTPHdr::reset() |
696 | 0 | { |
697 | 0 | m_heap = nullptr; |
698 | 0 | m_http = nullptr; |
699 | 0 | m_mime = nullptr; |
700 | 0 | m_url_cached.reset(); |
701 | 0 | } |
702 | | |
703 | | /*------------------------------------------------------------------------- |
704 | | -------------------------------------------------------------------------*/ |
705 | | |
706 | | inline void |
707 | | HTTPHdr::copy(const HTTPHdr *hdr) |
708 | 0 | { |
709 | 0 | ink_assert(hdr->valid()); |
710 | |
|
711 | 0 | if (valid()) { |
712 | 0 | http_hdr_copy_onto(hdr->m_http, hdr->m_heap, m_http, m_heap, (m_heap != hdr->m_heap) ? true : false); |
713 | 0 | } else { |
714 | 0 | m_heap = new_HdrHeap(); |
715 | 0 | m_http = http_hdr_clone(hdr->m_http, hdr->m_heap, m_heap); |
716 | 0 | m_mime = m_http->m_fields_impl; |
717 | 0 | } |
718 | 0 | } |
719 | | |
720 | | /*------------------------------------------------------------------------- |
721 | | -------------------------------------------------------------------------*/ |
722 | | |
723 | | inline void |
724 | | HTTPHdr::copy_shallow(const HTTPHdr *hdr) |
725 | 0 | { |
726 | 0 | ink_assert(hdr->valid()); |
727 | 0 |
|
728 | 0 | m_heap = hdr->m_heap; |
729 | 0 | m_http = hdr->m_http; |
730 | 0 | m_mime = hdr->m_mime; |
731 | 0 |
|
732 | 0 | if (hdr->type_get() == HTTPType::REQUEST && m_url_cached.valid()) |
733 | 0 | m_url_cached.copy_shallow(&hdr->m_url_cached); |
734 | 0 | } |
735 | | |
736 | | /*------------------------------------------------------------------------- |
737 | | -------------------------------------------------------------------------*/ |
738 | | |
739 | | inline int |
740 | | HTTPHdr::print(char *buf, int bufsize, int *bufindex, int *dumpoffset) const |
741 | 0 | { |
742 | 0 | ink_assert(valid()); |
743 | 0 | return http_hdr_print(m_http, buf, bufsize, bufindex, dumpoffset); |
744 | 0 | } |
745 | | |
746 | | /*------------------------------------------------------------------------- |
747 | | -------------------------------------------------------------------------*/ |
748 | | |
749 | | inline void |
750 | | HTTPHdr::_test_and_fill_target_cache() const |
751 | 0 | { |
752 | 0 | if (!m_target_cached) { |
753 | 0 | this->_fill_target_cache(); |
754 | 0 | return; |
755 | 0 | } |
756 | | |
757 | | // If host came from the Host header (not URL), check for staleness by verifying |
758 | | // the current Host header value length matches what we expect from cached values. |
759 | 0 | if (!m_target_in_url && m_host_mime != nullptr) { |
760 | 0 | int expected_len = m_host_length; |
761 | 0 | if (m_port_in_header && m_port > 0) { |
762 | | // Account for ":port" suffix in the raw Host header value. |
763 | 0 | expected_len += 1; // colon |
764 | 0 | if (m_port < 10) { |
765 | 0 | expected_len += 1; |
766 | 0 | } else if (m_port < 100) { |
767 | 0 | expected_len += 2; |
768 | 0 | } else if (m_port < 1000) { |
769 | 0 | expected_len += 3; |
770 | 0 | } else if (m_port < 10000) { |
771 | 0 | expected_len += 4; |
772 | 0 | } else { |
773 | 0 | expected_len += 5; |
774 | 0 | } |
775 | 0 | } |
776 | 0 | if (m_host_mime->m_len_value != expected_len) { |
777 | 0 | this->_fill_target_cache(); |
778 | 0 | } |
779 | 0 | } |
780 | 0 | } |
781 | | |
782 | | /*------------------------------------------------------------------------- |
783 | | -------------------------------------------------------------------------*/ |
784 | | |
785 | | inline std::string_view |
786 | | HTTPHdr::host_get() const |
787 | 0 | { |
788 | 0 | this->_test_and_fill_target_cache(); |
789 | 0 | if (m_target_in_url) { |
790 | 0 | return url_get()->host_get(); |
791 | 0 | } else if (m_host_mime) { |
792 | 0 | return std::string_view{m_host_mime->m_ptr_value, static_cast<std::string_view::size_type>(m_host_length)}; |
793 | 0 | } |
794 | | |
795 | 0 | return std::string_view{}; |
796 | 0 | } |
797 | | |
798 | | /*------------------------------------------------------------------------- |
799 | | -------------------------------------------------------------------------*/ |
800 | | |
801 | | inline int |
802 | | HTTPHdr::port_get() |
803 | 0 | { |
804 | 0 | this->_test_and_fill_target_cache(); |
805 | 0 | return m_port; |
806 | 0 | } |
807 | | |
808 | | /*------------------------------------------------------------------------- |
809 | | -------------------------------------------------------------------------*/ |
810 | | |
811 | | inline bool |
812 | | HTTPHdr::is_target_in_url() const |
813 | 0 | { |
814 | 0 | this->_test_and_fill_target_cache(); |
815 | 0 | return m_target_in_url; |
816 | 0 | } |
817 | | |
818 | | /*------------------------------------------------------------------------- |
819 | | -------------------------------------------------------------------------*/ |
820 | | |
821 | | inline bool |
822 | | HTTPHdr::is_port_in_header() const |
823 | 0 | { |
824 | 0 | this->_test_and_fill_target_cache(); |
825 | 0 | return m_port_in_header; |
826 | 0 | } |
827 | | |
828 | | /*------------------------------------------------------------------------- |
829 | | -------------------------------------------------------------------------*/ |
830 | | |
831 | | inline void |
832 | | HTTPHdr::mark_target_dirty() const |
833 | 0 | { |
834 | 0 | m_target_cached = false; |
835 | 0 | } |
836 | | /*------------------------------------------------------------------------- |
837 | | -------------------------------------------------------------------------*/ |
838 | | |
839 | | inline HTTPType |
840 | | http_hdr_type_get(HTTPHdrImpl *hh) |
841 | 0 | { |
842 | 0 | return (hh->m_polarity); |
843 | 0 | } |
844 | | |
845 | | /*------------------------------------------------------------------------- |
846 | | -------------------------------------------------------------------------*/ |
847 | | |
848 | | inline HTTPType |
849 | | HTTPHdr::type_get() const |
850 | 0 | { |
851 | 0 | ink_assert(valid()); |
852 | 0 | return http_hdr_type_get(m_http); |
853 | 0 | } |
854 | | |
855 | | /*------------------------------------------------------------------------- |
856 | | -------------------------------------------------------------------------*/ |
857 | | |
858 | | inline HTTPVersion |
859 | | HTTPHdr::version_get() const |
860 | 0 | { |
861 | 0 | ink_assert(valid()); |
862 | 0 | return m_http->m_version; |
863 | 0 | } |
864 | | |
865 | | /*------------------------------------------------------------------------- |
866 | | -------------------------------------------------------------------------*/ |
867 | | |
868 | | inline static HTTPKeepAlive |
869 | | is_header_keep_alive(const HTTPVersion &http_version, const MIMEField *con_hdr) |
870 | 0 | { |
871 | 0 | enum class ConToken { |
872 | 0 | NONE = 0, |
873 | 0 | KEEP_ALIVE, |
874 | 0 | CLOSE, |
875 | 0 | }; |
876 | 0 |
|
877 | 0 | auto con_token = ConToken::NONE; |
878 | 0 | HTTPKeepAlive keep_alive = HTTPKeepAlive::NO_KEEPALIVE; |
879 | 0 | // *unknown_tokens = false; |
880 | 0 |
|
881 | 0 | if (con_hdr) { |
882 | 0 | if (con_hdr->value_get_index("keep-alive"sv) >= 0) |
883 | 0 | con_token = ConToken::KEEP_ALIVE; |
884 | 0 | else if (con_hdr->value_get_index("close"sv) >= 0) |
885 | 0 | con_token = ConToken::CLOSE; |
886 | 0 | } |
887 | 0 |
|
888 | 0 | if (HTTP_1_0 == http_version) { |
889 | 0 | keep_alive = (con_token == ConToken::KEEP_ALIVE) ? (HTTPKeepAlive::KEEPALIVE) : (HTTPKeepAlive::NO_KEEPALIVE); |
890 | 0 | } else if (HTTP_1_1 == http_version) { |
891 | 0 | // We deviate from the spec here. If the we got a response where |
892 | 0 | // where there is no Connection header and the request 1.0 was |
893 | 0 | // 1.0 don't treat this as keep-alive since Netscape-Enterprise/3.6 SP1 |
894 | 0 | // server doesn't |
895 | 0 | keep_alive = ((con_token == ConToken::KEEP_ALIVE) || (con_token == ConToken::NONE && HTTP_1_1 == http_version)) ? |
896 | 0 | (HTTPKeepAlive::KEEPALIVE) : |
897 | 0 | (HTTPKeepAlive::NO_KEEPALIVE); |
898 | 0 | } else { |
899 | 0 | keep_alive = HTTPKeepAlive::NO_KEEPALIVE; |
900 | 0 | } |
901 | 0 | return (keep_alive); |
902 | 0 | } Unexecuted instantiation: fuzz_http.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*) |
903 | | |
904 | | inline HTTPKeepAlive |
905 | | HTTPHdr::keep_alive_get() const |
906 | 0 | { |
907 | 0 | HTTPKeepAlive retval = HTTPKeepAlive::NO_KEEPALIVE; |
908 | 0 | const MIMEField *pc = this->field_find(static_cast<std::string_view>(MIME_FIELD_PROXY_CONNECTION)); |
909 | 0 | if (pc != nullptr) { |
910 | 0 | retval = is_header_keep_alive(this->version_get(), pc); |
911 | 0 | } else { |
912 | 0 | const MIMEField *c = this->field_find(static_cast<std::string_view>(MIME_FIELD_CONNECTION)); |
913 | 0 | retval = is_header_keep_alive(this->version_get(), c); |
914 | 0 | } |
915 | 0 | return retval; |
916 | 0 | } |
917 | | |
918 | | inline bool |
919 | | HTTPHdr::is_keep_alive_set() const |
920 | 0 | { |
921 | 0 | return this->keep_alive_get() == HTTPKeepAlive::KEEPALIVE; |
922 | 0 | } |
923 | | |
924 | | /** |
925 | | Check the status code is informational and expecting final response |
926 | | - e.g. "100 Continue", "103 Early Hints" |
927 | | |
928 | | Please note that "101 Switching Protocol" is not included. |
929 | | */ |
930 | | inline bool |
931 | | HTTPHdr::expect_final_response() const |
932 | 0 | { |
933 | 0 | switch (this->status_get()) { |
934 | 0 | case HTTPStatus::CONTINUE: |
935 | 0 | case HTTPStatus::EARLY_HINTS: |
936 | 0 | return true; |
937 | 0 | default: |
938 | 0 | return false; |
939 | 0 | } |
940 | 0 | } |
941 | | |
942 | | /*------------------------------------------------------------------------- |
943 | | -------------------------------------------------------------------------*/ |
944 | | |
945 | | inline void |
946 | | HTTPHdr::version_set(HTTPVersion version) |
947 | 0 | { |
948 | 0 | ink_assert(valid()); |
949 | 0 | http_hdr_version_set(m_http, version); |
950 | 0 | } |
951 | | |
952 | | /*------------------------------------------------------------------------- |
953 | | -------------------------------------------------------------------------*/ |
954 | | |
955 | | inline std::string_view |
956 | | HTTPHdr::method_get() |
957 | 0 | { |
958 | 0 | ink_assert(valid()); |
959 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
960 | 0 |
|
961 | 0 | return http_hdr_method_get(m_http); |
962 | 0 | } |
963 | | |
964 | | inline int |
965 | | HTTPHdr::method_get_wksidx() const |
966 | 0 | { |
967 | 0 | ink_assert(valid()); |
968 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
969 | 0 |
|
970 | 0 | return (m_http->u.req.m_method_wks_idx); |
971 | 0 | } |
972 | | |
973 | | /*------------------------------------------------------------------------- |
974 | | -------------------------------------------------------------------------*/ |
975 | | |
976 | | inline void |
977 | | HTTPHdr::method_set(std::string_view value) |
978 | 0 | { |
979 | 0 | ink_assert(valid()); |
980 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
981 | 0 |
|
982 | 0 | int method_wks_idx = hdrtoken_tokenize(value.data(), static_cast<int>(value.length())); |
983 | 0 | http_hdr_method_set(m_heap, m_http, value, method_wks_idx, true); |
984 | 0 | } |
985 | | |
986 | | /*------------------------------------------------------------------------- |
987 | | -------------------------------------------------------------------------*/ |
988 | | |
989 | | inline URL * |
990 | | HTTPHdr::url_create(URL *u) |
991 | 0 | { |
992 | 0 | ink_assert(valid()); |
993 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
994 | 0 |
|
995 | 0 | u->set(this); |
996 | 0 | u->create(m_heap); |
997 | 0 | return (u); |
998 | 0 | } |
999 | | |
1000 | | /*------------------------------------------------------------------------- |
1001 | | -------------------------------------------------------------------------*/ |
1002 | | |
1003 | | inline URL * |
1004 | | HTTPHdr::url_get() const |
1005 | 0 | { |
1006 | 0 | ink_assert(valid()); |
1007 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1008 | | |
1009 | | // It's entirely possible that someone changed URL in our impl |
1010 | | // without updating the cached copy in the C++ layer. Check |
1011 | | // to see if this happened before handing back the url |
1012 | |
|
1013 | 0 | URLImpl *real_impl = m_http->u.req.m_url_impl; |
1014 | 0 | if (m_url_cached.m_url_impl != real_impl) { |
1015 | 0 | m_url_cached.set(this); |
1016 | 0 | m_url_cached.m_url_impl = real_impl; |
1017 | 0 | this->mark_target_dirty(); |
1018 | 0 | } |
1019 | 0 | return (&m_url_cached); |
1020 | 0 | } |
1021 | | |
1022 | | /*------------------------------------------------------------------------- |
1023 | | -------------------------------------------------------------------------*/ |
1024 | | |
1025 | | inline URL * |
1026 | | HTTPHdr::url_get(URL *url) |
1027 | 0 | { |
1028 | 0 | ink_assert(valid()); |
1029 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1030 | 0 |
|
1031 | 0 | url->set(this); // attach refcount |
1032 | 0 | url->m_url_impl = m_http->u.req.m_url_impl; |
1033 | 0 | return (url); |
1034 | 0 | } |
1035 | | |
1036 | | /*------------------------------------------------------------------------- |
1037 | | -------------------------------------------------------------------------*/ |
1038 | | |
1039 | | inline void |
1040 | | HTTPHdr::url_set(URL *url) |
1041 | 0 | { |
1042 | 0 | ink_assert(valid()); |
1043 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1044 | 0 |
|
1045 | 0 | URLImpl *url_impl = m_http->u.req.m_url_impl; |
1046 | 0 | ::url_copy_onto(url->m_url_impl, url->m_heap, url_impl, m_heap, true); |
1047 | 0 | } |
1048 | | |
1049 | | /*------------------------------------------------------------------------- |
1050 | | -------------------------------------------------------------------------*/ |
1051 | | |
1052 | | inline void |
1053 | | HTTPHdr::url_set(std::string_view value) |
1054 | 0 | { |
1055 | 0 | URLImpl *url_impl; |
1056 | 0 |
|
1057 | 0 | ink_assert(valid()); |
1058 | 0 | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1059 | 0 |
|
1060 | 0 | url_impl = m_http->u.req.m_url_impl; |
1061 | 0 | ::url_clear(url_impl); |
1062 | 0 | const char *str{value.data()}; |
1063 | 0 | ::url_parse(m_heap, url_impl, &str, str + value.length(), true); |
1064 | 0 | } |
1065 | | |
1066 | | /*------------------------------------------------------------------------- |
1067 | | -------------------------------------------------------------------------*/ |
1068 | | |
1069 | | inline HTTPStatus |
1070 | | http_hdr_status_get(HTTPHdrImpl const *hh) |
1071 | 0 | { |
1072 | 0 | ink_assert(hh->m_polarity == HTTPType::RESPONSE); |
1073 | 0 | return (HTTPStatus)hh->u.resp.m_status; |
1074 | 0 | } |
1075 | | |
1076 | | /*------------------------------------------------------------------------- |
1077 | | -------------------------------------------------------------------------*/ |
1078 | | |
1079 | | inline HTTPStatus |
1080 | | HTTPHdr::status_get() const |
1081 | 0 | { |
1082 | 0 | ink_assert(valid()); |
1083 | 0 |
|
1084 | 0 | if (m_http) { |
1085 | 0 | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1086 | 0 | return http_hdr_status_get(m_http); |
1087 | 0 | } |
1088 | 0 |
|
1089 | 0 | return HTTPStatus::NONE; |
1090 | 0 | } |
1091 | | |
1092 | | /*------------------------------------------------------------------------- |
1093 | | -------------------------------------------------------------------------*/ |
1094 | | |
1095 | | inline void |
1096 | | HTTPHdr::status_set(HTTPStatus status) |
1097 | 0 | { |
1098 | 0 | ink_assert(valid()); |
1099 | 0 | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1100 | 0 |
|
1101 | 0 | http_hdr_status_set(m_http, status); |
1102 | 0 | } |
1103 | | |
1104 | | /*------------------------------------------------------------------------- |
1105 | | -------------------------------------------------------------------------*/ |
1106 | | |
1107 | | inline std::string_view |
1108 | | HTTPHdr::reason_get() |
1109 | 0 | { |
1110 | 0 | ink_assert(valid()); |
1111 | 0 | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1112 | 0 |
|
1113 | 0 | return http_hdr_reason_get(m_http); |
1114 | 0 | } |
1115 | | |
1116 | | /*------------------------------------------------------------------------- |
1117 | | -------------------------------------------------------------------------*/ |
1118 | | |
1119 | | inline void |
1120 | | HTTPHdr::reason_set(std::string_view value) |
1121 | 0 | { |
1122 | 0 | ink_assert(valid()); |
1123 | 0 | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1124 | 0 |
|
1125 | 0 | http_hdr_reason_set(m_heap, m_http, value, true); |
1126 | 0 | } |
1127 | | |
1128 | | /*------------------------------------------------------------------------- |
1129 | | -------------------------------------------------------------------------*/ |
1130 | | |
1131 | | inline void |
1132 | | HTTPHdr::mark_early_data(bool flag) const |
1133 | 0 | { |
1134 | 0 | ink_assert(valid()); |
1135 | 0 | early_data = flag; |
1136 | 0 | } |
1137 | | |
1138 | | /*------------------------------------------------------------------------- |
1139 | | -------------------------------------------------------------------------*/ |
1140 | | |
1141 | | inline bool |
1142 | | HTTPHdr::is_early_data() const |
1143 | 0 | { |
1144 | 0 | ink_assert(valid()); |
1145 | 0 | return early_data; |
1146 | 0 | } |
1147 | | |
1148 | | /*------------------------------------------------------------------------- |
1149 | | -------------------------------------------------------------------------*/ |
1150 | | |
1151 | | inline ParseResult |
1152 | | HTTPHdr::parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, int strict_uri_parsing, |
1153 | | size_t max_request_line_size, size_t max_hdr_field_size) |
1154 | 9.36k | { |
1155 | 9.36k | ink_assert(valid()); |
1156 | 9.36k | ink_assert(m_http->m_polarity == HTTPType::REQUEST); |
1157 | | |
1158 | 9.36k | return http_parser_parse_req(parser, m_heap, m_http, start, end, true, eof, strict_uri_parsing, max_request_line_size, |
1159 | 9.36k | max_hdr_field_size); |
1160 | 9.36k | } |
1161 | | |
1162 | | /*------------------------------------------------------------------------- |
1163 | | -------------------------------------------------------------------------*/ |
1164 | | |
1165 | | inline ParseResult |
1166 | | HTTPHdr::parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof) |
1167 | 9.36k | { |
1168 | 9.36k | ink_assert(valid()); |
1169 | 9.36k | ink_assert(m_http->m_polarity == HTTPType::RESPONSE); |
1170 | | |
1171 | 9.36k | return http_parser_parse_resp(parser, m_heap, m_http, start, end, true, eof); |
1172 | 9.36k | } |
1173 | | |
1174 | | /*------------------------------------------------------------------------- |
1175 | | -------------------------------------------------------------------------*/ |
1176 | | |
1177 | | inline bool |
1178 | | HTTPHdr::is_cache_control_set(const char *cc_directive_wks) |
1179 | 0 | { |
1180 | 0 | ink_assert(valid()); |
1181 | 0 | ink_assert(hdrtoken_is_wks(cc_directive_wks)); |
1182 | 0 |
|
1183 | 0 | const HdrTokenHeapPrefix *prefix = hdrtoken_wks_to_prefix(cc_directive_wks); |
1184 | 0 | ink_assert(prefix->wks_token_type == HdrTokenType::CACHE_CONTROL); |
1185 | 0 |
|
1186 | 0 | uint32_t cc_mask = prefix->wks_type_specific.u.cache_control.cc_mask; |
1187 | 0 | if (get_cooked_cc_mask() & cc_mask) |
1188 | 0 | return (true); |
1189 | 0 | else |
1190 | 0 | return (false); |
1191 | 0 | } |
1192 | | |
1193 | | /*------------------------------------------------------------------------- |
1194 | | -------------------------------------------------------------------------*/ |
1195 | | |
1196 | | inline bool |
1197 | | HTTPHdr::is_pragma_no_cache_set() |
1198 | 0 | { |
1199 | 0 | ink_assert(valid()); |
1200 | 0 | return (get_cooked_pragma_no_cache()); |
1201 | 0 | } |
1202 | | |
1203 | | inline char * |
1204 | | HTTPHdr::url_string_get_ref(int *length) |
1205 | 0 | { |
1206 | 0 | return this->url_string_get(USE_HDR_HEAP_MAGIC, length); |
1207 | 0 | } |
1208 | | |
1209 | | inline std::string_view |
1210 | | HTTPHdr::path_get() |
1211 | 0 | { |
1212 | 0 | URL *url = this->url_get(); |
1213 | 0 | if (url) { |
1214 | 0 | return url->path_get(); |
1215 | 0 | } |
1216 | 0 | return {}; |
1217 | 0 | } |
1218 | | |
1219 | | inline std::string_view |
1220 | | HTTPHdr::query_get() |
1221 | 0 | { |
1222 | 0 | URL *url = this->url_get(); |
1223 | 0 | if (url) { |
1224 | 0 | return url->query_get(); |
1225 | 0 | } |
1226 | 0 | return std::string_view{}; |
1227 | 0 | } |
1228 | | |
1229 | | inline std::string_view |
1230 | | HTTPHdr::fragment_get() |
1231 | 0 | { |
1232 | 0 | URL *url = this->url_get(); |
1233 | 0 | if (url) { |
1234 | 0 | return url->fragment_get(); |
1235 | 0 | } |
1236 | 0 | return std::string_view{}; |
1237 | 0 | } |
1238 | | |
1239 | | inline std::string_view |
1240 | | HTTPHdr::scheme_get() |
1241 | 0 | { |
1242 | 0 | URL *url = this->url_get(); |
1243 | 0 | if (url) { |
1244 | 0 | return url->scheme_get(); |
1245 | 0 | } |
1246 | 0 | return std::string_view{}; |
1247 | 0 | } |
1248 | | |
1249 | | /*------------------------------------------------------------------------- |
1250 | | -------------------------------------------------------------------------*/ |
1251 | | |
1252 | | enum class CacheAltMagic : uint32_t { |
1253 | | ALIVE = 0xabcddeed, |
1254 | | MARSHALED = 0xdcbadeed, |
1255 | | DEAD = 0xdeadeed, |
1256 | | }; |
1257 | | |
1258 | | // struct HTTPCacheAlt |
1259 | | struct HTTPCacheAlt { |
1260 | | HTTPCacheAlt(); |
1261 | | void copy(HTTPCacheAlt *to_copy); |
1262 | | void copy_frag_offsets_from(HTTPCacheAlt *src); |
1263 | | void destroy(); |
1264 | | |
1265 | | CacheAltMagic m_magic = CacheAltMagic::ALIVE; |
1266 | | |
1267 | | // Writeable is set to true is we reside |
1268 | | // in a buffer owned by this structure. |
1269 | | // INVARIANT: if own the buffer this HttpCacheAlt |
1270 | | // we also own the buffers for the request & |
1271 | | // response headers |
1272 | | int32_t m_writeable = 1; |
1273 | | int32_t m_unmarshal_len = -1; |
1274 | | |
1275 | | int32_t m_id = -1; |
1276 | | int32_t m_rid = -1; |
1277 | | |
1278 | | int32_t m_object_key[sizeof(CryptoHash) / sizeof(int32_t)]; |
1279 | | int32_t m_object_size[2]; |
1280 | | |
1281 | | HTTPHdr m_request_hdr; |
1282 | | HTTPHdr m_response_hdr; |
1283 | | |
1284 | | time_t m_request_sent_time = 0; |
1285 | | time_t m_response_received_time = 0; |
1286 | | |
1287 | | /// # of fragment offsets in this alternate. |
1288 | | /// @note This is one less than the number of fragments. |
1289 | | int m_frag_offset_count = 0; |
1290 | | /// Type of offset for a fragment. |
1291 | | using FragOffset = uint64_t; |
1292 | | /// Table of fragment offsets. |
1293 | | /// @note The offsets are forward looking so that frag[0] is the |
1294 | | /// first byte past the end of fragment 0 which is also the first |
1295 | | /// byte of fragment 1. For this reason there is no fragment offset |
1296 | | /// for the last fragment. |
1297 | | FragOffset *m_frag_offsets = nullptr; |
1298 | | /// # of fragment offsets built in to object. |
1299 | | static int constexpr N_INTEGRAL_FRAG_OFFSETS = 4; |
1300 | | /// Integral fragment offset table. |
1301 | | FragOffset m_integral_frag_offsets[N_INTEGRAL_FRAG_OFFSETS]; |
1302 | | |
1303 | | // With clustering, our alt may be in cluster |
1304 | | // incoming channel buffer, when we are |
1305 | | // destroyed we decrement the refcount |
1306 | | // on that buffer so that it gets destroyed |
1307 | | // We don't want to use a ref count ptr (Ptr<>) |
1308 | | // since our ownership model requires explicit |
1309 | | // destroys and ref count pointers defeat this |
1310 | | RefCountObj *m_ext_buffer = nullptr; |
1311 | | }; |
1312 | | |
1313 | | class HTTPInfo |
1314 | | { |
1315 | | public: |
1316 | | using FragOffset = HTTPCacheAlt::FragOffset; ///< Import type. |
1317 | | |
1318 | | HTTPCacheAlt *m_alt = nullptr; |
1319 | | |
1320 | 0 | HTTPInfo() {} |
1321 | 0 | ~HTTPInfo() { clear(); } |
1322 | | void |
1323 | | clear() |
1324 | 0 | { |
1325 | 0 | m_alt = nullptr; |
1326 | 0 | } |
1327 | | bool |
1328 | | valid() const |
1329 | 0 | { |
1330 | 0 | return m_alt != nullptr; |
1331 | 0 | } |
1332 | | |
1333 | | void create(); |
1334 | | void destroy(); |
1335 | | |
1336 | | void copy(HTTPInfo *to_copy); |
1337 | | void |
1338 | | copy_shallow(HTTPInfo *info) |
1339 | 0 | { |
1340 | 0 | m_alt = info->m_alt; |
1341 | 0 | } |
1342 | | void copy_frag_offsets_from(HTTPInfo *src); |
1343 | | HTTPInfo &operator=(const HTTPInfo &m); |
1344 | | |
1345 | | int marshal_length(); |
1346 | | int marshal(char *buf, int len); |
1347 | | static int unmarshal(char *buf, int len, RefCountObj *block_ref); |
1348 | | static int unmarshal_v24_1(char *buf, int len, RefCountObj *block_ref); |
1349 | | void set_buffer_reference(RefCountObj *block_ref); |
1350 | | int get_handle(char *buf, int len); |
1351 | | |
1352 | | int32_t |
1353 | | id_get() const |
1354 | 0 | { |
1355 | 0 | return m_alt->m_id; |
1356 | 0 | } |
1357 | | int32_t |
1358 | | rid_get() |
1359 | 0 | { |
1360 | 0 | return m_alt->m_rid; |
1361 | 0 | } |
1362 | | |
1363 | | void |
1364 | | id_set(int32_t id) |
1365 | 0 | { |
1366 | 0 | m_alt->m_id = id; |
1367 | 0 | } |
1368 | | void |
1369 | | rid_set(int32_t id) |
1370 | 0 | { |
1371 | 0 | m_alt->m_rid = id; |
1372 | 0 | } |
1373 | | |
1374 | | CryptoHash object_key_get(); |
1375 | | void object_key_get(CryptoHash *); |
1376 | | bool compare_object_key(const CryptoHash *); |
1377 | | int64_t object_size_get(); |
1378 | | |
1379 | | void |
1380 | | request_get(HTTPHdr *hdr) |
1381 | 0 | { |
1382 | 0 | hdr->copy_shallow(&m_alt->m_request_hdr); |
1383 | 0 | } |
1384 | | void |
1385 | | response_get(HTTPHdr *hdr) |
1386 | 0 | { |
1387 | 0 | hdr->copy_shallow(&m_alt->m_response_hdr); |
1388 | 0 | } |
1389 | | |
1390 | | HTTPHdr * |
1391 | | request_get() |
1392 | 0 | { |
1393 | 0 | return &m_alt->m_request_hdr; |
1394 | 0 | } |
1395 | | HTTPHdr * |
1396 | | response_get() |
1397 | 0 | { |
1398 | 0 | return &m_alt->m_response_hdr; |
1399 | 0 | } |
1400 | | |
1401 | | URL * |
1402 | | request_url_get(URL *url = nullptr) |
1403 | 0 | { |
1404 | 0 | return m_alt->m_request_hdr.url_get(url); |
1405 | 0 | } |
1406 | | |
1407 | | time_t |
1408 | | request_sent_time_get() |
1409 | 0 | { |
1410 | 0 | return m_alt->m_request_sent_time; |
1411 | 0 | } |
1412 | | time_t |
1413 | | response_received_time_get() |
1414 | 0 | { |
1415 | 0 | return m_alt->m_response_received_time; |
1416 | 0 | } |
1417 | | |
1418 | | void object_key_set(CryptoHash &hash); |
1419 | | void object_size_set(int64_t size); |
1420 | | |
1421 | | void |
1422 | | request_set(const HTTPHdr *req) |
1423 | 0 | { |
1424 | 0 | m_alt->m_request_hdr.copy(req); |
1425 | 0 | } |
1426 | | void |
1427 | | response_set(const HTTPHdr *resp) |
1428 | 0 | { |
1429 | 0 | m_alt->m_response_hdr.copy(resp); |
1430 | 0 | } |
1431 | | |
1432 | | void |
1433 | | request_sent_time_set(time_t t) |
1434 | 0 | { |
1435 | 0 | m_alt->m_request_sent_time = t; |
1436 | 0 | } |
1437 | | void |
1438 | | response_received_time_set(time_t t) |
1439 | 0 | { |
1440 | 0 | m_alt->m_response_received_time = t; |
1441 | 0 | } |
1442 | | |
1443 | | /// Get the fragment table. |
1444 | | FragOffset *get_frag_table(); |
1445 | | /// Get the # of fragment offsets |
1446 | | /// @note This is the size of the fragment offset table, and one less |
1447 | | /// than the actual # of fragments. |
1448 | | int get_frag_offset_count(); |
1449 | | /// Add an @a offset to the end of the fragment offset table. |
1450 | | void push_frag_offset(FragOffset offset); |
1451 | | |
1452 | | // Sanity check functions |
1453 | | static bool check_marshalled(char *buf, int len); |
1454 | | |
1455 | | private: |
1456 | | HTTPInfo(const HTTPInfo &h); |
1457 | | }; |
1458 | | |
1459 | | inline void |
1460 | | HTTPInfo::destroy() |
1461 | 0 | { |
1462 | 0 | if (m_alt) { |
1463 | 0 | if (m_alt->m_writeable) { |
1464 | 0 | m_alt->destroy(); |
1465 | 0 | } else if (m_alt->m_ext_buffer) { |
1466 | 0 | if (m_alt->m_ext_buffer->refcount_dec() == 0) { |
1467 | 0 | m_alt->m_ext_buffer->free(); |
1468 | 0 | } |
1469 | 0 | } |
1470 | 0 | } |
1471 | 0 | clear(); |
1472 | 0 | } |
1473 | | |
1474 | | inline HTTPInfo & |
1475 | | HTTPInfo::operator=(const HTTPInfo &m) |
1476 | 0 | { |
1477 | 0 | m_alt = m.m_alt; |
1478 | 0 | return *this; |
1479 | 0 | } |
1480 | | |
1481 | | inline CryptoHash |
1482 | | HTTPInfo::object_key_get() |
1483 | 0 | { |
1484 | 0 | CryptoHash val; |
1485 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&val); |
1486 | 0 |
|
1487 | 0 | memcpy(pi, m_alt->m_object_key, sizeof(CryptoHash)); |
1488 | 0 |
|
1489 | 0 | return val; |
1490 | 0 | } |
1491 | | |
1492 | | inline void |
1493 | | HTTPInfo::object_key_get(CryptoHash *hash) |
1494 | 0 | { |
1495 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(hash); |
1496 | 0 | memcpy(pi, m_alt->m_object_key, CRYPTO_HASH_SIZE); |
1497 | 0 | } |
1498 | | |
1499 | | inline bool |
1500 | | HTTPInfo::compare_object_key(const CryptoHash *hash) |
1501 | 0 | { |
1502 | 0 | int32_t const *pi = reinterpret_cast<int32_t const *>(hash); |
1503 | 0 | return memcmp(pi, m_alt->m_object_key, CRYPTO_HASH_SIZE) == 0; |
1504 | 0 | } |
1505 | | |
1506 | | inline int64_t |
1507 | | HTTPInfo::object_size_get() |
1508 | 0 | { |
1509 | 0 | int64_t val = 0; // make gcc shut up. |
1510 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&val); |
1511 | 0 |
|
1512 | 0 | pi[0] = m_alt->m_object_size[0]; |
1513 | 0 | pi[1] = m_alt->m_object_size[1]; |
1514 | 0 | return val; |
1515 | 0 | } |
1516 | | |
1517 | | inline void |
1518 | | HTTPInfo::object_key_set(CryptoHash &hash) |
1519 | 0 | { |
1520 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&hash); |
1521 | 0 | memcpy(m_alt->m_object_key, pi, CRYPTO_HASH_SIZE); |
1522 | 0 | } |
1523 | | |
1524 | | inline void |
1525 | | HTTPInfo::object_size_set(int64_t size) |
1526 | 0 | { |
1527 | 0 | int32_t *pi = reinterpret_cast<int32_t *>(&size); |
1528 | 0 | m_alt->m_object_size[0] = pi[0]; |
1529 | 0 | m_alt->m_object_size[1] = pi[1]; |
1530 | 0 | } |
1531 | | |
1532 | | inline HTTPInfo::FragOffset * |
1533 | | HTTPInfo::get_frag_table() |
1534 | 0 | { |
1535 | 0 | return m_alt ? m_alt->m_frag_offsets : nullptr; |
1536 | 0 | } |
1537 | | |
1538 | | inline int |
1539 | | HTTPInfo::get_frag_offset_count() |
1540 | 0 | { |
1541 | 0 | return m_alt ? m_alt->m_frag_offset_count : 0; |
1542 | 0 | } |