Coverage Report

Created: 2026-04-07 06:45

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