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