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 "tscore/Arena.h"
28 #include "tscore/CryptoHash.h"
29 #include "tscore/HTTPVersion.h"
30 #include "MIME.h"
31 #include "URL.h"
32
33 #include "tscore/ink_apidefs.h"
34
35 class Http2HeaderTable;
36
37 enum HTTPStatus {
38 HTTP_STATUS_NONE = 0,
39
40 HTTP_STATUS_CONTINUE = 100,
41 HTTP_STATUS_SWITCHING_PROTOCOL = 101,
42 HTTP_STATUS_EARLY_HINTS = 103,
43
44 HTTP_STATUS_OK = 200,
45 HTTP_STATUS_CREATED = 201,
46 HTTP_STATUS_ACCEPTED = 202,
47 HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,
48 HTTP_STATUS_NO_CONTENT = 204,
49 HTTP_STATUS_RESET_CONTENT = 205,
50 HTTP_STATUS_PARTIAL_CONTENT = 206,
51
52 HTTP_STATUS_MULTIPLE_CHOICES = 300,
53 HTTP_STATUS_MOVED_PERMANENTLY = 301,
54 HTTP_STATUS_MOVED_TEMPORARILY = 302,
55 HTTP_STATUS_SEE_OTHER = 303,
56 HTTP_STATUS_NOT_MODIFIED = 304,
57 HTTP_STATUS_USE_PROXY = 305,
58 HTTP_STATUS_TEMPORARY_REDIRECT = 307,
59 HTTP_STATUS_PERMANENT_REDIRECT = 308,
60
61 HTTP_STATUS_BAD_REQUEST = 400,
62 HTTP_STATUS_UNAUTHORIZED = 401,
63 HTTP_STATUS_PAYMENT_REQUIRED = 402,
64 HTTP_STATUS_FORBIDDEN = 403,
65 HTTP_STATUS_NOT_FOUND = 404,
66 HTTP_STATUS_METHOD_NOT_ALLOWED = 405,
67 HTTP_STATUS_NOT_ACCEPTABLE = 406,
68 HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
69 HTTP_STATUS_REQUEST_TIMEOUT = 408,
70 HTTP_STATUS_CONFLICT = 409,
71 HTTP_STATUS_GONE = 410,
72 HTTP_STATUS_LENGTH_REQUIRED = 411,
73 HTTP_STATUS_PRECONDITION_FAILED = 412,
74 HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE = 413,
75 HTTP_STATUS_REQUEST_URI_TOO_LONG = 414,
76 HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,
77 HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416,
78 HTTP_STATUS_TOO_EARLY = 425,
79
80 HTTP_STATUS_INTERNAL_SERVER_ERROR = 500,
81 HTTP_STATUS_NOT_IMPLEMENTED = 501,
82 HTTP_STATUS_BAD_GATEWAY = 502,
83 HTTP_STATUS_SERVICE_UNAVAILABLE = 503,
84 HTTP_STATUS_GATEWAY_TIMEOUT = 504,
85 HTTP_STATUS_HTTPVER_NOT_SUPPORTED = 505
86 };
87
88 enum HTTPKeepAlive {
89 HTTP_KEEPALIVE_UNDEFINED = 0,
90 HTTP_NO_KEEPALIVE,
91 HTTP_KEEPALIVE,
92 };
93
94 enum HTTPWarningCode {
95 HTTP_WARNING_CODE_NONE = 0,
96
97 HTTP_WARNING_CODE_RESPONSE_STALE = 110,
98 HTTP_WARNING_CODE_REVALIDATION_FAILED = 111,
99 HTTP_WARNING_CODE_DISCONNECTED_OPERATION = 112,
100 HTTP_WARNING_CODE_HERUISTIC_EXPIRATION = 113,
101 HTTP_WARNING_CODE_TRANSFORMATION_APPLIED = 114,
102 HTTP_WARNING_CODE_MISC_WARNING = 199
103 };
104
105 /* squild log codes
106 There is code (e.g. logstats) that depends on these errors coming at the end of this enum */
107 enum SquidLogCode {
108 SQUID_LOG_EMPTY = '0',
109 SQUID_LOG_TCP_HIT = '1',
110 SQUID_LOG_TCP_DISK_HIT = '2',
111 SQUID_LOG_TCP_MEM_HIT = '.', // Don't want to change others codes
112 SQUID_LOG_TCP_MISS = '3',
113 SQUID_LOG_TCP_EXPIRED_MISS = '4',
114 SQUID_LOG_TCP_REFRESH_HIT = '5',
115 SQUID_LOG_TCP_REF_FAIL_HIT = '6',
116 SQUID_LOG_TCP_REFRESH_MISS = '7',
117 SQUID_LOG_TCP_CLIENT_REFRESH = '8',
118 SQUID_LOG_TCP_IMS_HIT = '9',
119 SQUID_LOG_TCP_IMS_MISS = 'a',
120 SQUID_LOG_TCP_SWAPFAIL = 'b',
121 SQUID_LOG_TCP_DENIED = 'c',
122 SQUID_LOG_TCP_WEBFETCH_MISS = 'd',
123 SQUID_LOG_TCP_FUTURE_2 = 'f',
124 SQUID_LOG_TCP_HIT_REDIRECT = '[', // standard redirect
125 SQUID_LOG_TCP_MISS_REDIRECT = ']', // standard redirect
126 SQUID_LOG_TCP_HIT_X_REDIRECT = '<', // extended redirect
127 SQUID_LOG_TCP_MISS_X_REDIRECT = '>', // extended redirect
128 SQUID_LOG_UDP_HIT = 'g',
129 SQUID_LOG_UDP_WEAK_HIT = 'h',
130 SQUID_LOG_UDP_HIT_OBJ = 'i',
131 SQUID_LOG_UDP_MISS = 'j',
132 SQUID_LOG_UDP_DENIED = 'k',
133 SQUID_LOG_UDP_INVALID = 'l',
134 SQUID_LOG_UDP_RELOADING = 'm',
135 SQUID_LOG_UDP_FUTURE_1 = 'n',
136 SQUID_LOG_UDP_FUTURE_2 = 'o',
137 SQUID_LOG_ERR_READ_TIMEOUT = 'p',
138 SQUID_LOG_ERR_LIFETIME_EXP = 'q',
139 SQUID_LOG_ERR_POST_ENTITY_TOO_LARGE = 'L',
140 SQUID_LOG_ERR_NO_CLIENTS_BIG_OBJ = 'r',
141 SQUID_LOG_ERR_READ_ERROR = 's',
142 SQUID_LOG_ERR_CLIENT_ABORT = 't', // Client side abort logging
143 SQUID_LOG_ERR_CONNECT_FAIL = 'u',
144 SQUID_LOG_ERR_INVALID_REQ = 'v',
145 SQUID_LOG_ERR_UNSUP_REQ = 'w',
146 SQUID_LOG_ERR_INVALID_URL = 'x',
147 SQUID_LOG_ERR_NO_FDS = 'y',
148 SQUID_LOG_ERR_DNS_FAIL = 'z',
149 SQUID_LOG_ERR_NOT_IMPLEMENTED = 'A',
150 SQUID_LOG_ERR_CANNOT_FETCH = 'B',
151 SQUID_LOG_ERR_NO_RELAY = 'C',
152 SQUID_LOG_ERR_DISK_IO = 'D',
153 SQUID_LOG_ERR_ZERO_SIZE_OBJECT = 'E',
154 SQUID_LOG_ERR_PROXY_DENIED = 'G',
155 SQUID_LOG_ERR_WEBFETCH_DETECTED = 'H',
156 SQUID_LOG_ERR_FUTURE_1 = 'I',
157 SQUID_LOG_ERR_CLIENT_READ_ERROR = 'J', // Client side abort logging
158 SQUID_LOG_ERR_LOOP_DETECTED = 'K', // Loop or cycle detected, request came back to this server
159 SQUID_LOG_ERR_UNKNOWN = 'Z'
160 };
161
162 // squild log subcodes
163 enum SquidSubcode {
164 SQUID_SUBCODE_EMPTY = '0',
165 SQUID_SUBCODE_NUM_REDIRECTIONS_EXCEEDED = '1',
166 };
167
168 /* squid hieratchy codes */
169 enum SquidHierarchyCode {
170 SQUID_HIER_EMPTY = '0',
171 SQUID_HIER_NONE = '1',
172 SQUID_HIER_DIRECT = '2',
173 SQUID_HIER_SIBLING_HIT = '3',
174 SQUID_HIER_PARENT_HIT = '4',
175 SQUID_HIER_DEFAULT_PARENT = '5',
176 SQUID_HIER_SINGLE_PARENT = '6',
177 SQUID_HIER_FIRST_UP_PARENT = '7',
178 SQUID_HIER_NO_PARENT_DIRECT = '8',
179 SQUID_HIER_FIRST_PARENT_MISS = '9',
180 SQUID_HIER_LOCAL_IP_DIRECT = 'a',
181 SQUID_HIER_FIREWALL_IP_DIRECT = 'b',
182 SQUID_HIER_NO_DIRECT_FAIL = 'c',
183 SQUID_HIER_SOURCE_FASTEST = 'd',
184 SQUID_HIER_SIBLING_UDP_HIT_OBJ = 'e',
185 SQUID_HIER_PARENT_UDP_HIT_OBJ = 'f',
186 SQUID_HIER_PASSTHROUGH_PARENT = 'g',
187 SQUID_HIER_SSL_PARENT_MISS = 'h',
188 SQUID_HIER_INVALID_CODE = 'i',
189 SQUID_HIER_TIMEOUT_DIRECT = 'j',
190 SQUID_HIER_TIMEOUT_SIBLING_HIT = 'k',
191 SQUID_HIER_TIMEOUT_PARENT_HIT = 'l',
192 SQUID_HIER_TIMEOUT_DEFAULT_PARENT = 'm',
193 SQUID_HIER_TIMEOUT_SINGLE_PARENT = 'n',
194 SQUID_HIER_TIMEOUT_FIRST_UP_PARENT = 'o',
195 SQUID_HIER_TIMEOUT_NO_PARENT_DIRECT = 'p',
196 SQUID_HIER_TIMEOUT_FIRST_PARENT_MISS = 'q',
197 SQUID_HIER_TIMEOUT_LOCAL_IP_DIRECT = 'r',
198 SQUID_HIER_TIMEOUT_FIREWALL_IP_DIRECT = 's',
199 SQUID_HIER_TIMEOUT_NO_DIRECT_FAIL = 't',
200 SQUID_HIER_TIMEOUT_SOURCE_FASTEST = 'u',
201 SQUID_HIER_TIMEOUT_SIBLING_UDP_HIT_OBJ = 'v',
202 SQUID_HIER_TIMEOUT_PARENT_UDP_HIT_OBJ = 'w',
203 SQUID_HIER_TIMEOUT_PASSTHROUGH_PARENT = 'x',
204 SQUID_HIER_TIMEOUT_TIMEOUT_SSL_PARENT_MISS = 'y',
205 SQUID_HIER_INVALID_ASSIGNED_CODE = 'z'
206 };
207
208 /* squid hit/miss codes */
209 enum SquidHitMissCode {
210 SQUID_HIT_RESERVED = '0', // Kinda wonky that this is '0', so skipping 'A' for now
211 SQUID_HIT_LEVEL_1 = 'B',
212 SQUID_HIT_LEVEL_2 = 'C',
213 SQUID_HIT_LEVEL_3 = 'D',
214 SQUID_HIT_LEVEL_4 = 'E',
215 SQUID_HIT_LEVEL_5 = 'F',
216 SQUID_HIT_LEVEL_6 = 'G',
217 SQUID_HIT_LEVEL_7 = 'H',
218 SQUID_HIT_LEVEL_8 = 'I',
219 SQUID_HIT_LEVEl_9 = 'J',
220 SQUID_MISS_NONE = '1',
221 SQUID_MISS_HTTP_NON_CACHE = '3',
222 SQUID_MISS_HTTP_NO_DLE = '5',
223 SQUID_MISS_HTTP_NO_LE = '6',
224 SQUID_MISS_HTTP_CONTENT = '7',
225 SQUID_MISS_PRAGMA_NOCACHE = '8',
226 SQUID_MISS_PASS = '9',
227 SQUID_MISS_PRE_EXPIRED = 'a',
228 SQUID_MISS_ERROR = 'b',
229 SQUID_MISS_CACHE_BYPASS = 'c',
230 SQUID_HIT_MISS_INVALID_ASSIGNED_CODE = 'z',
231 // These are pre-allocated with special semantics, added here for convenience
232 SQUID_HIT_RAM = SQUID_HIT_LEVEL_1,
233 SQUID_HIT_SSD = SQUID_HIT_LEVEL_2,
234 SQUID_HIT_DISK = SQUID_HIT_LEVEL_3,
235 SQUID_HIT_CLUSTER = SQUID_HIT_LEVEL_4,
236 SQUID_HIT_NET = SQUID_HIT_LEVEL_5
237 };
238
239 enum HTTPType {
240 HTTP_TYPE_UNKNOWN,
241 HTTP_TYPE_REQUEST,
242 HTTP_TYPE_RESPONSE,
243 };
244
245 struct HTTPHdrImpl : public HdrHeapObjImpl {
246 // HdrHeapObjImpl is 4 bytes
247 HTTPType m_polarity; // request or response or unknown
248 HTTPVersion m_version; // cooked version number
249 // 12 bytes means 4 bytes padding here on 64-bit architectures
250 union {
251 struct {
252 URLImpl *m_url_impl;
253 const char *m_ptr_method;
254 uint16_t m_len_method;
255 int16_t m_method_wks_idx;
256 } req;
257
258 struct {
259 const char *m_ptr_reason;
260 uint16_t m_len_reason;
261 int16_t m_status;
262 } resp;
263 } u;
264
265 MIMEHdrImpl *m_fields_impl;
266
267 // Marshaling Functions
268 int marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str);
269 void unmarshal(intptr_t offset);
270 void move_strings(HdrStrHeap *new_heap);
271 size_t strings_length();
272
273 // Sanity Check Functions
274 void check_strings(HeapCheck *heaps, int num_heaps);
275 };
276
277 struct HTTPValAccept {
278 char *type;
279 char *subtype;
280 double qvalue;
281 };
282
283 struct HTTPValAcceptCharset {
284 char *charset;
285 double qvalue;
286 };
287
288 struct HTTPValAcceptEncoding {
289 char *encoding;
290 double qvalue;
291 };
292
293 struct HTTPValAcceptLanguage {
294 char *language;
295 double qvalue;
296 };
297
298 struct HTTPValFieldList {
299 char *name;
300 HTTPValFieldList *next;
301 };
302
303 struct HTTPValCacheControl {
304 const char *directive;
305
306 union {
307 int delta_seconds;
308 HTTPValFieldList *field_names;
309 } u;
310 };
311
312 struct HTTPValRange {
313 int start;
314 int end;
315 HTTPValRange *next;
316 };
317
318 struct HTTPValTE {
319 char *encoding;
320 double qvalue;
321 };
322
323 struct HTTPParser {
324 bool m_parsing_http = false;
325 MIMEParser m_mime_parser;
326 };
327
328 extern const char *HTTP_METHOD_CONNECT;
329 extern const char *HTTP_METHOD_DELETE;
330 extern const char *HTTP_METHOD_GET;
331 extern const char *HTTP_METHOD_HEAD;
332 extern const char *HTTP_METHOD_OPTIONS;
333 extern const char *HTTP_METHOD_POST;
334 extern const char *HTTP_METHOD_PURGE;
335 extern const char *HTTP_METHOD_PUT;
336 extern const char *HTTP_METHOD_TRACE;
337 extern const char *HTTP_METHOD_PUSH;
338
339 extern int HTTP_WKSIDX_CONNECT;
340 extern int HTTP_WKSIDX_DELETE;
341 extern int HTTP_WKSIDX_GET;
342 extern int HTTP_WKSIDX_HEAD;
343 extern int HTTP_WKSIDX_OPTIONS;
344 extern int HTTP_WKSIDX_POST;
345 extern int HTTP_WKSIDX_PURGE;
346 extern int HTTP_WKSIDX_PUT;
347 extern int HTTP_WKSIDX_TRACE;
348 extern int HTTP_WKSIDX_PUSH;
349 extern int HTTP_WKSIDX_METHODS_CNT;
350
351 extern int HTTP_LEN_CONNECT;
352 extern int HTTP_LEN_DELETE;
353 extern int HTTP_LEN_GET;
354 extern int HTTP_LEN_HEAD;
355 extern int HTTP_LEN_OPTIONS;
356 extern int HTTP_LEN_POST;
357 extern int HTTP_LEN_PURGE;
358 extern int HTTP_LEN_PUT;
359 extern int HTTP_LEN_TRACE;
360 extern int HTTP_LEN_PUSH;
361
362 extern const char *HTTP_VALUE_BYTES;
363 extern const char *HTTP_VALUE_CHUNKED;
364 extern const char *HTTP_VALUE_CLOSE;
365 extern const char *HTTP_VALUE_COMPRESS;
366 extern const char *HTTP_VALUE_DEFLATE;
367 extern const char *HTTP_VALUE_GZIP;
368 extern const char *HTTP_VALUE_IDENTITY;
369 extern const char *HTTP_VALUE_KEEP_ALIVE;
370 extern const char *HTTP_VALUE_MAX_AGE;
371 extern const char *HTTP_VALUE_MAX_STALE;
372 extern const char *HTTP_VALUE_MIN_FRESH;
373 extern const char *HTTP_VALUE_MUST_REVALIDATE;
374 extern const char *HTTP_VALUE_NONE;
375 extern const char *HTTP_VALUE_NO_CACHE;
376 extern const char *HTTP_VALUE_NO_STORE;
377 extern const char *HTTP_VALUE_NO_TRANSFORM;
378 extern const char *HTTP_VALUE_ONLY_IF_CACHED;
379 extern const char *HTTP_VALUE_PRIVATE;
380 extern const char *HTTP_VALUE_PROXY_REVALIDATE;
381 extern const char *HTTP_VALUE_PUBLIC;
382 extern const char *HTTP_VALUE_S_MAXAGE;
383 extern const char *HTTP_VALUE_NEED_REVALIDATE_ONCE;
384 extern const char *HTTP_VALUE_100_CONTINUE;
385
386 extern int HTTP_LEN_BYTES;
387 extern int HTTP_LEN_CHUNKED;
388 extern int HTTP_LEN_CLOSE;
389 extern int HTTP_LEN_COMPRESS;
390 extern int HTTP_LEN_DEFLATE;
391 extern int HTTP_LEN_GZIP;
392 extern int HTTP_LEN_IDENTITY;
393 extern int HTTP_LEN_KEEP_ALIVE;
394 extern int HTTP_LEN_MAX_AGE;
395 extern int HTTP_LEN_MAX_STALE;
396 extern int HTTP_LEN_MIN_FRESH;
397 extern int HTTP_LEN_MUST_REVALIDATE;
398 extern int HTTP_LEN_NONE;
399 extern int HTTP_LEN_NO_CACHE;
400 extern int HTTP_LEN_NO_STORE;
401 extern int HTTP_LEN_NO_TRANSFORM;
402 extern int HTTP_LEN_ONLY_IF_CACHED;
403 extern int HTTP_LEN_PRIVATE;
404 extern int HTTP_LEN_PROXY_REVALIDATE;
405 extern int HTTP_LEN_PUBLIC;
406 extern int HTTP_LEN_S_MAXAGE;
407 extern int HTTP_LEN_NEED_REVALIDATE_ONCE;
408 extern int HTTP_LEN_100_CONTINUE;
409
410 /* Private */
411 void http_hdr_adjust(HTTPHdrImpl *hdrp, int32_t offset, int32_t length, int32_t delta);
412
413 /* Public */
414 void http_init();
415
416 inkcoreapi HTTPHdrImpl *http_hdr_create(HdrHeap *heap, HTTPType polarity);
417 void http_hdr_init(HdrHeap *heap, HTTPHdrImpl *hh, HTTPType polarity);
418 HTTPHdrImpl *http_hdr_clone(HTTPHdrImpl *s_hh, HdrHeap *s_heap, HdrHeap *d_heap);
419 void http_hdr_copy_onto(HTTPHdrImpl *s_hh, HdrHeap *s_heap, HTTPHdrImpl *d_hh, HdrHeap *d_heap, bool inherit_strs);
420
421 inkcoreapi int http_hdr_print(HdrHeap *heap, HTTPHdrImpl *hh, char *buf, int bufsize, int *bufindex, int *dumpoffset);
422
423 void http_hdr_describe(HdrHeapObjImpl *obj, bool recurse = true);
424
425 inkcoreapi bool http_hdr_version_set(HTTPHdrImpl *hh, const HTTPVersion &ver);
426
427 const char *http_hdr_method_get(HTTPHdrImpl *hh, int *length);
428 inkcoreapi void http_hdr_method_set(HdrHeap *heap, HTTPHdrImpl *hh, const char *method, int16_t method_wks_idx, int method_length,
429 bool must_copy);
430
431 void http_hdr_url_set(HdrHeap *heap, HTTPHdrImpl *hh, URLImpl *url);
432
433 // HTTPStatus http_hdr_status_get (HTTPHdrImpl *hh);
434 void http_hdr_status_set(HTTPHdrImpl *hh, HTTPStatus status);
435 const char *http_hdr_reason_get(HTTPHdrImpl *hh, int *length);
436 void http_hdr_reason_set(HdrHeap *heap, HTTPHdrImpl *hh, const char *value, int length, bool must_copy);
437 const char *http_hdr_reason_lookup(unsigned status);
438
439 void http_parser_init(HTTPParser *parser);
440 void http_parser_clear(HTTPParser *parser);
441 ParseResult http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end,
442 bool must_copy_strings, bool eof, bool strict_uri_parsing, size_t max_request_line_size,
443 size_t max_hdr_field_size);
444 ParseResult validate_hdr_host(HTTPHdrImpl *hh);
445 ParseResult validate_hdr_content_length(HdrHeap *heap, HTTPHdrImpl *hh);
446 ParseResult http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end,
447 bool must_copy_strings, bool eof);
448
449 HTTPStatus http_parse_status(const char *start, const char *end);
450 HTTPVersion http_parse_version(const char *start, const char *end);
451
452 /*
453 HTTPValAccept* http_parse_accept (const char *buf, Arena *arena);
454 HTTPValAcceptCharset* http_parse_accept_charset (const char *buf, Arena *arena);
455 HTTPValAcceptEncoding* http_parse_accept_encoding (const char *buf, Arena *arena);
456 HTTPValAcceptLanguage* http_parse_accept_language (const char *buf, Arena *arena);
457 HTTPValCacheControl* http_parse_cache_control (const char *buf, Arena *arena);
458 const char* http_parse_cache_directive (const char **buf);
459 HTTPValRange* http_parse_range (const char *buf, Arena *arena);
460 */
461 HTTPValTE *http_parse_te(const char *buf, int len, Arena *arena);
462
463 bool is_http1_hdr_version_supported(const HTTPVersion &http_version);
464
465 class IOBufferReader;
466
467 class HTTPHdr : public MIMEHdr
468 {
469 public:
470 HTTPHdrImpl *m_http = nullptr;
471 // This is all cached data and so is mutable.
472 mutable URL m_url_cached;
473 mutable MIMEField *m_host_mime = nullptr;
474 mutable int m_host_length = 0; ///< Length of hostname.
475 mutable int m_port = 0; ///< Target port.
476 mutable bool m_target_cached = false; ///< Whether host name and port are cached.
477 mutable bool m_target_in_url = false; ///< Whether host name and port are in the URL.
478 mutable bool m_100_continue_required = false; ///< Whether 100_continue is in the Expect header.
479 /// Set if the port was effectively specified in the header.
480 /// @c true if the target (in the URL or the HOST field) also specified
481 /// a port. That is, @c true if whatever source had the target host
482 /// also had a port, @c false otherwise.
483 mutable bool m_port_in_header = false;
484
485 mutable bool early_data = false;
486
487 HTTPHdr() = default; // Force the creation of the default constructor
488
489 int valid() const;
490
491 void create(HTTPType polarity, HdrHeap *heap = nullptr);
492 void clear();
493 void reset();
494 void copy(const HTTPHdr *hdr);
495 void copy_shallow(const HTTPHdr *hdr);
496
497 int unmarshal(char *buf, int len, RefCountObj *block_ref);
498
499 int print(char *buf, int bufsize, int *bufindex, int *dumpoffset);
500
501 int length_get() const;
502
503 HTTPType type_get() const;
504
505 HTTPVersion version_get() const;
506 void version_set(HTTPVersion version);
507
508 const char *method_get(int *length);
509 int method_get_wksidx();
510 void method_set(const char *value, int length);
511
512 URL *url_create(URL *url);
513
514 URL *url_get() const;
515 URL *url_get(URL *url);
516 /** Get a string with the effective URL in it.
517 If @a length is not @c NULL then the length of the string
518 is stored in the int pointed to by @a length.
519
520 Note that this can be different from getting the @c URL
521 and invoking @c URL::string_get if the host is in a header
522 field and not explicitly in the URL.
523 */
524 char *url_string_get(Arena *arena = nullptr, ///< Arena to use, or @c malloc if NULL.
525 int *length = nullptr ///< Store string length here.
526 );
527 /** Get a string with the effective URL in it.
528 This is automatically allocated if needed in the request heap.
529
530 @see url_string_get
531 */
532 char *url_string_get_ref(int *length = nullptr ///< Store string length here.
533 );
534
535 /** Print the URL.
536 Output is not null terminated.
537 @return 0 on failure, non-zero on success.
538 */
539 int url_print(char *buff, ///< Output buffer
540 int length, ///< Length of @a buffer
541 int *offset, ///< [in,out] ???
542 int *skip, ///< [in,out] ???
543 unsigned normalization_flags = URLNormalize::NONE ///< host/scheme normalized to lower case
544 );
545
546 /** Return the length of the URL that url_print() will create.
547 @return -1 on failure, non-negative on success.
548 */
549 int url_printed_length(unsigned normalizaion_flags = URLNormalize::NONE);
550
551 /** Get the URL path.
552 This is a reference, not allocated.
553 @return A pointer to the path or @c NULL if there is no valid URL.
554 */
555 const char *path_get(int *length ///< Storage for path length.
556 );
557
558 /** Get the URL matrix params.
559 This is a reference, not allocated.
560 @return A pointer to the matrix params or @c NULL if there is no valid URL.
561 */
562 const char *params_get(int *length ///< Storage for param length.
563 );
564
565 /** Get the URL query.
566 This is a reference, not allocated.
567 @return A pointer to the query or @c NULL if there is no valid URL.
568 */
569 const char *query_get(int *length ///< Storage for query length.
570 );
571
572 /** Get the URL fragment.
573 This is a reference, not allocated.
574 @return A pointer to the fragment or @c NULL if there is no valid URL.
575 */
576 const char *fragment_get(int *length ///< Storage for fragment length.
577 );
578
579 /** Get the target host name.
580 The length is returned in @a length if non-NULL.
581 @note The results are cached so this is fast after the first call.
582 @return A pointer to the host name.
583 */
584 const char *host_get(int *length = nullptr) const;
585
586 /** Get the target port.
587 If the target port is not found then it is adjusted to the
588 default port for the URL type.
589 @note The results are cached so this is fast after the first call.
590 @return The canonicalized target port.
591 */
592 int port_get();
593
594 /** Get the URL scheme.
595 This is a reference, not allocated.
596 @return A pointer to the scheme or @c NULL if there is no valid URL.
597 */
598 const char *scheme_get(int *length ///< Storage for path length.
599 );
600 void url_set(URL *url);
601 void url_set_as_server_url(URL *url);
602 void url_set(const char *str, int length);
603
604 /// Check location of target host.
605 /// @return @c true if the host was in the URL, @c false otherwise.
606 /// @note This returns @c false if the host is missing.
607 bool is_target_in_url() const;
608
609 /// Check if a port was specified in the target.
610 /// @return @c true if the port was part of the target.
611 bool is_port_in_header() const;
612
613 /// If the target is in the fields and not the URL, copy it to the @a url.
614 /// If @a url is @c NULL the cached URL in this header is used.
615 /// @note In the default case the copy is avoided if the cached URL already
616 /// has the target. If @a url is non @c NULL the copy is always performed.
617 void set_url_target_from_host_field(URL *url = nullptr);
618
619 /// Mark the target cache as invalid.
620 /// @internal Ugly but too many places currently that touch the
621 /// header internals, they must be able to do this.
622 void mark_target_dirty() const;
623
624 HTTPStatus status_get() const;
625 void status_set(HTTPStatus status);
626
627 const char *reason_get(int *length);
628 void reason_set(const char *value, int length);
629
630 void mark_early_data(bool flag = true) const;
631 bool is_early_data() const;
632
633 ParseResult parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, bool strict_uri_parsing = false,
634 size_t max_request_line_size = UINT16_MAX, size_t max_hdr_field_size = 131070);
635 ParseResult parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof);
636
637 ParseResult parse_req(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof, bool strict_uri_parsing = false,
638 size_t max_request_line_size = UINT16_MAX, size_t max_hdr_field_size = UINT16_MAX);
639 ParseResult parse_resp(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof);
640
641 bool check_hdr_implements();
642
643 public:
644 // Utility routines
645 bool is_cache_control_set(const char *cc_directive_wks);
646 bool is_pragma_no_cache_set();
647 bool is_keep_alive_set() const;
648 bool expect_final_response() const;
649 HTTPKeepAlive keep_alive_get() const;
650
651 protected:
652 /** Load the target cache.
653 @see m_host, m_port, m_target_in_url
654 */
655 void _fill_target_cache() const;
656 /** Test the cache and fill it if necessary.
657 @internal In contrast to @c _fill_target_cache, this method
658 is inline and checks whether the cache is already filled.
659 @ _fill_target_cache @b always does a cache fill.
660 */
661 void _test_and_fill_target_cache() const;
662
663 static Arena *const USE_HDR_HEAP_MAGIC;
664
665 // No gratuitous copies!
666 HTTPHdr(const HTTPHdr &m) = delete;
667 HTTPHdr &operator=(const HTTPHdr &m) = delete;
668
669 private:
670 friend class UrlPrintHack; // don't ask.
671 };
672
673 /*-------------------------------------------------------------------------
674 -------------------------------------------------------------------------*/
675
676 inline int
valid()677 HTTPHdr::valid() const
678 {
679 return (m_http && m_mime && m_heap);
680 }
681
682 /*-------------------------------------------------------------------------
683 -------------------------------------------------------------------------*/
684
685 inline void
create(HTTPType polarity,HdrHeap * heap)686 HTTPHdr::create(HTTPType polarity, HdrHeap *heap)
687 {
688 if (heap) {
689 m_heap = heap;
690 } else if (!m_heap) {
691 m_heap = new_HdrHeap();
692 }
693
694 m_http = http_hdr_create(m_heap, polarity);
695 m_mime = m_http->m_fields_impl;
696 }
697
698 inline void
clear()699 HTTPHdr::clear()
700 {
701 if (m_http && m_http->m_polarity == HTTP_TYPE_REQUEST) {
702 m_url_cached.clear();
703 }
704 this->HdrHeapSDKHandle::clear();
705 m_http = nullptr;
706 m_mime = nullptr;
707 }
708
709 inline void
reset()710 HTTPHdr::reset()
711 {
712 m_heap = nullptr;
713 m_http = nullptr;
714 m_mime = nullptr;
715 m_url_cached.reset();
716 }
717
718 /*-------------------------------------------------------------------------
719 -------------------------------------------------------------------------*/
720
721 inline void
copy(const HTTPHdr * hdr)722 HTTPHdr::copy(const HTTPHdr *hdr)
723 {
724 ink_assert(hdr->valid());
725
726 if (valid()) {
727 http_hdr_copy_onto(hdr->m_http, hdr->m_heap, m_http, m_heap, (m_heap != hdr->m_heap) ? true : false);
728 } else {
729 m_heap = new_HdrHeap();
730 m_http = http_hdr_clone(hdr->m_http, hdr->m_heap, m_heap);
731 m_mime = m_http->m_fields_impl;
732 }
733 }
734
735 /*-------------------------------------------------------------------------
736 -------------------------------------------------------------------------*/
737
738 inline void
copy_shallow(const HTTPHdr * hdr)739 HTTPHdr::copy_shallow(const HTTPHdr *hdr)
740 {
741 ink_assert(hdr->valid());
742
743 m_heap = hdr->m_heap;
744 m_http = hdr->m_http;
745 m_mime = hdr->m_mime;
746
747 if (hdr->type_get() == HTTP_TYPE_REQUEST && m_url_cached.valid())
748 m_url_cached.copy_shallow(&hdr->m_url_cached);
749 }
750
751 /*-------------------------------------------------------------------------
752 -------------------------------------------------------------------------*/
753
754 inline int
print(char * buf,int bufsize,int * bufindex,int * dumpoffset)755 HTTPHdr::print(char *buf, int bufsize, int *bufindex, int *dumpoffset)
756 {
757 ink_assert(valid());
758 return http_hdr_print(m_heap, m_http, buf, bufsize, bufindex, dumpoffset);
759 }
760
761 /*-------------------------------------------------------------------------
762 -------------------------------------------------------------------------*/
763
764 inline void
_test_and_fill_target_cache()765 HTTPHdr::_test_and_fill_target_cache() const
766 {
767 if (!m_target_cached)
768 this->_fill_target_cache();
769 }
770
771 /*-------------------------------------------------------------------------
772 -------------------------------------------------------------------------*/
773
774 inline const char *
host_get(int * length)775 HTTPHdr::host_get(int *length) const
776 {
777 this->_test_and_fill_target_cache();
778 if (m_target_in_url) {
779 return url_get()->host_get(length);
780 } else if (m_host_mime) {
781 if (length)
782 *length = m_host_length;
783 return m_host_mime->m_ptr_value;
784 }
785
786 if (length)
787 *length = 0;
788 return nullptr;
789 }
790
791 /*-------------------------------------------------------------------------
792 -------------------------------------------------------------------------*/
793
794 inline int
port_get()795 HTTPHdr::port_get()
796 {
797 this->_test_and_fill_target_cache();
798 return m_port;
799 }
800
801 /*-------------------------------------------------------------------------
802 -------------------------------------------------------------------------*/
803
804 inline bool
is_target_in_url()805 HTTPHdr::is_target_in_url() const
806 {
807 this->_test_and_fill_target_cache();
808 return m_target_in_url;
809 }
810
811 /*-------------------------------------------------------------------------
812 -------------------------------------------------------------------------*/
813
814 inline bool
is_port_in_header()815 HTTPHdr::is_port_in_header() const
816 {
817 this->_test_and_fill_target_cache();
818 return m_port_in_header;
819 }
820
821 /*-------------------------------------------------------------------------
822 -------------------------------------------------------------------------*/
823
824 inline void
mark_target_dirty()825 HTTPHdr::mark_target_dirty() const
826 {
827 m_target_cached = false;
828 }
829 /*-------------------------------------------------------------------------
830 -------------------------------------------------------------------------*/
831
832 inline HTTPType
http_hdr_type_get(HTTPHdrImpl * hh)833 http_hdr_type_get(HTTPHdrImpl *hh)
834 {
835 return (hh->m_polarity);
836 }
837
838 /*-------------------------------------------------------------------------
839 -------------------------------------------------------------------------*/
840
841 inline HTTPType
type_get()842 HTTPHdr::type_get() const
843 {
844 ink_assert(valid());
845 return http_hdr_type_get(m_http);
846 }
847
848 /*-------------------------------------------------------------------------
849 -------------------------------------------------------------------------*/
850
851 inline HTTPVersion
version_get()852 HTTPHdr::version_get() const
853 {
854 ink_assert(valid());
855 return m_http->m_version;
856 }
857
858 /*-------------------------------------------------------------------------
859 -------------------------------------------------------------------------*/
860
861 inline static HTTPKeepAlive
is_header_keep_alive(const HTTPVersion & http_version,const MIMEField * con_hdr)862 is_header_keep_alive(const HTTPVersion &http_version, const MIMEField *con_hdr)
863 {
864 enum {
865 CON_TOKEN_NONE = 0,
866 CON_TOKEN_KEEP_ALIVE,
867 CON_TOKEN_CLOSE,
868 };
869
870 int con_token = CON_TOKEN_NONE;
871 HTTPKeepAlive keep_alive = HTTP_NO_KEEPALIVE;
872 // *unknown_tokens = false;
873
874 if (con_hdr) {
875 if (con_hdr->value_get_index("keep-alive", 10) >= 0)
876 con_token = CON_TOKEN_KEEP_ALIVE;
877 else if (con_hdr->value_get_index("close", 5) >= 0)
878 con_token = CON_TOKEN_CLOSE;
879 }
880
881 if (HTTP_1_0 == http_version) {
882 keep_alive = (con_token == CON_TOKEN_KEEP_ALIVE) ? (HTTP_KEEPALIVE) : (HTTP_NO_KEEPALIVE);
883 } else if (HTTP_1_1 == http_version) {
884 // We deviate from the spec here. If the we got a response where
885 // where there is no Connection header and the request 1.0 was
886 // 1.0 don't treat this as keep-alive since Netscape-Enterprise/3.6 SP1
887 // server doesn't
888 keep_alive = ((con_token == CON_TOKEN_KEEP_ALIVE) || (con_token == CON_TOKEN_NONE && HTTP_1_1 == http_version)) ?
889 (HTTP_KEEPALIVE) :
890 (HTTP_NO_KEEPALIVE);
891 } else {
892 keep_alive = HTTP_NO_KEEPALIVE;
893 }
894 return (keep_alive);
895 }
896
897 inline HTTPKeepAlive
keep_alive_get()898 HTTPHdr::keep_alive_get() const
899 {
900 HTTPKeepAlive retval = HTTP_NO_KEEPALIVE;
901 const MIMEField *pc = this->field_find(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION);
902 if (pc != nullptr) {
903 retval = is_header_keep_alive(this->version_get(), pc);
904 } else {
905 const MIMEField *c = this->field_find(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);
906 retval = is_header_keep_alive(this->version_get(), c);
907 }
908 return retval;
909 }
910
911 inline bool
is_keep_alive_set()912 HTTPHdr::is_keep_alive_set() const
913 {
914 return this->keep_alive_get() == HTTP_KEEPALIVE;
915 }
916
917 /**
918 Check the status code is informational and expecting final response
919 - e.g. "100 Continue", "103 Early Hints"
920
921 Please note that "101 Switching Protocol" is not included.
922 */
923 inline bool
expect_final_response()924 HTTPHdr::expect_final_response() const
925 {
926 switch (this->status_get()) {
927 case HTTP_STATUS_CONTINUE:
928 case HTTP_STATUS_EARLY_HINTS:
929 return true;
930 default:
931 return false;
932 }
933 }
934
935 /*-------------------------------------------------------------------------
936 -------------------------------------------------------------------------*/
937
938 inline void
version_set(HTTPVersion version)939 HTTPHdr::version_set(HTTPVersion version)
940 {
941 ink_assert(valid());
942 http_hdr_version_set(m_http, version);
943 }
944
945 /*-------------------------------------------------------------------------
946 -------------------------------------------------------------------------*/
947
948 inline const char *
method_get(int * length)949 HTTPHdr::method_get(int *length)
950 {
951 ink_assert(valid());
952 ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
953
954 return http_hdr_method_get(m_http, length);
955 }
956
957 inline int
method_get_wksidx()958 HTTPHdr::method_get_wksidx()
959 {
960 ink_assert(valid());
961 ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
962
963 return (m_http->u.req.m_method_wks_idx);
964 }
965
966 /*-------------------------------------------------------------------------
967 -------------------------------------------------------------------------*/
968
969 inline void
method_set(const char * value,int length)970 HTTPHdr::method_set(const char *value, int length)
971 {
972 ink_assert(valid());
973 ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
974
975 int method_wks_idx = hdrtoken_tokenize(value, length);
976 http_hdr_method_set(m_heap, m_http, value, method_wks_idx, length, true);
977 }
978
979 /*-------------------------------------------------------------------------
980 -------------------------------------------------------------------------*/
981
982 inline URL *
url_create(URL * u)983 HTTPHdr::url_create(URL *u)
984 {
985 ink_assert(valid());
986 ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
987
988 u->set(this);
989 u->create(m_heap);
990 return (u);
991 }
992
993 /*-------------------------------------------------------------------------
994 -------------------------------------------------------------------------*/
995
996 inline URL *
url_get()997 HTTPHdr::url_get() const
998 {
999 ink_assert(valid());
1000 ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
1001
1002 // It's entirely possible that someone changed URL in our impl
1003 // without updating the cached copy in the C++ layer. Check
1004 // to see if this happened before handing back the url
1005
1006 URLImpl *real_impl = m_http->u.req.m_url_impl;
1007 if (m_url_cached.m_url_impl != real_impl) {
1008 m_url_cached.set(this);
1009 m_url_cached.m_url_impl = real_impl;
1010 this->mark_target_dirty();
1011 }
1012 return (&m_url_cached);
1013 }
1014
1015 /*-------------------------------------------------------------------------
1016 -------------------------------------------------------------------------*/
1017
1018 inline URL *
url_get(URL * url)1019 HTTPHdr::url_get(URL *url)
1020 {
1021 ink_assert(valid());
1022 ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
1023
1024 url->set(this); // attach refcount
1025 url->m_url_impl = m_http->u.req.m_url_impl;
1026 return (url);
1027 }
1028
1029 /*-------------------------------------------------------------------------
1030 -------------------------------------------------------------------------*/
1031
1032 inline void
url_set(URL * url)1033 HTTPHdr::url_set(URL *url)
1034 {
1035 ink_assert(valid());
1036 ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
1037
1038 URLImpl *url_impl = m_http->u.req.m_url_impl;
1039 ::url_copy_onto(url->m_url_impl, url->m_heap, url_impl, m_heap, true);
1040 }
1041
1042 /*-------------------------------------------------------------------------
1043 -------------------------------------------------------------------------*/
1044
1045 inline void
url_set_as_server_url(URL * url)1046 HTTPHdr::url_set_as_server_url(URL *url)
1047 {
1048 ink_assert(valid());
1049 ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
1050
1051 URLImpl *url_impl = m_http->u.req.m_url_impl;
1052 ::url_copy_onto_as_server_url(url->m_url_impl, url->m_heap, url_impl, m_heap, true);
1053 }
1054
1055 /*-------------------------------------------------------------------------
1056 -------------------------------------------------------------------------*/
1057
1058 inline void
url_set(const char * str,int length)1059 HTTPHdr::url_set(const char *str, int length)
1060 {
1061 URLImpl *url_impl;
1062
1063 ink_assert(valid());
1064 ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
1065
1066 url_impl = m_http->u.req.m_url_impl;
1067 ::url_clear(url_impl);
1068 ::url_parse(m_heap, url_impl, &str, str + length, true);
1069 }
1070
1071 /*-------------------------------------------------------------------------
1072 -------------------------------------------------------------------------*/
1073
1074 inline HTTPStatus
http_hdr_status_get(HTTPHdrImpl * hh)1075 http_hdr_status_get(HTTPHdrImpl *hh)
1076 {
1077 ink_assert(hh->m_polarity == HTTP_TYPE_RESPONSE);
1078 return (HTTPStatus)hh->u.resp.m_status;
1079 }
1080
1081 /*-------------------------------------------------------------------------
1082 -------------------------------------------------------------------------*/
1083
1084 inline HTTPStatus
status_get()1085 HTTPHdr::status_get() const
1086 {
1087 ink_assert(valid());
1088
1089 if (m_http) {
1090 ink_assert(m_http->m_polarity == HTTP_TYPE_RESPONSE);
1091 return http_hdr_status_get(m_http);
1092 }
1093
1094 return HTTP_STATUS_NONE;
1095 }
1096
1097 /*-------------------------------------------------------------------------
1098 -------------------------------------------------------------------------*/
1099
1100 inline void
status_set(HTTPStatus status)1101 HTTPHdr::status_set(HTTPStatus status)
1102 {
1103 ink_assert(valid());
1104 ink_assert(m_http->m_polarity == HTTP_TYPE_RESPONSE);
1105
1106 http_hdr_status_set(m_http, status);
1107 }
1108
1109 /*-------------------------------------------------------------------------
1110 -------------------------------------------------------------------------*/
1111
1112 inline const char *
reason_get(int * length)1113 HTTPHdr::reason_get(int *length)
1114 {
1115 ink_assert(valid());
1116 ink_assert(m_http->m_polarity == HTTP_TYPE_RESPONSE);
1117
1118 return http_hdr_reason_get(m_http, length);
1119 }
1120
1121 /*-------------------------------------------------------------------------
1122 -------------------------------------------------------------------------*/
1123
1124 inline void
reason_set(const char * value,int length)1125 HTTPHdr::reason_set(const char *value, int length)
1126 {
1127 ink_assert(valid());
1128 ink_assert(m_http->m_polarity == HTTP_TYPE_RESPONSE);
1129
1130 http_hdr_reason_set(m_heap, m_http, value, length, true);
1131 }
1132
1133 /*-------------------------------------------------------------------------
1134 -------------------------------------------------------------------------*/
1135
1136 inline void
mark_early_data(bool flag)1137 HTTPHdr::mark_early_data(bool flag) const
1138 {
1139 ink_assert(valid());
1140 early_data = flag;
1141 }
1142
1143 /*-------------------------------------------------------------------------
1144 -------------------------------------------------------------------------*/
1145
1146 inline bool
is_early_data()1147 HTTPHdr::is_early_data() const
1148 {
1149 ink_assert(valid());
1150 return early_data;
1151 }
1152
1153 /*-------------------------------------------------------------------------
1154 -------------------------------------------------------------------------*/
1155
1156 inline ParseResult
parse_req(HTTPParser * parser,const char ** start,const char * end,bool eof,bool strict_uri_parsing,size_t max_request_line_size,size_t max_hdr_field_size)1157 HTTPHdr::parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, bool strict_uri_parsing,
1158 size_t max_request_line_size, size_t max_hdr_field_size)
1159 {
1160 ink_assert(valid());
1161 ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
1162
1163 return http_parser_parse_req(parser, m_heap, m_http, start, end, true, eof, strict_uri_parsing, max_request_line_size,
1164 max_hdr_field_size);
1165 }
1166
1167 /*-------------------------------------------------------------------------
1168 -------------------------------------------------------------------------*/
1169
1170 inline ParseResult
parse_resp(HTTPParser * parser,const char ** start,const char * end,bool eof)1171 HTTPHdr::parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof)
1172 {
1173 ink_assert(valid());
1174 ink_assert(m_http->m_polarity == HTTP_TYPE_RESPONSE);
1175
1176 return http_parser_parse_resp(parser, m_heap, m_http, start, end, true, eof);
1177 }
1178
1179 /*-------------------------------------------------------------------------
1180 -------------------------------------------------------------------------*/
1181
1182 inline bool
is_cache_control_set(const char * cc_directive_wks)1183 HTTPHdr::is_cache_control_set(const char *cc_directive_wks)
1184 {
1185 ink_assert(valid());
1186 ink_assert(hdrtoken_is_wks(cc_directive_wks));
1187
1188 const HdrTokenHeapPrefix *prefix = hdrtoken_wks_to_prefix(cc_directive_wks);
1189 ink_assert(prefix->wks_token_type == HDRTOKEN_TYPE_CACHE_CONTROL);
1190
1191 uint32_t cc_mask = prefix->wks_type_specific.u.cache_control.cc_mask;
1192 if (get_cooked_cc_mask() & cc_mask)
1193 return (true);
1194 else
1195 return (false);
1196 }
1197
1198 /*-------------------------------------------------------------------------
1199 -------------------------------------------------------------------------*/
1200
1201 inline bool
is_pragma_no_cache_set()1202 HTTPHdr::is_pragma_no_cache_set()
1203 {
1204 ink_assert(valid());
1205 return (get_cooked_pragma_no_cache());
1206 }
1207
1208 inline char *
url_string_get_ref(int * length)1209 HTTPHdr::url_string_get_ref(int *length)
1210 {
1211 return this->url_string_get(USE_HDR_HEAP_MAGIC, length);
1212 }
1213
1214 inline const char *
path_get(int * length)1215 HTTPHdr::path_get(int *length)
1216 {
1217 URL *url = this->url_get();
1218 return url ? url->path_get(length) : nullptr;
1219 }
1220
1221 inline const char *
params_get(int * length)1222 HTTPHdr::params_get(int *length)
1223 {
1224 URL *url = this->url_get();
1225 return url ? url->params_get(length) : nullptr;
1226 }
1227
1228 inline const char *
query_get(int * length)1229 HTTPHdr::query_get(int *length)
1230 {
1231 URL *url = this->url_get();
1232 return url ? url->query_get(length) : nullptr;
1233 }
1234
1235 inline const char *
fragment_get(int * length)1236 HTTPHdr::fragment_get(int *length)
1237 {
1238 URL *url = this->url_get();
1239 return url ? url->fragment_get(length) : nullptr;
1240 }
1241
1242 inline const char *
scheme_get(int * length)1243 HTTPHdr::scheme_get(int *length)
1244 {
1245 URL *url = this->url_get();
1246 return url ? url->scheme_get(length) : nullptr;
1247 }
1248
1249 /*-------------------------------------------------------------------------
1250 -------------------------------------------------------------------------*/
1251
1252 enum {
1253 CACHE_ALT_MAGIC_ALIVE = 0xabcddeed,
1254 CACHE_ALT_MAGIC_MARSHALED = 0xdcbadeed,
1255 CACHE_ALT_MAGIC_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 uint32_t m_magic = CACHE_ALT_MAGIC_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 typedef uint64_t FragOffset;
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 typedef HTTPCacheAlt::FragOffset FragOffset; ///< Import type.
1317
1318 HTTPCacheAlt *m_alt = nullptr;
1319
HTTPInfo()1320 HTTPInfo() {}
~HTTPInfo()1321 ~HTTPInfo() { clear(); }
1322 void
clear()1323 clear()
1324 {
1325 m_alt = nullptr;
1326 }
1327 bool
valid()1328 valid() const
1329 {
1330 return m_alt != nullptr;
1331 }
1332
1333 void create();
1334 void destroy();
1335
1336 void copy(HTTPInfo *to_copy);
1337 void
copy_shallow(HTTPInfo * info)1338 copy_shallow(HTTPInfo *info)
1339 {
1340 m_alt = info->m_alt;
1341 }
1342 void copy_frag_offsets_from(HTTPInfo *src);
1343 HTTPInfo &operator=(const HTTPInfo &m);
1344
1345 inkcoreapi int marshal_length();
1346 inkcoreapi 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
id_get()1353 id_get() const
1354 {
1355 return m_alt->m_id;
1356 }
1357 int32_t
rid_get()1358 rid_get()
1359 {
1360 return m_alt->m_rid;
1361 }
1362
1363 void
id_set(int32_t id)1364 id_set(int32_t id)
1365 {
1366 m_alt->m_id = id;
1367 }
1368 void
rid_set(int32_t id)1369 rid_set(int32_t id)
1370 {
1371 m_alt->m_rid = id;
1372 }
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
request_get(HTTPHdr * hdr)1380 request_get(HTTPHdr *hdr)
1381 {
1382 hdr->copy_shallow(&m_alt->m_request_hdr);
1383 }
1384 void
response_get(HTTPHdr * hdr)1385 response_get(HTTPHdr *hdr)
1386 {
1387 hdr->copy_shallow(&m_alt->m_response_hdr);
1388 }
1389
1390 HTTPHdr *
request_get()1391 request_get()
1392 {
1393 return &m_alt->m_request_hdr;
1394 }
1395 HTTPHdr *
response_get()1396 response_get()
1397 {
1398 return &m_alt->m_response_hdr;
1399 }
1400
1401 URL *
1402 request_url_get(URL *url = nullptr)
1403 {
1404 return m_alt->m_request_hdr.url_get(url);
1405 }
1406
1407 time_t
request_sent_time_get()1408 request_sent_time_get()
1409 {
1410 return m_alt->m_request_sent_time;
1411 }
1412 time_t
response_received_time_get()1413 response_received_time_get()
1414 {
1415 return m_alt->m_response_received_time;
1416 }
1417
1418 void object_key_set(CryptoHash &hash);
1419 void object_size_set(int64_t size);
1420
1421 void
request_set(const HTTPHdr * req)1422 request_set(const HTTPHdr *req)
1423 {
1424 m_alt->m_request_hdr.copy(req);
1425 }
1426 void
response_set(const HTTPHdr * resp)1427 response_set(const HTTPHdr *resp)
1428 {
1429 m_alt->m_response_hdr.copy(resp);
1430 }
1431
1432 void
request_sent_time_set(time_t t)1433 request_sent_time_set(time_t t)
1434 {
1435 m_alt->m_request_sent_time = t;
1436 }
1437 void
response_received_time_set(time_t t)1438 response_received_time_set(time_t t)
1439 {
1440 m_alt->m_response_received_time = t;
1441 }
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
destroy()1460 HTTPInfo::destroy()
1461 {
1462 if (m_alt) {
1463 if (m_alt->m_writeable) {
1464 m_alt->destroy();
1465 } else if (m_alt->m_ext_buffer) {
1466 if (m_alt->m_ext_buffer->refcount_dec() == 0) {
1467 m_alt->m_ext_buffer->free();
1468 }
1469 }
1470 }
1471 clear();
1472 }
1473
1474 inline HTTPInfo &
1475 HTTPInfo::operator=(const HTTPInfo &m)
1476 {
1477 m_alt = m.m_alt;
1478 return *this;
1479 }
1480
1481 inline CryptoHash
object_key_get()1482 HTTPInfo::object_key_get()
1483 {
1484 CryptoHash val;
1485 int32_t *pi = reinterpret_cast<int32_t *>(&val);
1486
1487 memcpy(pi, m_alt->m_object_key, sizeof(CryptoHash));
1488
1489 return val;
1490 }
1491
1492 inline void
object_key_get(CryptoHash * hash)1493 HTTPInfo::object_key_get(CryptoHash *hash)
1494 {
1495 int32_t *pi = reinterpret_cast<int32_t *>(hash);
1496 memcpy(pi, m_alt->m_object_key, CRYPTO_HASH_SIZE);
1497 }
1498
1499 inline bool
compare_object_key(const CryptoHash * hash)1500 HTTPInfo::compare_object_key(const CryptoHash *hash)
1501 {
1502 int32_t const *pi = reinterpret_cast<int32_t const *>(hash);
1503 return memcmp(pi, m_alt->m_object_key, CRYPTO_HASH_SIZE) == 0;
1504 }
1505
1506 inline int64_t
object_size_get()1507 HTTPInfo::object_size_get()
1508 {
1509 int64_t val = 0; // make gcc shut up.
1510 int32_t *pi = reinterpret_cast<int32_t *>(&val);
1511
1512 pi[0] = m_alt->m_object_size[0];
1513 pi[1] = m_alt->m_object_size[1];
1514 return val;
1515 }
1516
1517 inline void
object_key_set(CryptoHash & hash)1518 HTTPInfo::object_key_set(CryptoHash &hash)
1519 {
1520 int32_t *pi = reinterpret_cast<int32_t *>(&hash);
1521 memcpy(m_alt->m_object_key, pi, CRYPTO_HASH_SIZE);
1522 }
1523
1524 inline void
object_size_set(int64_t size)1525 HTTPInfo::object_size_set(int64_t size)
1526 {
1527 int32_t *pi = reinterpret_cast<int32_t *>(&size);
1528 m_alt->m_object_size[0] = pi[0];
1529 m_alt->m_object_size[1] = pi[1];
1530 }
1531
1532 inline HTTPInfo::FragOffset *
get_frag_table()1533 HTTPInfo::get_frag_table()
1534 {
1535 return m_alt ? m_alt->m_frag_offsets : nullptr;
1536 }
1537
1538 inline int
get_frag_offset_count()1539 HTTPInfo::get_frag_offset_count()
1540 {
1541 return m_alt ? m_alt->m_frag_offset_count : 0;
1542 }
1543