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