Coverage Report

Created: 2026-03-28 06:49

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