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_memory.h"
27 #include "tscore/TsBuffer.h"
28 #include <cassert>
29 #include <cstdio>
30 #include <cstring>
31 #include <cctype>
32 #include <algorithm>
33 #include "MIME.h"
34 #include "HdrHeap.h"
35 #include "HdrToken.h"
36 #include "HdrUtils.h"
37 #include "HttpCompat.h"
38 
39 using ts::TextView;
40 
41 /***********************************************************************
42  *                                                                     *
43  *                    C O M P I L E    O P T I O N S                   *
44  *                                                                     *
45  ***********************************************************************/
46 #define TRACK_FIELD_FIND_CALLS 0
47 #define TRACK_COOKING 0
48 #define MIME_FORMAT_DATE_USE_LOOKUP_TABLE 1
49 
50 /***********************************************************************
51  *                                                                     *
52  *                          C O N S T A N T S                          *
53  *                                                                     *
54  ***********************************************************************/
55 static DFA *day_names_dfa   = nullptr;
56 static DFA *month_names_dfa = nullptr;
57 
58 static const char *day_names[] = {
59   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
60 };
61 
62 static const char *month_names[] = {
63   "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
64 };
65 
66 struct MDY {
67   uint8_t m;
68   uint8_t d;
69   uint16_t y;
70 };
71 
72 static MDY *_days_to_mdy_fast_lookup_table = nullptr;
73 static unsigned int _days_to_mdy_fast_lookup_table_first_day;
74 static unsigned int _days_to_mdy_fast_lookup_table_last_day;
75 
76 /***********************************************************************
77  *                                                                     *
78  *                             G L O B A L S                           *
79  *                                                                     *
80  ***********************************************************************/
81 const char *MIME_FIELD_ACCEPT;
82 const char *MIME_FIELD_ACCEPT_CHARSET;
83 const char *MIME_FIELD_ACCEPT_ENCODING;
84 const char *MIME_FIELD_ACCEPT_LANGUAGE;
85 const char *MIME_FIELD_ACCEPT_RANGES;
86 const char *MIME_FIELD_AGE;
87 const char *MIME_FIELD_ALLOW;
88 const char *MIME_FIELD_APPROVED;
89 const char *MIME_FIELD_AUTHORIZATION;
90 const char *MIME_FIELD_BYTES;
91 const char *MIME_FIELD_CACHE_CONTROL;
92 const char *MIME_FIELD_CLIENT_IP;
93 const char *MIME_FIELD_CONNECTION;
94 const char *MIME_FIELD_CONTENT_BASE;
95 const char *MIME_FIELD_CONTENT_ENCODING;
96 const char *MIME_FIELD_CONTENT_LANGUAGE;
97 const char *MIME_FIELD_CONTENT_LENGTH;
98 const char *MIME_FIELD_CONTENT_LOCATION;
99 const char *MIME_FIELD_CONTENT_MD5;
100 const char *MIME_FIELD_CONTENT_RANGE;
101 const char *MIME_FIELD_CONTENT_TYPE;
102 const char *MIME_FIELD_CONTROL;
103 const char *MIME_FIELD_COOKIE;
104 const char *MIME_FIELD_DATE;
105 const char *MIME_FIELD_DISTRIBUTION;
106 const char *MIME_FIELD_ETAG;
107 const char *MIME_FIELD_EXPECT;
108 const char *MIME_FIELD_EXPIRES;
109 const char *MIME_FIELD_FOLLOWUP_TO;
110 const char *MIME_FIELD_FROM;
111 const char *MIME_FIELD_HOST;
112 const char *MIME_FIELD_IF_MATCH;
113 const char *MIME_FIELD_IF_MODIFIED_SINCE;
114 const char *MIME_FIELD_IF_NONE_MATCH;
115 const char *MIME_FIELD_IF_RANGE;
116 const char *MIME_FIELD_IF_UNMODIFIED_SINCE;
117 const char *MIME_FIELD_KEEP_ALIVE;
118 const char *MIME_FIELD_KEYWORDS;
119 const char *MIME_FIELD_LAST_MODIFIED;
120 const char *MIME_FIELD_LINES;
121 const char *MIME_FIELD_LOCATION;
122 const char *MIME_FIELD_MAX_FORWARDS;
123 const char *MIME_FIELD_MESSAGE_ID;
124 const char *MIME_FIELD_NEWSGROUPS;
125 const char *MIME_FIELD_ORGANIZATION;
126 const char *MIME_FIELD_PATH;
127 const char *MIME_FIELD_PRAGMA;
128 const char *MIME_FIELD_PROXY_AUTHENTICATE;
129 const char *MIME_FIELD_PROXY_AUTHORIZATION;
130 const char *MIME_FIELD_PROXY_CONNECTION;
131 const char *MIME_FIELD_PUBLIC;
132 const char *MIME_FIELD_RANGE;
133 const char *MIME_FIELD_REFERENCES;
134 const char *MIME_FIELD_REFERER;
135 const char *MIME_FIELD_REPLY_TO;
136 const char *MIME_FIELD_RETRY_AFTER;
137 const char *MIME_FIELD_SENDER;
138 const char *MIME_FIELD_SERVER;
139 const char *MIME_FIELD_SET_COOKIE;
140 const char *MIME_FIELD_STRICT_TRANSPORT_SECURITY;
141 const char *MIME_FIELD_SUBJECT;
142 const char *MIME_FIELD_SUMMARY;
143 const char *MIME_FIELD_TE;
144 const char *MIME_FIELD_TRANSFER_ENCODING;
145 const char *MIME_FIELD_UPGRADE;
146 const char *MIME_FIELD_USER_AGENT;
147 const char *MIME_FIELD_VARY;
148 const char *MIME_FIELD_VIA;
149 const char *MIME_FIELD_WARNING;
150 const char *MIME_FIELD_WWW_AUTHENTICATE;
151 const char *MIME_FIELD_XREF;
152 const char *MIME_FIELD_ATS_INTERNAL;
153 const char *MIME_FIELD_X_ID;
154 const char *MIME_FIELD_X_FORWARDED_FOR;
155 const char *MIME_FIELD_FORWARDED;
156 const char *MIME_FIELD_SEC_WEBSOCKET_KEY;
157 const char *MIME_FIELD_SEC_WEBSOCKET_VERSION;
158 const char *MIME_FIELD_HTTP2_SETTINGS;
159 const char *MIME_FIELD_EARLY_DATA;
160 
161 const char *MIME_VALUE_BYTES;
162 const char *MIME_VALUE_CHUNKED;
163 const char *MIME_VALUE_CLOSE;
164 const char *MIME_VALUE_COMPRESS;
165 const char *MIME_VALUE_DEFLATE;
166 const char *MIME_VALUE_GZIP;
167 const char *MIME_VALUE_IDENTITY;
168 const char *MIME_VALUE_KEEP_ALIVE;
169 const char *MIME_VALUE_MAX_AGE;
170 const char *MIME_VALUE_MAX_STALE;
171 const char *MIME_VALUE_MIN_FRESH;
172 const char *MIME_VALUE_MUST_REVALIDATE;
173 const char *MIME_VALUE_NONE;
174 const char *MIME_VALUE_NO_CACHE;
175 const char *MIME_VALUE_NO_STORE;
176 const char *MIME_VALUE_NO_TRANSFORM;
177 const char *MIME_VALUE_ONLY_IF_CACHED;
178 const char *MIME_VALUE_PRIVATE;
179 const char *MIME_VALUE_PROXY_REVALIDATE;
180 const char *MIME_VALUE_PUBLIC;
181 const char *MIME_VALUE_S_MAXAGE;
182 const char *MIME_VALUE_NEED_REVALIDATE_ONCE;
183 const char *MIME_VALUE_WEBSOCKET;
184 const char *MIME_VALUE_H2C;
185 
186 // Cache-control: extension "need-revalidate-once" is used internally by T.S.
187 // to invalidate a document, and it is not returned/forwarded.
188 // If a cached document has this extension set (ie, is invalidated),
189 // then the T.S. needs to revalidate the document once before returning it.
190 // After a successful revalidation, the extension will be removed by T.S.
191 // To set or unset this directive should be done via the following two
192 // function:
193 //      set_cooked_cc_need_revalidate_once()
194 //      unset_cooked_cc_need_revalidate_once()
195 // To test, use regular Cache-control testing functions, eg,
196 //      is_cache_control_set(HTTP_VALUE_NEED_REVALIDATE_ONCE)
197 
198 int MIME_LEN_ACCEPT;
199 int MIME_LEN_ACCEPT_CHARSET;
200 int MIME_LEN_ACCEPT_ENCODING;
201 int MIME_LEN_ACCEPT_LANGUAGE;
202 int MIME_LEN_ACCEPT_RANGES;
203 int MIME_LEN_AGE;
204 int MIME_LEN_ALLOW;
205 int MIME_LEN_APPROVED;
206 int MIME_LEN_AUTHORIZATION;
207 int MIME_LEN_BYTES;
208 int MIME_LEN_CACHE_CONTROL;
209 int MIME_LEN_CLIENT_IP;
210 int MIME_LEN_CONNECTION;
211 int MIME_LEN_CONTENT_BASE;
212 int MIME_LEN_CONTENT_ENCODING;
213 int MIME_LEN_CONTENT_LANGUAGE;
214 int MIME_LEN_CONTENT_LENGTH;
215 int MIME_LEN_CONTENT_LOCATION;
216 int MIME_LEN_CONTENT_MD5;
217 int MIME_LEN_CONTENT_RANGE;
218 int MIME_LEN_CONTENT_TYPE;
219 int MIME_LEN_CONTROL;
220 int MIME_LEN_COOKIE;
221 int MIME_LEN_DATE;
222 int MIME_LEN_DISTRIBUTION;
223 int MIME_LEN_ETAG;
224 int MIME_LEN_EXPECT;
225 int MIME_LEN_EXPIRES;
226 int MIME_LEN_FOLLOWUP_TO;
227 int MIME_LEN_FROM;
228 int MIME_LEN_HOST;
229 int MIME_LEN_IF_MATCH;
230 int MIME_LEN_IF_MODIFIED_SINCE;
231 int MIME_LEN_IF_NONE_MATCH;
232 int MIME_LEN_IF_RANGE;
233 int MIME_LEN_IF_UNMODIFIED_SINCE;
234 int MIME_LEN_KEEP_ALIVE;
235 int MIME_LEN_KEYWORDS;
236 int MIME_LEN_LAST_MODIFIED;
237 int MIME_LEN_LINES;
238 int MIME_LEN_LOCATION;
239 int MIME_LEN_MAX_FORWARDS;
240 int MIME_LEN_MESSAGE_ID;
241 int MIME_LEN_NEWSGROUPS;
242 int MIME_LEN_ORGANIZATION;
243 int MIME_LEN_PATH;
244 int MIME_LEN_PRAGMA;
245 int MIME_LEN_PROXY_AUTHENTICATE;
246 int MIME_LEN_PROXY_AUTHORIZATION;
247 int MIME_LEN_PROXY_CONNECTION;
248 int MIME_LEN_PUBLIC;
249 int MIME_LEN_RANGE;
250 int MIME_LEN_REFERENCES;
251 int MIME_LEN_REFERER;
252 int MIME_LEN_REPLY_TO;
253 int MIME_LEN_RETRY_AFTER;
254 int MIME_LEN_SENDER;
255 int MIME_LEN_SERVER;
256 int MIME_LEN_SET_COOKIE;
257 int MIME_LEN_STRICT_TRANSPORT_SECURITY;
258 int MIME_LEN_SUBJECT;
259 int MIME_LEN_SUMMARY;
260 int MIME_LEN_TE;
261 int MIME_LEN_TRANSFER_ENCODING;
262 int MIME_LEN_UPGRADE;
263 int MIME_LEN_USER_AGENT;
264 int MIME_LEN_VARY;
265 int MIME_LEN_VIA;
266 int MIME_LEN_WARNING;
267 int MIME_LEN_WWW_AUTHENTICATE;
268 int MIME_LEN_XREF;
269 int MIME_LEN_ATS_INTERNAL;
270 int MIME_LEN_X_ID;
271 int MIME_LEN_X_FORWARDED_FOR;
272 int MIME_LEN_FORWARDED;
273 int MIME_LEN_SEC_WEBSOCKET_KEY;
274 int MIME_LEN_SEC_WEBSOCKET_VERSION;
275 int MIME_LEN_HTTP2_SETTINGS;
276 int MIME_LEN_EARLY_DATA;
277 
278 int MIME_WKSIDX_ACCEPT;
279 int MIME_WKSIDX_ACCEPT_CHARSET;
280 int MIME_WKSIDX_ACCEPT_ENCODING;
281 int MIME_WKSIDX_ACCEPT_LANGUAGE;
282 int MIME_WKSIDX_ACCEPT_RANGES;
283 int MIME_WKSIDX_AGE;
284 int MIME_WKSIDX_ALLOW;
285 int MIME_WKSIDX_APPROVED;
286 int MIME_WKSIDX_AUTHORIZATION;
287 int MIME_WKSIDX_BYTES;
288 int MIME_WKSIDX_CACHE_CONTROL;
289 int MIME_WKSIDX_CLIENT_IP;
290 int MIME_WKSIDX_CONNECTION;
291 int MIME_WKSIDX_CONTENT_BASE;
292 int MIME_WKSIDX_CONTENT_ENCODING;
293 int MIME_WKSIDX_CONTENT_LANGUAGE;
294 int MIME_WKSIDX_CONTENT_LENGTH;
295 int MIME_WKSIDX_CONTENT_LOCATION;
296 int MIME_WKSIDX_CONTENT_MD5;
297 int MIME_WKSIDX_CONTENT_RANGE;
298 int MIME_WKSIDX_CONTENT_TYPE;
299 int MIME_WKSIDX_CONTROL;
300 int MIME_WKSIDX_COOKIE;
301 int MIME_WKSIDX_DATE;
302 int MIME_WKSIDX_DISTRIBUTION;
303 int MIME_WKSIDX_ETAG;
304 int MIME_WKSIDX_EXPECT;
305 int MIME_WKSIDX_EXPIRES;
306 int MIME_WKSIDX_FOLLOWUP_TO;
307 int MIME_WKSIDX_FROM;
308 int MIME_WKSIDX_HOST;
309 int MIME_WKSIDX_IF_MATCH;
310 int MIME_WKSIDX_IF_MODIFIED_SINCE;
311 int MIME_WKSIDX_IF_NONE_MATCH;
312 int MIME_WKSIDX_IF_RANGE;
313 int MIME_WKSIDX_IF_UNMODIFIED_SINCE;
314 int MIME_WKSIDX_KEEP_ALIVE;
315 int MIME_WKSIDX_KEYWORDS;
316 int MIME_WKSIDX_LAST_MODIFIED;
317 int MIME_WKSIDX_LINES;
318 int MIME_WKSIDX_LOCATION;
319 int MIME_WKSIDX_MAX_FORWARDS;
320 int MIME_WKSIDX_MESSAGE_ID;
321 int MIME_WKSIDX_NEWSGROUPS;
322 int MIME_WKSIDX_ORGANIZATION;
323 int MIME_WKSIDX_PATH;
324 int MIME_WKSIDX_PRAGMA;
325 int MIME_WKSIDX_PROXY_AUTHENTICATE;
326 int MIME_WKSIDX_PROXY_AUTHORIZATION;
327 int MIME_WKSIDX_PROXY_CONNECTION;
328 int MIME_WKSIDX_PUBLIC;
329 int MIME_WKSIDX_RANGE;
330 int MIME_WKSIDX_REFERENCES;
331 int MIME_WKSIDX_REFERER;
332 int MIME_WKSIDX_REPLY_TO;
333 int MIME_WKSIDX_RETRY_AFTER;
334 int MIME_WKSIDX_SENDER;
335 int MIME_WKSIDX_SERVER;
336 int MIME_WKSIDX_SET_COOKIE;
337 int MIME_WKSIDX_STRICT_TRANSPORT_SECURITY;
338 int MIME_WKSIDX_SUBJECT;
339 int MIME_WKSIDX_SUMMARY;
340 int MIME_WKSIDX_TE;
341 int MIME_WKSIDX_TRANSFER_ENCODING;
342 int MIME_WKSIDX_UPGRADE;
343 int MIME_WKSIDX_USER_AGENT;
344 int MIME_WKSIDX_VARY;
345 int MIME_WKSIDX_VIA;
346 int MIME_WKSIDX_WARNING;
347 int MIME_WKSIDX_WWW_AUTHENTICATE;
348 int MIME_WKSIDX_XREF;
349 int MIME_WKSIDX_ATS_INTERNAL;
350 int MIME_WKSIDX_X_ID;
351 int MIME_WKSIDX_X_FORWARDED_FOR;
352 int MIME_WKSIDX_FORWARDED;
353 int MIME_WKSIDX_SEC_WEBSOCKET_KEY;
354 int MIME_WKSIDX_SEC_WEBSOCKET_VERSION;
355 int MIME_WKSIDX_HTTP2_SETTINGS;
356 int MIME_WKSIDX_EARLY_DATA;
357 
358 /***********************************************************************
359  *                                                                     *
360  *                 U T I L I T Y    R O U T I N E S                    *
361  *                                                                     *
362  ***********************************************************************/
363 inline static int
is_digit(char c)364 is_digit(char c)
365 {
366   return ((c <= '9') && (c >= '0'));
367 }
368 
369 inline static int
is_ws(char c)370 is_ws(char c)
371 {
372   return ((c == ParseRules::CHAR_SP) || (c == ParseRules::CHAR_HT));
373 }
374 
375 /***********************************************************************
376  *                                                                     *
377  *                    P R E S E N C E    B I T S                       *
378  *                                                                     *
379  ***********************************************************************/
380 uint64_t
mime_field_presence_mask(const char * well_known_str)381 mime_field_presence_mask(const char *well_known_str)
382 {
383   return hdrtoken_wks_to_mask(well_known_str);
384 }
385 
386 uint64_t
mime_field_presence_mask(int well_known_str_index)387 mime_field_presence_mask(int well_known_str_index)
388 {
389   return hdrtoken_index_to_mask(well_known_str_index);
390 }
391 
392 int
mime_field_presence_get(MIMEHdrImpl * h,const char * well_known_str)393 mime_field_presence_get(MIMEHdrImpl *h, const char *well_known_str)
394 {
395   uint64_t mask = mime_field_presence_mask(well_known_str);
396   return ((mask == 0) ? 1 : ((h->m_presence_bits & mask) == 0 ? 0 : 1));
397 }
398 
399 int
mime_field_presence_get(MIMEHdrImpl * h,int well_known_str_index)400 mime_field_presence_get(MIMEHdrImpl *h, int well_known_str_index)
401 {
402   const char *wks = hdrtoken_index_to_wks(well_known_str_index);
403   return mime_field_presence_get(h, wks);
404 }
405 
406 void
mime_hdr_presence_set(MIMEHdrImpl * h,const char * well_known_str)407 mime_hdr_presence_set(MIMEHdrImpl *h, const char *well_known_str)
408 {
409   uint64_t mask = mime_field_presence_mask(well_known_str);
410   if (mask != 0) {
411     h->m_presence_bits |= mask;
412   }
413 }
414 
415 void
mime_hdr_presence_set(MIMEHdrImpl * h,int well_known_str_index)416 mime_hdr_presence_set(MIMEHdrImpl *h, int well_known_str_index)
417 {
418   const char *wks = hdrtoken_index_to_wks(well_known_str_index);
419   mime_hdr_presence_set(h, wks);
420 }
421 
422 void
mime_hdr_presence_unset(MIMEHdrImpl * h,const char * well_known_str)423 mime_hdr_presence_unset(MIMEHdrImpl *h, const char *well_known_str)
424 {
425   uint64_t mask = mime_field_presence_mask(well_known_str);
426   if (mask != 0) {
427     h->m_presence_bits &= (~mask);
428   }
429 }
430 
431 void
mime_hdr_presence_unset(MIMEHdrImpl * h,int well_known_str_index)432 mime_hdr_presence_unset(MIMEHdrImpl *h, int well_known_str_index)
433 {
434   const char *wks = hdrtoken_index_to_wks(well_known_str_index);
435   mime_hdr_presence_unset(h, wks);
436 }
437 
438 /***********************************************************************
439  *                                                                     *
440  *                  S L O T    A C C E L E R A T O R S                 *
441  *                                                                     *
442  ***********************************************************************/
443 inline void
mime_hdr_init_accelerators_and_presence_bits(MIMEHdrImpl * mh)444 mime_hdr_init_accelerators_and_presence_bits(MIMEHdrImpl *mh)
445 {
446   mh->m_presence_bits        = 0;
447   mh->m_slot_accelerators[0] = 0xFFFFFFFF;
448   mh->m_slot_accelerators[1] = 0xFFFFFFFF;
449   mh->m_slot_accelerators[2] = 0xFFFFFFFF;
450   mh->m_slot_accelerators[3] = 0xFFFFFFFF;
451 }
452 
453 inline uint32_t
mime_hdr_get_accelerator_slotnum(MIMEHdrImpl * mh,int32_t slot_id)454 mime_hdr_get_accelerator_slotnum(MIMEHdrImpl *mh, int32_t slot_id)
455 {
456   ink_assert((slot_id != MIME_SLOTID_NONE) && (slot_id < 32));
457 
458   uint32_t word_index = slot_id / 8;                         // 4 words of 8 slots
459   uint32_t word       = mh->m_slot_accelerators[word_index]; // 8 slots of 4 bits each
460   uint32_t nybble     = slot_id % 8;                         // which of the 8 nybbles?
461   uint32_t slot       = ((word >> (nybble * 4)) & 15);       // grab the 4 bit slotnum
462   return slot;
463 }
464 
465 inline void
mime_hdr_set_accelerator_slotnum(MIMEHdrImpl * mh,int32_t slot_id,uint32_t slot_num)466 mime_hdr_set_accelerator_slotnum(MIMEHdrImpl *mh, int32_t slot_id, uint32_t slot_num)
467 {
468   ink_assert((slot_id != MIME_SLOTID_NONE) && (slot_id < 32));
469   ink_assert(slot_num < 16);
470 
471   uint32_t word_index = slot_id / 8;                         // 4 words of 8 slots
472   uint32_t word       = mh->m_slot_accelerators[word_index]; // 8 slots of 4 bits each
473   uint32_t nybble     = slot_id % 8;                         // which of the 8 nybbles?
474   uint32_t shift      = nybble * 4;                          // shift in chunks of 4 bits
475   uint32_t mask       = ~(MIME_FIELD_SLOTNUM_MASK << shift); // mask to zero out old slot
476   uint32_t graft      = (slot_num << shift);                 // plug to insert into slot
477   uint32_t new_word   = (word & mask) | graft;               // new value
478 
479   mh->m_slot_accelerators[word_index] = new_word;
480 }
481 
482 inline void
mime_hdr_set_accelerators_and_presence_bits(MIMEHdrImpl * mh,MIMEField * field)483 mime_hdr_set_accelerators_and_presence_bits(MIMEHdrImpl *mh, MIMEField *field)
484 {
485   int slot_id;
486   ptrdiff_t slot_num;
487   if (field->m_wks_idx < 0) {
488     return;
489   }
490 
491   ink_assert(mh);
492 
493   mime_hdr_presence_set(mh, field->m_wks_idx);
494 
495   slot_id = hdrtoken_index_to_slotid(field->m_wks_idx);
496   if (slot_id != MIME_SLOTID_NONE) {
497     if (mh->m_first_fblock.contains(field)) {
498       slot_num = (field - &(mh->m_first_fblock.m_field_slots[0]));
499       // constains() assure that the field is in the block, and the calculated
500       // slot_num will be between 0 and 15, which seem valid.
501       // However, strangely, this function regards slot number 14 and 15 as
502       // unknown for some reason that is not clear. It might be a bug.
503       // The block below is left to keep the original behavior. See also TS-4316.
504       if (slot_num >= MIME_FIELD_SLOTNUM_UNKNOWN) {
505         slot_num = MIME_FIELD_SLOTNUM_UNKNOWN;
506       }
507     } else {
508       slot_num = MIME_FIELD_SLOTNUM_UNKNOWN;
509     }
510     mime_hdr_set_accelerator_slotnum(mh, slot_id, slot_num);
511   }
512 }
513 
514 inline void
mime_hdr_unset_accelerators_and_presence_bits(MIMEHdrImpl * mh,MIMEField * field)515 mime_hdr_unset_accelerators_and_presence_bits(MIMEHdrImpl *mh, MIMEField *field)
516 {
517   int slot_id;
518   if (field->m_wks_idx < 0) {
519     return;
520   }
521 
522   mime_hdr_presence_unset(mh, field->m_wks_idx);
523 
524   slot_id = hdrtoken_index_to_slotid(field->m_wks_idx);
525   if (slot_id != MIME_SLOTID_NONE) {
526     mime_hdr_set_accelerator_slotnum(mh, slot_id, MIME_FIELD_SLOTNUM_MAX);
527   }
528 }
529 
530 /// Reset data in the header.
531 /// Clear all the presence bits and accelerators.
532 /// Update all the m_wks_idx values, presence bits and accelerators.
533 inline void
mime_hdr_reset_accelerators_and_presence_bits(MIMEHdrImpl * mh)534 mime_hdr_reset_accelerators_and_presence_bits(MIMEHdrImpl *mh)
535 {
536   mime_hdr_init_accelerators_and_presence_bits(mh);
537 
538   for (MIMEFieldBlockImpl *fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
539     for (MIMEField *field = fblock->m_field_slots, *limit = field + fblock->m_freetop; field < limit; ++field) {
540       if (field->is_live()) {
541         field->m_wks_idx = hdrtoken_tokenize(field->m_ptr_name, field->m_len_name);
542         if (field->is_dup_head()) {
543           mime_hdr_set_accelerators_and_presence_bits(mh, field);
544         }
545       }
546     }
547   }
548 }
549 
550 int
checksum_block(const char * s,int len)551 checksum_block(const char *s, int len)
552 {
553   int sum = 0;
554   while (len--) {
555     sum ^= *s++;
556   }
557   return sum;
558 }
559 
560 #ifdef ENABLE_MIME_SANITY_CHECK
561 void
mime_hdr_sanity_check(MIMEHdrImpl * mh)562 mime_hdr_sanity_check(MIMEHdrImpl *mh)
563 {
564   MIMEFieldBlockImpl *fblock, *blk, *last_fblock;
565   MIMEField *field, *next_dup;
566   uint32_t slot_index, index;
567   uint64_t masksum;
568 
569   ink_assert(mh != nullptr);
570 
571   masksum     = 0;
572   slot_index  = 0;
573   last_fblock = nullptr;
574 
575   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
576     for (index = 0; index < fblock->m_freetop; index++) {
577       field = &(fblock->m_field_slots[index]);
578 
579       if (field->is_live()) {
580         // dummy operations just to make sure deref doesn't crash
581         checksum_block(field->m_ptr_name, field->m_len_name);
582         if (field->m_ptr_value) {
583           checksum_block(field->m_ptr_value, field->m_len_value);
584         }
585 
586         if (field->m_n_v_raw_printable) {
587           int total_len = field->m_len_name + field->m_len_value + field->m_n_v_raw_printable_pad;
588           checksum_block(field->m_ptr_name, total_len);
589         }
590         // walk the dup list, quickly checking each cell
591         if (field->m_next_dup != nullptr) {
592           int field_slotnum = mime_hdr_field_slotnum(mh, field);
593 
594           for (next_dup = field->m_next_dup; next_dup; next_dup = next_dup->m_next_dup) {
595             int next_slotnum = mime_hdr_field_slotnum(mh, next_dup);
596             ink_release_assert((next_dup->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD) == 0);
597             ink_release_assert((next_dup->m_readiness == MIME_FIELD_SLOT_READINESS_LIVE));
598             ink_release_assert(next_dup->m_wks_idx == field->m_wks_idx);
599             ink_release_assert(next_dup->m_len_name == field->m_len_name);
600             ink_release_assert(strncasecmp(field->m_ptr_name, next_dup->m_ptr_name, field->m_len_name) == 0);
601             ink_release_assert(next_slotnum > field_slotnum);
602           }
603         }
604         // if this is a well known string, check presence bits & slot accelerators
605         if (field->m_wks_idx >= 0) {
606           const char *wks = hdrtoken_index_to_wks(field->m_wks_idx);
607           int len         = hdrtoken_index_to_length(field->m_wks_idx);
608 
609           if (field->m_len_name != len || strncasecmp(field->m_ptr_name, wks, field->m_len_name) != 0) {
610             Warning("Encountered WKS hash collision on '%.*s'", field->m_len_name, field->m_ptr_name);
611           }
612 
613           uint64_t mask = mime_field_presence_mask(field->m_wks_idx);
614           masksum |= mask;
615 
616           int32_t slot_id = hdrtoken_index_to_slotid(field->m_wks_idx);
617           if ((slot_id != MIME_SLOTID_NONE) && (slot_index < MIME_FIELD_SLOTNUM_UNKNOWN) &&
618               (field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD)) {
619             uint32_t slot_num = mime_hdr_get_accelerator_slotnum(mh, slot_id);
620             if (slot_num <= 14) {
621               ink_release_assert(slot_num == slot_index);
622             }
623           }
624         } else {
625           int idx = hdrtoken_tokenize(field->m_ptr_name, field->m_len_name, nullptr);
626           ink_release_assert(idx < 0);
627         }
628 
629         // verify that the next dup pointer points to a block in this list
630         if (field->m_next_dup) {
631           bool found = false;
632           for (blk = &(mh->m_first_fblock); blk != nullptr; blk = blk->m_next) {
633             const char *addr = reinterpret_cast<const char *>(field->m_next_dup);
634             if ((addr >= reinterpret_cast<const char *>(blk)) &&
635                 (addr < reinterpret_cast<const char *>(blk) + sizeof(MIMEFieldBlockImpl))) {
636               found = true;
637               break;
638             }
639           }
640           ink_release_assert(found);
641         }
642         // re-find the field --- should always find the head dup
643         MIMEField *mf = mime_hdr_field_find(mh, field->m_ptr_name, field->m_len_name);
644         ink_release_assert(mf != nullptr);
645         if (mf == field) {
646           ink_release_assert((field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD) != 0);
647         } else {
648           ink_release_assert((field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD) == 0);
649         }
650       }
651 
652       ++slot_index;
653     }
654     last_fblock = fblock;
655   }
656 
657   ink_release_assert(last_fblock == mh->m_fblock_list_tail);
658   ink_release_assert(masksum == mh->m_presence_bits);
659 }
660 #endif
661 
662 void
mime_init()663 mime_init()
664 {
665   static int init = 1;
666 
667   if (init) {
668     init = 0;
669 
670     hdrtoken_init();
671     day_names_dfa = new DFA;
672     day_names_dfa->compile(day_names, SIZEOF(day_names), RE_CASE_INSENSITIVE);
673 
674     month_names_dfa = new DFA;
675     month_names_dfa->compile(month_names, SIZEOF(month_names), RE_CASE_INSENSITIVE);
676 
677     MIME_FIELD_ACCEPT                    = hdrtoken_string_to_wks("Accept");
678     MIME_FIELD_ACCEPT_CHARSET            = hdrtoken_string_to_wks("Accept-Charset");
679     MIME_FIELD_ACCEPT_ENCODING           = hdrtoken_string_to_wks("Accept-Encoding");
680     MIME_FIELD_ACCEPT_LANGUAGE           = hdrtoken_string_to_wks("Accept-Language");
681     MIME_FIELD_ACCEPT_RANGES             = hdrtoken_string_to_wks("Accept-Ranges");
682     MIME_FIELD_AGE                       = hdrtoken_string_to_wks("Age");
683     MIME_FIELD_ALLOW                     = hdrtoken_string_to_wks("Allow");
684     MIME_FIELD_APPROVED                  = hdrtoken_string_to_wks("Approved");
685     MIME_FIELD_AUTHORIZATION             = hdrtoken_string_to_wks("Authorization");
686     MIME_FIELD_BYTES                     = hdrtoken_string_to_wks("Bytes");
687     MIME_FIELD_CACHE_CONTROL             = hdrtoken_string_to_wks("Cache-Control");
688     MIME_FIELD_CLIENT_IP                 = hdrtoken_string_to_wks("Client-ip");
689     MIME_FIELD_CONNECTION                = hdrtoken_string_to_wks("Connection");
690     MIME_FIELD_CONTENT_BASE              = hdrtoken_string_to_wks("Content-Base");
691     MIME_FIELD_CONTENT_ENCODING          = hdrtoken_string_to_wks("Content-Encoding");
692     MIME_FIELD_CONTENT_LANGUAGE          = hdrtoken_string_to_wks("Content-Language");
693     MIME_FIELD_CONTENT_LENGTH            = hdrtoken_string_to_wks("Content-Length");
694     MIME_FIELD_CONTENT_LOCATION          = hdrtoken_string_to_wks("Content-Location");
695     MIME_FIELD_CONTENT_MD5               = hdrtoken_string_to_wks("Content-MD5");
696     MIME_FIELD_CONTENT_RANGE             = hdrtoken_string_to_wks("Content-Range");
697     MIME_FIELD_CONTENT_TYPE              = hdrtoken_string_to_wks("Content-Type");
698     MIME_FIELD_CONTROL                   = hdrtoken_string_to_wks("Control");
699     MIME_FIELD_COOKIE                    = hdrtoken_string_to_wks("Cookie");
700     MIME_FIELD_DATE                      = hdrtoken_string_to_wks("Date");
701     MIME_FIELD_DISTRIBUTION              = hdrtoken_string_to_wks("Distribution");
702     MIME_FIELD_ETAG                      = hdrtoken_string_to_wks("Etag");
703     MIME_FIELD_EXPECT                    = hdrtoken_string_to_wks("Expect");
704     MIME_FIELD_EXPIRES                   = hdrtoken_string_to_wks("Expires");
705     MIME_FIELD_FOLLOWUP_TO               = hdrtoken_string_to_wks("Followup-To");
706     MIME_FIELD_FROM                      = hdrtoken_string_to_wks("From");
707     MIME_FIELD_HOST                      = hdrtoken_string_to_wks("Host");
708     MIME_FIELD_IF_MATCH                  = hdrtoken_string_to_wks("If-Match");
709     MIME_FIELD_IF_MODIFIED_SINCE         = hdrtoken_string_to_wks("If-Modified-Since");
710     MIME_FIELD_IF_NONE_MATCH             = hdrtoken_string_to_wks("If-None-Match");
711     MIME_FIELD_IF_RANGE                  = hdrtoken_string_to_wks("If-Range");
712     MIME_FIELD_IF_UNMODIFIED_SINCE       = hdrtoken_string_to_wks("If-Unmodified-Since");
713     MIME_FIELD_KEEP_ALIVE                = hdrtoken_string_to_wks("Keep-Alive");
714     MIME_FIELD_KEYWORDS                  = hdrtoken_string_to_wks("Keywords");
715     MIME_FIELD_LAST_MODIFIED             = hdrtoken_string_to_wks("Last-Modified");
716     MIME_FIELD_LINES                     = hdrtoken_string_to_wks("Lines");
717     MIME_FIELD_LOCATION                  = hdrtoken_string_to_wks("Location");
718     MIME_FIELD_MAX_FORWARDS              = hdrtoken_string_to_wks("Max-Forwards");
719     MIME_FIELD_MESSAGE_ID                = hdrtoken_string_to_wks("Message-ID");
720     MIME_FIELD_NEWSGROUPS                = hdrtoken_string_to_wks("Newsgroups");
721     MIME_FIELD_ORGANIZATION              = hdrtoken_string_to_wks("Organization");
722     MIME_FIELD_PATH                      = hdrtoken_string_to_wks("Path");
723     MIME_FIELD_PRAGMA                    = hdrtoken_string_to_wks("Pragma");
724     MIME_FIELD_PROXY_AUTHENTICATE        = hdrtoken_string_to_wks("Proxy-Authenticate");
725     MIME_FIELD_PROXY_AUTHORIZATION       = hdrtoken_string_to_wks("Proxy-Authorization");
726     MIME_FIELD_PROXY_CONNECTION          = hdrtoken_string_to_wks("Proxy-Connection");
727     MIME_FIELD_PUBLIC                    = hdrtoken_string_to_wks("Public");
728     MIME_FIELD_RANGE                     = hdrtoken_string_to_wks("Range");
729     MIME_FIELD_REFERENCES                = hdrtoken_string_to_wks("References");
730     MIME_FIELD_REFERER                   = hdrtoken_string_to_wks("Referer");
731     MIME_FIELD_REPLY_TO                  = hdrtoken_string_to_wks("Reply-To");
732     MIME_FIELD_RETRY_AFTER               = hdrtoken_string_to_wks("Retry-After");
733     MIME_FIELD_SENDER                    = hdrtoken_string_to_wks("Sender");
734     MIME_FIELD_SERVER                    = hdrtoken_string_to_wks("Server");
735     MIME_FIELD_SET_COOKIE                = hdrtoken_string_to_wks("Set-Cookie");
736     MIME_FIELD_STRICT_TRANSPORT_SECURITY = hdrtoken_string_to_wks("Strict-Transport-Security");
737     MIME_FIELD_SUBJECT                   = hdrtoken_string_to_wks("Subject");
738     MIME_FIELD_SUMMARY                   = hdrtoken_string_to_wks("Summary");
739     MIME_FIELD_TE                        = hdrtoken_string_to_wks("TE");
740     MIME_FIELD_TRANSFER_ENCODING         = hdrtoken_string_to_wks("Transfer-Encoding");
741     MIME_FIELD_UPGRADE                   = hdrtoken_string_to_wks("Upgrade");
742     MIME_FIELD_USER_AGENT                = hdrtoken_string_to_wks("User-Agent");
743     MIME_FIELD_VARY                      = hdrtoken_string_to_wks("Vary");
744     MIME_FIELD_VIA                       = hdrtoken_string_to_wks("Via");
745     MIME_FIELD_WARNING                   = hdrtoken_string_to_wks("Warning");
746     MIME_FIELD_WWW_AUTHENTICATE          = hdrtoken_string_to_wks("Www-Authenticate");
747     MIME_FIELD_XREF                      = hdrtoken_string_to_wks("Xref");
748     MIME_FIELD_ATS_INTERNAL              = hdrtoken_string_to_wks("@Ats-Internal");
749     MIME_FIELD_X_ID                      = hdrtoken_string_to_wks("X-ID");
750     MIME_FIELD_X_FORWARDED_FOR           = hdrtoken_string_to_wks("X-Forwarded-For");
751     MIME_FIELD_FORWARDED                 = hdrtoken_string_to_wks("Forwarded");
752     MIME_FIELD_SEC_WEBSOCKET_KEY         = hdrtoken_string_to_wks("Sec-WebSocket-Key");
753     MIME_FIELD_SEC_WEBSOCKET_VERSION     = hdrtoken_string_to_wks("Sec-WebSocket-Version");
754     MIME_FIELD_HTTP2_SETTINGS            = hdrtoken_string_to_wks("HTTP2-Settings");
755     MIME_FIELD_EARLY_DATA                = hdrtoken_string_to_wks("Early-Data");
756 
757     MIME_LEN_ACCEPT                    = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT);
758     MIME_LEN_ACCEPT_CHARSET            = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_CHARSET);
759     MIME_LEN_ACCEPT_ENCODING           = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_ENCODING);
760     MIME_LEN_ACCEPT_LANGUAGE           = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_LANGUAGE);
761     MIME_LEN_ACCEPT_RANGES             = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_RANGES);
762     MIME_LEN_AGE                       = hdrtoken_wks_to_length(MIME_FIELD_AGE);
763     MIME_LEN_ALLOW                     = hdrtoken_wks_to_length(MIME_FIELD_ALLOW);
764     MIME_LEN_APPROVED                  = hdrtoken_wks_to_length(MIME_FIELD_APPROVED);
765     MIME_LEN_AUTHORIZATION             = hdrtoken_wks_to_length(MIME_FIELD_AUTHORIZATION);
766     MIME_LEN_BYTES                     = hdrtoken_wks_to_length(MIME_FIELD_BYTES);
767     MIME_LEN_CACHE_CONTROL             = hdrtoken_wks_to_length(MIME_FIELD_CACHE_CONTROL);
768     MIME_LEN_CLIENT_IP                 = hdrtoken_wks_to_length(MIME_FIELD_CLIENT_IP);
769     MIME_LEN_CONNECTION                = hdrtoken_wks_to_length(MIME_FIELD_CONNECTION);
770     MIME_LEN_CONTENT_BASE              = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_BASE);
771     MIME_LEN_CONTENT_ENCODING          = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_ENCODING);
772     MIME_LEN_CONTENT_LANGUAGE          = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_LANGUAGE);
773     MIME_LEN_CONTENT_LENGTH            = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_LENGTH);
774     MIME_LEN_CONTENT_LOCATION          = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_LOCATION);
775     MIME_LEN_CONTENT_MD5               = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_MD5);
776     MIME_LEN_CONTENT_RANGE             = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_RANGE);
777     MIME_LEN_CONTENT_TYPE              = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_TYPE);
778     MIME_LEN_CONTROL                   = hdrtoken_wks_to_length(MIME_FIELD_CONTROL);
779     MIME_LEN_COOKIE                    = hdrtoken_wks_to_length(MIME_FIELD_COOKIE);
780     MIME_LEN_DATE                      = hdrtoken_wks_to_length(MIME_FIELD_DATE);
781     MIME_LEN_DISTRIBUTION              = hdrtoken_wks_to_length(MIME_FIELD_DISTRIBUTION);
782     MIME_LEN_ETAG                      = hdrtoken_wks_to_length(MIME_FIELD_ETAG);
783     MIME_LEN_EXPECT                    = hdrtoken_wks_to_length(MIME_FIELD_EXPECT);
784     MIME_LEN_EXPIRES                   = hdrtoken_wks_to_length(MIME_FIELD_EXPIRES);
785     MIME_LEN_FOLLOWUP_TO               = hdrtoken_wks_to_length(MIME_FIELD_FOLLOWUP_TO);
786     MIME_LEN_FROM                      = hdrtoken_wks_to_length(MIME_FIELD_FROM);
787     MIME_LEN_HOST                      = hdrtoken_wks_to_length(MIME_FIELD_HOST);
788     MIME_LEN_IF_MATCH                  = hdrtoken_wks_to_length(MIME_FIELD_IF_MATCH);
789     MIME_LEN_IF_MODIFIED_SINCE         = hdrtoken_wks_to_length(MIME_FIELD_IF_MODIFIED_SINCE);
790     MIME_LEN_IF_NONE_MATCH             = hdrtoken_wks_to_length(MIME_FIELD_IF_NONE_MATCH);
791     MIME_LEN_IF_RANGE                  = hdrtoken_wks_to_length(MIME_FIELD_IF_RANGE);
792     MIME_LEN_IF_UNMODIFIED_SINCE       = hdrtoken_wks_to_length(MIME_FIELD_IF_UNMODIFIED_SINCE);
793     MIME_LEN_KEEP_ALIVE                = hdrtoken_wks_to_length(MIME_FIELD_KEEP_ALIVE);
794     MIME_LEN_KEYWORDS                  = hdrtoken_wks_to_length(MIME_FIELD_KEYWORDS);
795     MIME_LEN_LAST_MODIFIED             = hdrtoken_wks_to_length(MIME_FIELD_LAST_MODIFIED);
796     MIME_LEN_LINES                     = hdrtoken_wks_to_length(MIME_FIELD_LINES);
797     MIME_LEN_LOCATION                  = hdrtoken_wks_to_length(MIME_FIELD_LOCATION);
798     MIME_LEN_MAX_FORWARDS              = hdrtoken_wks_to_length(MIME_FIELD_MAX_FORWARDS);
799     MIME_LEN_MESSAGE_ID                = hdrtoken_wks_to_length(MIME_FIELD_MESSAGE_ID);
800     MIME_LEN_NEWSGROUPS                = hdrtoken_wks_to_length(MIME_FIELD_NEWSGROUPS);
801     MIME_LEN_ORGANIZATION              = hdrtoken_wks_to_length(MIME_FIELD_ORGANIZATION);
802     MIME_LEN_PATH                      = hdrtoken_wks_to_length(MIME_FIELD_PATH);
803     MIME_LEN_PRAGMA                    = hdrtoken_wks_to_length(MIME_FIELD_PRAGMA);
804     MIME_LEN_PROXY_AUTHENTICATE        = hdrtoken_wks_to_length(MIME_FIELD_PROXY_AUTHENTICATE);
805     MIME_LEN_PROXY_AUTHORIZATION       = hdrtoken_wks_to_length(MIME_FIELD_PROXY_AUTHORIZATION);
806     MIME_LEN_PROXY_CONNECTION          = hdrtoken_wks_to_length(MIME_FIELD_PROXY_CONNECTION);
807     MIME_LEN_PUBLIC                    = hdrtoken_wks_to_length(MIME_FIELD_PUBLIC);
808     MIME_LEN_RANGE                     = hdrtoken_wks_to_length(MIME_FIELD_RANGE);
809     MIME_LEN_REFERENCES                = hdrtoken_wks_to_length(MIME_FIELD_REFERENCES);
810     MIME_LEN_REFERER                   = hdrtoken_wks_to_length(MIME_FIELD_REFERER);
811     MIME_LEN_REPLY_TO                  = hdrtoken_wks_to_length(MIME_FIELD_REPLY_TO);
812     MIME_LEN_RETRY_AFTER               = hdrtoken_wks_to_length(MIME_FIELD_RETRY_AFTER);
813     MIME_LEN_SENDER                    = hdrtoken_wks_to_length(MIME_FIELD_SENDER);
814     MIME_LEN_SERVER                    = hdrtoken_wks_to_length(MIME_FIELD_SERVER);
815     MIME_LEN_SET_COOKIE                = hdrtoken_wks_to_length(MIME_FIELD_SET_COOKIE);
816     MIME_LEN_STRICT_TRANSPORT_SECURITY = hdrtoken_wks_to_length(MIME_FIELD_STRICT_TRANSPORT_SECURITY);
817     MIME_LEN_SUBJECT                   = hdrtoken_wks_to_length(MIME_FIELD_SUBJECT);
818     MIME_LEN_SUMMARY                   = hdrtoken_wks_to_length(MIME_FIELD_SUMMARY);
819     MIME_LEN_TE                        = hdrtoken_wks_to_length(MIME_FIELD_TE);
820     MIME_LEN_TRANSFER_ENCODING         = hdrtoken_wks_to_length(MIME_FIELD_TRANSFER_ENCODING);
821     MIME_LEN_UPGRADE                   = hdrtoken_wks_to_length(MIME_FIELD_UPGRADE);
822     MIME_LEN_USER_AGENT                = hdrtoken_wks_to_length(MIME_FIELD_USER_AGENT);
823     MIME_LEN_VARY                      = hdrtoken_wks_to_length(MIME_FIELD_VARY);
824     MIME_LEN_VIA                       = hdrtoken_wks_to_length(MIME_FIELD_VIA);
825     MIME_LEN_WARNING                   = hdrtoken_wks_to_length(MIME_FIELD_WARNING);
826     MIME_LEN_WWW_AUTHENTICATE          = hdrtoken_wks_to_length(MIME_FIELD_WWW_AUTHENTICATE);
827     MIME_LEN_XREF                      = hdrtoken_wks_to_length(MIME_FIELD_XREF);
828     MIME_LEN_ATS_INTERNAL              = hdrtoken_wks_to_length(MIME_FIELD_ATS_INTERNAL);
829     MIME_LEN_X_ID                      = hdrtoken_wks_to_length(MIME_FIELD_X_ID);
830     MIME_LEN_X_FORWARDED_FOR           = hdrtoken_wks_to_length(MIME_FIELD_X_FORWARDED_FOR);
831     MIME_LEN_FORWARDED                 = hdrtoken_wks_to_length(MIME_FIELD_FORWARDED);
832     MIME_LEN_SEC_WEBSOCKET_KEY         = hdrtoken_wks_to_length(MIME_FIELD_SEC_WEBSOCKET_KEY);
833     MIME_LEN_SEC_WEBSOCKET_VERSION     = hdrtoken_wks_to_length(MIME_FIELD_SEC_WEBSOCKET_VERSION);
834     MIME_LEN_HTTP2_SETTINGS            = hdrtoken_wks_to_length(MIME_FIELD_HTTP2_SETTINGS);
835     MIME_LEN_EARLY_DATA                = hdrtoken_wks_to_length(MIME_FIELD_EARLY_DATA);
836 
837     MIME_WKSIDX_ACCEPT                    = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT);
838     MIME_WKSIDX_ACCEPT_CHARSET            = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_CHARSET);
839     MIME_WKSIDX_ACCEPT_ENCODING           = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_ENCODING);
840     MIME_WKSIDX_ACCEPT_LANGUAGE           = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_LANGUAGE);
841     MIME_WKSIDX_ACCEPT_RANGES             = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_RANGES);
842     MIME_WKSIDX_AGE                       = hdrtoken_wks_to_index(MIME_FIELD_AGE);
843     MIME_WKSIDX_ALLOW                     = hdrtoken_wks_to_index(MIME_FIELD_ALLOW);
844     MIME_WKSIDX_APPROVED                  = hdrtoken_wks_to_index(MIME_FIELD_APPROVED);
845     MIME_WKSIDX_AUTHORIZATION             = hdrtoken_wks_to_index(MIME_FIELD_AUTHORIZATION);
846     MIME_WKSIDX_BYTES                     = hdrtoken_wks_to_index(MIME_FIELD_BYTES);
847     MIME_WKSIDX_CACHE_CONTROL             = hdrtoken_wks_to_index(MIME_FIELD_CACHE_CONTROL);
848     MIME_WKSIDX_CLIENT_IP                 = hdrtoken_wks_to_index(MIME_FIELD_CLIENT_IP);
849     MIME_WKSIDX_CONNECTION                = hdrtoken_wks_to_index(MIME_FIELD_CONNECTION);
850     MIME_WKSIDX_CONTENT_BASE              = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_BASE);
851     MIME_WKSIDX_CONTENT_ENCODING          = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_ENCODING);
852     MIME_WKSIDX_CONTENT_LANGUAGE          = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_LANGUAGE);
853     MIME_WKSIDX_CONTENT_LENGTH            = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_LENGTH);
854     MIME_WKSIDX_CONTENT_LOCATION          = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_LOCATION);
855     MIME_WKSIDX_CONTENT_MD5               = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_MD5);
856     MIME_WKSIDX_CONTENT_RANGE             = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_RANGE);
857     MIME_WKSIDX_CONTENT_TYPE              = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_TYPE);
858     MIME_WKSIDX_CONTROL                   = hdrtoken_wks_to_index(MIME_FIELD_CONTROL);
859     MIME_WKSIDX_COOKIE                    = hdrtoken_wks_to_index(MIME_FIELD_COOKIE);
860     MIME_WKSIDX_DATE                      = hdrtoken_wks_to_index(MIME_FIELD_DATE);
861     MIME_WKSIDX_DISTRIBUTION              = hdrtoken_wks_to_index(MIME_FIELD_DISTRIBUTION);
862     MIME_WKSIDX_ETAG                      = hdrtoken_wks_to_index(MIME_FIELD_ETAG);
863     MIME_WKSIDX_EXPECT                    = hdrtoken_wks_to_index(MIME_FIELD_EXPECT);
864     MIME_WKSIDX_EXPIRES                   = hdrtoken_wks_to_index(MIME_FIELD_EXPIRES);
865     MIME_WKSIDX_FOLLOWUP_TO               = hdrtoken_wks_to_index(MIME_FIELD_FOLLOWUP_TO);
866     MIME_WKSIDX_FROM                      = hdrtoken_wks_to_index(MIME_FIELD_FROM);
867     MIME_WKSIDX_HOST                      = hdrtoken_wks_to_index(MIME_FIELD_HOST);
868     MIME_WKSIDX_IF_MATCH                  = hdrtoken_wks_to_index(MIME_FIELD_IF_MATCH);
869     MIME_WKSIDX_IF_MODIFIED_SINCE         = hdrtoken_wks_to_index(MIME_FIELD_IF_MODIFIED_SINCE);
870     MIME_WKSIDX_IF_NONE_MATCH             = hdrtoken_wks_to_index(MIME_FIELD_IF_NONE_MATCH);
871     MIME_WKSIDX_IF_RANGE                  = hdrtoken_wks_to_index(MIME_FIELD_IF_RANGE);
872     MIME_WKSIDX_IF_UNMODIFIED_SINCE       = hdrtoken_wks_to_index(MIME_FIELD_IF_UNMODIFIED_SINCE);
873     MIME_WKSIDX_KEEP_ALIVE                = hdrtoken_wks_to_index(MIME_FIELD_KEEP_ALIVE);
874     MIME_WKSIDX_KEYWORDS                  = hdrtoken_wks_to_index(MIME_FIELD_KEYWORDS);
875     MIME_WKSIDX_LAST_MODIFIED             = hdrtoken_wks_to_index(MIME_FIELD_LAST_MODIFIED);
876     MIME_WKSIDX_LINES                     = hdrtoken_wks_to_index(MIME_FIELD_LINES);
877     MIME_WKSIDX_LOCATION                  = hdrtoken_wks_to_index(MIME_FIELD_LOCATION);
878     MIME_WKSIDX_MAX_FORWARDS              = hdrtoken_wks_to_index(MIME_FIELD_MAX_FORWARDS);
879     MIME_WKSIDX_MESSAGE_ID                = hdrtoken_wks_to_index(MIME_FIELD_MESSAGE_ID);
880     MIME_WKSIDX_NEWSGROUPS                = hdrtoken_wks_to_index(MIME_FIELD_NEWSGROUPS);
881     MIME_WKSIDX_ORGANIZATION              = hdrtoken_wks_to_index(MIME_FIELD_ORGANIZATION);
882     MIME_WKSIDX_PATH                      = hdrtoken_wks_to_index(MIME_FIELD_PATH);
883     MIME_WKSIDX_PRAGMA                    = hdrtoken_wks_to_index(MIME_FIELD_PRAGMA);
884     MIME_WKSIDX_PROXY_AUTHENTICATE        = hdrtoken_wks_to_index(MIME_FIELD_PROXY_AUTHENTICATE);
885     MIME_WKSIDX_PROXY_AUTHORIZATION       = hdrtoken_wks_to_index(MIME_FIELD_PROXY_AUTHORIZATION);
886     MIME_WKSIDX_PROXY_CONNECTION          = hdrtoken_wks_to_index(MIME_FIELD_PROXY_CONNECTION);
887     MIME_WKSIDX_PUBLIC                    = hdrtoken_wks_to_index(MIME_FIELD_PUBLIC);
888     MIME_WKSIDX_RANGE                     = hdrtoken_wks_to_index(MIME_FIELD_RANGE);
889     MIME_WKSIDX_REFERENCES                = hdrtoken_wks_to_index(MIME_FIELD_REFERENCES);
890     MIME_WKSIDX_REFERER                   = hdrtoken_wks_to_index(MIME_FIELD_REFERER);
891     MIME_WKSIDX_REPLY_TO                  = hdrtoken_wks_to_index(MIME_FIELD_REPLY_TO);
892     MIME_WKSIDX_RETRY_AFTER               = hdrtoken_wks_to_index(MIME_FIELD_RETRY_AFTER);
893     MIME_WKSIDX_SENDER                    = hdrtoken_wks_to_index(MIME_FIELD_SENDER);
894     MIME_WKSIDX_SERVER                    = hdrtoken_wks_to_index(MIME_FIELD_SERVER);
895     MIME_WKSIDX_SET_COOKIE                = hdrtoken_wks_to_index(MIME_FIELD_SET_COOKIE);
896     MIME_WKSIDX_STRICT_TRANSPORT_SECURITY = hdrtoken_wks_to_index(MIME_FIELD_STRICT_TRANSPORT_SECURITY);
897     MIME_WKSIDX_SUBJECT                   = hdrtoken_wks_to_index(MIME_FIELD_SUBJECT);
898     MIME_WKSIDX_SUMMARY                   = hdrtoken_wks_to_index(MIME_FIELD_SUMMARY);
899     MIME_WKSIDX_TE                        = hdrtoken_wks_to_index(MIME_FIELD_TE);
900     MIME_WKSIDX_TRANSFER_ENCODING         = hdrtoken_wks_to_index(MIME_FIELD_TRANSFER_ENCODING);
901     MIME_WKSIDX_UPGRADE                   = hdrtoken_wks_to_index(MIME_FIELD_UPGRADE);
902     MIME_WKSIDX_USER_AGENT                = hdrtoken_wks_to_index(MIME_FIELD_USER_AGENT);
903     MIME_WKSIDX_VARY                      = hdrtoken_wks_to_index(MIME_FIELD_VARY);
904     MIME_WKSIDX_VIA                       = hdrtoken_wks_to_index(MIME_FIELD_VIA);
905     MIME_WKSIDX_WARNING                   = hdrtoken_wks_to_index(MIME_FIELD_WARNING);
906     MIME_WKSIDX_WWW_AUTHENTICATE          = hdrtoken_wks_to_index(MIME_FIELD_WWW_AUTHENTICATE);
907     MIME_WKSIDX_XREF                      = hdrtoken_wks_to_index(MIME_FIELD_XREF);
908     MIME_WKSIDX_X_ID                      = hdrtoken_wks_to_index(MIME_FIELD_X_ID);
909     MIME_WKSIDX_X_FORWARDED_FOR           = hdrtoken_wks_to_index(MIME_FIELD_X_FORWARDED_FOR);
910     MIME_WKSIDX_FORWARDED                 = hdrtoken_wks_to_index(MIME_FIELD_FORWARDED);
911     MIME_WKSIDX_SEC_WEBSOCKET_KEY         = hdrtoken_wks_to_index(MIME_FIELD_SEC_WEBSOCKET_KEY);
912     MIME_WKSIDX_SEC_WEBSOCKET_VERSION     = hdrtoken_wks_to_index(MIME_FIELD_SEC_WEBSOCKET_VERSION);
913     MIME_WKSIDX_HTTP2_SETTINGS            = hdrtoken_wks_to_index(MIME_FIELD_HTTP2_SETTINGS);
914     MIME_WKSIDX_EARLY_DATA                = hdrtoken_wks_to_index(MIME_FIELD_EARLY_DATA);
915 
916     MIME_VALUE_BYTES                = hdrtoken_string_to_wks("bytes");
917     MIME_VALUE_CHUNKED              = hdrtoken_string_to_wks("chunked");
918     MIME_VALUE_CLOSE                = hdrtoken_string_to_wks("close");
919     MIME_VALUE_COMPRESS             = hdrtoken_string_to_wks("compress");
920     MIME_VALUE_DEFLATE              = hdrtoken_string_to_wks("deflate");
921     MIME_VALUE_GZIP                 = hdrtoken_string_to_wks("gzip");
922     MIME_VALUE_IDENTITY             = hdrtoken_string_to_wks("identity");
923     MIME_VALUE_KEEP_ALIVE           = hdrtoken_string_to_wks("keep-alive");
924     MIME_VALUE_MAX_AGE              = hdrtoken_string_to_wks("max-age");
925     MIME_VALUE_MAX_STALE            = hdrtoken_string_to_wks("max-stale");
926     MIME_VALUE_MIN_FRESH            = hdrtoken_string_to_wks("min-fresh");
927     MIME_VALUE_MUST_REVALIDATE      = hdrtoken_string_to_wks("must-revalidate");
928     MIME_VALUE_NONE                 = hdrtoken_string_to_wks("none");
929     MIME_VALUE_NO_CACHE             = hdrtoken_string_to_wks("no-cache");
930     MIME_VALUE_NO_STORE             = hdrtoken_string_to_wks("no-store");
931     MIME_VALUE_NO_TRANSFORM         = hdrtoken_string_to_wks("no-transform");
932     MIME_VALUE_ONLY_IF_CACHED       = hdrtoken_string_to_wks("only-if-cached");
933     MIME_VALUE_PRIVATE              = hdrtoken_string_to_wks("private");
934     MIME_VALUE_PROXY_REVALIDATE     = hdrtoken_string_to_wks("proxy-revalidate");
935     MIME_VALUE_PUBLIC               = hdrtoken_string_to_wks("public");
936     MIME_VALUE_S_MAXAGE             = hdrtoken_string_to_wks("s-maxage");
937     MIME_VALUE_NEED_REVALIDATE_ONCE = hdrtoken_string_to_wks("need-revalidate-once");
938     MIME_VALUE_WEBSOCKET            = hdrtoken_string_to_wks("websocket");
939     MIME_VALUE_H2C                  = hdrtoken_string_to_wks(MIME_UPGRADE_H2C_TOKEN);
940 
941     mime_init_date_format_table();
942     mime_init_cache_control_cooking_masks();
943   }
944 }
945 
946 void
mime_init_cache_control_cooking_masks()947 mime_init_cache_control_cooking_masks()
948 {
949   static struct {
950     const char *name;
951     uint32_t mask;
952   } cc_mask_table[] = {{"max-age", MIME_COOKED_MASK_CC_MAX_AGE},
953                        {"no-cache", MIME_COOKED_MASK_CC_NO_CACHE},
954                        {"no-store", MIME_COOKED_MASK_CC_NO_STORE},
955                        {"no-transform", MIME_COOKED_MASK_CC_NO_TRANSFORM},
956                        {"max-stale", MIME_COOKED_MASK_CC_MAX_STALE},
957                        {"min-fresh", MIME_COOKED_MASK_CC_MIN_FRESH},
958                        {"only-if-cached", MIME_COOKED_MASK_CC_ONLY_IF_CACHED},
959                        {"public", MIME_COOKED_MASK_CC_PUBLIC},
960                        {"private", MIME_COOKED_MASK_CC_PRIVATE},
961                        {"must-revalidate", MIME_COOKED_MASK_CC_MUST_REVALIDATE},
962                        {"proxy-revalidate", MIME_COOKED_MASK_CC_PROXY_REVALIDATE},
963                        {"s-maxage", MIME_COOKED_MASK_CC_S_MAXAGE},
964                        {"need-revalidate-once", MIME_COOKED_MASK_CC_NEED_REVALIDATE_ONCE},
965                        {nullptr, 0}};
966 
967   for (int i = 0; cc_mask_table[i].name != nullptr; i++) {
968     const char *wks                              = hdrtoken_string_to_wks(cc_mask_table[i].name);
969     HdrTokenHeapPrefix *p                        = hdrtoken_wks_to_prefix(wks);
970     p->wks_type_specific.u.cache_control.cc_mask = cc_mask_table[i].mask;
971   }
972 }
973 
974 void
mime_init_date_format_table()975 mime_init_date_format_table()
976 {
977   ////////////////////////////////////////////////////////////////
978   // to speed up the days_since_epoch to m/d/y conversion, we   //
979   // use a pre-computed lookup table to support the common case //
980   // of dates that are +/- one year from today --- this code    //
981   // builds the lookup table during the first call.             //
982   ////////////////////////////////////////////////////////////////
983 
984   time_t now_secs;
985   int i, now_days, first_days, last_days, num_days;
986   int m = 0, d = 0, y = 0;
987 
988   time(&now_secs);
989   now_days   = static_cast<int>(now_secs / (60 * 60 * 24));
990   first_days = now_days - 366;
991   last_days  = now_days + 366;
992   num_days   = last_days - first_days + 1;
993 
994   _days_to_mdy_fast_lookup_table           = static_cast<MDY *>(ats_malloc(num_days * sizeof(MDY)));
995   _days_to_mdy_fast_lookup_table_first_day = first_days;
996   _days_to_mdy_fast_lookup_table_last_day  = last_days;
997 
998   for (i = 0; i < num_days; i++) {
999     mime_days_since_epoch_to_mdy_slowcase(first_days + i, &m, &d, &y);
1000     _days_to_mdy_fast_lookup_table[i].m = m;
1001     _days_to_mdy_fast_lookup_table[i].d = d;
1002     _days_to_mdy_fast_lookup_table[i].y = y;
1003   }
1004 }
1005 
1006 MIMEHdrImpl *
mime_hdr_create(HdrHeap * heap)1007 mime_hdr_create(HdrHeap *heap)
1008 {
1009   MIMEHdrImpl *mh;
1010 
1011   mh = (MIMEHdrImpl *)heap->allocate_obj(sizeof(MIMEHdrImpl), HDR_HEAP_OBJ_MIME_HEADER);
1012   mime_hdr_init(mh);
1013   return mh;
1014 }
1015 
1016 void
_mime_hdr_field_block_init(MIMEFieldBlockImpl * fblock)1017 _mime_hdr_field_block_init(MIMEFieldBlockImpl *fblock)
1018 {
1019   fblock->m_freetop = 0;
1020   fblock->m_next    = nullptr;
1021 
1022 #ifdef BLOCK_INIT_PARANOIA
1023   int i;
1024 
1025   // FIX: Could eliminate this initialization loop if we assumed
1026   //      every slot above the freetop of the block was garbage;
1027   //      but to be safe, and help debugging, for now we are eating
1028   //      the cost of initializing all slots in a block.
1029 
1030   for (i = 0; i < MIME_FIELD_BLOCK_SLOTS; i++) {
1031     MIMEField *field   = &(fblock->m_field_slots[i]);
1032     field->m_readiness = MIME_FIELD_SLOT_READINESS_EMPTY;
1033   }
1034 #endif
1035 }
1036 
1037 void
mime_hdr_cooked_stuff_init(MIMEHdrImpl * mh,MIMEField * changing_field_or_null)1038 mime_hdr_cooked_stuff_init(MIMEHdrImpl *mh, MIMEField *changing_field_or_null)
1039 {
1040   // to be safe, reinitialize unless you know this call is for other cooked field
1041   if ((changing_field_or_null == nullptr) || (changing_field_or_null->m_wks_idx != MIME_WKSIDX_PRAGMA)) {
1042     mh->m_cooked_stuff.m_cache_control.m_mask           = 0;
1043     mh->m_cooked_stuff.m_cache_control.m_secs_max_age   = 0;
1044     mh->m_cooked_stuff.m_cache_control.m_secs_s_maxage  = 0;
1045     mh->m_cooked_stuff.m_cache_control.m_secs_max_stale = 0;
1046     mh->m_cooked_stuff.m_cache_control.m_secs_min_fresh = 0;
1047   }
1048   if ((changing_field_or_null == nullptr) || (changing_field_or_null->m_wks_idx != MIME_WKSIDX_CACHE_CONTROL)) {
1049     mh->m_cooked_stuff.m_pragma.m_no_cache = false;
1050   }
1051 }
1052 
1053 void
mime_hdr_init(MIMEHdrImpl * mh)1054 mime_hdr_init(MIMEHdrImpl *mh)
1055 {
1056   mime_hdr_init_accelerators_and_presence_bits(mh);
1057 
1058   mime_hdr_cooked_stuff_init(mh, nullptr);
1059 
1060   // first header is inline: fake an object header for uniformity
1061   obj_init_header((HdrHeapObjImpl *)&(mh->m_first_fblock), HDR_HEAP_OBJ_FIELD_BLOCK, sizeof(MIMEFieldBlockImpl), 0);
1062 
1063   _mime_hdr_field_block_init(&(mh->m_first_fblock));
1064   mh->m_fblock_list_tail = &(mh->m_first_fblock);
1065 
1066   MIME_HDR_SANITY_CHECK(mh);
1067 }
1068 
1069 MIMEFieldBlockImpl *
_mime_field_block_copy(MIMEFieldBlockImpl * s_fblock,HdrHeap *,HdrHeap * d_heap)1070 _mime_field_block_copy(MIMEFieldBlockImpl *s_fblock, HdrHeap * /* s_heap ATS_UNUSED */, HdrHeap *d_heap)
1071 {
1072   MIMEFieldBlockImpl *d_fblock;
1073 
1074   d_fblock = (MIMEFieldBlockImpl *)d_heap->allocate_obj(sizeof(MIMEFieldBlockImpl), HDR_HEAP_OBJ_FIELD_BLOCK);
1075   memcpy(d_fblock, s_fblock, sizeof(MIMEFieldBlockImpl));
1076   return d_fblock;
1077 }
1078 
1079 void
_mime_field_block_destroy(HdrHeap * heap,MIMEFieldBlockImpl * fblock)1080 _mime_field_block_destroy(HdrHeap *heap, MIMEFieldBlockImpl *fblock)
1081 {
1082   heap->deallocate_obj(fblock);
1083 }
1084 
1085 void
mime_hdr_destroy_field_block_list(HdrHeap * heap,MIMEFieldBlockImpl * head)1086 mime_hdr_destroy_field_block_list(HdrHeap *heap, MIMEFieldBlockImpl *head)
1087 {
1088   MIMEFieldBlockImpl *next;
1089 
1090   while (head != nullptr) {
1091     next = head->m_next;
1092     _mime_field_block_destroy(heap, head);
1093     head = next;
1094   }
1095 }
1096 
1097 void
mime_hdr_destroy(HdrHeap * heap,MIMEHdrImpl * mh)1098 mime_hdr_destroy(HdrHeap *heap, MIMEHdrImpl *mh)
1099 {
1100   mime_hdr_destroy_field_block_list(heap, mh->m_first_fblock.m_next);
1101 
1102   // INKqa11458: if we deallocate mh here and call TSMLocRelease
1103   // again, the plugin fails in assert. We leave deallocating to
1104   // the plugin using TSMLocRelease
1105 
1106   // heap->deallocate_obj(mh);
1107 }
1108 
1109 void
mime_hdr_copy_onto(MIMEHdrImpl * s_mh,HdrHeap * s_heap,MIMEHdrImpl * d_mh,HdrHeap * d_heap,bool inherit_strs)1110 mime_hdr_copy_onto(MIMEHdrImpl *s_mh, HdrHeap *s_heap, MIMEHdrImpl *d_mh, HdrHeap *d_heap, bool inherit_strs)
1111 {
1112   int block_count;
1113   MIMEFieldBlockImpl *s_fblock, *d_fblock, *prev_d_fblock;
1114 
1115   // If there are chained field blocks beyond the first one, we're just going to
1116   //   destroy them.  Ideally, we'd use them if the copied in header needed
1117   //   extra blocks.  It's too late in the Tomcat code cycle to implement
1118   //   reuse.
1119   if (d_mh->m_first_fblock.m_next) {
1120     mime_hdr_destroy_field_block_list(d_heap, d_mh->m_first_fblock.m_next);
1121   }
1122 
1123   ink_assert(((char *)&(s_mh->m_first_fblock.m_field_slots[MIME_FIELD_BLOCK_SLOTS]) - (char *)s_mh) == sizeof(struct MIMEHdrImpl));
1124 
1125   int top             = s_mh->m_first_fblock.m_freetop;
1126   char *end           = reinterpret_cast<char *>(&(s_mh->m_first_fblock.m_field_slots[top]));
1127   int bytes_below_top = end - reinterpret_cast<char *>(s_mh);
1128 
1129   // copies useful part of enclosed first block too
1130   memcpy(d_mh, s_mh, bytes_below_top);
1131 
1132   if (d_mh->m_first_fblock.m_next == nullptr) // common case: no other block
1133   {
1134     d_mh->m_fblock_list_tail = &(d_mh->m_first_fblock);
1135     block_count              = 1;
1136   } else // uncommon case: block list exists
1137   {
1138     prev_d_fblock = &(d_mh->m_first_fblock);
1139     block_count   = 1;
1140     for (s_fblock = s_mh->m_first_fblock.m_next; s_fblock != nullptr; s_fblock = s_fblock->m_next) {
1141       ++block_count;
1142       d_fblock              = _mime_field_block_copy(s_fblock, s_heap, d_heap);
1143       prev_d_fblock->m_next = d_fblock;
1144       prev_d_fblock         = d_fblock;
1145     }
1146     d_mh->m_fblock_list_tail = prev_d_fblock;
1147   }
1148 
1149   if (inherit_strs) {
1150     d_heap->inherit_string_heaps(s_heap);
1151   }
1152 
1153   mime_hdr_field_block_list_adjust(block_count, &(s_mh->m_first_fblock), &(d_mh->m_first_fblock));
1154 
1155   MIME_HDR_SANITY_CHECK(s_mh);
1156   MIME_HDR_SANITY_CHECK(d_mh);
1157 }
1158 
1159 MIMEHdrImpl *
mime_hdr_clone(MIMEHdrImpl * s_mh,HdrHeap * s_heap,HdrHeap * d_heap,bool inherit_strs)1160 mime_hdr_clone(MIMEHdrImpl *s_mh, HdrHeap *s_heap, HdrHeap *d_heap, bool inherit_strs)
1161 {
1162   MIMEHdrImpl *d_mh;
1163 
1164   d_mh = mime_hdr_create(d_heap);
1165   mime_hdr_copy_onto(s_mh, s_heap, d_mh, d_heap, inherit_strs);
1166   return d_mh;
1167 }
1168 
1169 /** Move a pointer from one list to another, keeping the relative offset.
1170  * @return A pointer that has the same relative offset to @a dest_base as
1171  * @a dest_ptr does to @a src_base.
1172  */
1173 static inline MIMEField *
rebase(MIMEField * dest_ptr,void * dest_base,void * src_base)1174 rebase(MIMEField *dest_ptr, ///< Original pointer into @src_base memory.
1175        void *dest_base,     ///< New base pointer.
1176        void *src_base       ///< Original base pointer.
1177 )
1178 {
1179   return reinterpret_cast<MIMEField *>(reinterpret_cast<char *>(dest_ptr) +
1180                                        (static_cast<char *>(dest_base) - static_cast<char *>(src_base)));
1181 }
1182 
1183 static inline void
relocate(MIMEField * field,MIMEFieldBlockImpl * dest_block,MIMEFieldBlockImpl * src_block)1184 relocate(MIMEField *field, MIMEFieldBlockImpl *dest_block, MIMEFieldBlockImpl *src_block)
1185 {
1186   for (; src_block; src_block = src_block->m_next, dest_block = dest_block->m_next) {
1187     ink_release_assert(dest_block);
1188 
1189     if (field->m_next_dup >= src_block->m_field_slots && field->m_next_dup < src_block->m_field_slots + src_block->m_freetop) {
1190       field->m_next_dup = rebase(field->m_next_dup, dest_block->m_field_slots, src_block->m_field_slots);
1191       return;
1192     }
1193   }
1194 }
1195 
1196 void
mime_hdr_field_block_list_adjust(int,MIMEFieldBlockImpl * old_list,MIMEFieldBlockImpl * new_list)1197 mime_hdr_field_block_list_adjust(int /* block_count ATS_UNUSED */, MIMEFieldBlockImpl *old_list, MIMEFieldBlockImpl *new_list)
1198 {
1199   for (MIMEFieldBlockImpl *new_blk = new_list; new_blk; new_blk = new_blk->m_next) {
1200     for (MIMEField *field = new_blk->m_field_slots, *end = field + new_blk->m_freetop; field != end; ++field) {
1201       if (field->is_live() && field->m_next_dup) {
1202         relocate(field, new_list, old_list);
1203       }
1204     }
1205   }
1206 }
1207 
1208 int
mime_hdr_length_get(MIMEHdrImpl * mh)1209 mime_hdr_length_get(MIMEHdrImpl *mh)
1210 {
1211   unsigned int length, index;
1212   MIMEFieldBlockImpl *fblock;
1213   MIMEField *field;
1214 
1215   length = 2;
1216 
1217   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1218     for (index = 0; index < fblock->m_freetop; index++) {
1219       field = &(fblock->m_field_slots[index]);
1220       if (field->is_live()) {
1221         length += mime_field_length_get(field);
1222       }
1223     }
1224   }
1225 
1226   return length;
1227 }
1228 
1229 void
mime_hdr_fields_clear(HdrHeap * heap,MIMEHdrImpl * mh)1230 mime_hdr_fields_clear(HdrHeap *heap, MIMEHdrImpl *mh)
1231 {
1232   mime_hdr_destroy_field_block_list(heap, mh->m_first_fblock.m_next);
1233   mime_hdr_init(mh);
1234 }
1235 
1236 MIMEField *
_mime_hdr_field_list_search_by_wks(MIMEHdrImpl * mh,int wks_idx)1237 _mime_hdr_field_list_search_by_wks(MIMEHdrImpl *mh, int wks_idx)
1238 {
1239   MIMEFieldBlockImpl *fblock;
1240   MIMEField *field, *too_far_field;
1241 
1242   ink_assert(hdrtoken_is_valid_wks_idx(wks_idx));
1243 
1244   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1245     field = &(fblock->m_field_slots[0]);
1246 
1247     too_far_field = &(fblock->m_field_slots[fblock->m_freetop]);
1248     while (field < too_far_field) {
1249       if (field->is_live() && (field->m_wks_idx == wks_idx)) {
1250         return field;
1251       }
1252       ++field;
1253     }
1254   }
1255 
1256   return nullptr;
1257 }
1258 
1259 MIMEField *
_mime_hdr_field_list_search_by_string(MIMEHdrImpl * mh,const char * field_name_str,int field_name_len)1260 _mime_hdr_field_list_search_by_string(MIMEHdrImpl *mh, const char *field_name_str, int field_name_len)
1261 {
1262   MIMEFieldBlockImpl *fblock;
1263   MIMEField *field, *too_far_field;
1264 
1265   ink_assert(mh);
1266   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1267     field = &(fblock->m_field_slots[0]);
1268 
1269     too_far_field = &(fblock->m_field_slots[fblock->m_freetop]);
1270     while (field < too_far_field) {
1271       if (field->is_live() && (field_name_len == field->m_len_name) &&
1272           (strncasecmp(field->m_ptr_name, field_name_str, field_name_len) == 0)) {
1273         return field;
1274       }
1275       ++field;
1276     }
1277   }
1278 
1279   return nullptr;
1280 }
1281 
1282 MIMEField *
_mime_hdr_field_list_search_by_slotnum(MIMEHdrImpl * mh,int slotnum)1283 _mime_hdr_field_list_search_by_slotnum(MIMEHdrImpl *mh, int slotnum)
1284 {
1285   unsigned int block_num, block_index;
1286   MIMEFieldBlockImpl *fblock;
1287 
1288   if (slotnum < MIME_FIELD_BLOCK_SLOTS) {
1289     fblock      = &(mh->m_first_fblock);
1290     block_index = slotnum;
1291     if (block_index >= fblock->m_freetop) {
1292       return nullptr;
1293     } else {
1294       return &(fblock->m_field_slots[block_index]);
1295     }
1296   } else {
1297     block_num   = slotnum / MIME_FIELD_BLOCK_SLOTS;
1298     block_index = slotnum % MIME_FIELD_BLOCK_SLOTS;
1299 
1300     fblock = &(mh->m_first_fblock);
1301     while (block_num-- && fblock) {
1302       fblock = fblock->m_next;
1303     }
1304     if ((fblock == nullptr) || (block_index >= fblock->m_freetop)) {
1305       return nullptr;
1306     } else {
1307       return &(fblock->m_field_slots[block_index]);
1308     }
1309   }
1310 }
1311 
1312 MIMEField *
mime_hdr_field_find(MIMEHdrImpl * mh,const char * field_name_str,int field_name_len)1313 mime_hdr_field_find(MIMEHdrImpl *mh, const char *field_name_str, int field_name_len)
1314 {
1315   HdrTokenHeapPrefix *token_info;
1316   const bool is_wks = hdrtoken_is_wks(field_name_str);
1317 
1318   ink_assert(field_name_len >= 0);
1319 
1320   ////////////////////////////////////////////
1321   // do presence check and slot accelerator //
1322   ////////////////////////////////////////////
1323 
1324 #if TRACK_FIELD_FIND_CALLS
1325   Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): is_wks = %d", mh, field_name_len, field_name_str, is_wks);
1326 #endif
1327 
1328   if (is_wks) {
1329     token_info = hdrtoken_wks_to_prefix(field_name_str);
1330     if ((token_info->wks_info.mask) && ((mh->m_presence_bits & token_info->wks_info.mask) == 0)) {
1331 #if TRACK_FIELD_FIND_CALLS
1332       Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): MISS (due to presence bits)", mh, field_name_len, field_name_str);
1333 #endif
1334       return nullptr;
1335     }
1336 
1337     int32_t slot_id = token_info->wks_info.slotid;
1338 
1339     if (slot_id != MIME_SLOTID_NONE) {
1340       uint32_t slotnum = mime_hdr_get_accelerator_slotnum(mh, slot_id);
1341 
1342       if (slotnum != MIME_FIELD_SLOTNUM_UNKNOWN) {
1343         MIMEField *f = _mime_hdr_field_list_search_by_slotnum(mh, slotnum);
1344         ink_assert((f == nullptr) || f->is_live());
1345 #if TRACK_FIELD_FIND_CALLS
1346         Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): %s (due to slot accelerators)", mh, field_name_len,
1347               field_name_str, (f ? "HIT" : "MISS"));
1348 #endif
1349         return f;
1350       } else {
1351 #if TRACK_FIELD_FIND_CALLS
1352         Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): UNKNOWN (slot too big)", mh, field_name_len, field_name_str);
1353 #endif
1354       }
1355     }
1356 
1357     ///////////////////////////////////////////////////////////////////////////
1358     // search by well-known string index or by case-insensitive string match //
1359     ///////////////////////////////////////////////////////////////////////////
1360 
1361     MIMEField *f = _mime_hdr_field_list_search_by_wks(mh, token_info->wks_idx);
1362     ink_assert((f == nullptr) || f->is_live());
1363 #if TRACK_FIELD_FIND_CALLS
1364     Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): %s (due to WKS list walk)", mh, field_name_len, field_name_str,
1365           (f ? "HIT" : "MISS"));
1366 #endif
1367     return f;
1368   } else {
1369     MIMEField *f = _mime_hdr_field_list_search_by_string(mh, field_name_str, field_name_len);
1370 
1371     ink_assert((f == nullptr) || f->is_live());
1372 #if TRACK_FIELD_FIND_CALLS
1373     Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): %s (due to strcmp list walk)", mh, field_name_len, field_name_str,
1374           (f ? "HIT" : "MISS"));
1375 #endif
1376     return f;
1377   }
1378 }
1379 
1380 MIMEField *
mime_hdr_field_get(MIMEHdrImpl * mh,int idx)1381 mime_hdr_field_get(MIMEHdrImpl *mh, int idx)
1382 {
1383   unsigned int index;
1384   MIMEFieldBlockImpl *fblock;
1385   MIMEField *field;
1386   int got_idx;
1387 
1388   got_idx = -1;
1389 
1390   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1391     for (index = 0; index < fblock->m_freetop; index++) {
1392       field = &(fblock->m_field_slots[index]);
1393       if (field->is_live()) {
1394         ++got_idx;
1395       }
1396       if (got_idx == idx) {
1397         return field;
1398       }
1399     }
1400   }
1401 
1402   return nullptr;
1403 }
1404 
1405 MIMEField *
mime_hdr_field_get_slotnum(MIMEHdrImpl * mh,int slotnum)1406 mime_hdr_field_get_slotnum(MIMEHdrImpl *mh, int slotnum)
1407 {
1408   return _mime_hdr_field_list_search_by_slotnum(mh, slotnum);
1409 }
1410 
1411 int
mime_hdr_fields_count(MIMEHdrImpl * mh)1412 mime_hdr_fields_count(MIMEHdrImpl *mh)
1413 {
1414   unsigned int index;
1415   MIMEFieldBlockImpl *fblock;
1416   MIMEField *field;
1417   int count;
1418 
1419   count = 0;
1420 
1421   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1422     for (index = 0; index < fblock->m_freetop; index++) {
1423       field = &(fblock->m_field_slots[index]);
1424       if (field->is_live()) {
1425         ++count;
1426       }
1427     }
1428   }
1429 
1430   return count;
1431 }
1432 
1433 void
mime_field_init(MIMEField * field)1434 mime_field_init(MIMEField *field)
1435 {
1436   memset(field, 0, sizeof(MIMEField));
1437   field->m_readiness = MIME_FIELD_SLOT_READINESS_DETACHED;
1438   field->m_wks_idx   = -1;
1439 }
1440 
1441 MIMEField *
mime_field_create(HdrHeap * heap,MIMEHdrImpl * mh)1442 mime_field_create(HdrHeap *heap, MIMEHdrImpl *mh)
1443 {
1444   MIMEField *field;
1445   MIMEFieldBlockImpl *tail_fblock, *new_fblock;
1446 
1447   tail_fblock = mh->m_fblock_list_tail;
1448   if (tail_fblock->m_freetop >= MIME_FIELD_BLOCK_SLOTS) {
1449     new_fblock = (MIMEFieldBlockImpl *)heap->allocate_obj(sizeof(MIMEFieldBlockImpl), HDR_HEAP_OBJ_FIELD_BLOCK);
1450     _mime_hdr_field_block_init(new_fblock);
1451     tail_fblock->m_next    = new_fblock;
1452     tail_fblock            = new_fblock;
1453     mh->m_fblock_list_tail = new_fblock;
1454   }
1455 
1456   field = &(tail_fblock->m_field_slots[tail_fblock->m_freetop]);
1457   ++tail_fblock->m_freetop;
1458 
1459   mime_field_init(field);
1460 
1461   return field;
1462 }
1463 
1464 MIMEField *
mime_field_create_named(HdrHeap * heap,MIMEHdrImpl * mh,const char * name,int length)1465 mime_field_create_named(HdrHeap *heap, MIMEHdrImpl *mh, const char *name, int length)
1466 {
1467   MIMEField *field       = mime_field_create(heap, mh);
1468   int field_name_wks_idx = hdrtoken_tokenize(name, length);
1469   mime_field_name_set(heap, mh, field, field_name_wks_idx, name, length, true);
1470   return field;
1471 }
1472 
1473 void
mime_hdr_field_attach(MIMEHdrImpl * mh,MIMEField * field,int check_for_dups,MIMEField * prev_dup)1474 mime_hdr_field_attach(MIMEHdrImpl *mh, MIMEField *field, int check_for_dups, MIMEField *prev_dup)
1475 {
1476   MIME_HDR_SANITY_CHECK(mh);
1477 
1478   if (!field->is_detached()) {
1479     return;
1480   }
1481 
1482   ink_assert(field->m_ptr_name != nullptr);
1483 
1484   //////////////////////////////////////////////////
1485   // if we don't know the head dup, or are given  //
1486   // a non-head dup, then search for the head dup //
1487   //////////////////////////////////////////////////
1488 
1489   if (check_for_dups || (prev_dup && (!prev_dup->is_dup_head()))) {
1490     std::string_view name{field->name_get()};
1491     prev_dup = mime_hdr_field_find(mh, name.data(), static_cast<int>(name.size()));
1492     ink_assert((prev_dup == nullptr) || (prev_dup->is_dup_head()));
1493   }
1494 
1495   field->m_readiness = MIME_FIELD_SLOT_READINESS_LIVE;
1496 
1497   ////////////////////////////////////////////////////////////////////
1498   // now, attach the new field --- if there are dups, make sure the //
1499   // field is patched into the dup list in increasing slot order to //
1500   // maintain the invariant that dups are chained in slot order     //
1501   ////////////////////////////////////////////////////////////////////
1502 
1503   if (prev_dup) {
1504     MIMEField *next_dup;
1505     int field_slotnum, prev_slotnum, next_slotnum;
1506 
1507     /////////////////////////////////////////////////////////////////
1508     // walk down dup list looking for the last dup in slot-order   //
1509     // before this field object --- meaning a dup before the field //
1510     // in slot order who either has no next dup, or whose next dup //
1511     // is numerically after the field in slot order.               //
1512     /////////////////////////////////////////////////////////////////
1513 
1514     field_slotnum = mime_hdr_field_slotnum(mh, field);
1515     prev_slotnum  = mime_hdr_field_slotnum(mh, prev_dup);
1516     next_dup      = prev_dup->m_next_dup;
1517     next_slotnum  = (next_dup ? mime_hdr_field_slotnum(mh, next_dup) : -1);
1518 
1519     ink_assert(field_slotnum != prev_slotnum);
1520 
1521     while (prev_slotnum < field_slotnum) // break if prev after field
1522     {
1523       if (next_dup == nullptr) {
1524         break; // no next dup, we're done
1525       }
1526       if (next_slotnum > field_slotnum) {
1527         break; // next dup is after us, we're done
1528       }
1529       prev_dup     = next_dup;
1530       prev_slotnum = next_slotnum;
1531       next_dup     = prev_dup->m_next_dup;
1532     }
1533 
1534     /////////////////////////////////////////////////////
1535     // we get here if the prev_slotnum > field_slotnum //
1536     // (meaning we're now the first dup in the list),  //
1537     // or when we've found the correct prev and next   //
1538     /////////////////////////////////////////////////////
1539 
1540     if (prev_slotnum > field_slotnum) // we are now the head
1541     {
1542       /////////////////////////////////////////////////////////////
1543       // here, it turns out that "prev_dup" is actually after    //
1544       // "field" in the list of fields --- so, prev_dup is a bit //
1545       // of a misnomer, it is actually, the NEXT field!          //
1546       /////////////////////////////////////////////////////////////
1547 
1548       field->m_flags    = (field->m_flags | MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
1549       field->m_next_dup = prev_dup;
1550       prev_dup->m_flags = (prev_dup->m_flags & ~MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
1551       mime_hdr_set_accelerators_and_presence_bits(mh, field);
1552     } else // patch us after prev, and before next
1553     {
1554       ink_assert(prev_slotnum < field_slotnum);
1555       ink_assert((next_dup == nullptr) || (next_slotnum > field_slotnum));
1556       field->m_flags = (field->m_flags & ~MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
1557       ink_assert((next_dup == nullptr) || next_dup->is_live());
1558       prev_dup->m_next_dup = field;
1559       field->m_next_dup    = next_dup;
1560     }
1561   } else {
1562     field->m_flags = (field->m_flags | MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
1563     mime_hdr_set_accelerators_and_presence_bits(mh, field);
1564   }
1565 
1566   // Now keep the cooked cache consistent
1567   ink_assert(field->is_live());
1568   if (field->m_ptr_value && field->is_cooked()) {
1569     mh->recompute_cooked_stuff(field);
1570   }
1571 
1572   MIME_HDR_SANITY_CHECK(mh);
1573 }
1574 
1575 void
mime_hdr_field_detach(MIMEHdrImpl * mh,MIMEField * field,bool detach_all_dups)1576 mime_hdr_field_detach(MIMEHdrImpl *mh, MIMEField *field, bool detach_all_dups)
1577 {
1578   ink_assert(mh);
1579   MIMEField *next_dup = field->m_next_dup;
1580 
1581   // If this field is already detached, there's nothing to do. There must
1582   // not be a dup list if we detached correctly.
1583   if (field->is_detached()) {
1584     ink_assert(next_dup == nullptr);
1585     return;
1586   }
1587 
1588   ink_assert(field->is_live());
1589   MIME_HDR_SANITY_CHECK(mh);
1590 
1591   // Normally, this function is called with the current dup list head,
1592   // so, we need to update the accelerators after the patch out.  But, if
1593   // this function is ever called in the middle of a dup list, we need
1594   // to walk the list to find the previous dup in the list to patch out
1595   // the dup being detached.
1596 
1597   if (field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD) // head of list?
1598   {
1599     if (!next_dup) // only child
1600     {
1601       mime_hdr_unset_accelerators_and_presence_bits(mh, field);
1602     } else // next guy is dup head
1603     {
1604       next_dup->m_flags |= MIME_FIELD_SLOT_FLAGS_DUP_HEAD;
1605       mime_hdr_set_accelerators_and_presence_bits(mh, next_dup);
1606     }
1607   } else // need to walk list to find and patch out from predecessor
1608   {
1609     std::string_view name{field->name_get()};
1610     MIMEField *prev = mime_hdr_field_find(mh, name.data(), static_cast<int>(name.size()));
1611 
1612     while (prev && (prev->m_next_dup != field)) {
1613       prev = prev->m_next_dup;
1614     }
1615     ink_assert(prev != nullptr);
1616 
1617     if (prev->m_next_dup == field) {
1618       prev->m_next_dup = next_dup;
1619     }
1620   }
1621 
1622   // Field is now detached and alone
1623   field->m_readiness = MIME_FIELD_SLOT_READINESS_DETACHED;
1624   field->m_next_dup  = nullptr;
1625 
1626   // Because we changed the values through detaching,update the cooked cache
1627   if (field->is_cooked()) {
1628     mh->recompute_cooked_stuff(field);
1629   }
1630 
1631   MIME_HDR_SANITY_CHECK(mh);
1632 
1633   // At this point, the list should be back to a valid state, either the
1634   // next dup detached and the accelerators set to the next dup (if any),
1635   // or an interior dup detached and patched around.  If we are requested
1636   // to delete the whole dup list, we tail-recurse to delete it.
1637 
1638   if (detach_all_dups && next_dup) {
1639     mime_hdr_field_detach(mh, next_dup, detach_all_dups);
1640   }
1641 }
1642 
1643 void
mime_hdr_field_delete(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,bool delete_all_dups)1644 mime_hdr_field_delete(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, bool delete_all_dups)
1645 {
1646   if (delete_all_dups) {
1647     while (field) {
1648       MIMEField *next = field->m_next_dup;
1649       mime_hdr_field_delete(heap, mh, field, false);
1650       field = next;
1651     }
1652   } else {
1653     heap->free_string(field->m_ptr_name, field->m_len_name);
1654     heap->free_string(field->m_ptr_value, field->m_len_value);
1655 
1656     MIME_HDR_SANITY_CHECK(mh);
1657     mime_hdr_field_detach(mh, field, false);
1658 
1659     MIME_HDR_SANITY_CHECK(mh);
1660     mime_field_destroy(mh, field);
1661 
1662     MIMEFieldBlockImpl *prev_block = nullptr;
1663     bool can_destroy_block         = true;
1664     for (auto fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1665       if (prev_block != nullptr) {
1666         if (fblock->m_freetop == MIME_FIELD_BLOCK_SLOTS && fblock->contains(field)) {
1667           // Check if fields in all slots are deleted
1668           for (auto &m_field_slot : fblock->m_field_slots) {
1669             if (m_field_slot.m_readiness != MIME_FIELD_SLOT_READINESS_DELETED) {
1670               can_destroy_block = false;
1671               break;
1672             }
1673           }
1674           // Destroy a block and maintain the chain
1675           if (can_destroy_block) {
1676             prev_block->m_next = fblock->m_next;
1677             _mime_field_block_destroy(heap, fblock);
1678             if (prev_block->m_next == nullptr) {
1679               mh->m_fblock_list_tail = prev_block;
1680             }
1681           }
1682           break;
1683         }
1684       }
1685       prev_block = fblock;
1686     }
1687   }
1688 
1689   MIME_HDR_SANITY_CHECK(mh);
1690 }
1691 
1692 int
mime_hdr_field_slotnum(MIMEHdrImpl * mh,MIMEField * field)1693 mime_hdr_field_slotnum(MIMEHdrImpl *mh, MIMEField *field)
1694 {
1695   int slots_so_far;
1696   MIMEFieldBlockImpl *fblock;
1697 
1698   slots_so_far = 0;
1699   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1700     if (fblock->contains(field)) {
1701       MIMEField *first     = &(fblock->m_field_slots[0]);
1702       ptrdiff_t block_slot = field - first; // in units of MIMEField
1703       return slots_so_far + block_slot;
1704     }
1705     slots_so_far += MIME_FIELD_BLOCK_SLOTS;
1706   }
1707   return -1;
1708 }
1709 
1710 MIMEField *
mime_hdr_prepare_for_value_set(HdrHeap * heap,MIMEHdrImpl * mh,const char * name,int name_length)1711 mime_hdr_prepare_for_value_set(HdrHeap *heap, MIMEHdrImpl *mh, const char *name, int name_length)
1712 {
1713   int wks_idx;
1714   MIMEField *field;
1715 
1716   field = mime_hdr_field_find(mh, name, name_length);
1717 
1718   //////////////////////////////////////////////////////////////////////
1719   // this function returns with exactly one attached field created,   //
1720   // ready to have its value set.                                     //
1721   //                                                                  //
1722   // on return from field_find, there are 3 possibilities:            //
1723   //   no field found:      create attached, named field              //
1724   //   field found w/dups:  delete list, create attached, named field //
1725   //   dupless field found: return the field for mutation             //
1726   //////////////////////////////////////////////////////////////////////
1727 
1728   if (field == nullptr) // no fields of this name
1729   {
1730     wks_idx = hdrtoken_tokenize(name, name_length);
1731     field   = mime_field_create(heap, mh);
1732     mime_field_name_set(heap, mh, field, wks_idx, name, name_length, true);
1733     mime_hdr_field_attach(mh, field, 0, nullptr);
1734 
1735   } else if (field->m_next_dup) // list of more than 1 field
1736   {
1737     wks_idx = field->m_wks_idx;
1738     mime_hdr_field_delete(heap, mh, field, true);
1739     field = mime_field_create(heap, mh);
1740     mime_field_name_set(heap, mh, field, wks_idx, name, name_length, true);
1741     mime_hdr_field_attach(mh, field, 0, nullptr);
1742   }
1743   return field;
1744 }
1745 
1746 void
mime_field_destroy(MIMEHdrImpl *,MIMEField * field)1747 mime_field_destroy(MIMEHdrImpl * /* mh ATS_UNUSED */, MIMEField *field)
1748 {
1749   ink_assert(field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED);
1750   field->m_readiness = MIME_FIELD_SLOT_READINESS_DELETED;
1751 }
1752 
1753 std::string_view
name_get() const1754 MIMEField::name_get() const
1755 {
1756   if (m_wks_idx >= 0) {
1757     return {hdrtoken_index_to_wks(m_wks_idx), m_len_name};
1758   }
1759   return {m_ptr_name, m_len_name};
1760 }
1761 
1762 void
mime_field_name_set(HdrHeap * heap,MIMEHdrImpl *,MIMEField * field,int16_t name_wks_idx_or_neg1,const char * name,int length,bool must_copy_string)1763 mime_field_name_set(HdrHeap *heap, MIMEHdrImpl * /* mh ATS_UNUSED */, MIMEField *field, int16_t name_wks_idx_or_neg1,
1764                     const char *name, int length, bool must_copy_string)
1765 {
1766   ink_assert(field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED);
1767 
1768   field->m_wks_idx = name_wks_idx_or_neg1;
1769   mime_str_u16_set(heap, name, length, &(field->m_ptr_name), &(field->m_len_name), must_copy_string);
1770 
1771   if ((name_wks_idx_or_neg1 == MIME_WKSIDX_CACHE_CONTROL) || (name_wks_idx_or_neg1 == MIME_WKSIDX_PRAGMA)) {
1772     field->m_flags |= MIME_FIELD_SLOT_FLAGS_COOKED;
1773   }
1774 }
1775 
1776 int
value_get_index(const char * value,int length) const1777 MIMEField::value_get_index(const char *value, int length) const
1778 {
1779   int retval = -1;
1780 
1781   // if field doesn't support commas and there is just one instance, just compare the value
1782   if (!this->supports_commas() && !this->has_dups()) {
1783     if (this->m_len_value == static_cast<uint32_t>(length) && strncasecmp(value, this->m_ptr_value, length) == 0) {
1784       retval = 0;
1785     }
1786   } else {
1787     HdrCsvIter iter;
1788     int tok_len;
1789     int index       = 0;
1790     const char *tok = iter.get_first(this, &tok_len);
1791 
1792     while (tok) {
1793       if (tok_len == length && strncasecmp(tok, value, length) == 0) {
1794         retval = index;
1795         break;
1796       } else {
1797         index++;
1798       }
1799       tok = iter.get_next(&tok_len);
1800     }
1801   }
1802 
1803   return retval;
1804 }
1805 
1806 std::string_view
value_get() const1807 MIMEField::value_get() const
1808 {
1809   return {m_ptr_value, m_len_value};
1810 }
1811 
1812 int32_t
mime_field_value_get_int(const MIMEField * field)1813 mime_field_value_get_int(const MIMEField *field)
1814 {
1815   std::string_view value{field->value_get()};
1816 
1817   return mime_parse_int(value.data(), value.data() + value.size());
1818 }
1819 
1820 uint32_t
mime_field_value_get_uint(const MIMEField * field)1821 mime_field_value_get_uint(const MIMEField *field)
1822 {
1823   std::string_view value{field->value_get()};
1824 
1825   return mime_parse_uint(value.data(), value.data() + value.size());
1826 }
1827 
1828 int64_t
mime_field_value_get_int64(const MIMEField * field)1829 mime_field_value_get_int64(const MIMEField *field)
1830 {
1831   std::string_view value{field->value_get()};
1832 
1833   return mime_parse_int64(value.data(), value.data() + value.size());
1834 }
1835 
1836 time_t
mime_field_value_get_date(const MIMEField * field)1837 mime_field_value_get_date(const MIMEField *field)
1838 {
1839   std::string_view value{field->value_get()};
1840 
1841   return mime_parse_date(value.data(), value.data() + value.size());
1842 }
1843 
1844 const char *
mime_field_value_get_comma_val(const MIMEField * field,int * length,int idx)1845 mime_field_value_get_comma_val(const MIMEField *field, int *length, int idx)
1846 {
1847   // some fields (like Date) contain commas but should not be ripped apart
1848   if (!field->supports_commas()) {
1849     if (idx == 0) {
1850       return field->value_get(length);
1851     }
1852     return nullptr;
1853   } else {
1854     Str *str;
1855     StrList list(false);
1856 
1857     mime_field_value_get_comma_list(field, &list);
1858     str = list.get_idx(idx);
1859     if (str != nullptr) {
1860       *length = static_cast<int>(str->len);
1861       return str->str;
1862     } else {
1863       *length = 0;
1864       return nullptr;
1865     }
1866   }
1867 }
1868 
1869 int
mime_field_value_get_comma_val_count(const MIMEField * field)1870 mime_field_value_get_comma_val_count(const MIMEField *field)
1871 {
1872   // some fields (like Date) contain commas but should not be ripped apart
1873   if (!field->supports_commas()) {
1874     return ((field->m_len_value == 0) ? 0 : 1);
1875   } else {
1876     StrList list(false);
1877     int count = mime_field_value_get_comma_list(field, &list);
1878     return count;
1879   }
1880 }
1881 
1882 int
mime_field_value_get_comma_list(const MIMEField * field,StrList * list)1883 mime_field_value_get_comma_list(const MIMEField *field, StrList *list)
1884 {
1885   std::string_view value{field->value_get()};
1886 
1887   // if field doesn't support commas, don't rip apart.
1888   if (!field->supports_commas()) {
1889     list->append_string(value.data(), static_cast<int>(value.size()));
1890   } else {
1891     HttpCompat::parse_tok_list(list, 1, value.data(), static_cast<int>(value.size()), ',');
1892   }
1893 
1894   return list->count;
1895 }
1896 
1897 const char *
mime_field_value_str_from_strlist(HdrHeap * heap,int * new_str_len_return,StrList * list)1898 mime_field_value_str_from_strlist(HdrHeap *heap, int *new_str_len_return, StrList *list)
1899 {
1900   Str *cell;
1901   char *new_value, *dest;
1902   int i, new_value_len;
1903   // This works, because all strings are from the same heap when it is "split" into the list.
1904   HdrHeap::HeapGuard guard(heap, list->head->str);
1905 
1906   new_value_len = 0;
1907 
1908   // (1) walk the StrList cells, summing each cell's string lengths,
1909   //     and add 2 bytes for each ", " between cells
1910   cell = list->head;
1911   for (i = 0; i < list->count; i++) {
1912     new_value_len += cell->len;
1913     cell = cell->next;
1914   }
1915   if (list->count > 1) {
1916     new_value_len += (2 * (list->count - 1));
1917   }
1918 
1919   // (2) allocate new heap string
1920   new_value = heap->allocate_str(new_value_len);
1921 
1922   // (3) copy string pieces into new heap string
1923   dest = new_value;
1924   cell = list->head;
1925   for (i = 0; i < list->count; i++) {
1926     if (i != 0) {
1927       *dest++ = ',';
1928       *dest++ = ' ';
1929     }
1930     memcpy(dest, cell->str, cell->len);
1931     dest += cell->len;
1932     cell = cell->next;
1933   }
1934   ink_assert(dest - new_value == new_value_len);
1935 
1936   *new_str_len_return = new_value_len;
1937   return new_value;
1938 }
1939 
1940 void
mime_field_value_set_comma_val(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int idx,const char * new_piece_str,int new_piece_len)1941 mime_field_value_set_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx, const char *new_piece_str,
1942                                int new_piece_len)
1943 {
1944   int len;
1945   Str *cell;
1946   StrList list(false);
1947 
1948   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
1949   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
1950 
1951   // (2) if desired index isn't valid, then don't change the field
1952   if ((idx < 0) || (idx >= list.count)) {
1953     return;
1954   }
1955 
1956   // (3) mutate cell idx
1957   cell = list.get_idx(idx);
1958   ink_assert(cell != nullptr);
1959   cell->str = new_piece_str;
1960   cell->len = new_piece_len;
1961 
1962   // (4) reassemble the new string
1963   field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
1964   field->m_len_value = len;
1965 
1966   // (5) keep stuff fields consistent
1967   field->m_n_v_raw_printable = 0;
1968   if (field->is_live() && field->is_cooked()) {
1969     mh->recompute_cooked_stuff(field);
1970   }
1971 }
1972 
1973 void
mime_field_value_delete_comma_val(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int idx)1974 mime_field_value_delete_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx)
1975 {
1976   int len;
1977   Str *cell;
1978   StrList list(false);
1979 
1980   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
1981   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
1982 
1983   // (2) if desired index isn't valid, then don't change the field
1984   if ((idx < 0) || (idx >= list.count)) {
1985     return;
1986   }
1987 
1988   // (3) delete cell idx
1989   cell = list.get_idx(idx);
1990   list.detach(cell);
1991 
1992   /**********************************************/
1993   /*   Fix for bug INKqa09752                   */
1994   /*                                            */
1995   /*   If this is the last value                */
1996   /*   in the field, set the m_ptr_val to NULL  */
1997   /**********************************************/
1998 
1999   if (list.count == 0) {
2000     field->m_ptr_value = nullptr;
2001     field->m_len_value = 0;
2002   } else {
2003     /************************************/
2004     /*   End Fix for bug INKqa09752     */
2005     /************************************/
2006 
2007     // (4) reassemble the new string
2008     field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
2009     field->m_len_value = len;
2010   }
2011 
2012   // (5) keep stuff fields consistent
2013   field->m_n_v_raw_printable = 0;
2014   if (field->is_live() && field->is_cooked()) {
2015     mh->recompute_cooked_stuff(field);
2016   }
2017 }
2018 
2019 void
mime_field_value_insert_comma_val(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int idx,const char * new_piece_str,int new_piece_len)2020 mime_field_value_insert_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx, const char *new_piece_str,
2021                                   int new_piece_len)
2022 {
2023   int len;
2024   Str *cell, *prev;
2025   StrList list(false);
2026 
2027   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
2028   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
2029 
2030   // (2) if desired index isn't valid, then don't change the field
2031   if (idx < 0) {
2032     idx = list.count;
2033   }
2034   if (idx > list.count) {
2035     return;
2036   }
2037 
2038   // (3) create a new cell
2039   cell = list.new_cell(new_piece_str, new_piece_len);
2040 
2041   // (4) patch new cell into list at the right place
2042   if (idx == 0) {
2043     list.prepend(cell);
2044   } else {
2045     prev = list.get_idx(idx - 1);
2046     list.add_after(prev, cell);
2047   }
2048 
2049   // (5) reassemble the new string
2050   field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
2051   field->m_len_value = len;
2052 
2053   // (6) keep stuff fields consistent
2054   field->m_n_v_raw_printable = 0;
2055   if (field->is_live() && field->is_cooked()) {
2056     mh->recompute_cooked_stuff(field);
2057   }
2058 }
2059 
2060 void
mime_field_value_extend_comma_val(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int idx,const char * new_piece_str,int new_piece_len)2061 mime_field_value_extend_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx, const char *new_piece_str,
2062                                   int new_piece_len)
2063 {
2064   Str *cell;
2065   StrList list(false);
2066   int trimmed, len;
2067   size_t extended_len;
2068   char *dest, *temp_ptr, temp_buf[128];
2069 
2070   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
2071   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
2072 
2073   // (2) if desired index isn't valid, then don't change the field
2074   if ((idx < 0) || (idx >= list.count)) {
2075     return;
2076   }
2077 
2078   // (3) get the cell we want to modify
2079   cell = list.get_idx(idx);
2080   ink_assert(cell != nullptr);
2081 
2082   // (4) trim quotes if any
2083   if ((cell->len >= 2) && (cell->str[0] == '\"') && (cell->str[cell->len - 1] == '\"')) {
2084     trimmed = 1;
2085     cell->str += 1;
2086     cell->len -= 2;
2087   } else {
2088     trimmed = 0;
2089   }
2090 
2091   // (5) compute length of extended token
2092   extended_len = cell->len + new_piece_len + (trimmed ? 2 : 0);
2093 
2094   // (6) allocate temporary space to construct new value
2095   if (extended_len <= sizeof(temp_buf)) {
2096     temp_ptr = temp_buf;
2097   } else {
2098     temp_ptr = static_cast<char *>(ats_malloc(extended_len));
2099   }
2100 
2101   // (7) construct new extended token
2102   dest = temp_ptr;
2103   if (trimmed) {
2104     *dest++ = '\"';
2105   }
2106   memcpy(dest, cell->str, cell->len);
2107   dest += cell->len;
2108   memcpy(dest, new_piece_str, new_piece_len);
2109   dest += new_piece_len;
2110   if (trimmed) {
2111     *dest++ = '\"';
2112   }
2113   ink_assert((size_t)(dest - temp_ptr) == extended_len);
2114 
2115   // (8) assign the new token to the cell
2116   cell->str = temp_ptr;
2117   cell->len = extended_len;
2118 
2119   // (9) reassemble the new string
2120   field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
2121   field->m_len_value = len;
2122 
2123   // (10) keep stuff fields consistent
2124   field->m_n_v_raw_printable = 0;
2125   if (field->is_live() && field->is_cooked()) {
2126     mh->recompute_cooked_stuff(field);
2127   }
2128 
2129   // (11) free up any temporary storage
2130   if (extended_len > sizeof(temp_buf)) {
2131     ats_free(temp_ptr);
2132   }
2133 }
2134 
2135 void
mime_field_value_set(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,const char * value,int length,bool must_copy_string)2136 mime_field_value_set(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, const char *value, int length, bool must_copy_string)
2137 {
2138   heap->free_string(field->m_ptr_value, field->m_len_value);
2139 
2140   if (must_copy_string && value) {
2141     field->m_ptr_value = heap->duplicate_str(value, length);
2142   } else {
2143     field->m_ptr_value = value;
2144   }
2145 
2146   field->m_len_value         = length;
2147   field->m_n_v_raw_printable = 0;
2148 
2149   // Now keep the cooked cache consistent
2150   if (field->is_live() && field->is_cooked()) {
2151     mh->recompute_cooked_stuff(field);
2152   }
2153 }
2154 
2155 void
mime_field_value_set_int(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int32_t value)2156 mime_field_value_set_int(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int32_t value)
2157 {
2158   char buf[16];
2159   int len = mime_format_int(buf, value, sizeof(buf));
2160   mime_field_value_set(heap, mh, field, buf, len, true);
2161 }
2162 
2163 void
mime_field_value_set_uint(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,uint32_t value)2164 mime_field_value_set_uint(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, uint32_t value)
2165 {
2166   char buf[16];
2167   int len = mime_format_uint(buf, value, sizeof(buf));
2168   mime_field_value_set(heap, mh, field, buf, len, true);
2169 }
2170 
2171 void
mime_field_value_set_int64(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int64_t value)2172 mime_field_value_set_int64(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int64_t value)
2173 {
2174   char buf[20];
2175   int len = mime_format_int64(buf, value, sizeof(buf));
2176   mime_field_value_set(heap, mh, field, buf, len, true);
2177 }
2178 
2179 void
mime_field_value_set_date(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,time_t value)2180 mime_field_value_set_date(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, time_t value)
2181 {
2182   char buf[33];
2183   int len = mime_format_date(buf, value);
2184   mime_field_value_set(heap, mh, field, buf, len, true);
2185 }
2186 
2187 void
mime_field_name_value_set(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int16_t name_wks_idx_or_neg1,const char * name,int name_length,const char * value,int value_length,int n_v_raw_printable,int n_v_raw_length,bool must_copy_strings)2188 mime_field_name_value_set(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int16_t name_wks_idx_or_neg1, const char *name,
2189                           int name_length, const char *value, int value_length, int n_v_raw_printable, int n_v_raw_length,
2190                           bool must_copy_strings)
2191 {
2192   unsigned int n_v_raw_pad = n_v_raw_length - (name_length + value_length);
2193 
2194   ink_assert(field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED);
2195 
2196   if (must_copy_strings) {
2197     mime_field_name_set(heap, mh, field, name_wks_idx_or_neg1, name, name_length, true);
2198     mime_field_value_set(heap, mh, field, value, value_length, true);
2199   } else {
2200     field->m_wks_idx   = name_wks_idx_or_neg1;
2201     field->m_ptr_name  = name;
2202     field->m_ptr_value = value;
2203     field->m_len_name  = name_length;
2204     field->m_len_value = value_length;
2205     if (n_v_raw_printable && (n_v_raw_pad <= 7)) {
2206       field->m_n_v_raw_printable     = n_v_raw_printable;
2207       field->m_n_v_raw_printable_pad = n_v_raw_pad;
2208     } else {
2209       field->m_n_v_raw_printable = 0;
2210     }
2211 
2212     // Now keep the cooked cache consistent
2213     if ((name_wks_idx_or_neg1 == MIME_WKSIDX_CACHE_CONTROL) || (name_wks_idx_or_neg1 == MIME_WKSIDX_PRAGMA)) {
2214       field->m_flags |= MIME_FIELD_SLOT_FLAGS_COOKED;
2215     }
2216     if (field->is_live() && field->is_cooked()) {
2217       mh->recompute_cooked_stuff(field);
2218     }
2219   }
2220 }
2221 
2222 void
mime_field_value_append(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,const char * value,int length,bool prepend_comma,const char separator)2223 mime_field_value_append(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, const char *value, int length, bool prepend_comma,
2224                         const char separator)
2225 {
2226   int new_length = field->m_len_value + length;
2227   if (prepend_comma && field->m_len_value) {
2228     new_length += 2;
2229   }
2230 
2231   // Start by trying expand the string we already  have
2232   char *new_str = heap->expand_str(field->m_ptr_value, field->m_len_value, new_length);
2233 
2234   if (new_str == nullptr) {
2235     // Expansion failed.  Create a new string and copy over the value contents
2236     new_str = heap->allocate_str(new_length);
2237     memcpy(new_str, field->m_ptr_value, field->m_len_value);
2238   }
2239 
2240   char *ptr = new_str + field->m_len_value;
2241   if (prepend_comma && field->m_len_value) {
2242     *ptr++ = separator;
2243     *ptr++ = ' ';
2244   }
2245 
2246   memcpy(ptr, value, length);
2247 
2248   field->m_ptr_value         = new_str;
2249   field->m_len_value         = new_length;
2250   field->m_n_v_raw_printable = 0;
2251 
2252   // Now keep the cooked cache consistent
2253   if (field->is_live() && field->is_cooked()) {
2254     mh->recompute_cooked_stuff(field);
2255   }
2256 }
2257 
2258 MIMEField *
get_host_port_values(const char ** host_ptr,int * host_len,const char ** port_ptr,int * port_len)2259 MIMEHdr::get_host_port_values(const char **host_ptr, ///< Pointer to host.
2260                               int *host_len,         ///< Length of host.
2261                               const char **port_ptr, ///< Pointer to port.
2262                               int *port_len)
2263 {
2264   MIMEField *field = this->field_find(MIME_FIELD_HOST, MIME_LEN_HOST);
2265   if (host_ptr) {
2266     *host_ptr = nullptr;
2267   }
2268   if (host_len) {
2269     *host_len = 0;
2270   }
2271   if (port_ptr) {
2272     *port_ptr = nullptr;
2273   }
2274   if (port_len) {
2275     *port_len = 0;
2276   }
2277 
2278   if (field) {
2279     ts::TextView b{field->m_ptr_value, static_cast<size_t>(field->m_len_value)};
2280     ts::TextView host, port;
2281 
2282     if (b) {
2283       if ('[' == *b) {
2284         auto idx = b.find(']');
2285         if (idx <= b.size() && b[idx + 1] == ':') {
2286           host = b.take_prefix_at(idx + 1);
2287           port = b;
2288         } else {
2289           host = b;
2290         }
2291       } else {
2292         auto x = b.split_prefix_at(':');
2293         if (x) {
2294           host = x;
2295           port = b;
2296         } else {
2297           host = b;
2298         }
2299       }
2300 
2301       if (host) {
2302         if (host_ptr) {
2303           *host_ptr = host.data();
2304         }
2305         if (host_len) {
2306           *host_len = static_cast<int>(host.size());
2307         }
2308       }
2309       if (port) {
2310         if (port_ptr) {
2311           *port_ptr = port.data();
2312         }
2313         if (port_len) {
2314           *port_len = static_cast<int>(port.size());
2315         }
2316       }
2317     } else {
2318       field = nullptr; // no value in field, signal fail.
2319     }
2320   }
2321   return field;
2322 }
2323 
2324 /***********************************************************************
2325  *                                                                     *
2326  *                          P A R S E R                                *
2327  *                                                                     *
2328  ***********************************************************************/
2329 
2330 void
init()2331 MIMEScanner::init()
2332 {
2333   m_state = INITIAL_PARSE_STATE;
2334   // Ugly, but required because of how proxy allocation works - that leaves the instance in a
2335   // random state, so even assigning to it can crash. Because this method substitutes for a real
2336   // constructor in the proxy allocation system, call the CTOR here. Any memory that gets allocated
2337   // is supposed to be cleaned up by calling @c clear on this object.
2338   new (&m_line) std::string;
2339 }
2340 
2341 MIMEScanner &
append(TextView text)2342 MIMEScanner::append(TextView text)
2343 {
2344   m_line += text;
2345   return *this;
2346 }
2347 
2348 ParseResult
get(TextView & input,TextView & output,bool & output_shares_input,bool eof_p,ScanType scan_type)2349 MIMEScanner::get(TextView &input, TextView &output, bool &output_shares_input, bool eof_p, ScanType scan_type)
2350 {
2351   ParseResult zret = PARSE_RESULT_CONT;
2352   // Need this for handling dangling CR.
2353   static const char RAW_CR{ParseRules::CHAR_CR};
2354 
2355   auto text = input;
2356   while (PARSE_RESULT_CONT == zret && !text.empty()) {
2357     switch (m_state) {
2358     case MIME_PARSE_BEFORE: // waiting to find a field.
2359       m_line.resize(0);     // any caller should already be done with the buffer
2360       if (ParseRules::is_cr(*text)) {
2361         ++text;
2362         if (!text.empty() && ParseRules::is_lf(*text)) {
2363           // optimize a bit - this happens >99% of the time after a CR.
2364           ++text;
2365           zret = PARSE_RESULT_DONE;
2366         } else {
2367           m_state = MIME_PARSE_FOUND_CR;
2368         }
2369       } else if (ParseRules::is_lf(*text)) {
2370         ++text;
2371         zret = PARSE_RESULT_DONE; // Required by regression test.
2372       } else {
2373         // consume this character in the next state.
2374         m_state = MIME_PARSE_INSIDE;
2375       }
2376       break;
2377     case MIME_PARSE_FOUND_CR:
2378       // Looking for a field and found a CR, which should mean terminating the header.
2379       if (ParseRules::is_lf(*text)) {
2380         ++text;
2381         zret = PARSE_RESULT_DONE;
2382       } else {
2383         // This really should be an error (spec doesn't permit lone CR) but the regression tests
2384         // require it.
2385         this->append(TextView(&RAW_CR, 1)); // This is to fix a core dump of the icc 19.1 compiler when {&RAW_CR, 1} is used
2386         m_state = MIME_PARSE_INSIDE;
2387       }
2388       break;
2389     case MIME_PARSE_INSIDE: {
2390       auto lf_off = text.find(ParseRules::CHAR_LF);
2391       if (lf_off != TextView::npos) {
2392         text.remove_prefix(lf_off + 1); // drop up to and including LF
2393         if (LINE == scan_type) {
2394           zret    = PARSE_RESULT_OK;
2395           m_state = MIME_PARSE_BEFORE;
2396         } else {
2397           m_state = MIME_PARSE_AFTER; // looking for line folding.
2398         }
2399       } else { // no EOL, consume all text without changing state.
2400         text.remove_prefix(text.size());
2401       }
2402     } break;
2403     case MIME_PARSE_AFTER:
2404       // After a LF, the next line might be a continuation / folded line. That's indicated by a
2405       // starting whitespace. If that's the case, back up over the preceding CR/LF with space and
2406       // pretend it's the same line.
2407       if (ParseRules::is_ws(*text)) { // folded line.
2408         char *unfold = const_cast<char *>(text.data() - 1);
2409         *unfold--    = ' ';
2410         if (ParseRules::is_cr(*unfold)) {
2411           *unfold = ' ';
2412         }
2413         m_state = MIME_PARSE_INSIDE; // back inside the field.
2414       } else {
2415         m_state = MIME_PARSE_BEFORE; // field terminated.
2416         zret    = PARSE_RESULT_OK;
2417       }
2418       break;
2419     }
2420   }
2421 
2422   TextView parsed_text{input.data(), text.data()};
2423   bool save_parsed_text_p = !parsed_text.empty();
2424 
2425   if (PARSE_RESULT_CONT == zret) {
2426     // data ran out before we got a clear final result. There a number of things we need to check
2427     // and possibly adjust that result. It's less complex to do this cleanup than handle all of
2428     // these checks in the parser state machine.
2429     if (eof_p) {
2430       // Should never return PARSE_CONT if we've hit EOF.
2431       if (parsed_text.empty()) {
2432         // all input previously consumed. If we're between fields, that's cool.
2433         if (MIME_PARSE_INSIDE != m_state) {
2434           m_state = MIME_PARSE_BEFORE; // probably not needed...
2435           zret    = PARSE_RESULT_DONE;
2436         } else {
2437           zret = PARSE_RESULT_ERROR; // unterminated field.
2438         }
2439       } else if (MIME_PARSE_AFTER == m_state) {
2440         // Special case it seems - need to accept the final field even if there's no header
2441         // terminating CR LF. This is only reasonable after absolute end of input (EOF) because
2442         // otherwise this might be a multiline field where we haven't seen the next leading space.
2443         m_state = MIME_PARSE_BEFORE;
2444         zret    = PARSE_RESULT_OK;
2445       } else {
2446         // Partial input, no field / line CR LF
2447         zret = PARSE_RESULT_ERROR; // Unterminated field.
2448       }
2449     } else if (!parsed_text.empty()) {
2450       if (MIME_PARSE_INSIDE == m_state) {
2451         // Inside a field but more data is expected. Save what we've got.
2452         this->append(parsed_text);  // Do this here to force appending.
2453         save_parsed_text_p = false; // don't double append.
2454       } else if (MIME_PARSE_AFTER == m_state) {
2455         // After a field but we still have data. Need to parse it too.
2456         m_state = MIME_PARSE_BEFORE;
2457         zret    = PARSE_RESULT_OK;
2458       }
2459     }
2460   }
2461 
2462   if (save_parsed_text_p && !m_line.empty()) {
2463     // If we're already accumulating, continue to do so if we have data.
2464     this->append(parsed_text);
2465   }
2466 
2467   // adjust out arguments.
2468   output_shares_input = true;
2469   if (PARSE_RESULT_CONT != zret) {
2470     if (!m_line.empty()) {
2471       output              = m_line; // cleared when called with state MIME_PARSE_BEFORE
2472       output_shares_input = false;
2473     } else {
2474       output = parsed_text;
2475     }
2476   }
2477 
2478   // Make sure there are no null characters in the input scanned so far
2479   if (zret != PARSE_RESULT_ERROR && TextView::npos != parsed_text.find('\0')) {
2480     zret = PARSE_RESULT_ERROR;
2481   }
2482 
2483   input.remove_prefix(parsed_text.size());
2484   return zret;
2485 }
2486 
2487 void
_mime_parser_init(MIMEParser * parser)2488 _mime_parser_init(MIMEParser *parser)
2489 {
2490   parser->m_field       = 0;
2491   parser->m_field_flags = 0;
2492   parser->m_value       = -1;
2493 }
2494 //////////////////////////////////////////////////////
2495 // init     first time structure setup              //
2496 // clear    resets an already-initialized structure //
2497 //////////////////////////////////////////////////////
2498 void
mime_parser_init(MIMEParser * parser)2499 mime_parser_init(MIMEParser *parser)
2500 {
2501   parser->m_scanner.init();
2502   _mime_parser_init(parser);
2503 }
2504 
2505 void
mime_parser_clear(MIMEParser * parser)2506 mime_parser_clear(MIMEParser *parser)
2507 {
2508   parser->m_scanner.clear();
2509   _mime_parser_init(parser);
2510 }
2511 
2512 ParseResult
mime_parser_parse(MIMEParser * parser,HdrHeap * heap,MIMEHdrImpl * mh,const char ** real_s,const char * real_e,bool must_copy_strings,bool eof,bool remove_ws_from_field_name,size_t max_hdr_field_size)2513 mime_parser_parse(MIMEParser *parser, HdrHeap *heap, MIMEHdrImpl *mh, const char **real_s, const char *real_e,
2514                   bool must_copy_strings, bool eof, bool remove_ws_from_field_name, size_t max_hdr_field_size)
2515 {
2516   ParseResult err;
2517   bool line_is_real;
2518 
2519   MIMEScanner *scanner = &parser->m_scanner;
2520 
2521   while (true) {
2522     ////////////////////////////////////////////////////////////////////////////
2523     // get a name:value line, with all continuation lines glued into one line //
2524     ////////////////////////////////////////////////////////////////////////////
2525 
2526     TextView text{*real_s, real_e};
2527     TextView parsed;
2528     err     = scanner->get(text, parsed, line_is_real, eof, MIMEScanner::FIELD);
2529     *real_s = text.data();
2530     if (err != PARSE_RESULT_OK) {
2531       return err;
2532     }
2533 
2534     //////////////////////////////////////////////////
2535     // if got a LF or CR on its own, end the header //
2536     //////////////////////////////////////////////////
2537 
2538     if ((parsed.size() >= 2) && (parsed[0] == ParseRules::CHAR_CR) && (parsed[1] == ParseRules::CHAR_LF)) {
2539       return PARSE_RESULT_DONE;
2540     }
2541 
2542     if ((parsed.size() >= 1) && (parsed[0] == ParseRules::CHAR_LF)) {
2543       return PARSE_RESULT_DONE;
2544     }
2545 
2546     /////////////////////////////////////////////
2547     // find pointers into the name:value field //
2548     /////////////////////////////////////////////
2549 
2550     /**
2551      * Fix for INKqa09141. The is_token function fails for '@' character.
2552      * Header names starting with '@' signs are valid headers. Hence we
2553      * have to add one more check to see if the first parameter is '@'
2554      * character then, the header name is valid.
2555      **/
2556     if ((!ParseRules::is_token(*parsed)) && (*parsed != '@')) {
2557       continue; // toss away garbage line
2558     }
2559 
2560     // find name last
2561     auto field_value = parsed; // need parsed as is later on.
2562     auto field_name  = field_value.split_prefix_at(':');
2563     if (field_name.empty()) {
2564       continue; // toss away garbage line
2565     }
2566 
2567     // RFC7230 section 3.2.4:
2568     // No whitespace is allowed between the header field-name and colon.  In
2569     // the past, differences in the handling of such whitespace have led to
2570     // security vulnerabilities in request routing and response handling.  A
2571     // server MUST reject any received request message that contains
2572     // whitespace between a header field-name and colon with a response code
2573     // of 400 (Bad Request).
2574     // A proxy MUST remove any such whitespace from a response message before
2575     // forwarding the message downstream.
2576     bool raw_print_field = true;
2577     if (is_ws(field_name.back())) {
2578       if (!remove_ws_from_field_name) {
2579         return PARSE_RESULT_ERROR;
2580       }
2581       field_name.rtrim_if(&ParseRules::is_ws);
2582       raw_print_field = false;
2583     } else if (parsed.suffix(2) != "\r\n") {
2584       raw_print_field = false;
2585     }
2586 
2587     // find value first
2588     field_value.ltrim_if(&ParseRules::is_ws);
2589     field_value.rtrim_if(&ParseRules::is_wslfcr);
2590 
2591     // Make sure the name + value is not longer than configured max_hdr_field_size
2592     if (field_name.size() + field_value.size() > max_hdr_field_size) {
2593       return PARSE_RESULT_ERROR;
2594     }
2595 
2596     //    int total_line_length = (int)(field_line_last - field_line_first + 1);
2597 
2598     //////////////////////////////////////////////////////////////////////
2599     // if we can't leave the name & value in the real buffer, copy them //
2600     //////////////////////////////////////////////////////////////////////
2601 
2602     if (must_copy_strings || (!line_is_real)) {
2603       char *dup       = heap->duplicate_str(parsed.data(), parsed.size());
2604       ptrdiff_t delta = dup - parsed.data();
2605       field_name.assign(field_name.data() + delta, field_name.size());
2606       field_value.assign(field_value.data() + delta, field_value.size());
2607     }
2608     ///////////////////////
2609     // tokenize the name //
2610     ///////////////////////
2611 
2612     int field_name_wks_idx = hdrtoken_tokenize(field_name.data(), field_name.size());
2613 
2614     ///////////////////////////////////////////
2615     // build and insert the new field object //
2616     ///////////////////////////////////////////
2617 
2618     MIMEField *field = mime_field_create(heap, mh);
2619     mime_field_name_value_set(heap, mh, field, field_name_wks_idx, field_name.data(), field_name.size(), field_value.data(),
2620                               field_value.size(), raw_print_field, parsed.size(), false);
2621     mime_hdr_field_attach(mh, field, 1, nullptr);
2622   }
2623 }
2624 
2625 void
mime_hdr_describe(HdrHeapObjImpl * raw,bool recurse)2626 mime_hdr_describe(HdrHeapObjImpl *raw, bool recurse)
2627 {
2628   MIMEFieldBlockImpl *fblock;
2629   MIMEHdrImpl *obj = (MIMEHdrImpl *)raw;
2630 
2631   Debug("http", "\t[PBITS: 0x%08X%08X, SLACC: 0x%04X%04X%04X%04X, HEADBLK: %p, TAILBLK: %p]",
2632         (uint32_t)((obj->m_presence_bits >> 32) & (TOK_64_CONST(0xFFFFFFFF))),
2633         (uint32_t)((obj->m_presence_bits >> 0) & (TOK_64_CONST(0xFFFFFFFF))), obj->m_slot_accelerators[0],
2634         obj->m_slot_accelerators[1], obj->m_slot_accelerators[2], obj->m_slot_accelerators[3], &(obj->m_first_fblock),
2635         obj->m_fblock_list_tail);
2636 
2637   Debug("http", "\t[CBITS: 0x%08X, T_MAXAGE: %d, T_SMAXAGE: %d, T_MAXSTALE: %d, T_MINFRESH: %d, PNO$: %d]",
2638         obj->m_cooked_stuff.m_cache_control.m_mask, obj->m_cooked_stuff.m_cache_control.m_secs_max_age,
2639         obj->m_cooked_stuff.m_cache_control.m_secs_s_maxage, obj->m_cooked_stuff.m_cache_control.m_secs_max_stale,
2640         obj->m_cooked_stuff.m_cache_control.m_secs_min_fresh, obj->m_cooked_stuff.m_pragma.m_no_cache);
2641   for (fblock = &(obj->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
2642     if (recurse || (fblock == &(obj->m_first_fblock))) {
2643       obj_describe((HdrHeapObjImpl *)fblock, recurse);
2644     }
2645   }
2646 }
2647 
2648 void
mime_field_block_describe(HdrHeapObjImpl * raw,bool)2649 mime_field_block_describe(HdrHeapObjImpl *raw, bool /* recurse ATS_UNUSED */)
2650 {
2651   unsigned int i;
2652   static const char *readiness_names[] = {"EMPTY", "DETACHED", "LIVE", "DELETED"};
2653 
2654   MIMEFieldBlockImpl *obj = (MIMEFieldBlockImpl *)raw;
2655 
2656   Debug("http", "[FREETOP: %d, NEXTBLK: %p]", obj->m_freetop, obj->m_next);
2657 
2658   for (i = 0; i < obj->m_freetop; i++) {
2659     MIMEField *f = &(obj->m_field_slots[i]);
2660     Debug("http", "\tSLOT #%2d (%p), %-8s", i, f, readiness_names[f->m_readiness]);
2661 
2662     switch (f->m_readiness) {
2663     case MIME_FIELD_SLOT_READINESS_EMPTY:
2664       break;
2665     case MIME_FIELD_SLOT_READINESS_DETACHED:
2666     case MIME_FIELD_SLOT_READINESS_LIVE:
2667     case MIME_FIELD_SLOT_READINESS_DELETED:
2668       Debug("http", "[N: \"%.*s\", N_LEN: %d, N_IDX: %d, ", f->m_len_name, (f->m_ptr_name ? f->m_ptr_name : "NULL"), f->m_len_name,
2669             f->m_wks_idx);
2670       Debug("http", "V: \"%.*s\", V_LEN: %d, ", f->m_len_value, (f->m_ptr_value ? f->m_ptr_value : "NULL"), f->m_len_value);
2671       Debug("http", "NEXTDUP: %p, RAW: %d, RAWLEN: %d, F: %d]", f->m_next_dup, f->m_n_v_raw_printable,
2672             f->m_len_name + f->m_len_value + f->m_n_v_raw_printable_pad, f->m_flags);
2673       break;
2674     }
2675     Debug("http", "\n");
2676   }
2677 }
2678 
2679 int
mime_hdr_print(HdrHeap *,MIMEHdrImpl * mh,char * buf_start,int buf_length,int * buf_index_inout,int * buf_chars_to_skip_inout)2680 mime_hdr_print(HdrHeap * /* heap ATS_UNUSED */, MIMEHdrImpl *mh, char *buf_start, int buf_length, int *buf_index_inout,
2681                int *buf_chars_to_skip_inout)
2682 {
2683   MIMEFieldBlockImpl *fblock;
2684   MIMEField *field;
2685   uint32_t index;
2686 
2687 #define SIMPLE_MIME_HDR_PRINT
2688 #ifdef SIMPLE_MIME_HDR_PRINT
2689   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
2690     for (index = 0; index < fblock->m_freetop; index++) {
2691       field = &(fblock->m_field_slots[index]);
2692       if (field->is_live()) {
2693         if (!mime_field_print(field, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout)) {
2694           return 0;
2695         }
2696       }
2697     }
2698   }
2699 #else
2700   // FIX: if not raw_printable, need to print with mime_field_print,
2701   //      not mime_mem_print
2702   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
2703     const char *contig_start = NULL;
2704     int this_length, contig_length = 0;
2705     for (index = 0; index < fblock->m_freetop; index++) {
2706       field       = &(fblock->m_field_slots[index]);
2707       this_length = field->m_len_name + field->m_len_value + field->m_n_v_raw_printable_pad;
2708       if (field->is_live()) {
2709         if ((field->m_ptr_name == contig_start + contig_length) && field->m_n_v_raw_printable &&
2710             ((buf_index_inout == NULL) || (contig_length + this_length <= buf_length - *buf_index_inout))) {
2711           contig_length += this_length;
2712         } else {
2713           if (contig_length > 0) {
2714             if (!mime_mem_print(contig_start, contig_length, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout))
2715               return 0;
2716           }
2717           contig_start  = field->m_ptr_name;
2718           contig_length = this_length;
2719         }
2720       }
2721     }
2722 
2723     if (contig_length > 0) {
2724       if (!mime_mem_print(contig_start, contig_length, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout))
2725         return 0;
2726     }
2727   }
2728 #endif
2729 
2730   if (!mime_mem_print("\r\n", 2, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout)) {
2731     return 0;
2732   }
2733 
2734   return 1;
2735 }
2736 
2737 namespace
2738 {
2739 int
mime_mem_print_(const char * src_d,int src_l,char * buf_start,int buf_length,int * buf_index_inout,int * buf_chars_to_skip_inout,int (* char_transform)(int char_in))2740 mime_mem_print_(const char *src_d, int src_l, char *buf_start, int buf_length, int *buf_index_inout, int *buf_chars_to_skip_inout,
2741                 int (*char_transform)(int char_in))
2742 {
2743   if (buf_start == nullptr) { // this case should only be used by test_header
2744     ink_release_assert(buf_index_inout == nullptr);
2745     ink_release_assert(buf_chars_to_skip_inout == nullptr);
2746     while (src_l--) {
2747       putchar(*src_d++);
2748     }
2749     return 1;
2750   }
2751 
2752   ink_assert(src_d != nullptr);
2753 
2754   if (*buf_chars_to_skip_inout > 0) {
2755     if (*buf_chars_to_skip_inout >= src_l) {
2756       *buf_chars_to_skip_inout -= src_l;
2757       return 1;
2758     } else {
2759       src_l -= *buf_chars_to_skip_inout;
2760       src_d += *buf_chars_to_skip_inout;
2761       *buf_chars_to_skip_inout = 0;
2762     }
2763   }
2764 
2765   int copy_l = std::min(buf_length - *buf_index_inout, src_l);
2766   if (copy_l > 0) {
2767     buf_start += *buf_index_inout;
2768     std::transform(src_d, src_d + copy_l, buf_start, char_transform);
2769     *buf_index_inout += copy_l;
2770   }
2771   return (src_l == copy_l);
2772 }
2773 
2774 int
to_same_char(int ch)2775 to_same_char(int ch)
2776 {
2777   return ch;
2778 }
2779 
2780 } // end anonymous namespace
2781 
2782 int
mime_mem_print(const char * src_d,int src_l,char * buf_start,int buf_length,int * buf_index_inout,int * buf_chars_to_skip_inout)2783 mime_mem_print(const char *src_d, int src_l, char *buf_start, int buf_length, int *buf_index_inout, int *buf_chars_to_skip_inout)
2784 {
2785   return mime_mem_print_(src_d, src_l, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout, to_same_char);
2786 }
2787 
2788 int
mime_mem_print_lc(const char * src_d,int src_l,char * buf_start,int buf_length,int * buf_index_inout,int * buf_chars_to_skip_inout)2789 mime_mem_print_lc(const char *src_d, int src_l, char *buf_start, int buf_length, int *buf_index_inout, int *buf_chars_to_skip_inout)
2790 {
2791   return mime_mem_print_(src_d, src_l, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout, std::tolower);
2792 }
2793 
2794 int
mime_field_print(MIMEField * field,char * buf_start,int buf_length,int * buf_index_inout,int * buf_chars_to_skip_inout)2795 mime_field_print(MIMEField *field, char *buf_start, int buf_length, int *buf_index_inout, int *buf_chars_to_skip_inout)
2796 {
2797 #define TRY(x) \
2798   if (!x)      \
2799   return 0
2800 
2801   int total_len;
2802 
2803   // Don't print names that begin with an '@'.
2804   if (field->m_ptr_name[0] == '@') {
2805     return 1;
2806   }
2807 
2808   if (field->m_n_v_raw_printable) {
2809     total_len = field->m_len_name + field->m_len_value + field->m_n_v_raw_printable_pad;
2810 
2811     if ((buf_start != nullptr) && (*buf_chars_to_skip_inout == 0) && (total_len <= (buf_length - *buf_index_inout))) {
2812       buf_start += *buf_index_inout;
2813       memcpy(buf_start, field->m_ptr_name, total_len);
2814       *buf_index_inout += total_len;
2815 
2816     } else {
2817       TRY(mime_mem_print(field->m_ptr_name, total_len, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
2818     }
2819   } else {
2820     total_len = field->m_len_name + field->m_len_value + 2 + 2;
2821 
2822     // try to handle on fast path
2823 
2824     if ((buf_start != nullptr) && (*buf_chars_to_skip_inout == 0) && (total_len <= (buf_length - *buf_index_inout))) {
2825       buf_start += *buf_index_inout;
2826 
2827       memcpy(buf_start, field->m_ptr_name, field->m_len_name);
2828       buf_start += field->m_len_name;
2829 
2830       buf_start[0] = ':';
2831       buf_start[1] = ' ';
2832       buf_start += 2;
2833 
2834       memcpy(buf_start, field->m_ptr_value, field->m_len_value);
2835       buf_start += field->m_len_value;
2836 
2837       buf_start[0] = '\r';
2838       buf_start[1] = '\n';
2839 
2840       *buf_index_inout += total_len;
2841     } else {
2842       TRY(mime_mem_print(field->m_ptr_name, field->m_len_name, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
2843       TRY(mime_mem_print(": ", 2, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
2844       TRY(mime_mem_print(field->m_ptr_value, field->m_len_value, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
2845       TRY(mime_mem_print("\r\n", 2, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
2846     }
2847   }
2848 
2849   return 1;
2850 
2851 #undef TRY
2852 }
2853 
2854 const char *
mime_str_u16_set(HdrHeap * heap,const char * s_str,int s_len,const char ** d_str,uint16_t * d_len,bool must_copy)2855 mime_str_u16_set(HdrHeap *heap, const char *s_str, int s_len, const char **d_str, uint16_t *d_len, bool must_copy)
2856 {
2857   ink_assert(s_len >= 0 && s_len < UINT16_MAX);
2858   // INKqa08287 - keep track of free string space.
2859   //  INVARIANT: passed in result pointers must be to
2860   //    either NULL or be valid ptr for a string already
2861   //    the string heaps
2862   heap->free_string(*d_str, *d_len);
2863 
2864   if (must_copy && s_str) {
2865     s_str = heap->duplicate_str(s_str, s_len);
2866   }
2867   *d_str = s_str;
2868   *d_len = s_len;
2869   return s_str;
2870 }
2871 
2872 int
mime_field_length_get(MIMEField * field)2873 mime_field_length_get(MIMEField *field)
2874 {
2875   if (field->m_n_v_raw_printable) {
2876     return (field->m_len_name + field->m_len_value + field->m_n_v_raw_printable_pad);
2877   } else {
2878     return (field->m_len_name + field->m_len_value + 4); // add ": \r\n"
2879   }
2880 }
2881 
2882 int
mime_format_int(char * buf,int32_t val,size_t buf_len)2883 mime_format_int(char *buf, int32_t val, size_t buf_len)
2884 {
2885   return ink_fast_itoa(val, buf, buf_len);
2886 }
2887 
2888 int
mime_format_uint(char * buf,uint32_t val,size_t buf_len)2889 mime_format_uint(char *buf, uint32_t val, size_t buf_len)
2890 {
2891   return ink_fast_uitoa(val, buf, buf_len);
2892 }
2893 
2894 int
mime_format_int64(char * buf,int64_t val,size_t buf_len)2895 mime_format_int64(char *buf, int64_t val, size_t buf_len)
2896 {
2897   return ink_fast_ltoa(val, buf, buf_len);
2898 }
2899 
2900 void
mime_days_since_epoch_to_mdy_slowcase(unsigned int days_since_jan_1_1970,int * m_return,int * d_return,int * y_return)2901 mime_days_since_epoch_to_mdy_slowcase(unsigned int days_since_jan_1_1970, int *m_return, int *d_return, int *y_return)
2902 {
2903   static const int DAYS_OFFSET = 25508;
2904 
2905   static const char months[] = {
2906     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
2907     2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
2908     4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
2909     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  6,
2910     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  7,
2911     7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  8,
2912     8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  9,  9,
2913     9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  10, 10,
2914     10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11,
2915     11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 0,  0,  0,
2916     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,
2917     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1};
2918 
2919   static const int days[12] = {305, 336, -1, 30, 60, 91, 121, 152, 183, 213, 244, 274};
2920 
2921   int mday, year, month, d, dp;
2922 
2923   mday = days_since_jan_1_1970;
2924 
2925   /* guess the year and refine the guess */
2926   year = mday / 365 + 69;
2927   d = dp = (year * 365) + (year / 4) - (year / 100) + (year / 100 + 3) / 4 - DAYS_OFFSET - 1;
2928 
2929   while (dp < mday) {
2930     d = dp;
2931     year += 1;
2932     dp = (year * 365) + (year / 4) - (year / 100) + (year / 100 + 3) / 4 - DAYS_OFFSET - 1;
2933   }
2934 
2935   /* convert the days */
2936   d = mday - d;
2937   if ((d < 0) || (d > 366)) {
2938     ink_assert(!"bad date");
2939   } else {
2940     month = months[d];
2941     if (month > 1) {
2942       year -= 1;
2943     }
2944 
2945     mday = d - days[month] - 1;
2946     year += 1900;
2947 
2948     *m_return = month;
2949     *d_return = mday;
2950     *y_return = year;
2951   }
2952 }
2953 
2954 void
mime_days_since_epoch_to_mdy(unsigned int days_since_jan_1_1970,int * m_return,int * d_return,int * y_return)2955 mime_days_since_epoch_to_mdy(unsigned int days_since_jan_1_1970, int *m_return, int *d_return, int *y_return)
2956 {
2957   ink_assert(_days_to_mdy_fast_lookup_table != nullptr);
2958 
2959   /////////////////////////////////////////////////////////////
2960   // if we have a fast lookup entry for this date, return it //
2961   /////////////////////////////////////////////////////////////
2962 
2963   if ((days_since_jan_1_1970 >= _days_to_mdy_fast_lookup_table_first_day) &&
2964       (days_since_jan_1_1970 <= _days_to_mdy_fast_lookup_table_last_day)) {
2965     ////////////////////////////////////////////////////////////////
2966     // to speed up the days_since_epoch to m/d/y conversion, we   //
2967     // use a pre-computed lookup table to support the common case //
2968     // of dates that are +/- one year from today.                 //
2969     ////////////////////////////////////////////////////////////////
2970 
2971     int i     = days_since_jan_1_1970 - _days_to_mdy_fast_lookup_table_first_day;
2972     *m_return = _days_to_mdy_fast_lookup_table[i].m;
2973     *d_return = _days_to_mdy_fast_lookup_table[i].d;
2974     *y_return = _days_to_mdy_fast_lookup_table[i].y;
2975     return;
2976   }
2977   ////////////////////////////////////
2978   // otherwise, return the slow way //
2979   ////////////////////////////////////
2980 
2981   mime_days_since_epoch_to_mdy_slowcase(days_since_jan_1_1970, m_return, d_return, y_return);
2982 }
2983 
2984 int
mime_format_date(char * buffer,time_t value)2985 mime_format_date(char *buffer, time_t value)
2986 {
2987   // must be 3 characters!
2988   static const char *daystrs[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
2989 
2990   // must be 3 characters!
2991   static const char *monthstrs[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
2992 
2993   static const char *digitstrs[] = {
2994     "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
2995     "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
2996     "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
2997     "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
2998     "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
2999   };
3000 
3001   char *buf;
3002   int sec, min, hour, wday, mday = 0, year = 0, month = 0;
3003 
3004   buf = buffer;
3005 
3006   sec = static_cast<int>(value % 60);
3007   value /= 60;
3008   min = static_cast<int>(value % 60);
3009   value /= 60;
3010   hour = static_cast<int>(value % 24);
3011   value /= 24;
3012 
3013   /* Jan 1, 1970 was a Thursday */
3014   wday = static_cast<int>((4 + value) % 7);
3015 
3016 /* value is days since Jan 1, 1970 */
3017 #if MIME_FORMAT_DATE_USE_LOOKUP_TABLE
3018   mime_days_since_epoch_to_mdy(value, &month, &mday, &year);
3019 #else
3020   mime_days_since_epoch_to_mdy_slowcase(value, &month, &mday, &year);
3021 #endif
3022 
3023   /* arrange the date in the buffer */
3024   ink_assert((mday >= 0) && (mday <= 99));
3025   ink_assert((hour >= 0) && (hour <= 99));
3026   ink_assert((min >= 0) && (min <= 99));
3027   ink_assert((sec >= 0) && (sec <= 99));
3028 
3029   /* the day string */
3030   const char *three_char_day = daystrs[wday];
3031   buf[0]                     = three_char_day[0];
3032   buf[1]                     = three_char_day[1];
3033   buf[2]                     = three_char_day[2];
3034   buf += 3;
3035 
3036   buf[0] = ',';
3037   buf[1] = ' ';
3038   buf += 2;
3039 
3040   /* the day of month */
3041   buf[0] = digitstrs[mday][0];
3042   buf[1] = digitstrs[mday][1];
3043   buf[2] = ' ';
3044   buf += 3;
3045 
3046   /* the month string */
3047   const char *three_char_month = monthstrs[month];
3048   buf[0]                       = three_char_month[0];
3049   buf[1]                       = three_char_month[1];
3050   buf[2]                       = three_char_month[2];
3051   buf += 3;
3052 
3053   /* the year */
3054   buf[0] = ' ';
3055 
3056   if ((year >= 2000) && (year <= 2009)) {
3057     buf[1] = '2';
3058     buf[2] = '0';
3059     buf[3] = '0';
3060     buf[4] = (year - 2000) + '0';
3061   } else if ((year >= 1990) && (year <= 1999)) {
3062     buf[1] = '1';
3063     buf[2] = '9';
3064     buf[3] = '9';
3065     buf[4] = (year - 1990) + '0';
3066   } else {
3067     buf[4] = (year % 10) + '0';
3068     year /= 10;
3069     buf[3] = (year % 10) + '0';
3070     year /= 10;
3071     buf[2] = (year % 10) + '0';
3072     year /= 10;
3073     buf[1] = (year % 10) + '0';
3074   }
3075   buf[5] = ' ';
3076   buf += 6;
3077 
3078   /* the hour */
3079   buf[0] = digitstrs[hour][0];
3080   buf[1] = digitstrs[hour][1];
3081   buf[2] = ':';
3082   buf += 3;
3083 
3084   /* the minute */
3085   buf[0] = digitstrs[min][0];
3086   buf[1] = digitstrs[min][1];
3087   buf[2] = ':';
3088   buf += 3;
3089 
3090   /* the second */
3091   buf[0] = digitstrs[sec][0];
3092   buf[1] = digitstrs[sec][1];
3093   buf[2] = ' ';
3094   buf += 3;
3095 
3096   /* the timezone string */
3097   buf[0] = 'G';
3098   buf[1] = 'M';
3099   buf[2] = 'T';
3100   buf[3] = '\0';
3101   buf += 3;
3102 
3103   return buf - buffer; // not counting NUL
3104 }
3105 
3106 int32_t
mime_parse_int(const char * buf,const char * end)3107 mime_parse_int(const char *buf, const char *end)
3108 {
3109   int32_t num;
3110   bool negative;
3111 
3112   if (!buf || (buf == end)) {
3113     return 0;
3114   }
3115 
3116   if (is_digit(*buf)) { // fast case
3117     num = *buf++ - '0';
3118     while ((buf != end) && is_digit(*buf)) {
3119       if (num != INT_MAX) {
3120         int new_num = (num * 10) + (*buf++ - '0');
3121 
3122         num = (new_num < num ? INT_MAX : new_num); // Check for overflow
3123       } else {
3124         ++buf; // Skip the remaining (valid) digits since we reached MAX/MIN_INT
3125       }
3126     }
3127 
3128     return num;
3129   } else {
3130     num      = 0;
3131     negative = false;
3132 
3133     while ((buf != end) && ParseRules::is_space(*buf)) {
3134       buf += 1;
3135     }
3136 
3137     if ((buf != end) && (*buf == '-')) {
3138       negative = true;
3139       buf += 1;
3140     }
3141     // NOTE: we first compute the value as negative then correct the
3142     // sign back to positive. This enables us to correctly parse MININT.
3143     while ((buf != end) && is_digit(*buf)) {
3144       if (num != INT_MIN) {
3145         int new_num = (num * 10) - (*buf++ - '0');
3146 
3147         num = (new_num > num ? INT_MIN : new_num); // Check for overflow, so to speak, see above re: negative
3148       } else {
3149         ++buf; // Skip the remaining (valid) digits since we reached MAX/MIN_INT
3150       }
3151     }
3152 
3153     if (!negative) {
3154       num = -num;
3155     }
3156 
3157     return num;
3158   }
3159 }
3160 
3161 uint32_t
mime_parse_uint(const char * buf,const char * end)3162 mime_parse_uint(const char *buf, const char *end)
3163 {
3164   uint32_t num;
3165 
3166   if (!buf || (buf == end)) {
3167     return 0;
3168   }
3169 
3170   if (is_digit(*buf)) // fast case
3171   {
3172     num = *buf++ - '0';
3173     while ((buf != end) && is_digit(*buf)) {
3174       num = (num * 10) + (*buf++ - '0');
3175     }
3176     return num;
3177   } else {
3178     num = 0;
3179     while ((buf != end) && ParseRules::is_space(*buf)) {
3180       buf += 1;
3181     }
3182     while ((buf != end) && is_digit(*buf)) {
3183       num = (num * 10) + (*buf++ - '0');
3184     }
3185     return num;
3186   }
3187 }
3188 
3189 int64_t
mime_parse_int64(const char * buf,const char * end)3190 mime_parse_int64(const char *buf, const char *end)
3191 {
3192   int64_t num;
3193   bool negative;
3194 
3195   if (!buf || (buf == end)) {
3196     return 0;
3197   }
3198 
3199   if (is_digit(*buf)) // fast case
3200   {
3201     num = *buf++ - '0';
3202     while ((buf != end) && is_digit(*buf)) {
3203       num = (num * 10) + (*buf++ - '0');
3204     }
3205     return num;
3206   } else {
3207     num      = 0;
3208     negative = false;
3209 
3210     while ((buf != end) && ParseRules::is_space(*buf)) {
3211       buf += 1;
3212     }
3213 
3214     if ((buf != end) && (*buf == '-')) {
3215       negative = true;
3216       buf += 1;
3217     }
3218     // NOTE: we first compute the value as negative then correct the
3219     // sign back to positive. This enables us to correctly parse MININT.
3220     while ((buf != end) && is_digit(*buf)) {
3221       num = (num * 10) - (*buf++ - '0');
3222     }
3223 
3224     if (!negative) {
3225       num = -num;
3226     }
3227 
3228     return num;
3229   }
3230 }
3231 
3232 /*-------------------------------------------------------------------------
3233 
3234   mime_parse_rfc822_date_fastcase (const char *buf, int length, struct tm *tp)
3235 
3236   This routine is a fast case parser for date strings that are guaranteed
3237   to be in the rfc822/rfc1123 format.  It uses integer binary searches to
3238   convert daya and month names into integral indices.
3239 
3240   This routine only supports rfc822/rfc1123 dates.  It must be called
3241   with NO leading whitespace, with a length >= 29 characters, and with
3242   a comma in buf[3].  The caller MUST ensure these conditions.
3243 
3244         Sun, 06 Nov 1994 08:49:37 GMT
3245         01234567890123456789012345678
3246 
3247   This function handles the common case dates fast.  The day and month
3248   are processed as 3 character integers before falling to DFA.  This
3249   table shows string, hash (24 bit values of 3 characters), and the
3250   resulting string index.
3251 
3252         Fri 0x467269 5    Apr 0x417072 3
3253         Mon 0x4D6F6E 1    Aug 0x417567 7
3254         Sat 0x536174 6    Dec 0x446563 11
3255         Sun 0x53756E 0    Feb 0x466562 1
3256         Thu 0x546875 4    Jan 0x4A616E 0
3257         Tue 0x547565 2    Jul 0x4A756C 6
3258         Wed 0x576564 3    Jun 0x4A756E 5
3259                           Mar 0x4D6172 2
3260                           May 0x4D6179 4
3261                           Nov 0x4E6F76 10
3262                           Oct 0x4F6374 9
3263                           Sep 0x536570 8
3264 
3265   -------------------------------------------------------------------------*/
3266 int
mime_parse_rfc822_date_fastcase(const char * buf,int length,struct tm * tp)3267 mime_parse_rfc822_date_fastcase(const char *buf, int length, struct tm *tp)
3268 {
3269   unsigned int three_char_wday, three_char_mon;
3270   std::string_view view{buf, size_t(length)};
3271 
3272   ink_assert(length >= 29);
3273   ink_assert(!is_ws(buf[0]));
3274   ink_assert(buf[3] == ',');
3275 
3276   ////////////////////////////
3277   // binary search for wday //
3278   ////////////////////////////
3279   tp->tm_wday     = -1;
3280   three_char_wday = (buf[0] << 16) | (buf[1] << 8) | buf[2];
3281   if (three_char_wday <= 0x53756E) {
3282     if (three_char_wday == 0x467269) {
3283       tp->tm_wday = 5;
3284     } else if (three_char_wday == 0x4D6F6E) {
3285       tp->tm_wday = 1;
3286     } else if (three_char_wday == 0x536174) {
3287       tp->tm_wday = 6;
3288     } else if (three_char_wday == 0x53756E) {
3289       tp->tm_wday = 0;
3290     }
3291   } else {
3292     if (three_char_wday == 0x546875) {
3293       tp->tm_wday = 4;
3294     } else if (three_char_wday == 0x547565) {
3295       tp->tm_wday = 2;
3296     } else if (three_char_wday == 0x576564) {
3297       tp->tm_wday = 3;
3298     }
3299   }
3300   if (tp->tm_wday < 0) {
3301     tp->tm_wday = day_names_dfa->match(view);
3302     if (tp->tm_wday < 0) {
3303       return 0;
3304     }
3305   }
3306   //////////////////////////
3307   // extract day of month //
3308   //////////////////////////
3309   tp->tm_mday = (buf[5] - '0') * 10 + (buf[6] - '0');
3310 
3311   /////////////////////////////
3312   // binary search for month //
3313   /////////////////////////////
3314   tp->tm_mon     = -1;
3315   three_char_mon = (buf[8] << 16) | (buf[9] << 8) | buf[10];
3316   if (three_char_mon <= 0x4A756C) {
3317     if (three_char_mon <= 0x446563) {
3318       if (three_char_mon == 0x417072) {
3319         tp->tm_mon = 3;
3320       } else if (three_char_mon == 0x417567) {
3321         tp->tm_mon = 7;
3322       } else if (three_char_mon == 0x446563) {
3323         tp->tm_mon = 11;
3324       }
3325     } else {
3326       if (three_char_mon == 0x466562) {
3327         tp->tm_mon = 1;
3328       } else if (three_char_mon == 0x4A616E) {
3329         tp->tm_mon = 0;
3330       } else if (three_char_mon == 0x4A756C) {
3331         tp->tm_mon = 6;
3332       }
3333     }
3334   } else {
3335     if (three_char_mon <= 0x4D6179) {
3336       if (three_char_mon == 0x4A756E) {
3337         tp->tm_mon = 5;
3338       } else if (three_char_mon == 0x4D6172) {
3339         tp->tm_mon = 2;
3340       } else if (three_char_mon == 0x4D6179) {
3341         tp->tm_mon = 4;
3342       }
3343     } else {
3344       if (three_char_mon == 0x4E6F76) {
3345         tp->tm_mon = 10;
3346       } else if (three_char_mon == 0x4F6374) {
3347         tp->tm_mon = 9;
3348       } else if (three_char_mon == 0x536570) {
3349         tp->tm_mon = 8;
3350       }
3351     }
3352   }
3353   if (tp->tm_mon < 0) {
3354     tp->tm_mon = month_names_dfa->match(view);
3355     if (tp->tm_mon < 0) {
3356       return 0;
3357     }
3358   }
3359   //////////////////
3360   // extract year //
3361   //////////////////
3362   tp->tm_year = ((buf[12] - '0') * 1000 + (buf[13] - '0') * 100 + (buf[14] - '0') * 10 + (buf[15] - '0')) - 1900;
3363 
3364   //////////////////
3365   // extract time //
3366   //////////////////
3367   tp->tm_hour = (buf[17] - '0') * 10 + (buf[18] - '0');
3368   tp->tm_min  = (buf[20] - '0') * 10 + (buf[21] - '0');
3369   tp->tm_sec  = (buf[23] - '0') * 10 + (buf[24] - '0');
3370   if ((buf[19] != ':') || (buf[22] != ':')) {
3371     return 0;
3372   }
3373   return 1;
3374 }
3375 
3376 /*-------------------------------------------------------------------------
3377    Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
3378    Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
3379    Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
3380    6 Nov 1994 08:49:37 GMT        ; NNTP-style date
3381   -------------------------------------------------------------------------*/
3382 time_t
mime_parse_date(const char * buf,const char * end)3383 mime_parse_date(const char *buf, const char *end)
3384 {
3385   static const int DAYS_OFFSET = 25508;
3386   static const int days[12]    = {305, 336, -1, 30, 60, 91, 121, 152, 183, 213, 244, 274};
3387 
3388   struct tm tp;
3389   time_t t;
3390   int year;
3391   int month;
3392   int mday;
3393 
3394   if (!buf) {
3395     return static_cast<time_t>(0);
3396   }
3397 
3398   while ((buf != end) && is_ws(*buf)) {
3399     buf += 1;
3400   }
3401 
3402   if ((buf != end) && is_digit(*buf)) { // NNTP date
3403     if (!mime_parse_mday(buf, end, &tp.tm_mday)) {
3404       return static_cast<time_t>(0);
3405     }
3406     if (!mime_parse_month(buf, end, &tp.tm_mon)) {
3407       return static_cast<time_t>(0);
3408     }
3409     if (!mime_parse_year(buf, end, &tp.tm_year)) {
3410       return static_cast<time_t>(0);
3411     }
3412     if (!mime_parse_time(buf, end, &tp.tm_hour, &tp.tm_min, &tp.tm_sec)) {
3413       return static_cast<time_t>(0);
3414     }
3415   } else if (end && (end - buf >= 29) && (buf[3] == ',')) {
3416     if (!mime_parse_rfc822_date_fastcase(buf, end - buf, &tp)) {
3417       return static_cast<time_t>(0);
3418     }
3419   } else {
3420     if (!mime_parse_day(buf, end, &tp.tm_wday)) {
3421       return static_cast<time_t>(0);
3422     }
3423 
3424     while ((buf != end) && is_ws(*buf)) {
3425       buf += 1;
3426     }
3427 
3428     if ((buf != end) && ((*buf == ',') || is_digit(*buf))) {
3429       // RFC 822 or RFC 850 time format
3430       if (!mime_parse_mday(buf, end, &tp.tm_mday)) {
3431         return static_cast<time_t>(0);
3432       }
3433       if (!mime_parse_month(buf, end, &tp.tm_mon)) {
3434         return static_cast<time_t>(0);
3435       }
3436       if (!mime_parse_year(buf, end, &tp.tm_year)) {
3437         return static_cast<time_t>(0);
3438       }
3439       if (!mime_parse_time(buf, end, &tp.tm_hour, &tp.tm_min, &tp.tm_sec)) {
3440         return static_cast<time_t>(0);
3441       }
3442       // ignore timezone specifier...should always be GMT anyways
3443     } else {
3444       // ANSI C's asctime format
3445       if (!mime_parse_month(buf, end, &tp.tm_mon)) {
3446         return static_cast<time_t>(0);
3447       }
3448       if (!mime_parse_mday(buf, end, &tp.tm_mday)) {
3449         return static_cast<time_t>(0);
3450       }
3451       if (!mime_parse_time(buf, end, &tp.tm_hour, &tp.tm_min, &tp.tm_sec)) {
3452         return static_cast<time_t>(0);
3453       }
3454       if (!mime_parse_year(buf, end, &tp.tm_year)) {
3455         return static_cast<time_t>(0);
3456       }
3457     }
3458   }
3459 
3460   year  = tp.tm_year;
3461   month = tp.tm_mon;
3462   mday  = tp.tm_mday;
3463 
3464   // what should we do?
3465   if (year > 137) {
3466     return static_cast<time_t>(INT_MAX);
3467   }
3468   if (year < 70) {
3469     return static_cast<time_t>(0);
3470   }
3471 
3472   mday += days[month];
3473   /* month base == march */
3474   if (month < 2) {
3475     year -= 1;
3476   }
3477   mday += (year * 365) + (year / 4) - (year / 100) + (year / 100 + 3) / 4;
3478   mday -= DAYS_OFFSET;
3479 
3480   t = ((mday * 24 + tp.tm_hour) * 60 + tp.tm_min) * 60 + tp.tm_sec;
3481 
3482   return t;
3483 }
3484 
3485 bool
mime_parse_day(const char * & buf,const char * end,int * day)3486 mime_parse_day(const char *&buf, const char *end, int *day)
3487 {
3488   const char *e;
3489 
3490   while ((buf != end) && *buf && !ParseRules::is_alpha(*buf)) {
3491     buf += 1;
3492   }
3493 
3494   e = buf;
3495   while ((e != end) && *e && ParseRules::is_alpha(*e)) {
3496     e += 1;
3497   }
3498 
3499   *day = day_names_dfa->match({buf, size_t(e - buf)});
3500   if (*day < 0) {
3501     return false;
3502   } else {
3503     buf = e;
3504     return true;
3505   }
3506 }
3507 
3508 bool
mime_parse_month(const char * & buf,const char * end,int * month)3509 mime_parse_month(const char *&buf, const char *end, int *month)
3510 {
3511   const char *e;
3512 
3513   while ((buf != end) && *buf && !ParseRules::is_alpha(*buf)) {
3514     buf += 1;
3515   }
3516 
3517   e = buf;
3518   while ((e != end) && *e && ParseRules::is_alpha(*e)) {
3519     e += 1;
3520   }
3521 
3522   *month = month_names_dfa->match({buf, size_t(e - buf)});
3523   if (*month < 0) {
3524     return false;
3525   } else {
3526     buf = e;
3527     return true;
3528   }
3529 }
3530 
3531 bool
mime_parse_mday(const char * & buf,const char * end,int * mday)3532 mime_parse_mday(const char *&buf, const char *end, int *mday)
3533 {
3534   return mime_parse_integer(buf, end, mday);
3535 }
3536 
3537 bool
mime_parse_year(const char * & buf,const char * end,int * year)3538 mime_parse_year(const char *&buf, const char *end, int *year)
3539 {
3540   int val;
3541 
3542   while ((buf != end) && *buf && !is_digit(*buf)) {
3543     buf += 1;
3544   }
3545 
3546   if ((buf == end) || (*buf == '\0')) {
3547     return false;
3548   }
3549 
3550   val = 0;
3551 
3552   while ((buf != end) && *buf && is_digit(*buf)) {
3553     val = (val * 10) + (*buf++ - '0');
3554   }
3555 
3556   if (val >= 1900) {
3557     val -= 1900;
3558   } else if (val < 70) {
3559     val += 100;
3560   }
3561 
3562   *year = val;
3563 
3564   return true;
3565 }
3566 
3567 bool
mime_parse_time(const char * & buf,const char * end,int * hour,int * min,int * sec)3568 mime_parse_time(const char *&buf, const char *end, int *hour, int *min, int *sec)
3569 {
3570   if (!mime_parse_integer(buf, end, hour)) {
3571     return false;
3572   }
3573   if (!mime_parse_integer(buf, end, min)) {
3574     return false;
3575   }
3576   if (!mime_parse_integer(buf, end, sec)) {
3577     return false;
3578   }
3579   return true;
3580 }
3581 
3582 // This behaves slightly different than mime_parse_int(), int that we actually
3583 // return a "bool" for success / failure on "reasonable" parsing. This kinda
3584 // dumb, because we have two interfaces, where one does not move along the
3585 // buf pointer, but this one does (and the ones using this function do).
3586 bool
mime_parse_integer(const char * & buf,const char * end,int * integer)3587 mime_parse_integer(const char *&buf, const char *end, int *integer)
3588 {
3589   while ((buf != end) && *buf && !is_digit(*buf) && (*buf != '-')) {
3590     buf += 1;
3591   }
3592 
3593   if ((buf == end) || (*buf == '\0')) {
3594     return false;
3595   }
3596 
3597   int32_t num;
3598   bool negative;
3599 
3600   // This code is copied verbatim from mime_parse_int ... Sigh. Maybe amc is right, and
3601   // we really need to clean this up. But, as such, we should redo all these interfaces,
3602   // and that's a big undertaking (and we'd want to move these strings all to string_view's).
3603   if (is_digit(*buf)) { // fast case
3604     num = *buf++ - '0';
3605     while ((buf != end) && is_digit(*buf)) {
3606       if (num != INT_MAX) {
3607         int new_num = (num * 10) + (*buf++ - '0');
3608 
3609         num = (new_num < num ? INT_MAX : new_num); // Check for overflow
3610       } else {
3611         ++buf; // Skip the remaining (valid) digits since we reached MAX/MIN_INT
3612       }
3613     }
3614   } else {
3615     num      = 0;
3616     negative = false;
3617 
3618     while ((buf != end) && ParseRules::is_space(*buf)) {
3619       buf += 1;
3620     }
3621 
3622     if ((buf != end) && (*buf == '-')) {
3623       negative = true;
3624       buf += 1;
3625     }
3626     // NOTE: we first compute the value as negative then correct the
3627     // sign back to positive. This enables us to correctly parse MININT.
3628     while ((buf != end) && is_digit(*buf)) {
3629       if (num != INT_MIN) {
3630         int new_num = (num * 10) - (*buf++ - '0');
3631 
3632         num = (new_num > num ? INT_MIN : new_num); // Check for overflow, so to speak, see above re: negative
3633       } else {
3634         ++buf; // Skip the remaining (valid) digits since we reached MAX/MIN_INT
3635       }
3636     }
3637 
3638     if (!negative) {
3639       num = -num;
3640     }
3641   }
3642 
3643   *integer = num;
3644 
3645   return true;
3646 }
3647 
3648 /***********************************************************************
3649  *                                                                     *
3650  *                        M A R S H A L I N G                          *
3651  *                                                                     *
3652  ***********************************************************************/
3653 int
marshal(MarshalXlate * ptr_xlate,int num_ptr,MarshalXlate * str_xlate,int num_str)3654 MIMEFieldBlockImpl::marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str)
3655 {
3656   // printf("FieldBlockImpl:marshal  num_ptr = %d  num_str = %d\n", num_ptr, num_str);
3657   HDR_MARSHAL_PTR(m_next, MIMEFieldBlockImpl, ptr_xlate, num_ptr);
3658 
3659   if ((num_str == 1) && (num_ptr == 1)) {
3660     for (uint32_t index = 0; index < m_freetop; index++) {
3661       MIMEField *field = &(m_field_slots[index]);
3662 
3663       if (field->is_live()) {
3664         HDR_MARSHAL_STR_1(field->m_ptr_name, str_xlate);
3665         HDR_MARSHAL_STR_1(field->m_ptr_value, str_xlate);
3666         if (field->m_next_dup) {
3667           HDR_MARSHAL_PTR_1(field->m_next_dup, MIMEField, ptr_xlate);
3668         }
3669       }
3670     }
3671   } else {
3672     for (uint32_t index = 0; index < m_freetop; index++) {
3673       MIMEField *field = &(m_field_slots[index]);
3674 
3675       if (field->is_live()) {
3676         HDR_MARSHAL_STR(field->m_ptr_name, str_xlate, num_str);
3677         HDR_MARSHAL_STR(field->m_ptr_value, str_xlate, num_str);
3678         if (field->m_next_dup) {
3679           HDR_MARSHAL_PTR(field->m_next_dup, MIMEField, ptr_xlate, num_ptr);
3680         }
3681       }
3682     }
3683   }
3684   return 0;
3685 }
3686 
3687 void
unmarshal(intptr_t offset)3688 MIMEFieldBlockImpl::unmarshal(intptr_t offset)
3689 {
3690   HDR_UNMARSHAL_PTR(m_next, MIMEFieldBlockImpl, offset);
3691 
3692   for (uint32_t index = 0; index < m_freetop; index++) {
3693     MIMEField *field = &(m_field_slots[index]);
3694 
3695     if (field->is_live()) {
3696       HDR_UNMARSHAL_STR(field->m_ptr_name, offset);
3697       HDR_UNMARSHAL_STR(field->m_ptr_value, offset);
3698       if (field->m_next_dup) {
3699         HDR_UNMARSHAL_PTR(field->m_next_dup, MIMEField, offset);
3700       }
3701     } else {
3702       // Clear out other types of slots
3703       field->m_readiness = MIME_FIELD_SLOT_READINESS_EMPTY;
3704     }
3705   }
3706 }
3707 
3708 void
move_strings(HdrStrHeap * new_heap)3709 MIMEFieldBlockImpl::move_strings(HdrStrHeap *new_heap)
3710 {
3711   for (uint32_t index = 0; index < m_freetop; index++) {
3712     MIMEField *field = &(m_field_slots[index]);
3713 
3714     if (field->is_live() || field->is_detached()) {
3715       // FIX ME - Should do the field in one shot and preserve
3716       //   raw_printable if it's set
3717       field->m_n_v_raw_printable = 0;
3718 
3719       HDR_MOVE_STR(field->m_ptr_name, field->m_len_name);
3720       HDR_MOVE_STR(field->m_ptr_value, field->m_len_value);
3721     }
3722   }
3723 }
3724 
3725 size_t
strings_length()3726 MIMEFieldBlockImpl::strings_length()
3727 {
3728   size_t ret = 0;
3729 
3730   for (uint32_t index = 0; index < m_freetop; index++) {
3731     MIMEField *field = &(m_field_slots[index]);
3732 
3733     if (field->m_readiness == MIME_FIELD_SLOT_READINESS_LIVE || field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED) {
3734       ret += field->m_len_name;
3735       ret += field->m_len_value;
3736     }
3737   }
3738   return ret;
3739 }
3740 
3741 bool
contains(const MIMEField * field)3742 MIMEFieldBlockImpl::contains(const MIMEField *field)
3743 {
3744   MIMEField *first = &(m_field_slots[0]);
3745   MIMEField *last  = &(m_field_slots[MIME_FIELD_BLOCK_SLOTS - 1]);
3746   return (field >= first) && (field <= last);
3747 }
3748 
3749 void
check_strings(HeapCheck * heaps,int num_heaps)3750 MIMEFieldBlockImpl::check_strings(HeapCheck *heaps, int num_heaps)
3751 {
3752   for (uint32_t index = 0; index < m_freetop; index++) {
3753     MIMEField *field = &(m_field_slots[index]);
3754 
3755     if (field->is_live() || field->is_detached()) {
3756       // FIX ME - Should check raw printing characters as well
3757       CHECK_STR(field->m_ptr_name, field->m_len_name, heaps, num_heaps);
3758       CHECK_STR(field->m_ptr_value, field->m_len_value, heaps, num_heaps);
3759     }
3760   }
3761 }
3762 
3763 int
marshal(MarshalXlate * ptr_xlate,int num_ptr,MarshalXlate * str_xlate,int num_str)3764 MIMEHdrImpl::marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str)
3765 {
3766   // printf("MIMEHdrImpl:marshal  num_ptr = %d  num_str = %d\n", num_ptr, num_str);
3767   HDR_MARSHAL_PTR(m_fblock_list_tail, MIMEFieldBlockImpl, ptr_xlate, num_ptr);
3768   return m_first_fblock.marshal(ptr_xlate, num_ptr, str_xlate, num_str);
3769 }
3770 
3771 void
unmarshal(intptr_t offset)3772 MIMEHdrImpl::unmarshal(intptr_t offset)
3773 {
3774   HDR_UNMARSHAL_PTR(m_fblock_list_tail, MIMEFieldBlockImpl, offset);
3775   m_first_fblock.unmarshal(offset);
3776 }
3777 
3778 void
move_strings(HdrStrHeap * new_heap)3779 MIMEHdrImpl::move_strings(HdrStrHeap *new_heap)
3780 {
3781   m_first_fblock.move_strings(new_heap);
3782 }
3783 
3784 size_t
strings_length()3785 MIMEHdrImpl::strings_length()
3786 {
3787   return m_first_fblock.strings_length();
3788 }
3789 
3790 void
check_strings(HeapCheck * heaps,int num_heaps)3791 MIMEHdrImpl::check_strings(HeapCheck *heaps, int num_heaps)
3792 {
3793   m_first_fblock.check_strings(heaps, num_heaps);
3794 }
3795 
3796 void
recompute_accelerators_and_presence_bits()3797 MIMEHdrImpl::recompute_accelerators_and_presence_bits()
3798 {
3799   mime_hdr_reset_accelerators_and_presence_bits(this);
3800 }
3801 
3802 /***********************************************************************
3803  *                                                                     *
3804  *                 C O O K E D    V A L U E    C A C H E               *
3805  *                                                                     *
3806  ***********************************************************************/
3807 
3808 ////////////////////////////////////////////////////////
3809 // we need to recook the cooked values cache when:    //
3810 //                                                    //
3811 //      setting the value and the field is live       //
3812 //      attaching the field and the field isn't empty //
3813 //      detaching the field                           //
3814 ////////////////////////////////////////////////////////
3815 
3816 void
recompute_cooked_stuff(MIMEField * changing_field_or_null)3817 MIMEHdrImpl::recompute_cooked_stuff(MIMEField *changing_field_or_null)
3818 {
3819   int len, tlen;
3820   const char *s;
3821   const char *c;
3822   const char *e;
3823   const char *token_wks;
3824   MIMEField *field;
3825   uint32_t mask = 0;
3826 
3827   mime_hdr_cooked_stuff_init(this, changing_field_or_null);
3828 
3829   //////////////////////////////////////////////////
3830   // (1) cook the Cache-Control header if present //
3831   //////////////////////////////////////////////////
3832 
3833   // to be safe, recompute unless you know this call is for other cooked field
3834   if ((changing_field_or_null == nullptr) || (changing_field_or_null->m_wks_idx != MIME_WKSIDX_PRAGMA)) {
3835     field = mime_hdr_field_find(this, MIME_FIELD_CACHE_CONTROL, MIME_LEN_CACHE_CONTROL);
3836 
3837     if (field) {
3838       // try pathpaths first -- unlike most other fastpaths, this one
3839       // is probably more useful for polygraph than for the real world
3840       if (!field->has_dups()) {
3841         s = field->value_get(&len);
3842         if (ptr_len_casecmp(s, len, "public", 6) == 0) {
3843           mask = MIME_COOKED_MASK_CC_PUBLIC;
3844           m_cooked_stuff.m_cache_control.m_mask |= mask;
3845         } else if (ptr_len_casecmp(s, len, "private,no-cache", 16) == 0) {
3846           mask = MIME_COOKED_MASK_CC_PRIVATE | MIME_COOKED_MASK_CC_NO_CACHE;
3847           m_cooked_stuff.m_cache_control.m_mask |= mask;
3848         }
3849       }
3850 
3851       if (mask == 0) {
3852         HdrCsvIter csv_iter;
3853 
3854         for (s = csv_iter.get_first(field, &len); s != nullptr; s = csv_iter.get_next(&len)) {
3855           e = s + len;
3856           for (c = s; (c < e) && (ParseRules::is_token(*c)); c++) {
3857             ;
3858           }
3859           tlen = c - s;
3860 
3861           // If >= 0 then this is a well known token
3862           if (hdrtoken_tokenize(s, tlen, &token_wks) >= 0) {
3863 #if TRACK_COOKING
3864             Debug("http", "recompute_cooked_stuff: got field '%s'", token_wks);
3865 #endif
3866 
3867             HdrTokenHeapPrefix *p = hdrtoken_wks_to_prefix(token_wks);
3868             mask                  = p->wks_type_specific.u.cache_control.cc_mask;
3869             m_cooked_stuff.m_cache_control.m_mask |= mask;
3870 
3871 #if TRACK_COOKING
3872             Debug("http", "                        set mask 0x%0X", mask);
3873 #endif
3874 
3875             if (mask & (MIME_COOKED_MASK_CC_MAX_AGE | MIME_COOKED_MASK_CC_S_MAXAGE | MIME_COOKED_MASK_CC_MAX_STALE |
3876                         MIME_COOKED_MASK_CC_MIN_FRESH)) {
3877               int value;
3878 
3879               if (mime_parse_integer(c, e, &value)) {
3880 #if TRACK_COOKING
3881                 Debug("http", "                        set integer value %d", value);
3882 #endif
3883                 if (token_wks == MIME_VALUE_MAX_AGE) {
3884                   m_cooked_stuff.m_cache_control.m_secs_max_age = value;
3885                 } else if (token_wks == MIME_VALUE_MIN_FRESH) {
3886                   m_cooked_stuff.m_cache_control.m_secs_min_fresh = value;
3887                 } else if (token_wks == MIME_VALUE_MAX_STALE) {
3888                   m_cooked_stuff.m_cache_control.m_secs_max_stale = value;
3889                 } else if (token_wks == MIME_VALUE_S_MAXAGE) {
3890                   m_cooked_stuff.m_cache_control.m_secs_s_maxage = value;
3891                 }
3892               } else {
3893 #if TRACK_COOKING
3894                 Debug("http", "                        set integer value %d", INT_MAX);
3895 #endif
3896                 if (token_wks == MIME_VALUE_MAX_STALE) {
3897                   m_cooked_stuff.m_cache_control.m_secs_max_stale = INT_MAX;
3898                 }
3899               }
3900             }
3901           }
3902         }
3903       }
3904     }
3905   }
3906   ///////////////////////////////////////////
3907   // (2) cook the Pragma header if present //
3908   ///////////////////////////////////////////
3909 
3910   if ((changing_field_or_null == nullptr) || (changing_field_or_null->m_wks_idx != MIME_WKSIDX_CACHE_CONTROL)) {
3911     field = mime_hdr_field_find(this, MIME_FIELD_PRAGMA, MIME_LEN_PRAGMA);
3912     if (field) {
3913       if (!field->has_dups()) { // try fastpath first
3914         s = field->value_get(&len);
3915         if (ptr_len_casecmp(s, len, "no-cache", 8) == 0) {
3916           m_cooked_stuff.m_pragma.m_no_cache = true;
3917           return;
3918         }
3919       }
3920 
3921       {
3922         HdrCsvIter csv_iter;
3923 
3924         for (s = csv_iter.get_first(field, &len); s != nullptr; s = csv_iter.get_next(&len)) {
3925           e = s + len;
3926           for (c = s; (c < e) && (ParseRules::is_token(*c)); c++) {
3927             ;
3928           }
3929           tlen = c - s;
3930 
3931           if (hdrtoken_tokenize(s, tlen, &token_wks) >= 0) {
3932             if (token_wks == MIME_VALUE_NO_CACHE) {
3933               m_cooked_stuff.m_pragma.m_no_cache = true;
3934             }
3935           }
3936         }
3937       }
3938     }
3939   }
3940 }
3941