Coverage Report

Created: 2026-05-21 06:15

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