xref: /trafficserver/proxy/hdrs/HTTP.cc (revision 4cfd5a73)
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 #include "tscore/ink_defs.h"
25 #include "tscore/ink_platform.h"
26 #include "tscore/ink_inet.h"
27 #include <cassert>
28 #include <cstdio>
29 #include <cstring>
30 #include "HTTP.h"
31 #include "HdrToken.h"
32 #include "tscore/Diags.h"
33 
34 /***********************************************************************
35  *                                                                     *
36  *                    C O M P I L E    O P T I O N S                   *
37  *                                                                     *
38  ***********************************************************************/
39 
40 #define ENABLE_PARSER_FAST_PATHS 1
41 
42 /***********************************************************************
43  *                                                                     *
44  *                          C O N S T A N T S                          *
45  *                                                                     *
46  ***********************************************************************/
47 
48 const char *HTTP_METHOD_CONNECT;
49 const char *HTTP_METHOD_DELETE;
50 const char *HTTP_METHOD_GET;
51 const char *HTTP_METHOD_HEAD;
52 const char *HTTP_METHOD_OPTIONS;
53 const char *HTTP_METHOD_POST;
54 const char *HTTP_METHOD_PURGE;
55 const char *HTTP_METHOD_PUT;
56 const char *HTTP_METHOD_TRACE;
57 const char *HTTP_METHOD_PUSH;
58 
59 int HTTP_WKSIDX_CONNECT;
60 int HTTP_WKSIDX_DELETE;
61 int HTTP_WKSIDX_GET;
62 int HTTP_WKSIDX_HEAD;
63 int HTTP_WKSIDX_OPTIONS;
64 int HTTP_WKSIDX_POST;
65 int HTTP_WKSIDX_PURGE;
66 int HTTP_WKSIDX_PUT;
67 int HTTP_WKSIDX_TRACE;
68 int HTTP_WKSIDX_PUSH;
69 int HTTP_WKSIDX_METHODS_CNT = 0;
70 
71 int HTTP_LEN_CONNECT;
72 int HTTP_LEN_DELETE;
73 int HTTP_LEN_GET;
74 int HTTP_LEN_HEAD;
75 int HTTP_LEN_OPTIONS;
76 int HTTP_LEN_POST;
77 int HTTP_LEN_PURGE;
78 int HTTP_LEN_PUT;
79 int HTTP_LEN_TRACE;
80 int HTTP_LEN_PUSH;
81 
82 const char *HTTP_VALUE_BYTES;
83 const char *HTTP_VALUE_CHUNKED;
84 const char *HTTP_VALUE_CLOSE;
85 const char *HTTP_VALUE_COMPRESS;
86 const char *HTTP_VALUE_DEFLATE;
87 const char *HTTP_VALUE_GZIP;
88 const char *HTTP_VALUE_IDENTITY;
89 const char *HTTP_VALUE_KEEP_ALIVE;
90 const char *HTTP_VALUE_MAX_AGE;
91 const char *HTTP_VALUE_MAX_STALE;
92 const char *HTTP_VALUE_MIN_FRESH;
93 const char *HTTP_VALUE_MUST_REVALIDATE;
94 const char *HTTP_VALUE_NONE;
95 const char *HTTP_VALUE_NO_CACHE;
96 const char *HTTP_VALUE_NO_STORE;
97 const char *HTTP_VALUE_NO_TRANSFORM;
98 const char *HTTP_VALUE_ONLY_IF_CACHED;
99 const char *HTTP_VALUE_PRIVATE;
100 const char *HTTP_VALUE_PROXY_REVALIDATE;
101 const char *HTTP_VALUE_PUBLIC;
102 const char *HTTP_VALUE_S_MAXAGE;
103 const char *HTTP_VALUE_NEED_REVALIDATE_ONCE;
104 const char *HTTP_VALUE_100_CONTINUE;
105 // Cache-control: extension "need-revalidate-once" is used internally by T.S.
106 // to invalidate a document, and it is not returned/forwarded.
107 // If a cached document has this extension set (ie, is invalidated),
108 // then the T.S. needs to revalidate the document once before returning it.
109 // After a successful revalidation, the extension will be removed by T.S.
110 // To set or unset this directive should be done via the following two
111 // function:
112 //      set_cooked_cc_need_revalidate_once()
113 //      unset_cooked_cc_need_revalidate_once()
114 // To test, use regular Cache-control testing functions, eg,
115 //      is_cache_control_set(HTTP_VALUE_NEED_REVALIDATE_ONCE)
116 
117 int HTTP_LEN_BYTES;
118 int HTTP_LEN_CHUNKED;
119 int HTTP_LEN_CLOSE;
120 int HTTP_LEN_COMPRESS;
121 int HTTP_LEN_DEFLATE;
122 int HTTP_LEN_GZIP;
123 int HTTP_LEN_IDENTITY;
124 int HTTP_LEN_KEEP_ALIVE;
125 int HTTP_LEN_MAX_AGE;
126 int HTTP_LEN_MAX_STALE;
127 int HTTP_LEN_MIN_FRESH;
128 int HTTP_LEN_MUST_REVALIDATE;
129 int HTTP_LEN_NONE;
130 int HTTP_LEN_NO_CACHE;
131 int HTTP_LEN_NO_STORE;
132 int HTTP_LEN_NO_TRANSFORM;
133 int HTTP_LEN_ONLY_IF_CACHED;
134 int HTTP_LEN_PRIVATE;
135 int HTTP_LEN_PROXY_REVALIDATE;
136 int HTTP_LEN_PUBLIC;
137 int HTTP_LEN_S_MAXAGE;
138 int HTTP_LEN_NEED_REVALIDATE_ONCE;
139 int HTTP_LEN_100_CONTINUE;
140 
141 Arena *const HTTPHdr::USE_HDR_HEAP_MAGIC = reinterpret_cast<Arena *>(1);
142 
143 /***********************************************************************
144  *                                                                     *
145  *                 U T I L I T Y    R O U T I N E S                    *
146  *                                                                     *
147  ***********************************************************************/
148 
149 inline static int
is_digit(char c)150 is_digit(char c)
151 {
152   return ((c <= '9') && (c >= '0'));
153 }
154 
155 /***********************************************************************
156  *                                                                     *
157  *                         M A I N    C O D E                          *
158  *                                                                     *
159  ***********************************************************************/
160 
161 void
http_hdr_adjust(HTTPHdrImpl *,int32_t,int32_t,int32_t)162 http_hdr_adjust(HTTPHdrImpl * /* hdrp ATS_UNUSED */, int32_t /* offset ATS_UNUSED */, int32_t /* length ATS_UNUSED */,
163                 int32_t /* delta ATS_UNUSED */)
164 {
165   ink_release_assert(!"http_hdr_adjust not implemented");
166 }
167 
168 /*-------------------------------------------------------------------------
169   -------------------------------------------------------------------------*/
170 
171 void
http_init()172 http_init()
173 {
174   static int init = 1;
175 
176   if (init) {
177     init = 0;
178 
179     mime_init();
180     url_init();
181 
182     HTTP_METHOD_CONNECT = hdrtoken_string_to_wks("CONNECT");
183     HTTP_METHOD_DELETE  = hdrtoken_string_to_wks("DELETE");
184     HTTP_METHOD_GET     = hdrtoken_string_to_wks("GET");
185     HTTP_METHOD_HEAD    = hdrtoken_string_to_wks("HEAD");
186     HTTP_METHOD_OPTIONS = hdrtoken_string_to_wks("OPTIONS");
187     HTTP_METHOD_POST    = hdrtoken_string_to_wks("POST");
188     HTTP_METHOD_PURGE   = hdrtoken_string_to_wks("PURGE");
189     HTTP_METHOD_PUT     = hdrtoken_string_to_wks("PUT");
190     HTTP_METHOD_TRACE   = hdrtoken_string_to_wks("TRACE");
191     HTTP_METHOD_PUSH    = hdrtoken_string_to_wks("PUSH");
192 
193     // HTTP methods index calculation. Don't forget to count them!
194     // Don't change the order of calculation! Each index has related bitmask (see http quick filter)
195     HTTP_WKSIDX_CONNECT = hdrtoken_wks_to_index(HTTP_METHOD_CONNECT);
196     HTTP_WKSIDX_METHODS_CNT++;
197     HTTP_WKSIDX_DELETE = hdrtoken_wks_to_index(HTTP_METHOD_DELETE);
198     HTTP_WKSIDX_METHODS_CNT++;
199     HTTP_WKSIDX_GET = hdrtoken_wks_to_index(HTTP_METHOD_GET);
200     HTTP_WKSIDX_METHODS_CNT++;
201     HTTP_WKSIDX_HEAD = hdrtoken_wks_to_index(HTTP_METHOD_HEAD);
202     HTTP_WKSIDX_METHODS_CNT++;
203     HTTP_WKSIDX_OPTIONS = hdrtoken_wks_to_index(HTTP_METHOD_OPTIONS);
204     HTTP_WKSIDX_METHODS_CNT++;
205     HTTP_WKSIDX_POST = hdrtoken_wks_to_index(HTTP_METHOD_POST);
206     HTTP_WKSIDX_METHODS_CNT++;
207     HTTP_WKSIDX_PURGE = hdrtoken_wks_to_index(HTTP_METHOD_PURGE);
208     HTTP_WKSIDX_METHODS_CNT++;
209     HTTP_WKSIDX_PUT = hdrtoken_wks_to_index(HTTP_METHOD_PUT);
210     HTTP_WKSIDX_METHODS_CNT++;
211     HTTP_WKSIDX_TRACE = hdrtoken_wks_to_index(HTTP_METHOD_TRACE);
212     HTTP_WKSIDX_METHODS_CNT++;
213     HTTP_WKSIDX_PUSH = hdrtoken_wks_to_index(HTTP_METHOD_PUSH);
214     HTTP_WKSIDX_METHODS_CNT++;
215 
216     HTTP_LEN_CONNECT = hdrtoken_wks_to_length(HTTP_METHOD_CONNECT);
217     HTTP_LEN_DELETE  = hdrtoken_wks_to_length(HTTP_METHOD_DELETE);
218     HTTP_LEN_GET     = hdrtoken_wks_to_length(HTTP_METHOD_GET);
219     HTTP_LEN_HEAD    = hdrtoken_wks_to_length(HTTP_METHOD_HEAD);
220     HTTP_LEN_OPTIONS = hdrtoken_wks_to_length(HTTP_METHOD_OPTIONS);
221     HTTP_LEN_POST    = hdrtoken_wks_to_length(HTTP_METHOD_POST);
222     HTTP_LEN_PURGE   = hdrtoken_wks_to_length(HTTP_METHOD_PURGE);
223     HTTP_LEN_PUT     = hdrtoken_wks_to_length(HTTP_METHOD_PUT);
224     HTTP_LEN_TRACE   = hdrtoken_wks_to_length(HTTP_METHOD_TRACE);
225     HTTP_LEN_PUSH    = hdrtoken_wks_to_length(HTTP_METHOD_PUSH);
226 
227     HTTP_VALUE_BYTES                = hdrtoken_string_to_wks("bytes");
228     HTTP_VALUE_CHUNKED              = hdrtoken_string_to_wks("chunked");
229     HTTP_VALUE_CLOSE                = hdrtoken_string_to_wks("close");
230     HTTP_VALUE_COMPRESS             = hdrtoken_string_to_wks("compress");
231     HTTP_VALUE_DEFLATE              = hdrtoken_string_to_wks("deflate");
232     HTTP_VALUE_GZIP                 = hdrtoken_string_to_wks("gzip");
233     HTTP_VALUE_IDENTITY             = hdrtoken_string_to_wks("identity");
234     HTTP_VALUE_KEEP_ALIVE           = hdrtoken_string_to_wks("keep-alive");
235     HTTP_VALUE_MAX_AGE              = hdrtoken_string_to_wks("max-age");
236     HTTP_VALUE_MAX_STALE            = hdrtoken_string_to_wks("max-stale");
237     HTTP_VALUE_MIN_FRESH            = hdrtoken_string_to_wks("min-fresh");
238     HTTP_VALUE_MUST_REVALIDATE      = hdrtoken_string_to_wks("must-revalidate");
239     HTTP_VALUE_NONE                 = hdrtoken_string_to_wks("none");
240     HTTP_VALUE_NO_CACHE             = hdrtoken_string_to_wks("no-cache");
241     HTTP_VALUE_NO_STORE             = hdrtoken_string_to_wks("no-store");
242     HTTP_VALUE_NO_TRANSFORM         = hdrtoken_string_to_wks("no-transform");
243     HTTP_VALUE_ONLY_IF_CACHED       = hdrtoken_string_to_wks("only-if-cached");
244     HTTP_VALUE_PRIVATE              = hdrtoken_string_to_wks("private");
245     HTTP_VALUE_PROXY_REVALIDATE     = hdrtoken_string_to_wks("proxy-revalidate");
246     HTTP_VALUE_PUBLIC               = hdrtoken_string_to_wks("public");
247     HTTP_VALUE_S_MAXAGE             = hdrtoken_string_to_wks("s-maxage");
248     HTTP_VALUE_NEED_REVALIDATE_ONCE = hdrtoken_string_to_wks("need-revalidate-once");
249     HTTP_VALUE_100_CONTINUE         = hdrtoken_string_to_wks("100-continue");
250 
251     HTTP_LEN_BYTES                = hdrtoken_wks_to_length(HTTP_VALUE_BYTES);
252     HTTP_LEN_CHUNKED              = hdrtoken_wks_to_length(HTTP_VALUE_CHUNKED);
253     HTTP_LEN_CLOSE                = hdrtoken_wks_to_length(HTTP_VALUE_CLOSE);
254     HTTP_LEN_COMPRESS             = hdrtoken_wks_to_length(HTTP_VALUE_COMPRESS);
255     HTTP_LEN_DEFLATE              = hdrtoken_wks_to_length(HTTP_VALUE_DEFLATE);
256     HTTP_LEN_GZIP                 = hdrtoken_wks_to_length(HTTP_VALUE_GZIP);
257     HTTP_LEN_IDENTITY             = hdrtoken_wks_to_length(HTTP_VALUE_IDENTITY);
258     HTTP_LEN_KEEP_ALIVE           = hdrtoken_wks_to_length(HTTP_VALUE_KEEP_ALIVE);
259     HTTP_LEN_MAX_AGE              = hdrtoken_wks_to_length(HTTP_VALUE_MAX_AGE);
260     HTTP_LEN_MAX_STALE            = hdrtoken_wks_to_length(HTTP_VALUE_MAX_STALE);
261     HTTP_LEN_MIN_FRESH            = hdrtoken_wks_to_length(HTTP_VALUE_MIN_FRESH);
262     HTTP_LEN_MUST_REVALIDATE      = hdrtoken_wks_to_length(HTTP_VALUE_MUST_REVALIDATE);
263     HTTP_LEN_NONE                 = hdrtoken_wks_to_length(HTTP_VALUE_NONE);
264     HTTP_LEN_NO_CACHE             = hdrtoken_wks_to_length(HTTP_VALUE_NO_CACHE);
265     HTTP_LEN_NO_STORE             = hdrtoken_wks_to_length(HTTP_VALUE_NO_STORE);
266     HTTP_LEN_NO_TRANSFORM         = hdrtoken_wks_to_length(HTTP_VALUE_NO_TRANSFORM);
267     HTTP_LEN_ONLY_IF_CACHED       = hdrtoken_wks_to_length(HTTP_VALUE_ONLY_IF_CACHED);
268     HTTP_LEN_PRIVATE              = hdrtoken_wks_to_length(HTTP_VALUE_PRIVATE);
269     HTTP_LEN_PROXY_REVALIDATE     = hdrtoken_wks_to_length(HTTP_VALUE_PROXY_REVALIDATE);
270     HTTP_LEN_PUBLIC               = hdrtoken_wks_to_length(HTTP_VALUE_PUBLIC);
271     HTTP_LEN_S_MAXAGE             = hdrtoken_wks_to_length(HTTP_VALUE_S_MAXAGE);
272     HTTP_LEN_NEED_REVALIDATE_ONCE = hdrtoken_wks_to_length(HTTP_VALUE_NEED_REVALIDATE_ONCE);
273     HTTP_LEN_100_CONTINUE         = hdrtoken_wks_to_length(HTTP_VALUE_100_CONTINUE);
274   }
275 }
276 
277 /*-------------------------------------------------------------------------
278   -------------------------------------------------------------------------*/
279 
280 HTTPHdrImpl *
http_hdr_create(HdrHeap * heap,HTTPType polarity)281 http_hdr_create(HdrHeap *heap, HTTPType polarity)
282 {
283   HTTPHdrImpl *hh;
284 
285   hh = (HTTPHdrImpl *)heap->allocate_obj(sizeof(HTTPHdrImpl), HDR_HEAP_OBJ_HTTP_HEADER);
286   http_hdr_init(heap, hh, polarity);
287   return (hh);
288 }
289 
290 /*-------------------------------------------------------------------------
291   -------------------------------------------------------------------------*/
292 
293 void
http_hdr_init(HdrHeap * heap,HTTPHdrImpl * hh,HTTPType polarity)294 http_hdr_init(HdrHeap *heap, HTTPHdrImpl *hh, HTTPType polarity)
295 {
296   memset(&(hh->u), 0, sizeof(hh->u));
297   hh->m_polarity    = polarity;
298   hh->m_version     = HTTP_VERSION(1, 0);
299   hh->m_fields_impl = mime_hdr_create(heap);
300   if (polarity == HTTP_TYPE_REQUEST) {
301     hh->u.req.m_url_impl       = url_create(heap);
302     hh->u.req.m_method_wks_idx = -1;
303   }
304 }
305 
306 /*-------------------------------------------------------------------------
307   -------------------------------------------------------------------------*/
308 
309 void
http_hdr_copy_onto(HTTPHdrImpl * s_hh,HdrHeap * s_heap,HTTPHdrImpl * d_hh,HdrHeap * d_heap,bool inherit_strs)310 http_hdr_copy_onto(HTTPHdrImpl *s_hh, HdrHeap *s_heap, HTTPHdrImpl *d_hh, HdrHeap *d_heap, bool inherit_strs)
311 {
312   MIMEHdrImpl *s_mh, *d_mh;
313   URLImpl *s_url, *d_url;
314   HTTPType d_polarity;
315 
316   s_mh       = s_hh->m_fields_impl;
317   s_url      = s_hh->u.req.m_url_impl;
318   d_mh       = d_hh->m_fields_impl;
319   d_url      = d_hh->u.req.m_url_impl;
320   d_polarity = d_hh->m_polarity;
321 
322   ink_assert(s_hh->m_polarity != HTTP_TYPE_UNKNOWN);
323   ink_assert(s_mh != nullptr);
324   ink_assert(d_mh != nullptr);
325 
326   memcpy(d_hh, s_hh, sizeof(HTTPHdrImpl));
327   d_hh->m_fields_impl = d_mh; // restore pre-memcpy mime impl
328 
329   if (s_hh->m_polarity == HTTP_TYPE_REQUEST) {
330     if (d_polarity == HTTP_TYPE_REQUEST) {
331       d_hh->u.req.m_url_impl = d_url; // restore pre-memcpy url impl
332     } else {
333       d_url = d_hh->u.req.m_url_impl = url_create(d_heap); // create url
334     }
335     url_copy_onto(s_url, s_heap, d_url, d_heap, false);
336   } else if (d_polarity == HTTP_TYPE_REQUEST) {
337     // gender bender.  Need to kill off old url
338     url_clear(d_url);
339   }
340 
341   mime_hdr_copy_onto(s_mh, s_heap, d_mh, d_heap, false);
342   if (inherit_strs) {
343     d_heap->inherit_string_heaps(s_heap);
344   }
345 }
346 
347 /*-------------------------------------------------------------------------
348   -------------------------------------------------------------------------*/
349 
350 HTTPHdrImpl *
http_hdr_clone(HTTPHdrImpl * s_hh,HdrHeap * s_heap,HdrHeap * d_heap)351 http_hdr_clone(HTTPHdrImpl *s_hh, HdrHeap *s_heap, HdrHeap *d_heap)
352 {
353   HTTPHdrImpl *d_hh;
354 
355   // FIX: A future optimization is to copy contiguous objects with
356   //      one single memcpy.  For this first optimization, we just
357   //      copy each object separately.
358 
359   d_hh = http_hdr_create(d_heap, s_hh->m_polarity);
360   http_hdr_copy_onto(s_hh, s_heap, d_hh, d_heap, ((s_heap != d_heap) ? true : false));
361   return (d_hh);
362 }
363 
364 /*-------------------------------------------------------------------------
365   -------------------------------------------------------------------------*/
366 
367 static inline char *
http_hdr_version_to_string(int32_t version,char * buf9)368 http_hdr_version_to_string(int32_t version, char *buf9)
369 {
370   ink_assert(HTTP_MAJOR(version) < 10);
371   ink_assert(HTTP_MINOR(version) < 10);
372 
373   buf9[0] = 'H';
374   buf9[1] = 'T';
375   buf9[2] = 'T';
376   buf9[3] = 'P';
377   buf9[4] = '/';
378   buf9[5] = '0' + HTTP_MAJOR(version);
379   buf9[6] = '.';
380   buf9[7] = '0' + HTTP_MINOR(version);
381   buf9[8] = '\0';
382 
383   return (buf9);
384 }
385 
386 /*-------------------------------------------------------------------------
387   -------------------------------------------------------------------------*/
388 
389 int
http_version_print(int32_t version,char * buf,int bufsize,int * bufindex,int * dumpoffset)390 http_version_print(int32_t version, char *buf, int bufsize, int *bufindex, int *dumpoffset)
391 {
392 #define TRY(x) \
393   if (!x)      \
394   return 0
395 
396   char tmpbuf[16];
397   http_hdr_version_to_string(version, tmpbuf);
398   TRY(mime_mem_print(tmpbuf, 8, buf, bufsize, bufindex, dumpoffset));
399   return 1;
400 
401 #undef TRY
402 }
403 
404 /*-------------------------------------------------------------------------
405   -------------------------------------------------------------------------*/
406 
407 int
http_hdr_print(HdrHeap * heap,HTTPHdrImpl * hdr,char * buf,int bufsize,int * bufindex,int * dumpoffset)408 http_hdr_print(HdrHeap *heap, HTTPHdrImpl *hdr, char *buf, int bufsize, int *bufindex, int *dumpoffset)
409 {
410 #define TRY(x) \
411   if (!x)      \
412   return 0
413 
414   int tmplen, hdrstat;
415   char tmpbuf[32];
416   char *p;
417 
418   ink_assert((hdr->m_polarity == HTTP_TYPE_REQUEST) || (hdr->m_polarity == HTTP_TYPE_RESPONSE));
419 
420   if (hdr->m_polarity == HTTP_TYPE_REQUEST) {
421     if (hdr->u.req.m_ptr_method == nullptr) {
422       return 1;
423     }
424 
425     if ((buf != nullptr) && (*dumpoffset == 0) && (bufsize - *bufindex >= hdr->u.req.m_len_method + 1)) { // fastpath
426 
427       p = buf + *bufindex;
428       memcpy(p, hdr->u.req.m_ptr_method, hdr->u.req.m_len_method);
429       p += hdr->u.req.m_len_method;
430       *p++ = ' ';
431       *bufindex += hdr->u.req.m_len_method + 1;
432 
433       if (hdr->u.req.m_url_impl) {
434         TRY(url_print(hdr->u.req.m_url_impl, buf, bufsize, bufindex, dumpoffset));
435         if (bufsize - *bufindex >= 1) {
436           if (hdr->u.req.m_method_wks_idx == HTTP_WKSIDX_CONNECT) {
437             *bufindex -= 1; // remove trailing slash for CONNECT request
438           }
439           p    = buf + *bufindex;
440           *p++ = ' ';
441           *bufindex += 1;
442         } else {
443           return 0;
444         }
445       }
446 
447       if (bufsize - *bufindex >= 9) {
448         http_hdr_version_to_string(hdr->m_version, p);
449         *bufindex += 9 - 1; // overwrite '\0';
450       } else {
451         TRY(http_version_print(hdr->m_version, buf, bufsize, bufindex, dumpoffset));
452       }
453 
454       if (bufsize - *bufindex >= 2) {
455         p    = buf + *bufindex;
456         *p++ = '\r';
457         *p++ = '\n';
458         *bufindex += 2;
459       } else {
460         TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
461       }
462 
463       TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
464 
465     } else {
466       TRY(mime_mem_print(hdr->u.req.m_ptr_method, hdr->u.req.m_len_method, buf, bufsize, bufindex, dumpoffset));
467 
468       TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
469 
470       if (hdr->u.req.m_url_impl) {
471         TRY(url_print(hdr->u.req.m_url_impl, buf, bufsize, bufindex, dumpoffset));
472         TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
473       }
474 
475       TRY(http_version_print(hdr->m_version, buf, bufsize, bufindex, dumpoffset));
476 
477       TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
478 
479       TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
480     }
481 
482   } else { //  hdr->m_polarity == HTTP_TYPE_RESPONSE
483 
484     if ((buf != nullptr) && (*dumpoffset == 0) && (bufsize - *bufindex >= 9 + 6 + 1)) { // fastpath
485 
486       p = buf + *bufindex;
487       http_hdr_version_to_string(hdr->m_version, p);
488       p += 8; // overwrite '\0' with space
489       *p++ = ' ';
490       *bufindex += 9;
491 
492       hdrstat = http_hdr_status_get(hdr);
493       if (hdrstat == 200) {
494         *p++   = '2';
495         *p++   = '0';
496         *p++   = '0';
497         tmplen = 3;
498       } else {
499         tmplen = mime_format_int(p, hdrstat, (bufsize - (p - buf)));
500         ink_assert(tmplen <= 6);
501         p += tmplen;
502       }
503       *p++ = ' ';
504       *bufindex += tmplen + 1;
505 
506       if (hdr->u.resp.m_ptr_reason) {
507         TRY(mime_mem_print(hdr->u.resp.m_ptr_reason, hdr->u.resp.m_len_reason, buf, bufsize, bufindex, dumpoffset));
508       }
509 
510       if (bufsize - *bufindex >= 2) {
511         p    = buf + *bufindex;
512         *p++ = '\r';
513         *p++ = '\n';
514         *bufindex += 2;
515       } else {
516         TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
517       }
518 
519       TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
520 
521     } else {
522       TRY(http_version_print(hdr->m_version, buf, bufsize, bufindex, dumpoffset));
523 
524       TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
525 
526       tmplen = mime_format_int(tmpbuf, http_hdr_status_get(hdr), sizeof(tmpbuf));
527 
528       TRY(mime_mem_print(tmpbuf, tmplen, buf, bufsize, bufindex, dumpoffset));
529 
530       TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
531 
532       if (hdr->u.resp.m_ptr_reason) {
533         TRY(mime_mem_print(hdr->u.resp.m_ptr_reason, hdr->u.resp.m_len_reason, buf, bufsize, bufindex, dumpoffset));
534       }
535 
536       TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
537 
538       TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
539     }
540   }
541 
542   return 1;
543 
544 #undef TRY
545 }
546 
547 /*-------------------------------------------------------------------------
548   -------------------------------------------------------------------------*/
549 
550 void
http_hdr_describe(HdrHeapObjImpl * raw,bool recurse)551 http_hdr_describe(HdrHeapObjImpl *raw, bool recurse)
552 {
553   HTTPHdrImpl *obj = (HTTPHdrImpl *)raw;
554 
555   if (obj->m_polarity == HTTP_TYPE_REQUEST) {
556     Debug("http", "[TYPE: REQ, V: %04X, URL: %p, METHOD: \"%.*s\", METHOD_LEN: %d, FIELDS: %p]", obj->m_version,
557           obj->u.req.m_url_impl, obj->u.req.m_len_method, (obj->u.req.m_ptr_method ? obj->u.req.m_ptr_method : "NULL"),
558           obj->u.req.m_len_method, obj->m_fields_impl);
559     if (recurse) {
560       if (obj->u.req.m_url_impl) {
561         obj_describe(obj->u.req.m_url_impl, recurse);
562       }
563       if (obj->m_fields_impl) {
564         obj_describe(obj->m_fields_impl, recurse);
565       }
566     }
567   } else {
568     Debug("http", "[TYPE: RSP, V: %04X, STATUS: %d, REASON: \"%.*s\", REASON_LEN: %d, FIELDS: %p]", obj->m_version,
569           obj->u.resp.m_status, obj->u.resp.m_len_reason, (obj->u.resp.m_ptr_reason ? obj->u.resp.m_ptr_reason : "NULL"),
570           obj->u.resp.m_len_reason, obj->m_fields_impl);
571     if (recurse) {
572       if (obj->m_fields_impl) {
573         obj_describe(obj->m_fields_impl, recurse);
574       }
575     }
576   }
577 }
578 
579 /*-------------------------------------------------------------------------
580   -------------------------------------------------------------------------*/
581 
582 int
length_get() const583 HTTPHdr::length_get() const
584 {
585   int length = 0;
586 
587   if (m_http->m_polarity == HTTP_TYPE_REQUEST) {
588     if (m_http->u.req.m_ptr_method) {
589       length = m_http->u.req.m_len_method;
590     } else {
591       length = 0;
592     }
593 
594     length += 1; // " "
595 
596     if (m_http->u.req.m_url_impl) {
597       length += url_length_get(m_http->u.req.m_url_impl);
598     }
599 
600     length += 1; // " "
601 
602     length += 8; // HTTP/%d.%d
603 
604     length += 2; // "\r\n"
605   } else if (m_http->m_polarity == HTTP_TYPE_RESPONSE) {
606     if (m_http->u.resp.m_ptr_reason) {
607       length = m_http->u.resp.m_len_reason;
608     } else {
609       length = 0;
610     }
611 
612     length += 8; // HTTP/%d.%d
613 
614     length += 1; // " "
615 
616     length += 3; // status
617 
618     length += 1; // " "
619 
620     length += 2; // "\r\n"
621   }
622 
623   length += mime_hdr_length_get(m_http->m_fields_impl);
624 
625   return length;
626 }
627 
628 /*-------------------------------------------------------------------------
629   -------------------------------------------------------------------------*/
630 
631 void
http_hdr_type_set(HTTPHdrImpl * hh,HTTPType type)632 http_hdr_type_set(HTTPHdrImpl *hh, HTTPType type)
633 {
634   hh->m_polarity = type;
635 }
636 
637 /*-------------------------------------------------------------------------
638   -------------------------------------------------------------------------*/
639 
640 void
http_hdr_version_set(HTTPHdrImpl * hh,int32_t ver)641 http_hdr_version_set(HTTPHdrImpl *hh, int32_t ver)
642 {
643   hh->m_version = ver;
644 }
645 
646 /*-------------------------------------------------------------------------
647   -------------------------------------------------------------------------*/
648 
649 const char *
http_hdr_method_get(HTTPHdrImpl * hh,int * length)650 http_hdr_method_get(HTTPHdrImpl *hh, int *length)
651 {
652   const char *str;
653 
654   ink_assert(hh->m_polarity == HTTP_TYPE_REQUEST);
655 
656   if (hh->u.req.m_method_wks_idx >= 0) {
657     str     = hdrtoken_index_to_wks(hh->u.req.m_method_wks_idx);
658     *length = hdrtoken_index_to_length(hh->u.req.m_method_wks_idx);
659   } else {
660     str     = hh->u.req.m_ptr_method;
661     *length = hh->u.req.m_len_method;
662   }
663 
664   return (str);
665 }
666 
667 /*-------------------------------------------------------------------------
668   -------------------------------------------------------------------------*/
669 
670 void
http_hdr_method_set(HdrHeap * heap,HTTPHdrImpl * hh,const char * method,int16_t method_wks_idx,int method_length,bool must_copy)671 http_hdr_method_set(HdrHeap *heap, HTTPHdrImpl *hh, const char *method, int16_t method_wks_idx, int method_length, bool must_copy)
672 {
673   ink_assert(hh->m_polarity == HTTP_TYPE_REQUEST);
674 
675   hh->u.req.m_method_wks_idx = method_wks_idx;
676   mime_str_u16_set(heap, method, method_length, &(hh->u.req.m_ptr_method), &(hh->u.req.m_len_method), must_copy);
677 }
678 
679 /*-------------------------------------------------------------------------
680   -------------------------------------------------------------------------*/
681 
682 void
http_hdr_url_set(HdrHeap * heap,HTTPHdrImpl * hh,URLImpl * url)683 http_hdr_url_set(HdrHeap *heap, HTTPHdrImpl *hh, URLImpl *url)
684 {
685   ink_assert(hh->m_polarity == HTTP_TYPE_REQUEST);
686   if (hh->u.req.m_url_impl != url) {
687     if (hh->u.req.m_url_impl != nullptr) {
688       heap->deallocate_obj(hh->u.req.m_url_impl);
689     }
690     // Clone into new heap if the URL was allocated against a different heap
691     if (reinterpret_cast<char *>(url) < heap->m_data_start || reinterpret_cast<char *>(url) >= heap->m_free_start) {
692       hh->u.req.m_url_impl = static_cast<URLImpl *>(heap->allocate_obj(url->m_length, url->m_type));
693       memcpy(hh->u.req.m_url_impl, url, url->m_length);
694       // Make sure there is a read_write heap
695       if (heap->m_read_write_heap.get() == nullptr) {
696         int url_string_length   = url->strings_length();
697         heap->m_read_write_heap = new_HdrStrHeap(url_string_length);
698       }
699       hh->u.req.m_url_impl->rehome_strings(heap);
700     } else {
701       hh->u.req.m_url_impl = url;
702     }
703   }
704 }
705 
706 /*-------------------------------------------------------------------------
707   -------------------------------------------------------------------------*/
708 
709 void
http_hdr_status_set(HTTPHdrImpl * hh,HTTPStatus status)710 http_hdr_status_set(HTTPHdrImpl *hh, HTTPStatus status)
711 {
712   ink_assert(hh->m_polarity == HTTP_TYPE_RESPONSE);
713   hh->u.resp.m_status = status;
714 }
715 
716 /*-------------------------------------------------------------------------
717   -------------------------------------------------------------------------*/
718 
719 const char *
http_hdr_reason_get(HTTPHdrImpl * hh,int * length)720 http_hdr_reason_get(HTTPHdrImpl *hh, int *length)
721 {
722   ink_assert(hh->m_polarity == HTTP_TYPE_RESPONSE);
723   *length = hh->u.resp.m_len_reason;
724   return (hh->u.resp.m_ptr_reason);
725 }
726 
727 /*-------------------------------------------------------------------------
728   -------------------------------------------------------------------------*/
729 
730 void
http_hdr_reason_set(HdrHeap * heap,HTTPHdrImpl * hh,const char * value,int length,bool must_copy)731 http_hdr_reason_set(HdrHeap *heap, HTTPHdrImpl *hh, const char *value, int length, bool must_copy)
732 {
733   ink_assert(hh->m_polarity == HTTP_TYPE_RESPONSE);
734   mime_str_u16_set(heap, value, length, &(hh->u.resp.m_ptr_reason), &(hh->u.resp.m_len_reason), must_copy);
735 }
736 
737 /*-------------------------------------------------------------------------
738   -------------------------------------------------------------------------*/
739 
740 const char *
http_hdr_reason_lookup(unsigned status)741 http_hdr_reason_lookup(unsigned status)
742 {
743 #define HTTP_STATUS_ENTRY(value, reason) \
744   case value:                            \
745     return #reason
746 
747   switch (status) {
748     HTTP_STATUS_ENTRY(0, None);                  // TS_HTTP_STATUS_NONE
749     HTTP_STATUS_ENTRY(100, Continue);            // [RFC2616]
750     HTTP_STATUS_ENTRY(101, Switching Protocols); // [RFC2616]
751     HTTP_STATUS_ENTRY(102, Processing);          // [RFC2518]
752     HTTP_STATUS_ENTRY(103, Early Hints);         // TODO: add RFC number
753     // 103-199 Unassigned
754     HTTP_STATUS_ENTRY(200, OK);                              // [RFC2616]
755     HTTP_STATUS_ENTRY(201, Created);                         // [RFC2616]
756     HTTP_STATUS_ENTRY(202, Accepted);                        // [RFC2616]
757     HTTP_STATUS_ENTRY(203, Non - Authoritative Information); // [RFC2616]
758     HTTP_STATUS_ENTRY(204, No Content);                      // [RFC2616]
759     HTTP_STATUS_ENTRY(205, Reset Content);                   // [RFC2616]
760     HTTP_STATUS_ENTRY(206, Partial Content);                 // [RFC2616]
761     HTTP_STATUS_ENTRY(207, Multi - Status);                  // [RFC4918]
762     HTTP_STATUS_ENTRY(208, Already Reported);                // [RFC5842]
763     // 209-225 Unassigned
764     HTTP_STATUS_ENTRY(226, IM Used); // [RFC3229]
765     // 227-299 Unassigned
766     HTTP_STATUS_ENTRY(300, Multiple Choices);  // [RFC2616]
767     HTTP_STATUS_ENTRY(301, Moved Permanently); // [RFC2616]
768     HTTP_STATUS_ENTRY(302, Found);             // [RFC2616]
769     HTTP_STATUS_ENTRY(303, See Other);         // [RFC2616]
770     HTTP_STATUS_ENTRY(304, Not Modified);      // [RFC2616]
771     HTTP_STATUS_ENTRY(305, Use Proxy);         // [RFC2616]
772     // 306 Reserved                                                   // [RFC2616]
773     HTTP_STATUS_ENTRY(307, Temporary Redirect); // [RFC2616]
774     HTTP_STATUS_ENTRY(308, Permanent Redirect); // [RFC-reschke-http-status-308-07]
775     // 309-399 Unassigned
776     HTTP_STATUS_ENTRY(400, Bad Request);                     // [RFC2616]
777     HTTP_STATUS_ENTRY(401, Unauthorized);                    // [RFC2616]
778     HTTP_STATUS_ENTRY(402, Payment Required);                // [RFC2616]
779     HTTP_STATUS_ENTRY(403, Forbidden);                       // [RFC2616]
780     HTTP_STATUS_ENTRY(404, Not Found);                       // [RFC2616]
781     HTTP_STATUS_ENTRY(405, Method Not Allowed);              // [RFC2616]
782     HTTP_STATUS_ENTRY(406, Not Acceptable);                  // [RFC2616]
783     HTTP_STATUS_ENTRY(407, Proxy Authentication Required);   // [RFC2616]
784     HTTP_STATUS_ENTRY(408, Request Timeout);                 // [RFC2616]
785     HTTP_STATUS_ENTRY(409, Conflict);                        // [RFC2616]
786     HTTP_STATUS_ENTRY(410, Gone);                            // [RFC2616]
787     HTTP_STATUS_ENTRY(411, Length Required);                 // [RFC2616]
788     HTTP_STATUS_ENTRY(412, Precondition Failed);             // [RFC2616]
789     HTTP_STATUS_ENTRY(413, Request Entity Too Large);        // [RFC2616]
790     HTTP_STATUS_ENTRY(414, Request - URI Too Long);          // [RFC2616]
791     HTTP_STATUS_ENTRY(415, Unsupported Media Type);          // [RFC2616]
792     HTTP_STATUS_ENTRY(416, Requested Range Not Satisfiable); // [RFC2616]
793     HTTP_STATUS_ENTRY(417, Expectation Failed);              // [RFC2616]
794     HTTP_STATUS_ENTRY(422, Unprocessable Entity);            // [RFC4918]
795     HTTP_STATUS_ENTRY(423, Locked);                          // [RFC4918]
796     HTTP_STATUS_ENTRY(424, Failed Dependency);               // [RFC4918]
797     // 425 Reserved                                                   // [RFC2817]
798     HTTP_STATUS_ENTRY(426, Upgrade Required); // [RFC2817]
799     // 427 Unassigned
800     HTTP_STATUS_ENTRY(428, Precondition Required); // [RFC6585]
801     HTTP_STATUS_ENTRY(429, Too Many Requests);     // [RFC6585]
802     // 430 Unassigned
803     HTTP_STATUS_ENTRY(431, Request Header Fields Too Large); // [RFC6585]
804     // 432-499 Unassigned
805     HTTP_STATUS_ENTRY(500, Internal Server Error);      // [RFC2616]
806     HTTP_STATUS_ENTRY(501, Not Implemented);            // [RFC2616]
807     HTTP_STATUS_ENTRY(502, Bad Gateway);                // [RFC2616]
808     HTTP_STATUS_ENTRY(503, Service Unavailable);        // [RFC2616]
809     HTTP_STATUS_ENTRY(504, Gateway Timeout);            // [RFC2616]
810     HTTP_STATUS_ENTRY(505, HTTP Version Not Supported); // [RFC2616]
811     HTTP_STATUS_ENTRY(506, Variant Also Negotiates);    // [RFC2295]
812     HTTP_STATUS_ENTRY(507, Insufficient Storage);       // [RFC4918]
813     HTTP_STATUS_ENTRY(508, Loop Detected);              // [RFC5842]
814     // 509 Unassigned
815     HTTP_STATUS_ENTRY(510, Not Extended);                    // [RFC2774]
816     HTTP_STATUS_ENTRY(511, Network Authentication Required); // [RFC6585]
817     // 512-599 Unassigned
818   }
819 
820 #undef HTTP_STATUS_ENTRY
821 
822   return nullptr;
823 }
824 
825 //////////////////////////////////////////////////////
826 // init     first time structure setup              //
827 // clear    resets an already-initialized structure //
828 //////////////////////////////////////////////////////
829 
830 void
http_parser_init(HTTPParser * parser)831 http_parser_init(HTTPParser *parser)
832 {
833   parser->m_parsing_http = true;
834   mime_parser_init(&parser->m_mime_parser);
835 }
836 
837 void
http_parser_clear(HTTPParser * parser)838 http_parser_clear(HTTPParser *parser)
839 {
840   parser->m_parsing_http = true;
841   mime_parser_clear(&parser->m_mime_parser);
842 }
843 
844 /*-------------------------------------------------------------------------
845   -------------------------------------------------------------------------*/
846 
847 #define GETNEXT(label) \
848   {                    \
849     cur += 1;          \
850     if (cur >= end) {  \
851       goto label;      \
852     }                  \
853   }
854 
855 #define GETPREV(label)      \
856   {                         \
857     cur -= 1;               \
858     if (cur < line_start) { \
859       goto label;           \
860     }                       \
861   }
862 
863 // NOTE: end is ONE CHARACTER PAST end of string!
864 
865 ParseResult
http_parser_parse_req(HTTPParser * parser,HdrHeap * heap,HTTPHdrImpl * hh,const char ** start,const char * end,bool must_copy_strings,bool eof,bool strict_uri_parsing,size_t max_request_line_size,size_t max_hdr_field_size)866 http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end,
867                       bool must_copy_strings, bool eof, bool strict_uri_parsing, size_t max_request_line_size,
868                       size_t max_hdr_field_size)
869 {
870   if (parser->m_parsing_http) {
871     MIMEScanner *scanner = &parser->m_mime_parser.m_scanner;
872     URLImpl *url;
873 
874     ParseResult err;
875     bool line_is_real;
876     const char *cur;
877     const char *line_start;
878     const char *real_end;
879     const char *method_start;
880     const char *method_end;
881     const char *url_start;
882     const char *url_end;
883     const char *version_start;
884     const char *version_end;
885 
886     ts::TextView text, parsed;
887 
888     real_end = end;
889 
890   start:
891     hh->m_polarity = HTTP_TYPE_REQUEST;
892 
893     // Make sure the line is not longer than max_request_line_size
894     if (scanner->get_buffered_line_size() > max_request_line_size) {
895       return PARSE_RESULT_ERROR;
896     }
897 
898     text.assign(*start, real_end);
899     err    = scanner->get(text, parsed, line_is_real, eof, MIMEScanner::LINE);
900     *start = text.data();
901     if (err < 0) {
902       return err;
903     }
904     // We have to get a request line.  If we get parse done here,
905     //   that meas we got an empty request
906     if (err == PARSE_RESULT_DONE) {
907       return PARSE_RESULT_ERROR;
908     }
909     if (err == PARSE_RESULT_CONT) {
910       return err;
911     }
912 
913     ink_assert(parsed.size() < UINT16_MAX);
914     line_start = cur = parsed.data();
915     end              = parsed.data_end();
916 
917     if (static_cast<unsigned>(end - line_start) > max_request_line_size) {
918       return PARSE_RESULT_ERROR;
919     }
920 
921     must_copy_strings = (must_copy_strings || (!line_is_real));
922 
923 #if (ENABLE_PARSER_FAST_PATHS)
924     // first try fast path
925     if (end - cur >= 16) {
926       if (((cur[0] ^ 'G') | (cur[1] ^ 'E') | (cur[2] ^ 'T')) != 0) {
927         goto slow_case;
928       }
929       if (((end[-10] ^ 'H') | (end[-9] ^ 'T') | (end[-8] ^ 'T') | (end[-7] ^ 'P') | (end[-6] ^ '/') | (end[-4] ^ '.') |
930            (end[-2] ^ '\r') | (end[-1] ^ '\n')) != 0) {
931         goto slow_case;
932       }
933       if (!(is_digit(end[-5]) && is_digit(end[-3]))) {
934         goto slow_case;
935       }
936       if (!(ParseRules::is_space(cur[3]) && (!ParseRules::is_space(cur[4])) && (!ParseRules::is_space(end[-12])) &&
937             ParseRules::is_space(end[-11]))) {
938         goto slow_case;
939       }
940       if (&(cur[4]) >= &(end[-11])) {
941         goto slow_case;
942       }
943 
944       int32_t version = HTTP_VERSION(end[-5] - '0', end[-3] - '0');
945 
946       http_hdr_method_set(heap, hh, &(cur[0]), hdrtoken_wks_to_index(HTTP_METHOD_GET), 3, must_copy_strings);
947       ink_assert(hh->u.req.m_url_impl != nullptr);
948       url       = hh->u.req.m_url_impl;
949       url_start = &(cur[4]);
950       err       = ::url_parse(heap, url, &url_start, &(end[-11]), must_copy_strings, strict_uri_parsing);
951       if (err < 0) {
952         return err;
953       }
954       http_hdr_version_set(hh, version);
955 
956       end                    = real_end;
957       parser->m_parsing_http = false;
958       if (version == HTTP_VERSION(0, 9)) {
959         return PARSE_RESULT_ERROR;
960       }
961 
962       ParseResult ret =
963         mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof, max_hdr_field_size);
964       // If we're done with the main parse do some validation
965       if (ret == PARSE_RESULT_DONE) {
966         ret = validate_hdr_host(hh); // check HOST header
967       }
968       if (ret == PARSE_RESULT_DONE) {
969         ret = validate_hdr_content_length(heap, hh);
970       }
971       return ret;
972     }
973 #endif
974 
975   slow_case:
976 
977     method_start  = nullptr;
978     method_end    = nullptr;
979     url_start     = nullptr;
980     url_end       = nullptr;
981     version_start = nullptr;
982     version_end   = nullptr;
983     url           = nullptr;
984 
985     if (ParseRules::is_cr(*cur))
986       GETNEXT(done);
987     if (ParseRules::is_lf(*cur)) {
988       goto start;
989     }
990 
991   parse_method1:
992 
993     if (ParseRules::is_ws(*cur)) {
994       GETNEXT(done);
995       goto parse_method1;
996     }
997     if (!ParseRules::is_token(*cur)) {
998       goto done;
999     }
1000     method_start = cur;
1001     GETNEXT(done);
1002   parse_method2:
1003     if (ParseRules::is_ws(*cur)) {
1004       method_end = cur;
1005       goto parse_version1;
1006     }
1007     if (!ParseRules::is_token(*cur)) {
1008       goto done;
1009     }
1010     GETNEXT(done);
1011     goto parse_method2;
1012 
1013   parse_version1:
1014     cur = end - 1;
1015     if (ParseRules::is_lf(*cur) && (cur >= line_start)) {
1016       cur -= 1;
1017     }
1018     if (ParseRules::is_cr(*cur) && (cur >= line_start)) {
1019       cur -= 1;
1020     }
1021     // A client may add extra white spaces after the HTTP version.
1022     // So, skip white spaces.
1023     while (ParseRules::is_ws(*cur) && (cur >= line_start)) {
1024       cur -= 1;
1025     }
1026     version_end = cur + 1;
1027   parse_version2:
1028     if (ParseRules::is_digit(*cur)) {
1029       GETPREV(parse_url);
1030       goto parse_version2;
1031     }
1032     if (*cur == '.') {
1033       GETPREV(parse_url);
1034       goto parse_version3;
1035     }
1036     goto parse_url;
1037   parse_version3:
1038     if (ParseRules::is_digit(*cur)) {
1039       GETPREV(parse_url);
1040       goto parse_version3;
1041     }
1042     if (*cur == '/') {
1043       GETPREV(parse_url);
1044       goto parse_version4;
1045     }
1046     goto parse_url;
1047   parse_version4:
1048     if ((*cur != 'P') && (*cur != 'p')) {
1049       goto parse_url;
1050     }
1051     GETPREV(parse_url);
1052     if ((*cur != 'T') && (*cur != 't')) {
1053       goto parse_url;
1054     }
1055     GETPREV(parse_url);
1056     if ((*cur != 'T') && (*cur != 't')) {
1057       goto parse_url;
1058     }
1059     GETPREV(parse_url);
1060     if ((*cur != 'H') && (*cur != 'h')) {
1061       goto parse_url;
1062     }
1063     version_start = cur;
1064 
1065   parse_url:
1066     url_start = method_end + 1;
1067     if (version_start) {
1068       url_end = version_start - 1;
1069     } else {
1070       url_end = end - 1;
1071     }
1072     while ((url_start < end) && ParseRules::is_ws(*url_start)) {
1073       url_start += 1;
1074     }
1075     while ((url_end >= line_start) && ParseRules::is_wslfcr(*url_end)) {
1076       url_end -= 1;
1077     }
1078     url_end += 1;
1079 
1080   done:
1081     if (!method_start || !method_end) {
1082       return PARSE_RESULT_ERROR;
1083     }
1084 
1085     // checking these with an if statement makes coverity flag as dead code because
1086     // url_start and url_end logically cannot be 0 at this time
1087     ink_assert(url_start);
1088     ink_assert(url_end);
1089 
1090     int method_wks_idx = hdrtoken_tokenize(method_start, static_cast<int>(method_end - method_start));
1091     http_hdr_method_set(heap, hh, method_start, method_wks_idx, static_cast<int>(method_end - method_start), must_copy_strings);
1092 
1093     ink_assert(hh->u.req.m_url_impl != nullptr);
1094 
1095     url = hh->u.req.m_url_impl;
1096     err = ::url_parse(heap, url, &url_start, url_end, must_copy_strings, strict_uri_parsing);
1097 
1098     if (err < 0) {
1099       return err;
1100     }
1101 
1102     int32_t version;
1103     if (version_start && version_end) {
1104       version = http_parse_version(version_start, version_end);
1105     } else {
1106       return PARSE_RESULT_ERROR;
1107     }
1108 
1109     if (version == HTTP_VERSION(0, 9)) {
1110       return PARSE_RESULT_ERROR;
1111     }
1112 
1113     http_hdr_version_set(hh, version);
1114 
1115     end                    = real_end;
1116     parser->m_parsing_http = false;
1117 
1118     ParseResult ret =
1119       mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof, max_hdr_field_size);
1120     // If we're done with the main parse do some validation
1121     if (ret == PARSE_RESULT_DONE) {
1122       ret = validate_hdr_host(hh); // check HOST header
1123     }
1124     if (ret == PARSE_RESULT_DONE) {
1125       ret = validate_hdr_content_length(heap, hh);
1126     }
1127     return ret;
1128   }
1129 
1130   return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof, max_hdr_field_size);
1131 }
1132 
1133 ParseResult
validate_hdr_host(HTTPHdrImpl * hh)1134 validate_hdr_host(HTTPHdrImpl *hh)
1135 {
1136   ParseResult ret       = PARSE_RESULT_DONE;
1137   MIMEField *host_field = mime_hdr_field_find(hh->m_fields_impl, MIME_FIELD_HOST, MIME_LEN_HOST);
1138   if (host_field) {
1139     if (host_field->has_dups()) {
1140       ret = PARSE_RESULT_ERROR; // can't have more than 1 host field.
1141     } else {
1142       int host_len         = 0;
1143       const char *host_val = host_field->value_get(&host_len);
1144       std::string_view addr, port, rest, host(host_val, host_len);
1145       if (0 == ats_ip_parse(host, &addr, &port, &rest)) {
1146         if (!port.empty()) {
1147           if (port.size() > 5) {
1148             return PARSE_RESULT_ERROR;
1149           }
1150           int port_i = ink_atoi(port.data(), port.size());
1151           if (port_i >= 65536 || port_i <= 0) {
1152             return PARSE_RESULT_ERROR;
1153           }
1154         }
1155         if (!validate_host_name(addr)) {
1156           return PARSE_RESULT_ERROR;
1157         }
1158         if (PARSE_RESULT_DONE == ret && !std::all_of(rest.begin(), rest.end(), &ParseRules::is_ws)) {
1159           return PARSE_RESULT_ERROR;
1160         }
1161       } else {
1162         ret = PARSE_RESULT_ERROR;
1163       }
1164     }
1165   }
1166   return ret;
1167 }
1168 
1169 ParseResult
validate_hdr_content_length(HdrHeap * heap,HTTPHdrImpl * hh)1170 validate_hdr_content_length(HdrHeap *heap, HTTPHdrImpl *hh)
1171 {
1172   MIMEField *content_length_field = mime_hdr_field_find(hh->m_fields_impl, MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH);
1173 
1174   if (content_length_field) {
1175     // RFC 7230 section 3.3.3:
1176     // If a message is received with both a Transfer-Encoding and a
1177     // Content-Length header field, the Transfer-Encoding overrides
1178     // the Content-Length
1179     if (mime_hdr_field_find(hh->m_fields_impl, MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING) != nullptr) {
1180       // Delete all Content-Length headers
1181       Debug("http", "Transfer-Encoding header and Content-Length headers the request, removing all Content-Length headers");
1182       mime_hdr_field_delete(heap, hh->m_fields_impl, content_length_field);
1183       return PARSE_RESULT_DONE;
1184     }
1185 
1186     // RFC 7230 section 3.3.3:
1187     // If a message is received without Transfer-Encoding and with
1188     // either multiple Content-Length header fields having differing
1189     // field-values or a single Content-Length header field having an
1190     // invalid value, then the message framing is invalid and the
1191     // recipient MUST treat it as an unrecoverable error.  If this is a
1192     // request message, the server MUST respond with a 400 (Bad Request)
1193     // status code and then close the connection
1194     int content_length_len         = 0;
1195     const char *content_length_val = content_length_field->value_get(&content_length_len);
1196 
1197     while (content_length_field->has_dups()) {
1198       int content_length_len_2         = 0;
1199       const char *content_length_val_2 = content_length_field->m_next_dup->value_get(&content_length_len_2);
1200 
1201       if ((content_length_len != content_length_len_2) ||
1202           (memcmp(content_length_val, content_length_val_2, content_length_len) != 0)) {
1203         // Values are different, parse error
1204         Debug("http", "Content-Length headers don't match, returning parse error");
1205         return PARSE_RESULT_ERROR;
1206       } else {
1207         // Delete the duplicate since it has the same value
1208         Debug("http", "Deleting duplicate Content-Length header");
1209         mime_hdr_field_delete(heap, hh->m_fields_impl, content_length_field->m_next_dup, false);
1210       }
1211     }
1212   }
1213 
1214   return PARSE_RESULT_DONE;
1215 }
1216 
1217 /*-------------------------------------------------------------------------
1218   -------------------------------------------------------------------------*/
1219 
1220 ParseResult
http_parser_parse_resp(HTTPParser * parser,HdrHeap * heap,HTTPHdrImpl * hh,const char ** start,const char * end,bool must_copy_strings,bool eof)1221 http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end,
1222                        bool must_copy_strings, bool eof)
1223 {
1224   if (parser->m_parsing_http) {
1225     MIMEScanner *scanner = &parser->m_mime_parser.m_scanner;
1226 
1227     ParseResult err;
1228     bool line_is_real;
1229     const char *cur;
1230     const char *line_start;
1231     const char *real_end;
1232     const char *version_start;
1233     const char *version_end;
1234     const char *status_start;
1235     const char *status_end;
1236     const char *reason_start;
1237     const char *reason_end;
1238     const char *old_start;
1239 
1240     real_end  = end;
1241     old_start = *start;
1242 
1243     hh->m_polarity = HTTP_TYPE_RESPONSE;
1244 
1245     // Make sure the line is not longer than 64K
1246     if (scanner->get_buffered_line_size() >= UINT16_MAX) {
1247       return PARSE_RESULT_ERROR;
1248     }
1249 
1250     ts::TextView text{*start, real_end};
1251     ts::TextView parsed;
1252     err    = scanner->get(text, parsed, line_is_real, eof, MIMEScanner::LINE);
1253     *start = text.data();
1254     if (err < 0) {
1255       return err;
1256     }
1257     if ((err == PARSE_RESULT_DONE) || (err == PARSE_RESULT_CONT)) {
1258       return err;
1259     }
1260 
1261     ink_assert(parsed.size() < UINT16_MAX);
1262     line_start = cur = parsed.data();
1263     end              = parsed.data_end();
1264 
1265     must_copy_strings = (must_copy_strings || (!line_is_real));
1266 
1267 #if (ENABLE_PARSER_FAST_PATHS)
1268     // first try fast path
1269     if (end - cur >= 16) {
1270       int http_match =
1271         ((cur[0] ^ 'H') | (cur[1] ^ 'T') | (cur[2] ^ 'T') | (cur[3] ^ 'P') | (cur[4] ^ '/') | (cur[6] ^ '.') | (cur[8] ^ ' '));
1272       if ((http_match != 0) || (!(is_digit(cur[5]) && is_digit(cur[7]) && is_digit(cur[9]) && is_digit(cur[10]) &&
1273                                   is_digit(cur[11]) && (!ParseRules::is_space(cur[13]))))) {
1274         goto slow_case;
1275       }
1276 
1277       reason_start = &(cur[13]);
1278       reason_end   = end - 1;
1279       while ((reason_end > reason_start + 1) && (ParseRules::is_space(reason_end[-1]))) {
1280         --reason_end;
1281       }
1282 
1283       int32_t version   = HTTP_VERSION(cur[5] - '0', cur[7] - '0');
1284       HTTPStatus status = static_cast<HTTPStatus>((cur[9] - '0') * 100 + (cur[10] - '0') * 10 + (cur[11] - '0'));
1285 
1286       http_hdr_version_set(hh, version);
1287       http_hdr_status_set(hh, status);
1288       http_hdr_reason_set(heap, hh, reason_start, static_cast<int>(reason_end - reason_start), must_copy_strings);
1289 
1290       end                    = real_end;
1291       parser->m_parsing_http = false;
1292       return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
1293     }
1294 #endif
1295 
1296   slow_case:
1297     version_start = nullptr;
1298     version_end   = nullptr;
1299     status_start  = nullptr;
1300     status_end    = nullptr;
1301     reason_start  = nullptr;
1302     reason_end    = nullptr;
1303 
1304     version_start = cur = line_start;
1305     if ((*cur != 'H') && (*cur != 'h')) {
1306       goto eoh;
1307     }
1308     GETNEXT(eoh);
1309     if ((*cur != 'T') && (*cur != 't')) {
1310       goto eoh;
1311     }
1312     GETNEXT(eoh);
1313     if ((*cur != 'T') && (*cur != 't')) {
1314       goto eoh;
1315     }
1316     GETNEXT(eoh);
1317     if ((*cur != 'P') && (*cur != 'p')) {
1318       goto eoh;
1319     }
1320     GETNEXT(eoh);
1321     if (*cur != '/') {
1322       goto eoh;
1323     }
1324     GETNEXT(eoh);
1325   parse_version2:
1326     if (ParseRules::is_digit(*cur)) {
1327       GETNEXT(eoh);
1328       goto parse_version2;
1329     }
1330     if (*cur == '.') {
1331       GETNEXT(eoh);
1332       goto parse_version3;
1333     }
1334     goto eoh;
1335   parse_version3:
1336     if (ParseRules::is_digit(*cur)) {
1337       GETNEXT(eoh);
1338       goto parse_version3;
1339     }
1340     if (ParseRules::is_ws(*cur)) {
1341       version_end = cur;
1342       GETNEXT(eoh);
1343       goto parse_status1;
1344     }
1345     goto eoh;
1346 
1347   parse_status1:
1348     if (ParseRules::is_ws(*cur)) {
1349       GETNEXT(done);
1350       goto parse_status1;
1351     }
1352     status_start = cur;
1353   parse_status2:
1354     status_end = cur;
1355     if (ParseRules::is_digit(*cur)) {
1356       GETNEXT(done);
1357       goto parse_status2;
1358     }
1359     if (ParseRules::is_ws(*cur)) {
1360       GETNEXT(done);
1361       goto parse_reason1;
1362     }
1363     goto done;
1364 
1365   parse_reason1:
1366     if (ParseRules::is_ws(*cur)) {
1367       GETNEXT(done);
1368       goto parse_reason1;
1369     }
1370     reason_start = cur;
1371     reason_end   = end - 1;
1372     while ((reason_end >= line_start) && (ParseRules::is_cr(*reason_end) || ParseRules::is_lf(*reason_end))) {
1373       reason_end -= 1;
1374     }
1375     reason_end += 1;
1376     goto done;
1377 
1378   eoh:
1379     *start = old_start;
1380     return PARSE_RESULT_ERROR; // This used to return PARSE_RESULT_DONE by default before
1381 
1382   done:
1383     if (!version_start || !version_end) {
1384       return PARSE_RESULT_ERROR;
1385     }
1386 
1387     int32_t version;
1388     version = http_parse_version(version_start, version_end);
1389 
1390     if (version == HTTP_VERSION(0, 9)) {
1391       return PARSE_RESULT_ERROR;
1392     }
1393 
1394     http_hdr_version_set(hh, version);
1395 
1396     if (status_start && status_end) {
1397       http_hdr_status_set(hh, http_parse_status(status_start, status_end));
1398     }
1399 
1400     if (reason_start && reason_end) {
1401       http_hdr_reason_set(heap, hh, reason_start, static_cast<int>(reason_end - reason_start), must_copy_strings);
1402     }
1403 
1404     end                    = real_end;
1405     parser->m_parsing_http = false;
1406   }
1407 
1408   return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
1409 }
1410 
1411 /*-------------------------------------------------------------------------
1412   -------------------------------------------------------------------------*/
1413 
1414 HTTPStatus
http_parse_status(const char * start,const char * end)1415 http_parse_status(const char *start, const char *end)
1416 {
1417   int status = 0;
1418 
1419   while ((start != end) && ParseRules::is_space(*start)) {
1420     start += 1;
1421   }
1422 
1423   while ((start != end) && ParseRules::is_digit(*start)) {
1424     status = (status * 10) + (*start++ - '0');
1425   }
1426 
1427   return static_cast<HTTPStatus>(status);
1428 }
1429 
1430 /*-------------------------------------------------------------------------
1431   -------------------------------------------------------------------------*/
1432 
1433 int32_t
http_parse_version(const char * start,const char * end)1434 http_parse_version(const char *start, const char *end)
1435 {
1436   int maj;
1437   int min;
1438 
1439   if ((end - start) < 8) {
1440     return HTTP_VERSION(0, 9);
1441   }
1442 
1443   if (((start[0] == 'H') || (start[0] == 'h')) && ((start[1] == 'T') || (start[1] == 't')) &&
1444       ((start[2] == 'T') || (start[2] == 't')) && ((start[3] == 'P') || (start[3] == 'p')) && (start[4] == '/')) {
1445     start += 5;
1446 
1447     maj = 0;
1448     min = 0;
1449 
1450     while ((start != end) && ParseRules::is_digit(*start)) {
1451       maj = (maj * 10) + (*start - '0');
1452       start += 1;
1453     }
1454 
1455     if (*start == '.') {
1456       start += 1;
1457     }
1458 
1459     while ((start != end) && ParseRules::is_digit(*start)) {
1460       min = (min * 10) + (*start - '0');
1461       start += 1;
1462     }
1463 
1464     return HTTP_VERSION(maj, min);
1465   }
1466 
1467   return HTTP_VERSION(0, 9);
1468 }
1469 
1470 /*-------------------------------------------------------------------------
1471   -------------------------------------------------------------------------*/
1472 
1473 static char *
http_str_store(Arena * arena,const char * str,int length)1474 http_str_store(Arena *arena, const char *str, int length)
1475 {
1476   const char *wks;
1477   int idx = hdrtoken_tokenize(str, length, &wks);
1478   if (idx < 0) {
1479     return arena->str_store(str, length);
1480   } else {
1481     return const_cast<char *>(wks);
1482   }
1483 }
1484 
1485 /*-------------------------------------------------------------------------
1486   -------------------------------------------------------------------------*/
1487 
1488 static void
http_skip_ws(const char * & buf,int & len)1489 http_skip_ws(const char *&buf, int &len)
1490 {
1491   while (len > 0 && *buf && ParseRules::is_ws(*buf)) {
1492     buf += 1;
1493     len -= 1;
1494   }
1495 }
1496 
1497 /*-------------------------------------------------------------------------
1498   -------------------------------------------------------------------------*/
1499 
1500 static double
http_parse_qvalue(const char * & buf,int & len)1501 http_parse_qvalue(const char *&buf, int &len)
1502 {
1503   double val = 1.0;
1504 
1505   if (*buf != ';') {
1506     return val;
1507   }
1508 
1509   buf += 1;
1510   len -= 1;
1511 
1512   while (len > 0 && *buf) {
1513     http_skip_ws(buf, len);
1514 
1515     if (*buf == 'q') {
1516       buf += 1;
1517       len -= 1;
1518       http_skip_ws(buf, len);
1519 
1520       if (*buf == '=') {
1521         double n;
1522         int f;
1523 
1524         buf += 1;
1525         len -= 1;
1526         http_skip_ws(buf, len);
1527 
1528         n = 0.0;
1529         while (len > 0 && *buf && ParseRules::is_digit(*buf)) {
1530           n = (n * 10) + (*buf++ - '0');
1531           len -= 1;
1532         }
1533 
1534         if (*buf == '.') {
1535           buf += 1;
1536           len -= 1;
1537 
1538           f = 10;
1539           while (len > 0 && *buf && ParseRules::is_digit(*buf)) {
1540             n += (*buf++ - '0') / static_cast<double>(f);
1541             f *= 10;
1542             len -= 1;
1543           }
1544         }
1545 
1546         val = n;
1547       }
1548     } else {
1549       // The current parameter is not a q-value, so go to the next param.
1550       while (len > 0 && *buf) {
1551         if (*buf != ';') {
1552           buf += 1;
1553           len -= 1;
1554         } else {
1555           // Move to the character after the semicolon.
1556           buf += 1;
1557           len -= 1;
1558           break;
1559         }
1560       }
1561     }
1562   }
1563 
1564   return val;
1565 }
1566 
1567 /*-------------------------------------------------------------------------
1568   -------------------------------------------------------------------------*/
1569 
1570 /*-------------------------------------------------------------------------
1571   TE        = "TE" ":" #( t-codings )
1572   t-codings = "trailers" | ( transfer-extension [ accept-params ] )
1573   -------------------------------------------------------------------------*/
1574 
1575 HTTPValTE *
http_parse_te(const char * buf,int len,Arena * arena)1576 http_parse_te(const char *buf, int len, Arena *arena)
1577 {
1578   HTTPValTE *val;
1579   const char *s;
1580 
1581   http_skip_ws(buf, len);
1582 
1583   s = buf;
1584 
1585   while (len > 0 && *buf && (*buf != ';')) {
1586     buf += 1;
1587     len -= 1;
1588   }
1589 
1590   val           = static_cast<HTTPValTE *>(arena->alloc(sizeof(HTTPValTE)));
1591   val->encoding = http_str_store(arena, s, static_cast<int>(buf - s));
1592   val->qvalue   = http_parse_qvalue(buf, len);
1593 
1594   return val;
1595 }
1596 
1597 void
_fill_target_cache() const1598 HTTPHdr::_fill_target_cache() const
1599 {
1600   URL *url = this->url_get();
1601   const char *port_ptr;
1602   int port_len;
1603 
1604   m_target_in_url  = false;
1605   m_port_in_header = false;
1606   m_host_mime      = nullptr;
1607   // Check in the URL first, then the HOST field.
1608   if (nullptr != url->host_get(&m_host_length)) {
1609     m_target_in_url  = true;
1610     m_port           = url->port_get();
1611     m_port_in_header = 0 != url->port_get_raw();
1612     m_host_mime      = nullptr;
1613   } else if (nullptr !=
1614              (m_host_mime = const_cast<HTTPHdr *>(this)->get_host_port_values(nullptr, &m_host_length, &port_ptr, &port_len))) {
1615     m_port = 0;
1616     if (port_ptr) {
1617       for (; port_len > 0 && is_digit(*port_ptr); ++port_ptr, --port_len) {
1618         m_port = m_port * 10 + *port_ptr - '0';
1619       }
1620     }
1621     m_port_in_header = (0 != m_port);
1622     m_port           = url_canonicalize_port(url->m_url_impl->m_url_type, m_port);
1623   }
1624 
1625   m_target_cached = true;
1626 }
1627 
1628 void
set_url_target_from_host_field(URL * url)1629 HTTPHdr::set_url_target_from_host_field(URL *url)
1630 {
1631   this->_test_and_fill_target_cache();
1632 
1633   if (!url) {
1634     // Use local cached URL and don't copy if the target
1635     // is already there.
1636     if (!m_target_in_url && m_host_mime && m_host_length) {
1637       m_url_cached.host_set(m_host_mime->m_ptr_value, m_host_length);
1638       if (m_port_in_header) {
1639         m_url_cached.port_set(m_port);
1640       }
1641       m_target_in_url = true; // it's there now.
1642     }
1643   } else {
1644     int host_len     = 0;
1645     const char *host = host_get(&host_len);
1646 
1647     url->host_set(host, host_len);
1648     if (m_port_in_header) {
1649       url->port_set(m_port);
1650     }
1651   }
1652 }
1653 
1654 // Very ugly, but a proper implementation will require
1655 // rewriting the URL class and all of its clients so that
1656 // clients access the URL through the HTTP header instance
1657 // unless they really need low level access. The header would
1658 // need to either keep two versions of the URL (pristine
1659 // and effective) or URl would have to provide access to
1660 // the URL printer.
1661 
1662 /// Hack the URL in the HTTP header to be 1.0 compliant, saving the
1663 /// original values so they can be restored.
1664 class UrlPrintHack
1665 {
1666   friend class HTTPHdr;
UrlPrintHack(HTTPHdr * hdr)1667   UrlPrintHack(HTTPHdr *hdr)
1668   {
1669     hdr->_test_and_fill_target_cache();
1670     if (hdr->m_url_cached.valid()) {
1671       URLImpl *ui = hdr->m_url_cached.m_url_impl;
1672 
1673       m_hdr = hdr; // mark as potentially having modified values.
1674 
1675       /* Get dirty. We reach in to the URL implementation to
1676          set the host and port if
1677          1) They are not already set
1678          AND
1679          2) The values were in a HTTP header.
1680       */
1681       if (!hdr->m_target_in_url && hdr->m_host_length && hdr->m_host_mime) {
1682         ink_assert(nullptr == ui->m_ptr_host); // shouldn't be non-zero if not in URL.
1683         ui->m_ptr_host    = hdr->m_host_mime->m_ptr_value;
1684         ui->m_len_host    = hdr->m_host_length;
1685         m_host_modified_p = true;
1686       } else {
1687         m_host_modified_p = false;
1688       }
1689 
1690       if (0 == hdr->m_url_cached.port_get_raw() && hdr->m_port_in_header) {
1691         ink_assert(nullptr == ui->m_ptr_port); // shouldn't be set if not in URL.
1692         ui->m_ptr_port    = m_port_buff;
1693         ui->m_len_port    = snprintf(m_port_buff, sizeof(m_port_buff), "%d", hdr->m_port);
1694         ui->m_port        = hdr->m_port;
1695         m_port_modified_p = true;
1696       } else {
1697         m_port_modified_p = false;
1698       }
1699     } else {
1700       m_hdr = nullptr;
1701     }
1702   }
1703 
1704   /// Destructor.
~UrlPrintHack()1705   ~UrlPrintHack()
1706   {
1707     if (m_hdr) { // There was a potentially modified header.
1708       URLImpl *ui = m_hdr->m_url_cached.m_url_impl;
1709       // Because we only modified if not set, we can just set these values
1710       // back to zero if modified. We want to be careful because if a
1711       // heap re-allocation happened while this was active, then a saved value
1712       // is wrong and will break things if restored. We don't have to worry
1713       // about these because, if modified, they were originally NULL and should
1714       // still be NULL after a re-allocate.
1715       if (m_port_modified_p) {
1716         ui->m_len_port = 0;
1717         ui->m_ptr_port = nullptr;
1718         ui->m_port     = 0;
1719       }
1720       if (m_host_modified_p) {
1721         ui->m_len_host = 0;
1722         ui->m_ptr_host = nullptr;
1723       }
1724     }
1725   }
1726 
1727   /// Check if the hack worked
1728   bool
is_valid() const1729   is_valid() const
1730   {
1731     return nullptr != m_hdr;
1732   }
1733 
1734   /// Saved values.
1735   ///@{
1736   bool m_host_modified_p = false;
1737   bool m_port_modified_p = false;
1738   HTTPHdr *m_hdr         = nullptr;
1739   ///@}
1740   /// Temporary buffer for port data.
1741   char m_port_buff[32];
1742 };
1743 
1744 char *
url_string_get(Arena * arena,int * length,bool normalized)1745 HTTPHdr::url_string_get(Arena *arena, int *length, bool normalized)
1746 {
1747   char *zret = nullptr;
1748   UrlPrintHack hack(this);
1749 
1750   if (hack.is_valid()) {
1751     // The use of a magic value for Arena to indicate the internal heap is
1752     // even uglier but it's less so than duplicating this entire method to
1753     // change that one thing.
1754 
1755     zret = (arena == USE_HDR_HEAP_MAGIC) ? m_url_cached.string_get_ref(length, normalized) :
1756                                            m_url_cached.string_get(arena, length, normalized);
1757   }
1758   return zret;
1759 }
1760 
1761 int
url_print(char * buff,int length,int * offset,int * skip,bool normalized)1762 HTTPHdr::url_print(char *buff, int length, int *offset, int *skip, bool normalized)
1763 {
1764   ink_release_assert(offset);
1765   ink_release_assert(skip);
1766 
1767   int zret = 0;
1768   UrlPrintHack hack(this);
1769   if (hack.is_valid()) {
1770     zret = m_url_cached.print(buff, length, offset, skip, normalized);
1771   }
1772   return zret;
1773 }
1774 
1775 int
url_printed_length()1776 HTTPHdr::url_printed_length()
1777 {
1778   int zret = -1;
1779   UrlPrintHack hack(this);
1780   if (hack.is_valid()) {
1781     zret = m_url_cached.length_get();
1782   }
1783   return zret;
1784 }
1785 
1786 /***********************************************************************
1787  *                                                                     *
1788  *                        M A R S H A L I N G                          *
1789  *                                                                     *
1790  ***********************************************************************/
1791 
1792 int
unmarshal(char * buf,int len,RefCountObj * block_ref)1793 HTTPHdr::unmarshal(char *buf, int len, RefCountObj *block_ref)
1794 {
1795   m_heap = reinterpret_cast<HdrHeap *>(buf);
1796 
1797   int res = m_heap->unmarshal(len, HDR_HEAP_OBJ_HTTP_HEADER, reinterpret_cast<HdrHeapObjImpl **>(&m_http), block_ref);
1798 
1799   if (res > 0) {
1800     m_mime = m_http->m_fields_impl;
1801   } else {
1802     clear();
1803   }
1804 
1805   return res;
1806 }
1807 
1808 int
marshal(MarshalXlate * ptr_xlate,int num_ptr,MarshalXlate * str_xlate,int num_str)1809 HTTPHdrImpl::marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str)
1810 {
1811   if (m_polarity == HTTP_TYPE_REQUEST) {
1812     HDR_MARSHAL_STR(u.req.m_ptr_method, str_xlate, num_str);
1813     HDR_MARSHAL_PTR(u.req.m_url_impl, URLImpl, ptr_xlate, num_ptr);
1814   } else if (m_polarity == HTTP_TYPE_RESPONSE) {
1815     HDR_MARSHAL_STR(u.resp.m_ptr_reason, str_xlate, num_str);
1816   } else {
1817     ink_release_assert(!"unknown m_polarity");
1818   }
1819 
1820   HDR_MARSHAL_PTR(m_fields_impl, MIMEHdrImpl, ptr_xlate, num_ptr);
1821 
1822   return 0;
1823 }
1824 
1825 void
unmarshal(intptr_t offset)1826 HTTPHdrImpl::unmarshal(intptr_t offset)
1827 {
1828   if (m_polarity == HTTP_TYPE_REQUEST) {
1829     HDR_UNMARSHAL_STR(u.req.m_ptr_method, offset);
1830     HDR_UNMARSHAL_PTR(u.req.m_url_impl, URLImpl, offset);
1831   } else if (m_polarity == HTTP_TYPE_RESPONSE) {
1832     HDR_UNMARSHAL_STR(u.resp.m_ptr_reason, offset);
1833   } else {
1834     ink_release_assert(!"unknown m_polarity");
1835   }
1836 
1837   HDR_UNMARSHAL_PTR(m_fields_impl, MIMEHdrImpl, offset);
1838 }
1839 
1840 void
move_strings(HdrStrHeap * new_heap)1841 HTTPHdrImpl::move_strings(HdrStrHeap *new_heap)
1842 {
1843   if (m_polarity == HTTP_TYPE_REQUEST) {
1844     HDR_MOVE_STR(u.req.m_ptr_method, u.req.m_len_method);
1845   } else if (m_polarity == HTTP_TYPE_RESPONSE) {
1846     HDR_MOVE_STR(u.resp.m_ptr_reason, u.resp.m_len_reason);
1847   } else {
1848     ink_release_assert(!"unknown m_polarity");
1849   }
1850 }
1851 
1852 size_t
strings_length()1853 HTTPHdrImpl::strings_length()
1854 {
1855   size_t ret = 0;
1856 
1857   if (m_polarity == HTTP_TYPE_REQUEST) {
1858     ret += u.req.m_len_method;
1859   } else if (m_polarity == HTTP_TYPE_RESPONSE) {
1860     ret += u.resp.m_len_reason;
1861   }
1862   return ret;
1863 }
1864 
1865 void
check_strings(HeapCheck * heaps,int num_heaps)1866 HTTPHdrImpl::check_strings(HeapCheck *heaps, int num_heaps)
1867 {
1868   if (m_polarity == HTTP_TYPE_REQUEST) {
1869     CHECK_STR(u.req.m_ptr_method, u.req.m_len_method, heaps, num_heaps);
1870   } else if (m_polarity == HTTP_TYPE_RESPONSE) {
1871     CHECK_STR(u.resp.m_ptr_reason, u.resp.m_len_reason, heaps, num_heaps);
1872   } else {
1873     ink_release_assert(!"unknown m_polarity");
1874   }
1875 }
1876 
1877 ClassAllocator<HTTPCacheAlt> httpCacheAltAllocator("httpCacheAltAllocator");
1878 
1879 /*-------------------------------------------------------------------------
1880   -------------------------------------------------------------------------*/
1881 int constexpr HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS;
1882 
HTTPCacheAlt()1883 HTTPCacheAlt::HTTPCacheAlt() : m_request_hdr(), m_response_hdr()
1884 
1885 {
1886   memset(&m_object_key[0], 0, CRYPTO_HASH_SIZE);
1887   m_object_size[0] = 0;
1888   m_object_size[1] = 0;
1889 }
1890 
1891 void
destroy()1892 HTTPCacheAlt::destroy()
1893 {
1894   ink_assert(m_magic == CACHE_ALT_MAGIC_ALIVE);
1895   ink_assert(m_writeable);
1896   m_magic     = CACHE_ALT_MAGIC_DEAD;
1897   m_writeable = 0;
1898   m_request_hdr.destroy();
1899   m_response_hdr.destroy();
1900   m_frag_offset_count = 0;
1901   if (m_frag_offsets && m_frag_offsets != m_integral_frag_offsets) {
1902     ats_free(m_frag_offsets);
1903     m_frag_offsets = nullptr;
1904   }
1905   httpCacheAltAllocator.free(this);
1906 }
1907 
1908 void
copy(HTTPCacheAlt * to_copy)1909 HTTPCacheAlt::copy(HTTPCacheAlt *to_copy)
1910 {
1911   m_magic = to_copy->m_magic;
1912   // m_writeable =      to_copy->m_writeable;
1913   m_unmarshal_len = to_copy->m_unmarshal_len;
1914   m_id            = to_copy->m_id;
1915   m_rid           = to_copy->m_rid;
1916   memcpy(&m_object_key[0], &to_copy->m_object_key[0], CRYPTO_HASH_SIZE);
1917   m_object_size[0] = to_copy->m_object_size[0];
1918   m_object_size[1] = to_copy->m_object_size[1];
1919 
1920   if (to_copy->m_request_hdr.valid()) {
1921     m_request_hdr.copy(&to_copy->m_request_hdr);
1922   }
1923 
1924   if (to_copy->m_response_hdr.valid()) {
1925     m_response_hdr.copy(&to_copy->m_response_hdr);
1926   }
1927 
1928   m_request_sent_time      = to_copy->m_request_sent_time;
1929   m_response_received_time = to_copy->m_response_received_time;
1930   this->copy_frag_offsets_from(to_copy);
1931 }
1932 
1933 void
copy_frag_offsets_from(HTTPCacheAlt * src)1934 HTTPCacheAlt::copy_frag_offsets_from(HTTPCacheAlt *src)
1935 {
1936   m_frag_offset_count = src->m_frag_offset_count;
1937   if (m_frag_offset_count > 0) {
1938     if (m_frag_offset_count > N_INTEGRAL_FRAG_OFFSETS) {
1939       /* Mixed feelings about this - technically we don't need it to be a
1940          power of two when copied because currently that means it is frozen.
1941          But that could change later and it would be a nasty bug to find.
1942          So we'll do it for now. The relative overhead is tiny.
1943       */
1944       int bcount = HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS * 2;
1945       while (bcount < m_frag_offset_count) {
1946         bcount *= 2;
1947       }
1948       m_frag_offsets = static_cast<FragOffset *>(ats_malloc(sizeof(FragOffset) * bcount));
1949     } else {
1950       m_frag_offsets = m_integral_frag_offsets;
1951     }
1952     memcpy(m_frag_offsets, src->m_frag_offsets, sizeof(FragOffset) * m_frag_offset_count);
1953   }
1954 }
1955 
1956 const int HTTP_ALT_MARSHAL_SIZE = HdrHeapMarshalBlocks{ts::round_up(sizeof(HTTPCacheAlt))};
1957 
1958 void
create()1959 HTTPInfo::create()
1960 {
1961   m_alt = httpCacheAltAllocator.alloc();
1962 }
1963 
1964 void
copy(HTTPInfo * hi)1965 HTTPInfo::copy(HTTPInfo *hi)
1966 {
1967   if (m_alt && m_alt->m_writeable) {
1968     destroy();
1969   }
1970 
1971   create();
1972   m_alt->copy(hi->m_alt);
1973 }
1974 
1975 void
copy_frag_offsets_from(HTTPInfo * src)1976 HTTPInfo::copy_frag_offsets_from(HTTPInfo *src)
1977 {
1978   if (m_alt && src->m_alt) {
1979     m_alt->copy_frag_offsets_from(src->m_alt);
1980   }
1981 }
1982 
1983 int
marshal_length()1984 HTTPInfo::marshal_length()
1985 {
1986   int len = HTTP_ALT_MARSHAL_SIZE;
1987 
1988   if (m_alt->m_request_hdr.valid()) {
1989     len += m_alt->m_request_hdr.m_heap->marshal_length();
1990   }
1991 
1992   if (m_alt->m_response_hdr.valid()) {
1993     len += m_alt->m_response_hdr.m_heap->marshal_length();
1994   }
1995 
1996   if (m_alt->m_frag_offset_count > HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS) {
1997     len += sizeof(FragOffset) * m_alt->m_frag_offset_count;
1998   }
1999 
2000   return len;
2001 }
2002 
2003 int
marshal(char * buf,int len)2004 HTTPInfo::marshal(char *buf, int len)
2005 {
2006   int tmp;
2007   int used                  = 0;
2008   HTTPCacheAlt *marshal_alt = reinterpret_cast<HTTPCacheAlt *>(buf);
2009   // non-zero only if the offsets are external. Otherwise they get
2010   // marshalled along with the alt struct.
2011   ink_assert(m_alt->m_magic == CACHE_ALT_MAGIC_ALIVE);
2012 
2013   // Make sure the buffer is aligned
2014   //    ink_assert(((intptr_t)buf) & 0x3 == 0);
2015 
2016   // Memcpy the whole object so that we can use it
2017   //   live later.  This involves copying a few
2018   //   extra bytes now but will save copying any
2019   //   bytes on the way out of the cache
2020   memcpy(buf, m_alt, sizeof(HTTPCacheAlt));
2021   marshal_alt->m_magic         = CACHE_ALT_MAGIC_MARSHALED;
2022   marshal_alt->m_writeable     = 0;
2023   marshal_alt->m_unmarshal_len = -1;
2024   marshal_alt->m_ext_buffer    = nullptr;
2025   buf += HTTP_ALT_MARSHAL_SIZE;
2026   used += HTTP_ALT_MARSHAL_SIZE;
2027 
2028   if (m_alt->m_frag_offset_count > HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS) {
2029     marshal_alt->m_frag_offsets = static_cast<FragOffset *>(reinterpret_cast<void *>(used));
2030     memcpy(buf, m_alt->m_frag_offsets, m_alt->m_frag_offset_count * sizeof(FragOffset));
2031     buf += m_alt->m_frag_offset_count * sizeof(FragOffset);
2032     used += m_alt->m_frag_offset_count * sizeof(FragOffset);
2033   } else {
2034     marshal_alt->m_frag_offsets = nullptr;
2035   }
2036 
2037   // The m_{request,response}_hdr->m_heap pointers are converted
2038   //    to zero based offsets from the start of the buffer we're
2039   //    marshalling in to
2040   if (m_alt->m_request_hdr.valid()) {
2041     tmp                               = m_alt->m_request_hdr.m_heap->marshal(buf, len - used);
2042     marshal_alt->m_request_hdr.m_heap = (HdrHeap *)static_cast<intptr_t>(used);
2043     ink_assert(((intptr_t)marshal_alt->m_request_hdr.m_heap) < len);
2044     buf += tmp;
2045     used += tmp;
2046   } else {
2047     marshal_alt->m_request_hdr.m_heap = nullptr;
2048   }
2049 
2050   if (m_alt->m_response_hdr.valid()) {
2051     tmp                                = m_alt->m_response_hdr.m_heap->marshal(buf, len - used);
2052     marshal_alt->m_response_hdr.m_heap = (HdrHeap *)static_cast<intptr_t>(used);
2053     ink_assert(((intptr_t)marshal_alt->m_response_hdr.m_heap) < len);
2054     used += tmp;
2055   } else {
2056     marshal_alt->m_response_hdr.m_heap = nullptr;
2057   }
2058 
2059   // The prior system failed the marshal if there wasn't
2060   //   enough space by measuring the space for every
2061   //   component. Seems much faster to check once to
2062   //   see if we spammed memory
2063   ink_release_assert(used <= len);
2064 
2065   return used;
2066 }
2067 
2068 int
unmarshal(char * buf,int len,RefCountObj * block_ref)2069 HTTPInfo::unmarshal(char *buf, int len, RefCountObj *block_ref)
2070 {
2071   HTTPCacheAlt *alt = reinterpret_cast<HTTPCacheAlt *>(buf);
2072   int orig_len      = len;
2073 
2074   if (alt->m_magic == CACHE_ALT_MAGIC_ALIVE) {
2075     // Already unmarshaled, must be a ram cache
2076     //  it
2077     ink_assert(alt->m_unmarshal_len > 0);
2078     ink_assert(alt->m_unmarshal_len <= len);
2079     return alt->m_unmarshal_len;
2080   } else if (alt->m_magic != CACHE_ALT_MAGIC_MARSHALED) {
2081     ink_assert(!"HTTPInfo::unmarshal bad magic");
2082     return -1;
2083   }
2084 
2085   ink_assert(alt->m_unmarshal_len < 0);
2086   alt->m_magic = CACHE_ALT_MAGIC_ALIVE;
2087   ink_assert(alt->m_writeable == 0);
2088   len -= HTTP_ALT_MARSHAL_SIZE;
2089 
2090   if (alt->m_frag_offset_count > HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS) {
2091     alt->m_frag_offsets = reinterpret_cast<FragOffset *>(buf + reinterpret_cast<intptr_t>(alt->m_frag_offsets));
2092     len -= sizeof(FragOffset) * alt->m_frag_offset_count;
2093     ink_assert(len >= 0);
2094   } else if (alt->m_frag_offset_count > 0) {
2095     alt->m_frag_offsets = alt->m_integral_frag_offsets;
2096   } else {
2097     alt->m_frag_offsets = nullptr; // should really already be zero.
2098   }
2099 
2100   HdrHeap *heap   = reinterpret_cast<HdrHeap *>(alt->m_request_hdr.m_heap ? (buf + (intptr_t)alt->m_request_hdr.m_heap) : nullptr);
2101   HTTPHdrImpl *hh = nullptr;
2102   int tmp;
2103   if (heap != nullptr) {
2104     tmp = heap->unmarshal(len, HDR_HEAP_OBJ_HTTP_HEADER, reinterpret_cast<HdrHeapObjImpl **>(&hh), block_ref);
2105     if (hh == nullptr || tmp < 0) {
2106       ink_assert(!"HTTPInfo::request unmarshal failed");
2107       return -1;
2108     }
2109     len -= tmp;
2110     alt->m_request_hdr.m_heap              = heap;
2111     alt->m_request_hdr.m_http              = hh;
2112     alt->m_request_hdr.m_mime              = hh->m_fields_impl;
2113     alt->m_request_hdr.m_url_cached.m_heap = heap;
2114   }
2115 
2116   heap = reinterpret_cast<HdrHeap *>(alt->m_response_hdr.m_heap ? (buf + (intptr_t)alt->m_response_hdr.m_heap) : nullptr);
2117   if (heap != nullptr) {
2118     tmp = heap->unmarshal(len, HDR_HEAP_OBJ_HTTP_HEADER, reinterpret_cast<HdrHeapObjImpl **>(&hh), block_ref);
2119     if (hh == nullptr || tmp < 0) {
2120       ink_assert(!"HTTPInfo::response unmarshal failed");
2121       return -1;
2122     }
2123     len -= tmp;
2124 
2125     alt->m_response_hdr.m_heap = heap;
2126     alt->m_response_hdr.m_http = hh;
2127     alt->m_response_hdr.m_mime = hh->m_fields_impl;
2128   }
2129 
2130   alt->m_unmarshal_len = orig_len - len;
2131 
2132   return alt->m_unmarshal_len;
2133 }
2134 
2135 int
unmarshal_v24_1(char * buf,int len,RefCountObj * block_ref)2136 HTTPInfo::unmarshal_v24_1(char *buf, int len, RefCountObj *block_ref)
2137 {
2138   HTTPCacheAlt *alt = reinterpret_cast<HTTPCacheAlt *>(buf);
2139   int orig_len      = len;
2140 
2141   if (alt->m_magic == CACHE_ALT_MAGIC_ALIVE) {
2142     // Already unmarshaled, must be a ram cache
2143     //  it
2144     ink_assert(alt->m_unmarshal_len > 0);
2145     ink_assert(alt->m_unmarshal_len <= len);
2146     return alt->m_unmarshal_len;
2147   } else if (alt->m_magic != CACHE_ALT_MAGIC_MARSHALED) {
2148     ink_assert(!"HTTPInfo::unmarshal bad magic");
2149     return -1;
2150   }
2151 
2152   ink_assert(alt->m_unmarshal_len < 0);
2153   alt->m_magic = CACHE_ALT_MAGIC_ALIVE;
2154   ink_assert(alt->m_writeable == 0);
2155   len -= HTTP_ALT_MARSHAL_SIZE;
2156 
2157   if (alt->m_frag_offset_count > HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS) {
2158     // stuff that didn't fit in the integral slots.
2159     int extra       = sizeof(FragOffset) * alt->m_frag_offset_count - sizeof(alt->m_integral_frag_offsets);
2160     char *extra_src = buf + reinterpret_cast<intptr_t>(alt->m_frag_offsets);
2161     // Actual buffer size, which must be a power of two.
2162     // Well, technically not, because we never modify an unmarshalled fragment
2163     // offset table, but it would be a nasty bug should that be done in the
2164     // future.
2165     int bcount = HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS * 2;
2166 
2167     while (bcount < alt->m_frag_offset_count) {
2168       bcount *= 2;
2169     }
2170     alt->m_frag_offsets =
2171       static_cast<FragOffset *>(ats_malloc(bcount * sizeof(FragOffset))); // WRONG - must round up to next power of 2.
2172     memcpy(alt->m_frag_offsets, alt->m_integral_frag_offsets, sizeof(alt->m_integral_frag_offsets));
2173     memcpy(alt->m_frag_offsets + HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS, extra_src, extra);
2174     len -= extra;
2175   } else if (alt->m_frag_offset_count > 0) {
2176     alt->m_frag_offsets = alt->m_integral_frag_offsets;
2177   } else {
2178     alt->m_frag_offsets = nullptr; // should really already be zero.
2179   }
2180 
2181   HdrHeap *heap   = reinterpret_cast<HdrHeap *>(alt->m_request_hdr.m_heap ? (buf + (intptr_t)alt->m_request_hdr.m_heap) : nullptr);
2182   HTTPHdrImpl *hh = nullptr;
2183   int tmp;
2184   if (heap != nullptr) {
2185     tmp = heap->unmarshal(len, HDR_HEAP_OBJ_HTTP_HEADER, reinterpret_cast<HdrHeapObjImpl **>(&hh), block_ref);
2186     if (hh == nullptr || tmp < 0) {
2187       ink_assert(!"HTTPInfo::request unmarshal failed");
2188       return -1;
2189     }
2190     len -= tmp;
2191     alt->m_request_hdr.m_heap              = heap;
2192     alt->m_request_hdr.m_http              = hh;
2193     alt->m_request_hdr.m_mime              = hh->m_fields_impl;
2194     alt->m_request_hdr.m_url_cached.m_heap = heap;
2195   }
2196 
2197   heap = reinterpret_cast<HdrHeap *>(alt->m_response_hdr.m_heap ? (buf + (intptr_t)alt->m_response_hdr.m_heap) : nullptr);
2198   if (heap != nullptr) {
2199     tmp = heap->unmarshal(len, HDR_HEAP_OBJ_HTTP_HEADER, reinterpret_cast<HdrHeapObjImpl **>(&hh), block_ref);
2200     if (hh == nullptr || tmp < 0) {
2201       ink_assert(!"HTTPInfo::response unmarshal failed");
2202       return -1;
2203     }
2204     len -= tmp;
2205 
2206     alt->m_response_hdr.m_heap = heap;
2207     alt->m_response_hdr.m_http = hh;
2208     alt->m_response_hdr.m_mime = hh->m_fields_impl;
2209   }
2210 
2211   alt->m_unmarshal_len = orig_len - len;
2212 
2213   return alt->m_unmarshal_len;
2214 }
2215 
2216 // bool HTTPInfo::check_marshalled(char* buf, int len)
2217 //  Checks a marhshalled HTTPInfo buffer to make
2218 //    sure it's sane.  Returns true if sane, false otherwise
2219 //
2220 bool
check_marshalled(char * buf,int len)2221 HTTPInfo::check_marshalled(char *buf, int len)
2222 {
2223   HTTPCacheAlt *alt = reinterpret_cast<HTTPCacheAlt *>(buf);
2224 
2225   if (alt->m_magic != CACHE_ALT_MAGIC_MARSHALED) {
2226     return false;
2227   }
2228 
2229   if (alt->m_writeable != false) {
2230     return false;
2231   }
2232 
2233   if (len < HTTP_ALT_MARSHAL_SIZE) {
2234     return false;
2235   }
2236 
2237   if (alt->m_request_hdr.m_heap == nullptr) {
2238     return false;
2239   }
2240 
2241   if ((intptr_t)alt->m_request_hdr.m_heap > len) {
2242     return false;
2243   }
2244 
2245   HdrHeap *heap = reinterpret_cast<HdrHeap *>(buf + (intptr_t)alt->m_request_hdr.m_heap);
2246   if (heap->check_marshalled(len) == false) {
2247     return false;
2248   }
2249 
2250   if (alt->m_response_hdr.m_heap == nullptr) {
2251     return false;
2252   }
2253 
2254   if ((intptr_t)alt->m_response_hdr.m_heap > len) {
2255     return false;
2256   }
2257 
2258   heap = reinterpret_cast<HdrHeap *>(buf + (intptr_t)alt->m_response_hdr.m_heap);
2259   if (heap->check_marshalled(len) == false) {
2260     return false;
2261   }
2262 
2263   return true;
2264 }
2265 
2266 // void HTTPInfo::set_buffer_reference(RefCountObj* block_ref)
2267 //
2268 //    Setting a buffer reference for the alt is separate from
2269 //     the unmarshalling operation because the clustering
2270 //     utilizes the system differently than cache does
2271 //    The cache maintains external refcounting of the buffer that
2272 //     the alt is in & doesn't always destroy the alt when its
2273 //     done with it because it figures it doesn't need to since
2274 //     it is managing the buffer
2275 //    The receiver of ClusterRPC system has the alt manage the
2276 //     buffer itself and therefore needs to call this function
2277 //     to set up the reference
2278 //
2279 void
set_buffer_reference(RefCountObj * block_ref)2280 HTTPInfo::set_buffer_reference(RefCountObj *block_ref)
2281 {
2282   ink_assert(m_alt->m_magic == CACHE_ALT_MAGIC_ALIVE);
2283 
2284   // Free existing reference
2285   if (m_alt->m_ext_buffer != nullptr) {
2286     if (m_alt->m_ext_buffer->refcount_dec() == 0) {
2287       m_alt->m_ext_buffer->free();
2288     }
2289   }
2290   // Set up the ref count for the external buffer
2291   //   if there is one
2292   if (block_ref) {
2293     block_ref->refcount_inc();
2294   }
2295 
2296   m_alt->m_ext_buffer = block_ref;
2297 }
2298 
2299 int
get_handle(char * buf,int len)2300 HTTPInfo::get_handle(char *buf, int len)
2301 {
2302   // All the offsets have already swizzled to pointers.  All we
2303   //  need to do is set m_alt and make sure things are sane
2304   HTTPCacheAlt *a = reinterpret_cast<HTTPCacheAlt *>(buf);
2305 
2306   if (a->m_magic == CACHE_ALT_MAGIC_ALIVE) {
2307     m_alt = a;
2308     ink_assert(m_alt->m_unmarshal_len > 0);
2309     ink_assert(m_alt->m_unmarshal_len <= len);
2310     return m_alt->m_unmarshal_len;
2311   }
2312 
2313   clear();
2314   return -1;
2315 }
2316 
2317 void
push_frag_offset(FragOffset offset)2318 HTTPInfo::push_frag_offset(FragOffset offset)
2319 {
2320   ink_assert(m_alt);
2321   if (nullptr == m_alt->m_frag_offsets) {
2322     m_alt->m_frag_offsets = m_alt->m_integral_frag_offsets;
2323   } else if (m_alt->m_frag_offset_count >= HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS &&
2324              0 == (m_alt->m_frag_offset_count & (m_alt->m_frag_offset_count - 1))) {
2325     // need more space than in integral storage and we're at an upgrade
2326     // size (power of 2).
2327     FragOffset *nf = static_cast<FragOffset *>(ats_malloc(sizeof(FragOffset) * (m_alt->m_frag_offset_count * 2)));
2328     memcpy(nf, m_alt->m_frag_offsets, sizeof(FragOffset) * m_alt->m_frag_offset_count);
2329     if (m_alt->m_frag_offsets != m_alt->m_integral_frag_offsets) {
2330       ats_free(m_alt->m_frag_offsets);
2331     }
2332     m_alt->m_frag_offsets = nf;
2333   }
2334 
2335   m_alt->m_frag_offsets[m_alt->m_frag_offset_count++] = offset;
2336 }
2337