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