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