xref: /trafficserver/proxy/hdrs/MIME.cc (revision 8236813e)
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 DEBUG
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 = (const char *)(field->m_next_dup);
634             if ((addr >= (const char *)(blk)) && (addr < (const char *)(blk) + sizeof(MIMEFieldBlockImpl))) {
635               found = true;
636               break;
637             }
638           }
639           ink_release_assert(found);
640         }
641         // re-find the field --- should always find the head dup
642         MIMEField *mf = mime_hdr_field_find(mh, field->m_ptr_name, field->m_len_name);
643         ink_release_assert(mf != nullptr);
644         if (mf == field) {
645           ink_release_assert((field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD) != 0);
646         } else {
647           ink_release_assert((field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD) == 0);
648         }
649       }
650 
651       ++slot_index;
652     }
653     last_fblock = fblock;
654   }
655 
656   ink_release_assert(last_fblock == mh->m_fblock_list_tail);
657   ink_release_assert(masksum == mh->m_presence_bits);
658 }
659 #endif
660 
661 void
mime_init()662 mime_init()
663 {
664   static int init = 1;
665 
666   if (init) {
667     init = 0;
668 
669     hdrtoken_init();
670     day_names_dfa = new DFA;
671     day_names_dfa->compile(day_names, SIZEOF(day_names), RE_CASE_INSENSITIVE);
672 
673     month_names_dfa = new DFA;
674     month_names_dfa->compile(month_names, SIZEOF(month_names), RE_CASE_INSENSITIVE);
675 
676     MIME_FIELD_ACCEPT                    = hdrtoken_string_to_wks("Accept");
677     MIME_FIELD_ACCEPT_CHARSET            = hdrtoken_string_to_wks("Accept-Charset");
678     MIME_FIELD_ACCEPT_ENCODING           = hdrtoken_string_to_wks("Accept-Encoding");
679     MIME_FIELD_ACCEPT_LANGUAGE           = hdrtoken_string_to_wks("Accept-Language");
680     MIME_FIELD_ACCEPT_RANGES             = hdrtoken_string_to_wks("Accept-Ranges");
681     MIME_FIELD_AGE                       = hdrtoken_string_to_wks("Age");
682     MIME_FIELD_ALLOW                     = hdrtoken_string_to_wks("Allow");
683     MIME_FIELD_APPROVED                  = hdrtoken_string_to_wks("Approved");
684     MIME_FIELD_AUTHORIZATION             = hdrtoken_string_to_wks("Authorization");
685     MIME_FIELD_BYTES                     = hdrtoken_string_to_wks("Bytes");
686     MIME_FIELD_CACHE_CONTROL             = hdrtoken_string_to_wks("Cache-Control");
687     MIME_FIELD_CLIENT_IP                 = hdrtoken_string_to_wks("Client-ip");
688     MIME_FIELD_CONNECTION                = hdrtoken_string_to_wks("Connection");
689     MIME_FIELD_CONTENT_BASE              = hdrtoken_string_to_wks("Content-Base");
690     MIME_FIELD_CONTENT_ENCODING          = hdrtoken_string_to_wks("Content-Encoding");
691     MIME_FIELD_CONTENT_LANGUAGE          = hdrtoken_string_to_wks("Content-Language");
692     MIME_FIELD_CONTENT_LENGTH            = hdrtoken_string_to_wks("Content-Length");
693     MIME_FIELD_CONTENT_LOCATION          = hdrtoken_string_to_wks("Content-Location");
694     MIME_FIELD_CONTENT_MD5               = hdrtoken_string_to_wks("Content-MD5");
695     MIME_FIELD_CONTENT_RANGE             = hdrtoken_string_to_wks("Content-Range");
696     MIME_FIELD_CONTENT_TYPE              = hdrtoken_string_to_wks("Content-Type");
697     MIME_FIELD_CONTROL                   = hdrtoken_string_to_wks("Control");
698     MIME_FIELD_COOKIE                    = hdrtoken_string_to_wks("Cookie");
699     MIME_FIELD_DATE                      = hdrtoken_string_to_wks("Date");
700     MIME_FIELD_DISTRIBUTION              = hdrtoken_string_to_wks("Distribution");
701     MIME_FIELD_ETAG                      = hdrtoken_string_to_wks("Etag");
702     MIME_FIELD_EXPECT                    = hdrtoken_string_to_wks("Expect");
703     MIME_FIELD_EXPIRES                   = hdrtoken_string_to_wks("Expires");
704     MIME_FIELD_FOLLOWUP_TO               = hdrtoken_string_to_wks("Followup-To");
705     MIME_FIELD_FROM                      = hdrtoken_string_to_wks("From");
706     MIME_FIELD_HOST                      = hdrtoken_string_to_wks("Host");
707     MIME_FIELD_IF_MATCH                  = hdrtoken_string_to_wks("If-Match");
708     MIME_FIELD_IF_MODIFIED_SINCE         = hdrtoken_string_to_wks("If-Modified-Since");
709     MIME_FIELD_IF_NONE_MATCH             = hdrtoken_string_to_wks("If-None-Match");
710     MIME_FIELD_IF_RANGE                  = hdrtoken_string_to_wks("If-Range");
711     MIME_FIELD_IF_UNMODIFIED_SINCE       = hdrtoken_string_to_wks("If-Unmodified-Since");
712     MIME_FIELD_KEEP_ALIVE                = hdrtoken_string_to_wks("Keep-Alive");
713     MIME_FIELD_KEYWORDS                  = hdrtoken_string_to_wks("Keywords");
714     MIME_FIELD_LAST_MODIFIED             = hdrtoken_string_to_wks("Last-Modified");
715     MIME_FIELD_LINES                     = hdrtoken_string_to_wks("Lines");
716     MIME_FIELD_LOCATION                  = hdrtoken_string_to_wks("Location");
717     MIME_FIELD_MAX_FORWARDS              = hdrtoken_string_to_wks("Max-Forwards");
718     MIME_FIELD_MESSAGE_ID                = hdrtoken_string_to_wks("Message-ID");
719     MIME_FIELD_NEWSGROUPS                = hdrtoken_string_to_wks("Newsgroups");
720     MIME_FIELD_ORGANIZATION              = hdrtoken_string_to_wks("Organization");
721     MIME_FIELD_PATH                      = hdrtoken_string_to_wks("Path");
722     MIME_FIELD_PRAGMA                    = hdrtoken_string_to_wks("Pragma");
723     MIME_FIELD_PROXY_AUTHENTICATE        = hdrtoken_string_to_wks("Proxy-Authenticate");
724     MIME_FIELD_PROXY_AUTHORIZATION       = hdrtoken_string_to_wks("Proxy-Authorization");
725     MIME_FIELD_PROXY_CONNECTION          = hdrtoken_string_to_wks("Proxy-Connection");
726     MIME_FIELD_PUBLIC                    = hdrtoken_string_to_wks("Public");
727     MIME_FIELD_RANGE                     = hdrtoken_string_to_wks("Range");
728     MIME_FIELD_REFERENCES                = hdrtoken_string_to_wks("References");
729     MIME_FIELD_REFERER                   = hdrtoken_string_to_wks("Referer");
730     MIME_FIELD_REPLY_TO                  = hdrtoken_string_to_wks("Reply-To");
731     MIME_FIELD_RETRY_AFTER               = hdrtoken_string_to_wks("Retry-After");
732     MIME_FIELD_SENDER                    = hdrtoken_string_to_wks("Sender");
733     MIME_FIELD_SERVER                    = hdrtoken_string_to_wks("Server");
734     MIME_FIELD_SET_COOKIE                = hdrtoken_string_to_wks("Set-Cookie");
735     MIME_FIELD_STRICT_TRANSPORT_SECURITY = hdrtoken_string_to_wks("Strict-Transport-Security");
736     MIME_FIELD_SUBJECT                   = hdrtoken_string_to_wks("Subject");
737     MIME_FIELD_SUMMARY                   = hdrtoken_string_to_wks("Summary");
738     MIME_FIELD_TE                        = hdrtoken_string_to_wks("TE");
739     MIME_FIELD_TRANSFER_ENCODING         = hdrtoken_string_to_wks("Transfer-Encoding");
740     MIME_FIELD_UPGRADE                   = hdrtoken_string_to_wks("Upgrade");
741     MIME_FIELD_USER_AGENT                = hdrtoken_string_to_wks("User-Agent");
742     MIME_FIELD_VARY                      = hdrtoken_string_to_wks("Vary");
743     MIME_FIELD_VIA                       = hdrtoken_string_to_wks("Via");
744     MIME_FIELD_WARNING                   = hdrtoken_string_to_wks("Warning");
745     MIME_FIELD_WWW_AUTHENTICATE          = hdrtoken_string_to_wks("Www-Authenticate");
746     MIME_FIELD_XREF                      = hdrtoken_string_to_wks("Xref");
747     MIME_FIELD_ATS_INTERNAL              = hdrtoken_string_to_wks("@Ats-Internal");
748     MIME_FIELD_X_ID                      = hdrtoken_string_to_wks("X-ID");
749     MIME_FIELD_X_FORWARDED_FOR           = hdrtoken_string_to_wks("X-Forwarded-For");
750     MIME_FIELD_FORWARDED                 = hdrtoken_string_to_wks("Forwarded");
751     MIME_FIELD_SEC_WEBSOCKET_KEY         = hdrtoken_string_to_wks("Sec-WebSocket-Key");
752     MIME_FIELD_SEC_WEBSOCKET_VERSION     = hdrtoken_string_to_wks("Sec-WebSocket-Version");
753     MIME_FIELD_HTTP2_SETTINGS            = hdrtoken_string_to_wks("HTTP2-Settings");
754     MIME_FIELD_EARLY_DATA                = hdrtoken_string_to_wks("Early-Data");
755 
756     MIME_LEN_ACCEPT                    = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT);
757     MIME_LEN_ACCEPT_CHARSET            = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_CHARSET);
758     MIME_LEN_ACCEPT_ENCODING           = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_ENCODING);
759     MIME_LEN_ACCEPT_LANGUAGE           = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_LANGUAGE);
760     MIME_LEN_ACCEPT_RANGES             = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_RANGES);
761     MIME_LEN_AGE                       = hdrtoken_wks_to_length(MIME_FIELD_AGE);
762     MIME_LEN_ALLOW                     = hdrtoken_wks_to_length(MIME_FIELD_ALLOW);
763     MIME_LEN_APPROVED                  = hdrtoken_wks_to_length(MIME_FIELD_APPROVED);
764     MIME_LEN_AUTHORIZATION             = hdrtoken_wks_to_length(MIME_FIELD_AUTHORIZATION);
765     MIME_LEN_BYTES                     = hdrtoken_wks_to_length(MIME_FIELD_BYTES);
766     MIME_LEN_CACHE_CONTROL             = hdrtoken_wks_to_length(MIME_FIELD_CACHE_CONTROL);
767     MIME_LEN_CLIENT_IP                 = hdrtoken_wks_to_length(MIME_FIELD_CLIENT_IP);
768     MIME_LEN_CONNECTION                = hdrtoken_wks_to_length(MIME_FIELD_CONNECTION);
769     MIME_LEN_CONTENT_BASE              = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_BASE);
770     MIME_LEN_CONTENT_ENCODING          = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_ENCODING);
771     MIME_LEN_CONTENT_LANGUAGE          = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_LANGUAGE);
772     MIME_LEN_CONTENT_LENGTH            = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_LENGTH);
773     MIME_LEN_CONTENT_LOCATION          = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_LOCATION);
774     MIME_LEN_CONTENT_MD5               = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_MD5);
775     MIME_LEN_CONTENT_RANGE             = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_RANGE);
776     MIME_LEN_CONTENT_TYPE              = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_TYPE);
777     MIME_LEN_CONTROL                   = hdrtoken_wks_to_length(MIME_FIELD_CONTROL);
778     MIME_LEN_COOKIE                    = hdrtoken_wks_to_length(MIME_FIELD_COOKIE);
779     MIME_LEN_DATE                      = hdrtoken_wks_to_length(MIME_FIELD_DATE);
780     MIME_LEN_DISTRIBUTION              = hdrtoken_wks_to_length(MIME_FIELD_DISTRIBUTION);
781     MIME_LEN_ETAG                      = hdrtoken_wks_to_length(MIME_FIELD_ETAG);
782     MIME_LEN_EXPECT                    = hdrtoken_wks_to_length(MIME_FIELD_EXPECT);
783     MIME_LEN_EXPIRES                   = hdrtoken_wks_to_length(MIME_FIELD_EXPIRES);
784     MIME_LEN_FOLLOWUP_TO               = hdrtoken_wks_to_length(MIME_FIELD_FOLLOWUP_TO);
785     MIME_LEN_FROM                      = hdrtoken_wks_to_length(MIME_FIELD_FROM);
786     MIME_LEN_HOST                      = hdrtoken_wks_to_length(MIME_FIELD_HOST);
787     MIME_LEN_IF_MATCH                  = hdrtoken_wks_to_length(MIME_FIELD_IF_MATCH);
788     MIME_LEN_IF_MODIFIED_SINCE         = hdrtoken_wks_to_length(MIME_FIELD_IF_MODIFIED_SINCE);
789     MIME_LEN_IF_NONE_MATCH             = hdrtoken_wks_to_length(MIME_FIELD_IF_NONE_MATCH);
790     MIME_LEN_IF_RANGE                  = hdrtoken_wks_to_length(MIME_FIELD_IF_RANGE);
791     MIME_LEN_IF_UNMODIFIED_SINCE       = hdrtoken_wks_to_length(MIME_FIELD_IF_UNMODIFIED_SINCE);
792     MIME_LEN_KEEP_ALIVE                = hdrtoken_wks_to_length(MIME_FIELD_KEEP_ALIVE);
793     MIME_LEN_KEYWORDS                  = hdrtoken_wks_to_length(MIME_FIELD_KEYWORDS);
794     MIME_LEN_LAST_MODIFIED             = hdrtoken_wks_to_length(MIME_FIELD_LAST_MODIFIED);
795     MIME_LEN_LINES                     = hdrtoken_wks_to_length(MIME_FIELD_LINES);
796     MIME_LEN_LOCATION                  = hdrtoken_wks_to_length(MIME_FIELD_LOCATION);
797     MIME_LEN_MAX_FORWARDS              = hdrtoken_wks_to_length(MIME_FIELD_MAX_FORWARDS);
798     MIME_LEN_MESSAGE_ID                = hdrtoken_wks_to_length(MIME_FIELD_MESSAGE_ID);
799     MIME_LEN_NEWSGROUPS                = hdrtoken_wks_to_length(MIME_FIELD_NEWSGROUPS);
800     MIME_LEN_ORGANIZATION              = hdrtoken_wks_to_length(MIME_FIELD_ORGANIZATION);
801     MIME_LEN_PATH                      = hdrtoken_wks_to_length(MIME_FIELD_PATH);
802     MIME_LEN_PRAGMA                    = hdrtoken_wks_to_length(MIME_FIELD_PRAGMA);
803     MIME_LEN_PROXY_AUTHENTICATE        = hdrtoken_wks_to_length(MIME_FIELD_PROXY_AUTHENTICATE);
804     MIME_LEN_PROXY_AUTHORIZATION       = hdrtoken_wks_to_length(MIME_FIELD_PROXY_AUTHORIZATION);
805     MIME_LEN_PROXY_CONNECTION          = hdrtoken_wks_to_length(MIME_FIELD_PROXY_CONNECTION);
806     MIME_LEN_PUBLIC                    = hdrtoken_wks_to_length(MIME_FIELD_PUBLIC);
807     MIME_LEN_RANGE                     = hdrtoken_wks_to_length(MIME_FIELD_RANGE);
808     MIME_LEN_REFERENCES                = hdrtoken_wks_to_length(MIME_FIELD_REFERENCES);
809     MIME_LEN_REFERER                   = hdrtoken_wks_to_length(MIME_FIELD_REFERER);
810     MIME_LEN_REPLY_TO                  = hdrtoken_wks_to_length(MIME_FIELD_REPLY_TO);
811     MIME_LEN_RETRY_AFTER               = hdrtoken_wks_to_length(MIME_FIELD_RETRY_AFTER);
812     MIME_LEN_SENDER                    = hdrtoken_wks_to_length(MIME_FIELD_SENDER);
813     MIME_LEN_SERVER                    = hdrtoken_wks_to_length(MIME_FIELD_SERVER);
814     MIME_LEN_SET_COOKIE                = hdrtoken_wks_to_length(MIME_FIELD_SET_COOKIE);
815     MIME_LEN_STRICT_TRANSPORT_SECURITY = hdrtoken_wks_to_length(MIME_FIELD_STRICT_TRANSPORT_SECURITY);
816     MIME_LEN_SUBJECT                   = hdrtoken_wks_to_length(MIME_FIELD_SUBJECT);
817     MIME_LEN_SUMMARY                   = hdrtoken_wks_to_length(MIME_FIELD_SUMMARY);
818     MIME_LEN_TE                        = hdrtoken_wks_to_length(MIME_FIELD_TE);
819     MIME_LEN_TRANSFER_ENCODING         = hdrtoken_wks_to_length(MIME_FIELD_TRANSFER_ENCODING);
820     MIME_LEN_UPGRADE                   = hdrtoken_wks_to_length(MIME_FIELD_UPGRADE);
821     MIME_LEN_USER_AGENT                = hdrtoken_wks_to_length(MIME_FIELD_USER_AGENT);
822     MIME_LEN_VARY                      = hdrtoken_wks_to_length(MIME_FIELD_VARY);
823     MIME_LEN_VIA                       = hdrtoken_wks_to_length(MIME_FIELD_VIA);
824     MIME_LEN_WARNING                   = hdrtoken_wks_to_length(MIME_FIELD_WARNING);
825     MIME_LEN_WWW_AUTHENTICATE          = hdrtoken_wks_to_length(MIME_FIELD_WWW_AUTHENTICATE);
826     MIME_LEN_XREF                      = hdrtoken_wks_to_length(MIME_FIELD_XREF);
827     MIME_LEN_ATS_INTERNAL              = hdrtoken_wks_to_length(MIME_FIELD_ATS_INTERNAL);
828     MIME_LEN_X_ID                      = hdrtoken_wks_to_length(MIME_FIELD_X_ID);
829     MIME_LEN_X_FORWARDED_FOR           = hdrtoken_wks_to_length(MIME_FIELD_X_FORWARDED_FOR);
830     MIME_LEN_FORWARDED                 = hdrtoken_wks_to_length(MIME_FIELD_FORWARDED);
831     MIME_LEN_SEC_WEBSOCKET_KEY         = hdrtoken_wks_to_length(MIME_FIELD_SEC_WEBSOCKET_KEY);
832     MIME_LEN_SEC_WEBSOCKET_VERSION     = hdrtoken_wks_to_length(MIME_FIELD_SEC_WEBSOCKET_VERSION);
833     MIME_LEN_HTTP2_SETTINGS            = hdrtoken_wks_to_length(MIME_FIELD_HTTP2_SETTINGS);
834     MIME_LEN_EARLY_DATA                = hdrtoken_wks_to_length(MIME_FIELD_EARLY_DATA);
835 
836     MIME_WKSIDX_ACCEPT                    = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT);
837     MIME_WKSIDX_ACCEPT_CHARSET            = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_CHARSET);
838     MIME_WKSIDX_ACCEPT_ENCODING           = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_ENCODING);
839     MIME_WKSIDX_ACCEPT_LANGUAGE           = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_LANGUAGE);
840     MIME_WKSIDX_ACCEPT_RANGES             = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_RANGES);
841     MIME_WKSIDX_AGE                       = hdrtoken_wks_to_index(MIME_FIELD_AGE);
842     MIME_WKSIDX_ALLOW                     = hdrtoken_wks_to_index(MIME_FIELD_ALLOW);
843     MIME_WKSIDX_APPROVED                  = hdrtoken_wks_to_index(MIME_FIELD_APPROVED);
844     MIME_WKSIDX_AUTHORIZATION             = hdrtoken_wks_to_index(MIME_FIELD_AUTHORIZATION);
845     MIME_WKSIDX_BYTES                     = hdrtoken_wks_to_index(MIME_FIELD_BYTES);
846     MIME_WKSIDX_CACHE_CONTROL             = hdrtoken_wks_to_index(MIME_FIELD_CACHE_CONTROL);
847     MIME_WKSIDX_CLIENT_IP                 = hdrtoken_wks_to_index(MIME_FIELD_CLIENT_IP);
848     MIME_WKSIDX_CONNECTION                = hdrtoken_wks_to_index(MIME_FIELD_CONNECTION);
849     MIME_WKSIDX_CONTENT_BASE              = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_BASE);
850     MIME_WKSIDX_CONTENT_ENCODING          = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_ENCODING);
851     MIME_WKSIDX_CONTENT_LANGUAGE          = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_LANGUAGE);
852     MIME_WKSIDX_CONTENT_LENGTH            = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_LENGTH);
853     MIME_WKSIDX_CONTENT_LOCATION          = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_LOCATION);
854     MIME_WKSIDX_CONTENT_MD5               = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_MD5);
855     MIME_WKSIDX_CONTENT_RANGE             = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_RANGE);
856     MIME_WKSIDX_CONTENT_TYPE              = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_TYPE);
857     MIME_WKSIDX_CONTROL                   = hdrtoken_wks_to_index(MIME_FIELD_CONTROL);
858     MIME_WKSIDX_COOKIE                    = hdrtoken_wks_to_index(MIME_FIELD_COOKIE);
859     MIME_WKSIDX_DATE                      = hdrtoken_wks_to_index(MIME_FIELD_DATE);
860     MIME_WKSIDX_DISTRIBUTION              = hdrtoken_wks_to_index(MIME_FIELD_DISTRIBUTION);
861     MIME_WKSIDX_ETAG                      = hdrtoken_wks_to_index(MIME_FIELD_ETAG);
862     MIME_WKSIDX_EXPECT                    = hdrtoken_wks_to_index(MIME_FIELD_EXPECT);
863     MIME_WKSIDX_EXPIRES                   = hdrtoken_wks_to_index(MIME_FIELD_EXPIRES);
864     MIME_WKSIDX_FOLLOWUP_TO               = hdrtoken_wks_to_index(MIME_FIELD_FOLLOWUP_TO);
865     MIME_WKSIDX_FROM                      = hdrtoken_wks_to_index(MIME_FIELD_FROM);
866     MIME_WKSIDX_HOST                      = hdrtoken_wks_to_index(MIME_FIELD_HOST);
867     MIME_WKSIDX_IF_MATCH                  = hdrtoken_wks_to_index(MIME_FIELD_IF_MATCH);
868     MIME_WKSIDX_IF_MODIFIED_SINCE         = hdrtoken_wks_to_index(MIME_FIELD_IF_MODIFIED_SINCE);
869     MIME_WKSIDX_IF_NONE_MATCH             = hdrtoken_wks_to_index(MIME_FIELD_IF_NONE_MATCH);
870     MIME_WKSIDX_IF_RANGE                  = hdrtoken_wks_to_index(MIME_FIELD_IF_RANGE);
871     MIME_WKSIDX_IF_UNMODIFIED_SINCE       = hdrtoken_wks_to_index(MIME_FIELD_IF_UNMODIFIED_SINCE);
872     MIME_WKSIDX_KEEP_ALIVE                = hdrtoken_wks_to_index(MIME_FIELD_KEEP_ALIVE);
873     MIME_WKSIDX_KEYWORDS                  = hdrtoken_wks_to_index(MIME_FIELD_KEYWORDS);
874     MIME_WKSIDX_LAST_MODIFIED             = hdrtoken_wks_to_index(MIME_FIELD_LAST_MODIFIED);
875     MIME_WKSIDX_LINES                     = hdrtoken_wks_to_index(MIME_FIELD_LINES);
876     MIME_WKSIDX_LOCATION                  = hdrtoken_wks_to_index(MIME_FIELD_LOCATION);
877     MIME_WKSIDX_MAX_FORWARDS              = hdrtoken_wks_to_index(MIME_FIELD_MAX_FORWARDS);
878     MIME_WKSIDX_MESSAGE_ID                = hdrtoken_wks_to_index(MIME_FIELD_MESSAGE_ID);
879     MIME_WKSIDX_NEWSGROUPS                = hdrtoken_wks_to_index(MIME_FIELD_NEWSGROUPS);
880     MIME_WKSIDX_ORGANIZATION              = hdrtoken_wks_to_index(MIME_FIELD_ORGANIZATION);
881     MIME_WKSIDX_PATH                      = hdrtoken_wks_to_index(MIME_FIELD_PATH);
882     MIME_WKSIDX_PRAGMA                    = hdrtoken_wks_to_index(MIME_FIELD_PRAGMA);
883     MIME_WKSIDX_PROXY_AUTHENTICATE        = hdrtoken_wks_to_index(MIME_FIELD_PROXY_AUTHENTICATE);
884     MIME_WKSIDX_PROXY_AUTHORIZATION       = hdrtoken_wks_to_index(MIME_FIELD_PROXY_AUTHORIZATION);
885     MIME_WKSIDX_PROXY_CONNECTION          = hdrtoken_wks_to_index(MIME_FIELD_PROXY_CONNECTION);
886     MIME_WKSIDX_PUBLIC                    = hdrtoken_wks_to_index(MIME_FIELD_PUBLIC);
887     MIME_WKSIDX_RANGE                     = hdrtoken_wks_to_index(MIME_FIELD_RANGE);
888     MIME_WKSIDX_REFERENCES                = hdrtoken_wks_to_index(MIME_FIELD_REFERENCES);
889     MIME_WKSIDX_REFERER                   = hdrtoken_wks_to_index(MIME_FIELD_REFERER);
890     MIME_WKSIDX_REPLY_TO                  = hdrtoken_wks_to_index(MIME_FIELD_REPLY_TO);
891     MIME_WKSIDX_RETRY_AFTER               = hdrtoken_wks_to_index(MIME_FIELD_RETRY_AFTER);
892     MIME_WKSIDX_SENDER                    = hdrtoken_wks_to_index(MIME_FIELD_SENDER);
893     MIME_WKSIDX_SERVER                    = hdrtoken_wks_to_index(MIME_FIELD_SERVER);
894     MIME_WKSIDX_SET_COOKIE                = hdrtoken_wks_to_index(MIME_FIELD_SET_COOKIE);
895     MIME_WKSIDX_STRICT_TRANSPORT_SECURITY = hdrtoken_wks_to_index(MIME_FIELD_STRICT_TRANSPORT_SECURITY);
896     MIME_WKSIDX_SUBJECT                   = hdrtoken_wks_to_index(MIME_FIELD_SUBJECT);
897     MIME_WKSIDX_SUMMARY                   = hdrtoken_wks_to_index(MIME_FIELD_SUMMARY);
898     MIME_WKSIDX_TE                        = hdrtoken_wks_to_index(MIME_FIELD_TE);
899     MIME_WKSIDX_TRANSFER_ENCODING         = hdrtoken_wks_to_index(MIME_FIELD_TRANSFER_ENCODING);
900     MIME_WKSIDX_UPGRADE                   = hdrtoken_wks_to_index(MIME_FIELD_UPGRADE);
901     MIME_WKSIDX_USER_AGENT                = hdrtoken_wks_to_index(MIME_FIELD_USER_AGENT);
902     MIME_WKSIDX_VARY                      = hdrtoken_wks_to_index(MIME_FIELD_VARY);
903     MIME_WKSIDX_VIA                       = hdrtoken_wks_to_index(MIME_FIELD_VIA);
904     MIME_WKSIDX_WARNING                   = hdrtoken_wks_to_index(MIME_FIELD_WARNING);
905     MIME_WKSIDX_WWW_AUTHENTICATE          = hdrtoken_wks_to_index(MIME_FIELD_WWW_AUTHENTICATE);
906     MIME_WKSIDX_XREF                      = hdrtoken_wks_to_index(MIME_FIELD_XREF);
907     MIME_WKSIDX_X_ID                      = hdrtoken_wks_to_index(MIME_FIELD_X_ID);
908     MIME_WKSIDX_X_FORWARDED_FOR           = hdrtoken_wks_to_index(MIME_FIELD_X_FORWARDED_FOR);
909     MIME_WKSIDX_FORWARDED                 = hdrtoken_wks_to_index(MIME_FIELD_FORWARDED);
910     MIME_WKSIDX_SEC_WEBSOCKET_KEY         = hdrtoken_wks_to_index(MIME_FIELD_SEC_WEBSOCKET_KEY);
911     MIME_WKSIDX_SEC_WEBSOCKET_VERSION     = hdrtoken_wks_to_index(MIME_FIELD_SEC_WEBSOCKET_VERSION);
912     MIME_WKSIDX_HTTP2_SETTINGS            = hdrtoken_wks_to_index(MIME_FIELD_HTTP2_SETTINGS);
913     MIME_WKSIDX_EARLY_DATA                = hdrtoken_wks_to_index(MIME_FIELD_EARLY_DATA);
914 
915     MIME_VALUE_BYTES                = hdrtoken_string_to_wks("bytes");
916     MIME_VALUE_CHUNKED              = hdrtoken_string_to_wks("chunked");
917     MIME_VALUE_CLOSE                = hdrtoken_string_to_wks("close");
918     MIME_VALUE_COMPRESS             = hdrtoken_string_to_wks("compress");
919     MIME_VALUE_DEFLATE              = hdrtoken_string_to_wks("deflate");
920     MIME_VALUE_GZIP                 = hdrtoken_string_to_wks("gzip");
921     MIME_VALUE_IDENTITY             = hdrtoken_string_to_wks("identity");
922     MIME_VALUE_KEEP_ALIVE           = hdrtoken_string_to_wks("keep-alive");
923     MIME_VALUE_MAX_AGE              = hdrtoken_string_to_wks("max-age");
924     MIME_VALUE_MAX_STALE            = hdrtoken_string_to_wks("max-stale");
925     MIME_VALUE_MIN_FRESH            = hdrtoken_string_to_wks("min-fresh");
926     MIME_VALUE_MUST_REVALIDATE      = hdrtoken_string_to_wks("must-revalidate");
927     MIME_VALUE_NONE                 = hdrtoken_string_to_wks("none");
928     MIME_VALUE_NO_CACHE             = hdrtoken_string_to_wks("no-cache");
929     MIME_VALUE_NO_STORE             = hdrtoken_string_to_wks("no-store");
930     MIME_VALUE_NO_TRANSFORM         = hdrtoken_string_to_wks("no-transform");
931     MIME_VALUE_ONLY_IF_CACHED       = hdrtoken_string_to_wks("only-if-cached");
932     MIME_VALUE_PRIVATE              = hdrtoken_string_to_wks("private");
933     MIME_VALUE_PROXY_REVALIDATE     = hdrtoken_string_to_wks("proxy-revalidate");
934     MIME_VALUE_PUBLIC               = hdrtoken_string_to_wks("public");
935     MIME_VALUE_S_MAXAGE             = hdrtoken_string_to_wks("s-maxage");
936     MIME_VALUE_NEED_REVALIDATE_ONCE = hdrtoken_string_to_wks("need-revalidate-once");
937     MIME_VALUE_WEBSOCKET            = hdrtoken_string_to_wks("websocket");
938     MIME_VALUE_H2C                  = hdrtoken_string_to_wks(MIME_UPGRADE_H2C_TOKEN);
939 
940     mime_init_date_format_table();
941     mime_init_cache_control_cooking_masks();
942   }
943 }
944 
945 void
mime_init_cache_control_cooking_masks()946 mime_init_cache_control_cooking_masks()
947 {
948   static struct {
949     const char *name;
950     uint32_t mask;
951   } cc_mask_table[] = {{"max-age", MIME_COOKED_MASK_CC_MAX_AGE},
952                        {"no-cache", MIME_COOKED_MASK_CC_NO_CACHE},
953                        {"no-store", MIME_COOKED_MASK_CC_NO_STORE},
954                        {"no-transform", MIME_COOKED_MASK_CC_NO_TRANSFORM},
955                        {"max-stale", MIME_COOKED_MASK_CC_MAX_STALE},
956                        {"min-fresh", MIME_COOKED_MASK_CC_MIN_FRESH},
957                        {"only-if-cached", MIME_COOKED_MASK_CC_ONLY_IF_CACHED},
958                        {"public", MIME_COOKED_MASK_CC_PUBLIC},
959                        {"private", MIME_COOKED_MASK_CC_PRIVATE},
960                        {"must-revalidate", MIME_COOKED_MASK_CC_MUST_REVALIDATE},
961                        {"proxy-revalidate", MIME_COOKED_MASK_CC_PROXY_REVALIDATE},
962                        {"s-maxage", MIME_COOKED_MASK_CC_S_MAXAGE},
963                        {"need-revalidate-once", MIME_COOKED_MASK_CC_NEED_REVALIDATE_ONCE},
964                        {nullptr, 0}};
965 
966   for (int i = 0; cc_mask_table[i].name != nullptr; i++) {
967     const char *wks                              = hdrtoken_string_to_wks(cc_mask_table[i].name);
968     HdrTokenHeapPrefix *p                        = hdrtoken_wks_to_prefix(wks);
969     p->wks_type_specific.u.cache_control.cc_mask = cc_mask_table[i].mask;
970   }
971 }
972 
973 void
mime_init_date_format_table()974 mime_init_date_format_table()
975 {
976   ////////////////////////////////////////////////////////////////
977   // to speed up the days_since_epoch to m/d/y conversion, we   //
978   // use a pre-computed lookup table to support the common case //
979   // of dates that are +/- one year from today --- this code    //
980   // builds the lookup table during the first call.             //
981   ////////////////////////////////////////////////////////////////
982 
983   time_t now_secs;
984   int i, now_days, first_days, last_days, num_days;
985   int m = 0, d = 0, y = 0;
986 
987   time(&now_secs);
988   now_days   = static_cast<int>(now_secs / (60 * 60 * 24));
989   first_days = now_days - 366;
990   last_days  = now_days + 366;
991   num_days   = last_days - first_days + 1;
992 
993   _days_to_mdy_fast_lookup_table           = static_cast<MDY *>(ats_malloc(num_days * sizeof(MDY)));
994   _days_to_mdy_fast_lookup_table_first_day = first_days;
995   _days_to_mdy_fast_lookup_table_last_day  = last_days;
996 
997   for (i = 0; i < num_days; i++) {
998     mime_days_since_epoch_to_mdy_slowcase(first_days + i, &m, &d, &y);
999     _days_to_mdy_fast_lookup_table[i].m = m;
1000     _days_to_mdy_fast_lookup_table[i].d = d;
1001     _days_to_mdy_fast_lookup_table[i].y = y;
1002   }
1003 }
1004 
1005 MIMEHdrImpl *
mime_hdr_create(HdrHeap * heap)1006 mime_hdr_create(HdrHeap *heap)
1007 {
1008   MIMEHdrImpl *mh;
1009 
1010   mh = (MIMEHdrImpl *)heap->allocate_obj(sizeof(MIMEHdrImpl), HDR_HEAP_OBJ_MIME_HEADER);
1011   mime_hdr_init(mh);
1012   return mh;
1013 }
1014 
1015 void
_mime_hdr_field_block_init(MIMEFieldBlockImpl * fblock)1016 _mime_hdr_field_block_init(MIMEFieldBlockImpl *fblock)
1017 {
1018   fblock->m_freetop = 0;
1019   fblock->m_next    = nullptr;
1020 
1021 #ifdef BLOCK_INIT_PARANOIA
1022   int i;
1023 
1024   // FIX: Could eliminate this initialization loop if we assumed
1025   //      every slot above the freetop of the block was garbage;
1026   //      but to be safe, and help debugging, for now we are eating
1027   //      the cost of initializing all slots in a block.
1028 
1029   for (i = 0; i < MIME_FIELD_BLOCK_SLOTS; i++) {
1030     MIMEField *field   = &(fblock->m_field_slots[i]);
1031     field->m_readiness = MIME_FIELD_SLOT_READINESS_EMPTY;
1032   }
1033 #endif
1034 }
1035 
1036 void
mime_hdr_cooked_stuff_init(MIMEHdrImpl * mh,MIMEField * changing_field_or_null)1037 mime_hdr_cooked_stuff_init(MIMEHdrImpl *mh, MIMEField *changing_field_or_null)
1038 {
1039   // to be safe, reinitialize unless you know this call is for other cooked field
1040   if ((changing_field_or_null == nullptr) || (changing_field_or_null->m_wks_idx != MIME_WKSIDX_PRAGMA)) {
1041     mh->m_cooked_stuff.m_cache_control.m_mask           = 0;
1042     mh->m_cooked_stuff.m_cache_control.m_secs_max_age   = 0;
1043     mh->m_cooked_stuff.m_cache_control.m_secs_s_maxage  = 0;
1044     mh->m_cooked_stuff.m_cache_control.m_secs_max_stale = 0;
1045     mh->m_cooked_stuff.m_cache_control.m_secs_min_fresh = 0;
1046   }
1047   if ((changing_field_or_null == nullptr) || (changing_field_or_null->m_wks_idx != MIME_WKSIDX_CACHE_CONTROL)) {
1048     mh->m_cooked_stuff.m_pragma.m_no_cache = false;
1049   }
1050 }
1051 
1052 void
mime_hdr_init(MIMEHdrImpl * mh)1053 mime_hdr_init(MIMEHdrImpl *mh)
1054 {
1055   mime_hdr_init_accelerators_and_presence_bits(mh);
1056 
1057   mime_hdr_cooked_stuff_init(mh, nullptr);
1058 
1059   // first header is inline: fake an object header for uniformity
1060   obj_init_header((HdrHeapObjImpl *)&(mh->m_first_fblock), HDR_HEAP_OBJ_FIELD_BLOCK, sizeof(MIMEFieldBlockImpl), 0);
1061 
1062   _mime_hdr_field_block_init(&(mh->m_first_fblock));
1063   mh->m_fblock_list_tail = &(mh->m_first_fblock);
1064 
1065   MIME_HDR_SANITY_CHECK(mh);
1066 }
1067 
1068 MIMEFieldBlockImpl *
_mime_field_block_copy(MIMEFieldBlockImpl * s_fblock,HdrHeap *,HdrHeap * d_heap)1069 _mime_field_block_copy(MIMEFieldBlockImpl *s_fblock, HdrHeap * /* s_heap ATS_UNUSED */, HdrHeap *d_heap)
1070 {
1071   MIMEFieldBlockImpl *d_fblock;
1072 
1073   d_fblock = (MIMEFieldBlockImpl *)d_heap->allocate_obj(sizeof(MIMEFieldBlockImpl), HDR_HEAP_OBJ_FIELD_BLOCK);
1074   memcpy(d_fblock, s_fblock, sizeof(MIMEFieldBlockImpl));
1075   return d_fblock;
1076 }
1077 
1078 void
_mime_field_block_destroy(HdrHeap * heap,MIMEFieldBlockImpl * fblock)1079 _mime_field_block_destroy(HdrHeap *heap, MIMEFieldBlockImpl *fblock)
1080 {
1081   heap->deallocate_obj(fblock);
1082 }
1083 
1084 void
mime_hdr_destroy_field_block_list(HdrHeap * heap,MIMEFieldBlockImpl * head)1085 mime_hdr_destroy_field_block_list(HdrHeap *heap, MIMEFieldBlockImpl *head)
1086 {
1087   MIMEFieldBlockImpl *next;
1088 
1089   while (head != nullptr) {
1090     next = head->m_next;
1091     _mime_field_block_destroy(heap, head);
1092     head = next;
1093   }
1094 }
1095 
1096 void
mime_hdr_destroy(HdrHeap * heap,MIMEHdrImpl * mh)1097 mime_hdr_destroy(HdrHeap *heap, MIMEHdrImpl *mh)
1098 {
1099   mime_hdr_destroy_field_block_list(heap, mh->m_first_fblock.m_next);
1100 
1101   // INKqa11458: if we deallocate mh here and call TSMLocRelease
1102   // again, the plugin fails in assert. We leave deallocating to
1103   // the plugin using TSMLocRelease
1104 
1105   // heap->deallocate_obj(mh);
1106 }
1107 
1108 void
mime_hdr_copy_onto(MIMEHdrImpl * s_mh,HdrHeap * s_heap,MIMEHdrImpl * d_mh,HdrHeap * d_heap,bool inherit_strs)1109 mime_hdr_copy_onto(MIMEHdrImpl *s_mh, HdrHeap *s_heap, MIMEHdrImpl *d_mh, HdrHeap *d_heap, bool inherit_strs)
1110 {
1111   int block_count;
1112   MIMEFieldBlockImpl *s_fblock, *d_fblock, *prev_d_fblock;
1113 
1114   // If there are chained field blocks beyond the first one, we're just going to
1115   //   destroy them.  Ideally, we'd use them if the copied in header needed
1116   //   extra blocks.  It's too late in the Tomcat code cycle to implement
1117   //   reuse.
1118   if (d_mh->m_first_fblock.m_next) {
1119     mime_hdr_destroy_field_block_list(d_heap, d_mh->m_first_fblock.m_next);
1120   }
1121 
1122   ink_assert(((char *)&(s_mh->m_first_fblock.m_field_slots[MIME_FIELD_BLOCK_SLOTS]) - (char *)s_mh) == sizeof(struct MIMEHdrImpl));
1123 
1124   int top             = s_mh->m_first_fblock.m_freetop;
1125   char *end           = reinterpret_cast<char *>(&(s_mh->m_first_fblock.m_field_slots[top]));
1126   int bytes_below_top = end - reinterpret_cast<char *>(s_mh);
1127 
1128   // copies useful part of enclosed first block too
1129   memcpy(d_mh, s_mh, bytes_below_top);
1130 
1131   if (d_mh->m_first_fblock.m_next == nullptr) // common case: no other block
1132   {
1133     d_mh->m_fblock_list_tail = &(d_mh->m_first_fblock);
1134     block_count              = 1;
1135   } else // uncommon case: block list exists
1136   {
1137     prev_d_fblock = &(d_mh->m_first_fblock);
1138     block_count   = 1;
1139     for (s_fblock = s_mh->m_first_fblock.m_next; s_fblock != nullptr; s_fblock = s_fblock->m_next) {
1140       ++block_count;
1141       d_fblock              = _mime_field_block_copy(s_fblock, s_heap, d_heap);
1142       prev_d_fblock->m_next = d_fblock;
1143       prev_d_fblock         = d_fblock;
1144     }
1145     d_mh->m_fblock_list_tail = prev_d_fblock;
1146   }
1147 
1148   if (inherit_strs) {
1149     d_heap->inherit_string_heaps(s_heap);
1150   }
1151 
1152   mime_hdr_field_block_list_adjust(block_count, &(s_mh->m_first_fblock), &(d_mh->m_first_fblock));
1153 
1154   MIME_HDR_SANITY_CHECK(s_mh);
1155   MIME_HDR_SANITY_CHECK(d_mh);
1156 }
1157 
1158 MIMEHdrImpl *
mime_hdr_clone(MIMEHdrImpl * s_mh,HdrHeap * s_heap,HdrHeap * d_heap,bool inherit_strs)1159 mime_hdr_clone(MIMEHdrImpl *s_mh, HdrHeap *s_heap, HdrHeap *d_heap, bool inherit_strs)
1160 {
1161   MIMEHdrImpl *d_mh;
1162 
1163   d_mh = mime_hdr_create(d_heap);
1164   mime_hdr_copy_onto(s_mh, s_heap, d_mh, d_heap, inherit_strs);
1165   return d_mh;
1166 }
1167 
1168 /** Move a pointer from one list to another, keeping the relative offset.
1169  * @return A pointer that has the same relative offset to @a dest_base as
1170  * @a dest_ptr does to @a src_base.
1171  */
1172 static inline MIMEField *
rebase(MIMEField * dest_ptr,void * dest_base,void * src_base)1173 rebase(MIMEField *dest_ptr, ///< Original pointer into @src_base memory.
1174        void *dest_base,     ///< New base pointer.
1175        void *src_base       ///< Original base pointer.
1176 )
1177 {
1178   return reinterpret_cast<MIMEField *>(reinterpret_cast<char *>(dest_ptr) +
1179                                        (static_cast<char *>(dest_base) - static_cast<char *>(src_base)));
1180 }
1181 
1182 static inline void
relocate(MIMEField * field,MIMEFieldBlockImpl * dest_block,MIMEFieldBlockImpl * src_block)1183 relocate(MIMEField *field, MIMEFieldBlockImpl *dest_block, MIMEFieldBlockImpl *src_block)
1184 {
1185   for (; src_block; src_block = src_block->m_next, dest_block = dest_block->m_next) {
1186     ink_release_assert(dest_block);
1187 
1188     if (field->m_next_dup >= src_block->m_field_slots && field->m_next_dup < src_block->m_field_slots + src_block->m_freetop) {
1189       field->m_next_dup = rebase(field->m_next_dup, dest_block->m_field_slots, src_block->m_field_slots);
1190       return;
1191     }
1192   }
1193 }
1194 
1195 void
mime_hdr_field_block_list_adjust(int,MIMEFieldBlockImpl * old_list,MIMEFieldBlockImpl * new_list)1196 mime_hdr_field_block_list_adjust(int /* block_count ATS_UNUSED */, MIMEFieldBlockImpl *old_list, MIMEFieldBlockImpl *new_list)
1197 {
1198   for (MIMEFieldBlockImpl *new_blk = new_list; new_blk; new_blk = new_blk->m_next) {
1199     for (MIMEField *field = new_blk->m_field_slots, *end = field + new_blk->m_freetop; field != end; ++field) {
1200       if (field->is_live() && field->m_next_dup) {
1201         relocate(field, new_list, old_list);
1202       }
1203     }
1204   }
1205 }
1206 
1207 int
mime_hdr_length_get(MIMEHdrImpl * mh)1208 mime_hdr_length_get(MIMEHdrImpl *mh)
1209 {
1210   unsigned int length, index;
1211   MIMEFieldBlockImpl *fblock;
1212   MIMEField *field;
1213 
1214   length = 2;
1215 
1216   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1217     for (index = 0; index < fblock->m_freetop; index++) {
1218       field = &(fblock->m_field_slots[index]);
1219       if (field->is_live()) {
1220         length += mime_field_length_get(field);
1221       }
1222     }
1223   }
1224 
1225   return length;
1226 }
1227 
1228 void
mime_hdr_fields_clear(HdrHeap * heap,MIMEHdrImpl * mh)1229 mime_hdr_fields_clear(HdrHeap *heap, MIMEHdrImpl *mh)
1230 {
1231   mime_hdr_destroy_field_block_list(heap, mh->m_first_fblock.m_next);
1232   mime_hdr_init(mh);
1233 }
1234 
1235 MIMEField *
_mime_hdr_field_list_search_by_wks(MIMEHdrImpl * mh,int wks_idx)1236 _mime_hdr_field_list_search_by_wks(MIMEHdrImpl *mh, int wks_idx)
1237 {
1238   MIMEFieldBlockImpl *fblock;
1239   MIMEField *field, *too_far_field;
1240 
1241   ink_assert(hdrtoken_is_valid_wks_idx(wks_idx));
1242 
1243   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1244     field = &(fblock->m_field_slots[0]);
1245 
1246     too_far_field = &(fblock->m_field_slots[fblock->m_freetop]);
1247     while (field < too_far_field) {
1248       if (field->is_live() && (field->m_wks_idx == wks_idx)) {
1249         return field;
1250       }
1251       ++field;
1252     }
1253   }
1254 
1255   return nullptr;
1256 }
1257 
1258 MIMEField *
_mime_hdr_field_list_search_by_string(MIMEHdrImpl * mh,const char * field_name_str,int field_name_len)1259 _mime_hdr_field_list_search_by_string(MIMEHdrImpl *mh, const char *field_name_str, int field_name_len)
1260 {
1261   MIMEFieldBlockImpl *fblock;
1262   MIMEField *field, *too_far_field;
1263 
1264   ink_assert(mh);
1265   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1266     field = &(fblock->m_field_slots[0]);
1267 
1268     too_far_field = &(fblock->m_field_slots[fblock->m_freetop]);
1269     while (field < too_far_field) {
1270       if (field->is_live() && (field_name_len == field->m_len_name) &&
1271           (strncasecmp(field->m_ptr_name, field_name_str, field_name_len) == 0)) {
1272         return field;
1273       }
1274       ++field;
1275     }
1276   }
1277 
1278   return nullptr;
1279 }
1280 
1281 MIMEField *
_mime_hdr_field_list_search_by_slotnum(MIMEHdrImpl * mh,int slotnum)1282 _mime_hdr_field_list_search_by_slotnum(MIMEHdrImpl *mh, int slotnum)
1283 {
1284   unsigned int block_num, block_index;
1285   MIMEFieldBlockImpl *fblock;
1286 
1287   if (slotnum < MIME_FIELD_BLOCK_SLOTS) {
1288     fblock      = &(mh->m_first_fblock);
1289     block_index = slotnum;
1290     if (block_index >= fblock->m_freetop) {
1291       return nullptr;
1292     } else {
1293       return &(fblock->m_field_slots[block_index]);
1294     }
1295   } else {
1296     block_num   = slotnum / MIME_FIELD_BLOCK_SLOTS;
1297     block_index = slotnum % MIME_FIELD_BLOCK_SLOTS;
1298 
1299     fblock = &(mh->m_first_fblock);
1300     while (block_num-- && fblock) {
1301       fblock = fblock->m_next;
1302     }
1303     if ((fblock == nullptr) || (block_index >= fblock->m_freetop)) {
1304       return nullptr;
1305     } else {
1306       return &(fblock->m_field_slots[block_index]);
1307     }
1308   }
1309 }
1310 
1311 MIMEField *
mime_hdr_field_find(MIMEHdrImpl * mh,const char * field_name_str,int field_name_len)1312 mime_hdr_field_find(MIMEHdrImpl *mh, const char *field_name_str, int field_name_len)
1313 {
1314   HdrTokenHeapPrefix *token_info;
1315   const bool is_wks = hdrtoken_is_wks(field_name_str);
1316 
1317   ink_assert(field_name_len >= 0);
1318 
1319   ////////////////////////////////////////////
1320   // do presence check and slot accelerator //
1321   ////////////////////////////////////////////
1322 
1323 #if TRACK_FIELD_FIND_CALLS
1324   Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): is_wks = %d", mh, field_name_len, field_name_str, is_wks);
1325 #endif
1326 
1327   if (is_wks) {
1328     token_info = hdrtoken_wks_to_prefix(field_name_str);
1329     if ((token_info->wks_info.mask) && ((mh->m_presence_bits & token_info->wks_info.mask) == 0)) {
1330 #if TRACK_FIELD_FIND_CALLS
1331       Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): MISS (due to presence bits)", mh, field_name_len, field_name_str);
1332 #endif
1333       return nullptr;
1334     }
1335 
1336     int32_t slot_id = token_info->wks_info.slotid;
1337 
1338     if (slot_id != MIME_SLOTID_NONE) {
1339       uint32_t slotnum = mime_hdr_get_accelerator_slotnum(mh, slot_id);
1340 
1341       if (slotnum != MIME_FIELD_SLOTNUM_UNKNOWN) {
1342         MIMEField *f = _mime_hdr_field_list_search_by_slotnum(mh, slotnum);
1343         ink_assert((f == nullptr) || f->is_live());
1344 #if TRACK_FIELD_FIND_CALLS
1345         Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): %s (due to slot accelerators)", mh, field_name_len,
1346               field_name_str, (f ? "HIT" : "MISS"));
1347 #endif
1348         return f;
1349       } else {
1350 #if TRACK_FIELD_FIND_CALLS
1351         Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): UNKNOWN (slot too big)", mh, field_name_len, field_name_str);
1352 #endif
1353       }
1354     }
1355 
1356     ///////////////////////////////////////////////////////////////////////////
1357     // search by well-known string index or by case-insensitive string match //
1358     ///////////////////////////////////////////////////////////////////////////
1359 
1360     MIMEField *f = _mime_hdr_field_list_search_by_wks(mh, token_info->wks_idx);
1361     ink_assert((f == nullptr) || f->is_live());
1362 #if TRACK_FIELD_FIND_CALLS
1363     Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): %s (due to WKS list walk)", mh, field_name_len, field_name_str,
1364           (f ? "HIT" : "MISS"));
1365 #endif
1366     return f;
1367   } else {
1368     MIMEField *f = _mime_hdr_field_list_search_by_string(mh, field_name_str, field_name_len);
1369 
1370     ink_assert((f == nullptr) || f->is_live());
1371 #if TRACK_FIELD_FIND_CALLS
1372     Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): %s (due to strcmp list walk)", mh, field_name_len, field_name_str,
1373           (f ? "HIT" : "MISS"));
1374 #endif
1375     return f;
1376   }
1377 }
1378 
1379 MIMEField *
mime_hdr_field_get(MIMEHdrImpl * mh,int idx)1380 mime_hdr_field_get(MIMEHdrImpl *mh, int idx)
1381 {
1382   unsigned int index;
1383   MIMEFieldBlockImpl *fblock;
1384   MIMEField *field;
1385   int got_idx;
1386 
1387   got_idx = -1;
1388 
1389   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1390     for (index = 0; index < fblock->m_freetop; index++) {
1391       field = &(fblock->m_field_slots[index]);
1392       if (field->is_live()) {
1393         ++got_idx;
1394       }
1395       if (got_idx == idx) {
1396         return field;
1397       }
1398     }
1399   }
1400 
1401   return nullptr;
1402 }
1403 
1404 MIMEField *
mime_hdr_field_get_slotnum(MIMEHdrImpl * mh,int slotnum)1405 mime_hdr_field_get_slotnum(MIMEHdrImpl *mh, int slotnum)
1406 {
1407   return _mime_hdr_field_list_search_by_slotnum(mh, slotnum);
1408 }
1409 
1410 int
mime_hdr_fields_count(MIMEHdrImpl * mh)1411 mime_hdr_fields_count(MIMEHdrImpl *mh)
1412 {
1413   unsigned int index;
1414   MIMEFieldBlockImpl *fblock;
1415   MIMEField *field;
1416   int count;
1417 
1418   count = 0;
1419 
1420   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1421     for (index = 0; index < fblock->m_freetop; index++) {
1422       field = &(fblock->m_field_slots[index]);
1423       if (field->is_live()) {
1424         ++count;
1425       }
1426     }
1427   }
1428 
1429   return count;
1430 }
1431 
1432 void
mime_field_init(MIMEField * field)1433 mime_field_init(MIMEField *field)
1434 {
1435   memset(field, 0, sizeof(MIMEField));
1436   field->m_readiness = MIME_FIELD_SLOT_READINESS_DETACHED;
1437   field->m_wks_idx   = -1;
1438 }
1439 
1440 MIMEField *
mime_field_create(HdrHeap * heap,MIMEHdrImpl * mh)1441 mime_field_create(HdrHeap *heap, MIMEHdrImpl *mh)
1442 {
1443   MIMEField *field;
1444   MIMEFieldBlockImpl *tail_fblock, *new_fblock;
1445 
1446   tail_fblock = mh->m_fblock_list_tail;
1447   if (tail_fblock->m_freetop >= MIME_FIELD_BLOCK_SLOTS) {
1448     new_fblock = (MIMEFieldBlockImpl *)heap->allocate_obj(sizeof(MIMEFieldBlockImpl), HDR_HEAP_OBJ_FIELD_BLOCK);
1449     _mime_hdr_field_block_init(new_fblock);
1450     tail_fblock->m_next    = new_fblock;
1451     tail_fblock            = new_fblock;
1452     mh->m_fblock_list_tail = new_fblock;
1453   }
1454 
1455   field = &(tail_fblock->m_field_slots[tail_fblock->m_freetop]);
1456   ++tail_fblock->m_freetop;
1457 
1458   mime_field_init(field);
1459 
1460   return field;
1461 }
1462 
1463 MIMEField *
mime_field_create_named(HdrHeap * heap,MIMEHdrImpl * mh,const char * name,int length)1464 mime_field_create_named(HdrHeap *heap, MIMEHdrImpl *mh, const char *name, int length)
1465 {
1466   MIMEField *field       = mime_field_create(heap, mh);
1467   int field_name_wks_idx = hdrtoken_tokenize(name, length);
1468   mime_field_name_set(heap, mh, field, field_name_wks_idx, name, length, true);
1469   return field;
1470 }
1471 
1472 void
mime_hdr_field_attach(MIMEHdrImpl * mh,MIMEField * field,int check_for_dups,MIMEField * prev_dup)1473 mime_hdr_field_attach(MIMEHdrImpl *mh, MIMEField *field, int check_for_dups, MIMEField *prev_dup)
1474 {
1475   MIME_HDR_SANITY_CHECK(mh);
1476 
1477   if (!field->is_detached()) {
1478     return;
1479   }
1480 
1481   ink_assert(field->m_ptr_name != nullptr);
1482 
1483   //////////////////////////////////////////////////
1484   // if we don't know the head dup, or are given  //
1485   // a non-head dup, then search for the head dup //
1486   //////////////////////////////////////////////////
1487 
1488   if (check_for_dups || (prev_dup && (!prev_dup->is_dup_head()))) {
1489     std::string_view name{field->name_get()};
1490     prev_dup = mime_hdr_field_find(mh, name.data(), static_cast<int>(name.size()));
1491     ink_assert((prev_dup == nullptr) || (prev_dup->is_dup_head()));
1492   }
1493 
1494   field->m_readiness = MIME_FIELD_SLOT_READINESS_LIVE;
1495 
1496   ////////////////////////////////////////////////////////////////////
1497   // now, attach the new field --- if there are dups, make sure the //
1498   // field is patched into the dup list in increasing slot order to //
1499   // maintain the invariant that dups are chained in slot order     //
1500   ////////////////////////////////////////////////////////////////////
1501 
1502   if (prev_dup) {
1503     MIMEField *next_dup;
1504     int field_slotnum, prev_slotnum, next_slotnum;
1505 
1506     /////////////////////////////////////////////////////////////////
1507     // walk down dup list looking for the last dup in slot-order   //
1508     // before this field object --- meaning a dup before the field //
1509     // in slot order who either has no next dup, or whose next dup //
1510     // is numerically after the field in slot order.               //
1511     /////////////////////////////////////////////////////////////////
1512 
1513     field_slotnum = mime_hdr_field_slotnum(mh, field);
1514     prev_slotnum  = mime_hdr_field_slotnum(mh, prev_dup);
1515     next_dup      = prev_dup->m_next_dup;
1516     next_slotnum  = (next_dup ? mime_hdr_field_slotnum(mh, next_dup) : -1);
1517 
1518     ink_assert(field_slotnum != prev_slotnum);
1519 
1520     while (prev_slotnum < field_slotnum) // break if prev after field
1521     {
1522       if (next_dup == nullptr) {
1523         break; // no next dup, we're done
1524       }
1525       if (next_slotnum > field_slotnum) {
1526         break; // next dup is after us, we're done
1527       }
1528       prev_dup     = next_dup;
1529       prev_slotnum = next_slotnum;
1530       next_dup     = prev_dup->m_next_dup;
1531     }
1532 
1533     /////////////////////////////////////////////////////
1534     // we get here if the prev_slotnum > field_slotnum //
1535     // (meaning we're now the first dup in the list),  //
1536     // or when we've found the correct prev and next   //
1537     /////////////////////////////////////////////////////
1538 
1539     if (prev_slotnum > field_slotnum) // we are now the head
1540     {
1541       /////////////////////////////////////////////////////////////
1542       // here, it turns out that "prev_dup" is actually after    //
1543       // "field" in the list of fields --- so, prev_dup is a bit //
1544       // of a misnomer, it is actually, the NEXT field!          //
1545       /////////////////////////////////////////////////////////////
1546 
1547       field->m_flags    = (field->m_flags | MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
1548       field->m_next_dup = prev_dup;
1549       prev_dup->m_flags = (prev_dup->m_flags & ~MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
1550       mime_hdr_set_accelerators_and_presence_bits(mh, field);
1551     } else // patch us after prev, and before next
1552     {
1553       ink_assert(prev_slotnum < field_slotnum);
1554       ink_assert((next_dup == nullptr) || (next_slotnum > field_slotnum));
1555       field->m_flags = (field->m_flags & ~MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
1556       ink_assert((next_dup == nullptr) || next_dup->is_live());
1557       prev_dup->m_next_dup = field;
1558       field->m_next_dup    = next_dup;
1559     }
1560   } else {
1561     field->m_flags = (field->m_flags | MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
1562     mime_hdr_set_accelerators_and_presence_bits(mh, field);
1563   }
1564 
1565   // Now keep the cooked cache consistent
1566   ink_assert(field->is_live());
1567   if (field->m_ptr_value && field->is_cooked()) {
1568     mh->recompute_cooked_stuff(field);
1569   }
1570 
1571   MIME_HDR_SANITY_CHECK(mh);
1572 }
1573 
1574 void
mime_hdr_field_detach(MIMEHdrImpl * mh,MIMEField * field,bool detach_all_dups)1575 mime_hdr_field_detach(MIMEHdrImpl *mh, MIMEField *field, bool detach_all_dups)
1576 {
1577   ink_assert(mh);
1578   MIMEField *next_dup = field->m_next_dup;
1579 
1580   // If this field is already detached, there's nothing to do. There must
1581   // not be a dup list if we detached correctly.
1582   if (field->is_detached()) {
1583     ink_assert(next_dup == nullptr);
1584     return;
1585   }
1586 
1587   ink_assert(field->is_live());
1588   MIME_HDR_SANITY_CHECK(mh);
1589 
1590   // Normally, this function is called with the current dup list head,
1591   // so, we need to update the accelerators after the patch out.  But, if
1592   // this function is ever called in the middle of a dup list, we need
1593   // to walk the list to find the previous dup in the list to patch out
1594   // the dup being detached.
1595 
1596   if (field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD) // head of list?
1597   {
1598     if (!next_dup) // only child
1599     {
1600       mime_hdr_unset_accelerators_and_presence_bits(mh, field);
1601     } else // next guy is dup head
1602     {
1603       next_dup->m_flags |= MIME_FIELD_SLOT_FLAGS_DUP_HEAD;
1604       mime_hdr_set_accelerators_and_presence_bits(mh, next_dup);
1605     }
1606   } else // need to walk list to find and patch out from predecessor
1607   {
1608     std::string_view name{field->name_get()};
1609     MIMEField *prev = mime_hdr_field_find(mh, name.data(), static_cast<int>(name.size()));
1610 
1611     while (prev && (prev->m_next_dup != field)) {
1612       prev = prev->m_next_dup;
1613     }
1614     ink_assert(prev != nullptr);
1615 
1616     if (prev->m_next_dup == field) {
1617       prev->m_next_dup = next_dup;
1618     }
1619   }
1620 
1621   // Field is now detached and alone
1622   field->m_readiness = MIME_FIELD_SLOT_READINESS_DETACHED;
1623   field->m_next_dup  = nullptr;
1624 
1625   // Because we changed the values through detaching,update the cooked cache
1626   if (field->is_cooked()) {
1627     mh->recompute_cooked_stuff(field);
1628   }
1629 
1630   MIME_HDR_SANITY_CHECK(mh);
1631 
1632   // At this point, the list should be back to a valid state, either the
1633   // next dup detached and the accelerators set to the next dup (if any),
1634   // or an interior dup detached and patched around.  If we are requested
1635   // to delete the whole dup list, we tail-recurse to delete it.
1636 
1637   if (detach_all_dups && next_dup) {
1638     mime_hdr_field_detach(mh, next_dup, detach_all_dups);
1639   }
1640 }
1641 
1642 void
mime_hdr_field_delete(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,bool delete_all_dups)1643 mime_hdr_field_delete(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, bool delete_all_dups)
1644 {
1645   if (delete_all_dups) {
1646     while (field) {
1647       MIMEField *next = field->m_next_dup;
1648       mime_hdr_field_delete(heap, mh, field, false);
1649       field = next;
1650     }
1651   } else {
1652     heap->free_string(field->m_ptr_name, field->m_len_name);
1653     heap->free_string(field->m_ptr_value, field->m_len_value);
1654 
1655     MIME_HDR_SANITY_CHECK(mh);
1656     mime_hdr_field_detach(mh, field, false);
1657 
1658     MIME_HDR_SANITY_CHECK(mh);
1659     mime_field_destroy(mh, field);
1660 
1661     MIMEFieldBlockImpl *prev_block = nullptr;
1662     bool can_destroy_block         = true;
1663     for (auto fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1664       if (prev_block != nullptr) {
1665         if (fblock->m_freetop == MIME_FIELD_BLOCK_SLOTS && fblock->contains(field)) {
1666           // Check if fields in all slots are deleted
1667           for (int i = 0; i < MIME_FIELD_BLOCK_SLOTS; ++i) {
1668             if (fblock->m_field_slots[i].m_readiness != MIME_FIELD_SLOT_READINESS_DELETED) {
1669               can_destroy_block = false;
1670               break;
1671             }
1672           }
1673           // Destroy a block and maintain the chain
1674           if (can_destroy_block) {
1675             prev_block->m_next = fblock->m_next;
1676             _mime_field_block_destroy(heap, fblock);
1677             if (prev_block->m_next == nullptr) {
1678               mh->m_fblock_list_tail = prev_block;
1679             }
1680           }
1681           break;
1682         }
1683       }
1684       prev_block = fblock;
1685     }
1686   }
1687 
1688   MIME_HDR_SANITY_CHECK(mh);
1689 }
1690 
1691 int
mime_hdr_field_slotnum(MIMEHdrImpl * mh,MIMEField * field)1692 mime_hdr_field_slotnum(MIMEHdrImpl *mh, MIMEField *field)
1693 {
1694   int slots_so_far;
1695   MIMEFieldBlockImpl *fblock;
1696 
1697   slots_so_far = 0;
1698   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
1699     if (fblock->contains(field)) {
1700       MIMEField *first     = &(fblock->m_field_slots[0]);
1701       ptrdiff_t block_slot = field - first; // in units of MIMEField
1702       return slots_so_far + block_slot;
1703     }
1704     slots_so_far += MIME_FIELD_BLOCK_SLOTS;
1705   }
1706   return -1;
1707 }
1708 
1709 MIMEField *
mime_hdr_prepare_for_value_set(HdrHeap * heap,MIMEHdrImpl * mh,const char * name,int name_length)1710 mime_hdr_prepare_for_value_set(HdrHeap *heap, MIMEHdrImpl *mh, const char *name, int name_length)
1711 {
1712   int wks_idx;
1713   MIMEField *field;
1714 
1715   field = mime_hdr_field_find(mh, name, name_length);
1716 
1717   //////////////////////////////////////////////////////////////////////
1718   // this function returns with exactly one attached field created,   //
1719   // ready to have its value set.                                     //
1720   //                                                                  //
1721   // on return from field_find, there are 3 possibilities:            //
1722   //   no field found:      create attached, named field              //
1723   //   field found w/dups:  delete list, create attached, named field //
1724   //   dupless field found: return the field for mutation             //
1725   //////////////////////////////////////////////////////////////////////
1726 
1727   if (field == nullptr) // no fields of this name
1728   {
1729     wks_idx = hdrtoken_tokenize(name, name_length);
1730     field   = mime_field_create(heap, mh);
1731     mime_field_name_set(heap, mh, field, wks_idx, name, name_length, true);
1732     mime_hdr_field_attach(mh, field, 0, nullptr);
1733 
1734   } else if (field->m_next_dup) // list of more than 1 field
1735   {
1736     wks_idx = field->m_wks_idx;
1737     mime_hdr_field_delete(heap, mh, field, true);
1738     field = mime_field_create(heap, mh);
1739     mime_field_name_set(heap, mh, field, wks_idx, name, name_length, true);
1740     mime_hdr_field_attach(mh, field, 0, nullptr);
1741   }
1742   return field;
1743 }
1744 
1745 void
mime_field_destroy(MIMEHdrImpl *,MIMEField * field)1746 mime_field_destroy(MIMEHdrImpl * /* mh ATS_UNUSED */, MIMEField *field)
1747 {
1748   ink_assert(field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED);
1749   field->m_readiness = MIME_FIELD_SLOT_READINESS_DELETED;
1750 }
1751 
1752 std::string_view
name_get() const1753 MIMEField::name_get() const
1754 {
1755   if (m_wks_idx >= 0) {
1756     return {hdrtoken_index_to_wks(m_wks_idx), m_len_name};
1757   }
1758   return {m_ptr_name, m_len_name};
1759 }
1760 
1761 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)1762 mime_field_name_set(HdrHeap *heap, MIMEHdrImpl * /* mh ATS_UNUSED */, MIMEField *field, int16_t name_wks_idx_or_neg1,
1763                     const char *name, int length, bool must_copy_string)
1764 {
1765   ink_assert(field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED);
1766 
1767   field->m_wks_idx = name_wks_idx_or_neg1;
1768   mime_str_u16_set(heap, name, length, &(field->m_ptr_name), &(field->m_len_name), must_copy_string);
1769 
1770   if ((name_wks_idx_or_neg1 == MIME_WKSIDX_CACHE_CONTROL) || (name_wks_idx_or_neg1 == MIME_WKSIDX_PRAGMA)) {
1771     field->m_flags |= MIME_FIELD_SLOT_FLAGS_COOKED;
1772   }
1773 }
1774 
1775 int
value_get_index(const char * value,int length) const1776 MIMEField::value_get_index(const char *value, int length) const
1777 {
1778   int retval = -1;
1779 
1780   // if field doesn't support commas and there is just one instance, just compare the value
1781   if (!this->supports_commas() && !this->has_dups()) {
1782     if (this->m_len_value == static_cast<uint32_t>(length) && strncasecmp(value, this->m_ptr_value, length) == 0) {
1783       retval = 0;
1784     }
1785   } else {
1786     HdrCsvIter iter;
1787     int tok_len;
1788     int index       = 0;
1789     const char *tok = iter.get_first(this, &tok_len);
1790 
1791     while (tok) {
1792       if (tok_len == length && strncasecmp(tok, value, length) == 0) {
1793         retval = index;
1794         break;
1795       } else {
1796         index++;
1797       }
1798       tok = iter.get_next(&tok_len);
1799     }
1800   }
1801 
1802   return retval;
1803 }
1804 
1805 std::string_view
value_get() const1806 MIMEField::value_get() const
1807 {
1808   return {m_ptr_value, m_len_value};
1809 }
1810 
1811 int32_t
mime_field_value_get_int(const MIMEField * field)1812 mime_field_value_get_int(const MIMEField *field)
1813 {
1814   std::string_view value{field->value_get()};
1815 
1816   return mime_parse_int(value.data(), value.data() + value.size());
1817 }
1818 
1819 uint32_t
mime_field_value_get_uint(const MIMEField * field)1820 mime_field_value_get_uint(const MIMEField *field)
1821 {
1822   std::string_view value{field->value_get()};
1823 
1824   return mime_parse_uint(value.data(), value.data() + value.size());
1825 }
1826 
1827 int64_t
mime_field_value_get_int64(const MIMEField * field)1828 mime_field_value_get_int64(const MIMEField *field)
1829 {
1830   std::string_view value{field->value_get()};
1831 
1832   return mime_parse_int64(value.data(), value.data() + value.size());
1833 }
1834 
1835 time_t
mime_field_value_get_date(const MIMEField * field)1836 mime_field_value_get_date(const MIMEField *field)
1837 {
1838   std::string_view value{field->value_get()};
1839 
1840   return mime_parse_date(value.data(), value.data() + value.size());
1841 }
1842 
1843 const char *
mime_field_value_get_comma_val(const MIMEField * field,int * length,int idx)1844 mime_field_value_get_comma_val(const MIMEField *field, int *length, int idx)
1845 {
1846   // some fields (like Date) contain commas but should not be ripped apart
1847   if (!field->supports_commas()) {
1848     if (idx == 0) {
1849       return field->value_get(length);
1850     }
1851     return nullptr;
1852   } else {
1853     Str *str;
1854     StrList list(false);
1855 
1856     mime_field_value_get_comma_list(field, &list);
1857     str = list.get_idx(idx);
1858     if (str != nullptr) {
1859       *length = static_cast<int>(str->len);
1860       return str->str;
1861     } else {
1862       *length = 0;
1863       return nullptr;
1864     }
1865   }
1866 }
1867 
1868 int
mime_field_value_get_comma_val_count(const MIMEField * field)1869 mime_field_value_get_comma_val_count(const MIMEField *field)
1870 {
1871   // some fields (like Date) contain commas but should not be ripped apart
1872   if (!field->supports_commas()) {
1873     return ((field->m_len_value == 0) ? 0 : 1);
1874   } else {
1875     StrList list(false);
1876     int count = mime_field_value_get_comma_list(field, &list);
1877     return count;
1878   }
1879 }
1880 
1881 int
mime_field_value_get_comma_list(const MIMEField * field,StrList * list)1882 mime_field_value_get_comma_list(const MIMEField *field, StrList *list)
1883 {
1884   std::string_view value{field->value_get()};
1885 
1886   // if field doesn't support commas, don't rip apart.
1887   if (!field->supports_commas()) {
1888     list->append_string(value.data(), static_cast<int>(value.size()));
1889   } else {
1890     HttpCompat::parse_tok_list(list, 1, value.data(), static_cast<int>(value.size()), ',');
1891   }
1892 
1893   return list->count;
1894 }
1895 
1896 const char *
mime_field_value_str_from_strlist(HdrHeap * heap,int * new_str_len_return,StrList * list)1897 mime_field_value_str_from_strlist(HdrHeap *heap, int *new_str_len_return, StrList *list)
1898 {
1899   Str *cell;
1900   char *new_value, *dest;
1901   int i, new_value_len;
1902   // This works, because all strings are from the same heap when it is "split" into the list.
1903   HdrHeap::HeapGuard guard(heap, list->head->str);
1904 
1905   new_value_len = 0;
1906 
1907   // (1) walk the StrList cells, summing each cell's string lengths,
1908   //     and add 2 bytes for each ", " between cells
1909   cell = list->head;
1910   for (i = 0; i < list->count; i++) {
1911     new_value_len += cell->len;
1912     cell = cell->next;
1913   }
1914   if (list->count > 1) {
1915     new_value_len += (2 * (list->count - 1));
1916   }
1917 
1918   // (2) allocate new heap string
1919   new_value = heap->allocate_str(new_value_len);
1920 
1921   // (3) copy string pieces into new heap string
1922   dest = new_value;
1923   cell = list->head;
1924   for (i = 0; i < list->count; i++) {
1925     if (i != 0) {
1926       *dest++ = ',';
1927       *dest++ = ' ';
1928     }
1929     memcpy(dest, cell->str, cell->len);
1930     dest += cell->len;
1931     cell = cell->next;
1932   }
1933   ink_assert(dest - new_value == new_value_len);
1934 
1935   *new_str_len_return = new_value_len;
1936   return new_value;
1937 }
1938 
1939 void
mime_field_value_set_comma_val(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int idx,const char * new_piece_str,int new_piece_len)1940 mime_field_value_set_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx, const char *new_piece_str,
1941                                int new_piece_len)
1942 {
1943   int len;
1944   Str *cell;
1945   StrList list(false);
1946 
1947   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
1948   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
1949 
1950   // (2) if desired index isn't valid, then don't change the field
1951   if ((idx < 0) || (idx >= list.count)) {
1952     return;
1953   }
1954 
1955   // (3) mutate cell idx
1956   cell = list.get_idx(idx);
1957   ink_assert(cell != nullptr);
1958   cell->str = new_piece_str;
1959   cell->len = new_piece_len;
1960 
1961   // (4) reassemble the new string
1962   field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
1963   field->m_len_value = len;
1964 
1965   // (5) keep stuff fields consistent
1966   field->m_n_v_raw_printable = 0;
1967   if (field->is_live() && field->is_cooked()) {
1968     mh->recompute_cooked_stuff(field);
1969   }
1970 }
1971 
1972 void
mime_field_value_delete_comma_val(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int idx)1973 mime_field_value_delete_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx)
1974 {
1975   int len;
1976   Str *cell;
1977   StrList list(false);
1978 
1979   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
1980   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
1981 
1982   // (2) if desired index isn't valid, then don't change the field
1983   if ((idx < 0) || (idx >= list.count)) {
1984     return;
1985   }
1986 
1987   // (3) delete cell idx
1988   cell = list.get_idx(idx);
1989   list.detach(cell);
1990 
1991   /**********************************************/
1992   /*   Fix for bug INKqa09752                   */
1993   /*                                            */
1994   /*   If this is the last value                */
1995   /*   in the field, set the m_ptr_val to NULL  */
1996   /**********************************************/
1997 
1998   if (list.count == 0) {
1999     field->m_ptr_value = nullptr;
2000     field->m_len_value = 0;
2001   } else {
2002     /************************************/
2003     /*   End Fix for bug INKqa09752     */
2004     /************************************/
2005 
2006     // (4) reassemble the new string
2007     field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
2008     field->m_len_value = len;
2009   }
2010 
2011   // (5) keep stuff fields consistent
2012   field->m_n_v_raw_printable = 0;
2013   if (field->is_live() && field->is_cooked()) {
2014     mh->recompute_cooked_stuff(field);
2015   }
2016 }
2017 
2018 void
mime_field_value_insert_comma_val(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int idx,const char * new_piece_str,int new_piece_len)2019 mime_field_value_insert_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx, const char *new_piece_str,
2020                                   int new_piece_len)
2021 {
2022   int len;
2023   Str *cell, *prev;
2024   StrList list(false);
2025 
2026   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
2027   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
2028 
2029   // (2) if desired index isn't valid, then don't change the field
2030   if (idx < 0) {
2031     idx = list.count;
2032   }
2033   if (idx > list.count) {
2034     return;
2035   }
2036 
2037   // (3) create a new cell
2038   cell = list.new_cell(new_piece_str, new_piece_len);
2039 
2040   // (4) patch new cell into list at the right place
2041   if (idx == 0) {
2042     list.prepend(cell);
2043   } else {
2044     prev = list.get_idx(idx - 1);
2045     list.add_after(prev, cell);
2046   }
2047 
2048   // (5) reassemble the new string
2049   field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
2050   field->m_len_value = len;
2051 
2052   // (6) keep stuff fields consistent
2053   field->m_n_v_raw_printable = 0;
2054   if (field->is_live() && field->is_cooked()) {
2055     mh->recompute_cooked_stuff(field);
2056   }
2057 }
2058 
2059 void
mime_field_value_extend_comma_val(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int idx,const char * new_piece_str,int new_piece_len)2060 mime_field_value_extend_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx, const char *new_piece_str,
2061                                   int new_piece_len)
2062 {
2063   Str *cell;
2064   StrList list(false);
2065   int trimmed, len;
2066   size_t extended_len;
2067   char *dest, *temp_ptr, temp_buf[128];
2068 
2069   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
2070   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
2071 
2072   // (2) if desired index isn't valid, then don't change the field
2073   if ((idx < 0) || (idx >= list.count)) {
2074     return;
2075   }
2076 
2077   // (3) get the cell we want to modify
2078   cell = list.get_idx(idx);
2079   ink_assert(cell != nullptr);
2080 
2081   // (4) trim quotes if any
2082   if ((cell->len >= 2) && (cell->str[0] == '\"') && (cell->str[cell->len - 1] == '\"')) {
2083     trimmed = 1;
2084     cell->str += 1;
2085     cell->len -= 2;
2086   } else {
2087     trimmed = 0;
2088   }
2089 
2090   // (5) compute length of extended token
2091   extended_len = cell->len + new_piece_len + (trimmed ? 2 : 0);
2092 
2093   // (6) allocate temporary space to construct new value
2094   if (extended_len <= sizeof(temp_buf)) {
2095     temp_ptr = temp_buf;
2096   } else {
2097     temp_ptr = static_cast<char *>(ats_malloc(extended_len));
2098   }
2099 
2100   // (7) construct new extended token
2101   dest = temp_ptr;
2102   if (trimmed) {
2103     *dest++ = '\"';
2104   }
2105   memcpy(dest, cell->str, cell->len);
2106   dest += cell->len;
2107   memcpy(dest, new_piece_str, new_piece_len);
2108   dest += new_piece_len;
2109   if (trimmed) {
2110     *dest++ = '\"';
2111   }
2112   ink_assert((size_t)(dest - temp_ptr) == extended_len);
2113 
2114   // (8) assign the new token to the cell
2115   cell->str = temp_ptr;
2116   cell->len = extended_len;
2117 
2118   // (9) reassemble the new string
2119   field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
2120   field->m_len_value = len;
2121 
2122   // (10) keep stuff fields consistent
2123   field->m_n_v_raw_printable = 0;
2124   if (field->is_live() && field->is_cooked()) {
2125     mh->recompute_cooked_stuff(field);
2126   }
2127 
2128   // (11) free up any temporary storage
2129   if (extended_len > sizeof(temp_buf)) {
2130     ats_free(temp_ptr);
2131   }
2132 }
2133 
2134 void
mime_field_value_set(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,const char * value,int length,bool must_copy_string)2135 mime_field_value_set(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, const char *value, int length, bool must_copy_string)
2136 {
2137   heap->free_string(field->m_ptr_value, field->m_len_value);
2138 
2139   if (must_copy_string && value) {
2140     field->m_ptr_value = heap->duplicate_str(value, length);
2141   } else {
2142     field->m_ptr_value = value;
2143   }
2144 
2145   field->m_len_value         = length;
2146   field->m_n_v_raw_printable = 0;
2147 
2148   // Now keep the cooked cache consistent
2149   if (field->is_live() && field->is_cooked()) {
2150     mh->recompute_cooked_stuff(field);
2151   }
2152 }
2153 
2154 void
mime_field_value_set_int(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int32_t value)2155 mime_field_value_set_int(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int32_t value)
2156 {
2157   char buf[16];
2158   int len = mime_format_int(buf, value, sizeof(buf));
2159   mime_field_value_set(heap, mh, field, buf, len, true);
2160 }
2161 
2162 void
mime_field_value_set_uint(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,uint32_t value)2163 mime_field_value_set_uint(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, uint32_t value)
2164 {
2165   char buf[16];
2166   int len = mime_format_uint(buf, value, sizeof(buf));
2167   mime_field_value_set(heap, mh, field, buf, len, true);
2168 }
2169 
2170 void
mime_field_value_set_int64(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,int64_t value)2171 mime_field_value_set_int64(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int64_t value)
2172 {
2173   char buf[20];
2174   int len = mime_format_int64(buf, value, sizeof(buf));
2175   mime_field_value_set(heap, mh, field, buf, len, true);
2176 }
2177 
2178 void
mime_field_value_set_date(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,time_t value)2179 mime_field_value_set_date(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, time_t value)
2180 {
2181   char buf[33];
2182   int len = mime_format_date(buf, value);
2183   mime_field_value_set(heap, mh, field, buf, len, true);
2184 }
2185 
2186 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)2187 mime_field_name_value_set(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int16_t name_wks_idx_or_neg1, const char *name,
2188                           int name_length, const char *value, int value_length, int n_v_raw_printable, int n_v_raw_length,
2189                           bool must_copy_strings)
2190 {
2191   unsigned int n_v_raw_pad = n_v_raw_length - (name_length + value_length);
2192 
2193   ink_assert(field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED);
2194 
2195   if (must_copy_strings) {
2196     mime_field_name_set(heap, mh, field, name_wks_idx_or_neg1, name, name_length, true);
2197     mime_field_value_set(heap, mh, field, value, value_length, true);
2198   } else {
2199     field->m_wks_idx   = name_wks_idx_or_neg1;
2200     field->m_ptr_name  = name;
2201     field->m_ptr_value = value;
2202     field->m_len_name  = name_length;
2203     field->m_len_value = value_length;
2204     if (n_v_raw_printable && (n_v_raw_pad <= 7)) {
2205       field->m_n_v_raw_printable     = n_v_raw_printable;
2206       field->m_n_v_raw_printable_pad = n_v_raw_pad;
2207     } else {
2208       field->m_n_v_raw_printable = 0;
2209     }
2210 
2211     // Now keep the cooked cache consistent
2212     if ((name_wks_idx_or_neg1 == MIME_WKSIDX_CACHE_CONTROL) || (name_wks_idx_or_neg1 == MIME_WKSIDX_PRAGMA)) {
2213       field->m_flags |= MIME_FIELD_SLOT_FLAGS_COOKED;
2214     }
2215     if (field->is_live() && field->is_cooked()) {
2216       mh->recompute_cooked_stuff(field);
2217     }
2218   }
2219 }
2220 
2221 void
mime_field_value_append(HdrHeap * heap,MIMEHdrImpl * mh,MIMEField * field,const char * value,int length,bool prepend_comma,const char separator)2222 mime_field_value_append(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, const char *value, int length, bool prepend_comma,
2223                         const char separator)
2224 {
2225   int new_length = field->m_len_value + length;
2226   if (prepend_comma && field->m_len_value) {
2227     new_length += 2;
2228   }
2229 
2230   // Start by trying expand the string we already  have
2231   char *new_str = heap->expand_str(field->m_ptr_value, field->m_len_value, new_length);
2232 
2233   if (new_str == nullptr) {
2234     // Expansion failed.  Create a new string and copy over the value contents
2235     new_str = heap->allocate_str(new_length);
2236     memcpy(new_str, field->m_ptr_value, field->m_len_value);
2237   }
2238 
2239   char *ptr = new_str + field->m_len_value;
2240   if (prepend_comma && field->m_len_value) {
2241     *ptr++ = separator;
2242     *ptr++ = ' ';
2243   }
2244 
2245   memcpy(ptr, value, length);
2246 
2247   field->m_ptr_value         = new_str;
2248   field->m_len_value         = new_length;
2249   field->m_n_v_raw_printable = 0;
2250 
2251   // Now keep the cooked cache consistent
2252   if (field->is_live() && field->is_cooked()) {
2253     mh->recompute_cooked_stuff(field);
2254   }
2255 }
2256 
2257 MIMEField *
get_host_port_values(const char ** host_ptr,int * host_len,const char ** port_ptr,int * port_len)2258 MIMEHdr::get_host_port_values(const char **host_ptr, ///< Pointer to host.
2259                               int *host_len,         ///< Length of host.
2260                               const char **port_ptr, ///< Pointer to port.
2261                               int *port_len)
2262 {
2263   MIMEField *field = this->field_find(MIME_FIELD_HOST, MIME_LEN_HOST);
2264   if (host_ptr) {
2265     *host_ptr = nullptr;
2266   }
2267   if (host_len) {
2268     *host_len = 0;
2269   }
2270   if (port_ptr) {
2271     *port_ptr = nullptr;
2272   }
2273   if (port_len) {
2274     *port_len = 0;
2275   }
2276 
2277   if (field) {
2278     ts::TextView b{field->m_ptr_value, static_cast<size_t>(field->m_len_value)};
2279     ts::TextView host, port;
2280 
2281     if (b) {
2282       if ('[' == *b) {
2283         auto idx = b.find(']');
2284         if (idx <= b.size() && b[idx + 1] == ':') {
2285           host = b.take_prefix_at(idx + 1);
2286           port = b;
2287         } else {
2288           host = b;
2289         }
2290       } else {
2291         auto x = b.split_prefix_at(':');
2292         if (x) {
2293           host = x;
2294           port = b;
2295         } else {
2296           host = b;
2297         }
2298       }
2299 
2300       if (host) {
2301         if (host_ptr) {
2302           *host_ptr = host.data();
2303         }
2304         if (host_len) {
2305           *host_len = static_cast<int>(host.size());
2306         }
2307       }
2308       if (port) {
2309         if (port_ptr) {
2310           *port_ptr = port.data();
2311         }
2312         if (port_len) {
2313           *port_len = static_cast<int>(port.size());
2314         }
2315       }
2316     } else {
2317       field = nullptr; // no value in field, signal fail.
2318     }
2319   }
2320   return field;
2321 }
2322 
2323 /***********************************************************************
2324  *                                                                     *
2325  *                          P A R S E R                                *
2326  *                                                                     *
2327  ***********************************************************************/
2328 
2329 void
init()2330 MIMEScanner::init()
2331 {
2332   m_state = INITIAL_PARSE_STATE;
2333   // Ugly, but required because of how proxy allocation works - that leaves the instance in a
2334   // random state, so even assigning to it can crash. Because this method substitutes for a real
2335   // constructor in the proxy allocation system, call the CTOR here. Any memory that gets allocated
2336   // is supposed to be cleaned up by calling @c clear on this object.
2337   new (&m_line) std::string;
2338 }
2339 
2340 MIMEScanner &
append(TextView text)2341 MIMEScanner::append(TextView text)
2342 {
2343   m_line += text;
2344   return *this;
2345 }
2346 
2347 ParseResult
get(TextView & input,TextView & output,bool & output_shares_input,bool eof_p,ScanType scan_type)2348 MIMEScanner::get(TextView &input, TextView &output, bool &output_shares_input, bool eof_p, ScanType scan_type)
2349 {
2350   ParseResult zret = PARSE_RESULT_CONT;
2351   // Need this for handling dangling CR.
2352   static const char RAW_CR{ParseRules::CHAR_CR};
2353 
2354   auto text = input;
2355   while (PARSE_RESULT_CONT == zret && !text.empty()) {
2356     switch (m_state) {
2357     case MIME_PARSE_BEFORE: // waiting to find a field.
2358       m_line.resize(0);     // any caller should already be done with the buffer
2359       if (ParseRules::is_cr(*text)) {
2360         ++text;
2361         if (!text.empty() && ParseRules::is_lf(*text)) {
2362           // optimize a bit - this happens >99% of the time after a CR.
2363           ++text;
2364           zret = PARSE_RESULT_DONE;
2365         } else {
2366           m_state = MIME_PARSE_FOUND_CR;
2367         }
2368       } else if (ParseRules::is_lf(*text)) {
2369         ++text;
2370         zret = PARSE_RESULT_DONE; // Required by regression test.
2371       } else {
2372         // consume this character in the next state.
2373         m_state = MIME_PARSE_INSIDE;
2374       }
2375       break;
2376     case MIME_PARSE_FOUND_CR:
2377       // Looking for a field and found a CR, which should mean terminating the header.
2378       if (ParseRules::is_lf(*text)) {
2379         ++text;
2380         zret = PARSE_RESULT_DONE;
2381       } else {
2382         // This really should be an error (spec doesn't permit lone CR) but the regression tests
2383         // require it.
2384         this->append({&RAW_CR, 1});
2385         m_state = MIME_PARSE_INSIDE;
2386       }
2387       break;
2388     case MIME_PARSE_INSIDE: {
2389       auto lf_off = text.find(ParseRules::CHAR_LF);
2390       if (lf_off != TextView::npos) {
2391         text.remove_prefix(lf_off + 1); // drop up to and including LF
2392         if (LINE == scan_type) {
2393           zret    = PARSE_RESULT_OK;
2394           m_state = MIME_PARSE_BEFORE;
2395         } else {
2396           m_state = MIME_PARSE_AFTER; // looking for line folding.
2397         }
2398       } else { // no EOL, consume all text without changing state.
2399         text.remove_prefix(text.size());
2400       }
2401     } break;
2402     case MIME_PARSE_AFTER:
2403       // After a LF, the next line might be a continuation / folded line. That's indicated by a
2404       // starting whitespace. If that's the case, back up over the preceding CR/LF with space and
2405       // pretend it's the same line.
2406       if (ParseRules::is_ws(*text)) { // folded line.
2407         char *unfold = const_cast<char *>(text.data() - 1);
2408         *unfold--    = ' ';
2409         if (ParseRules::is_cr(*unfold)) {
2410           *unfold = ' ';
2411         }
2412         m_state = MIME_PARSE_INSIDE; // back inside the field.
2413       } else {
2414         m_state = MIME_PARSE_BEFORE; // field terminated.
2415         zret    = PARSE_RESULT_OK;
2416       }
2417       break;
2418     }
2419   }
2420 
2421   TextView parsed_text{input.data(), text.data()};
2422   bool save_parsed_text_p = !parsed_text.empty();
2423 
2424   if (PARSE_RESULT_CONT == zret) {
2425     // data ran out before we got a clear final result. There a number of things we need to check
2426     // and possibly adjust that result. It's less complex to do this cleanup than handle all of
2427     // these checks in the parser state machine.
2428     if (eof_p) {
2429       // Should never return PARSE_CONT if we've hit EOF.
2430       if (parsed_text.empty()) {
2431         // all input previously consumed. If we're between fields, that's cool.
2432         if (MIME_PARSE_INSIDE != m_state) {
2433           m_state = MIME_PARSE_BEFORE; // probably not needed...
2434           zret    = PARSE_RESULT_DONE;
2435         } else {
2436           zret = PARSE_RESULT_ERROR; // unterminated field.
2437         }
2438       } else if (MIME_PARSE_AFTER == m_state) {
2439         // Special case it seems - need to accept the final field even if there's no header
2440         // terminating CR LF. This is only reasonable after absolute end of input (EOF) because
2441         // otherwise this might be a multiline field where we haven't seen the next leading space.
2442         m_state = MIME_PARSE_BEFORE;
2443         zret    = PARSE_RESULT_OK;
2444       } else {
2445         // Partial input, no field / line CR LF
2446         zret = PARSE_RESULT_ERROR; // Unterminated field.
2447       }
2448     } else if (!parsed_text.empty()) {
2449       if (MIME_PARSE_INSIDE == m_state) {
2450         // Inside a field but more data is expected. Save what we've got.
2451         this->append(parsed_text);  // Do this here to force appending.
2452         save_parsed_text_p = false; // don't double append.
2453       } else if (MIME_PARSE_AFTER == m_state) {
2454         // After a field but we still have data. Need to parse it too.
2455         m_state = MIME_PARSE_BEFORE;
2456         zret    = PARSE_RESULT_OK;
2457       }
2458     }
2459   }
2460 
2461   if (save_parsed_text_p && !m_line.empty()) {
2462     // If we're already accumulating, continue to do so if we have data.
2463     this->append(parsed_text);
2464   }
2465 
2466   // adjust out arguments.
2467   output_shares_input = true;
2468   if (PARSE_RESULT_CONT != zret) {
2469     if (!m_line.empty()) {
2470       output              = m_line; // cleared when called with state MIME_PARSE_BEFORE
2471       output_shares_input = false;
2472     } else {
2473       output = parsed_text;
2474     }
2475   }
2476 
2477   // Make sure there are no null characters in the input scanned so far
2478   if (zret != PARSE_RESULT_ERROR && TextView::npos != parsed_text.find('\0')) {
2479     zret = PARSE_RESULT_ERROR;
2480   }
2481 
2482   input.remove_prefix(parsed_text.size());
2483   return zret;
2484 }
2485 
2486 void
_mime_parser_init(MIMEParser * parser)2487 _mime_parser_init(MIMEParser *parser)
2488 {
2489   parser->m_field       = 0;
2490   parser->m_field_flags = 0;
2491   parser->m_value       = -1;
2492 }
2493 //////////////////////////////////////////////////////
2494 // init     first time structure setup              //
2495 // clear    resets an already-initialized structure //
2496 //////////////////////////////////////////////////////
2497 void
mime_parser_init(MIMEParser * parser)2498 mime_parser_init(MIMEParser *parser)
2499 {
2500   parser->m_scanner.init();
2501   _mime_parser_init(parser);
2502 }
2503 
2504 void
mime_parser_clear(MIMEParser * parser)2505 mime_parser_clear(MIMEParser *parser)
2506 {
2507   parser->m_scanner.clear();
2508   _mime_parser_init(parser);
2509 }
2510 
2511 ParseResult
mime_parser_parse(MIMEParser * parser,HdrHeap * heap,MIMEHdrImpl * mh,const char ** real_s,const char * real_e,bool must_copy_strings,bool eof,size_t max_hdr_field_size)2512 mime_parser_parse(MIMEParser *parser, HdrHeap *heap, MIMEHdrImpl *mh, const char **real_s, const char *real_e,
2513                   bool must_copy_strings, bool eof, size_t max_hdr_field_size)
2514 {
2515   ParseResult err;
2516   bool line_is_real;
2517 
2518   MIMEScanner *scanner = &parser->m_scanner;
2519 
2520   while (true) {
2521     ////////////////////////////////////////////////////////////////////////////
2522     // get a name:value line, with all continuation lines glued into one line //
2523     ////////////////////////////////////////////////////////////////////////////
2524 
2525     TextView text{*real_s, real_e};
2526     TextView parsed;
2527     err     = scanner->get(text, parsed, line_is_real, eof, MIMEScanner::FIELD);
2528     *real_s = text.data();
2529     if (err != PARSE_RESULT_OK) {
2530       return err;
2531     }
2532 
2533     //////////////////////////////////////////////////
2534     // if got a LF or CR on its own, end the header //
2535     //////////////////////////////////////////////////
2536 
2537     if ((parsed.size() >= 2) && (parsed[0] == ParseRules::CHAR_CR) && (parsed[1] == ParseRules::CHAR_LF)) {
2538       return PARSE_RESULT_DONE;
2539     }
2540 
2541     if ((parsed.size() >= 1) && (parsed[0] == ParseRules::CHAR_LF)) {
2542       return PARSE_RESULT_DONE;
2543     }
2544 
2545     /////////////////////////////////////////////
2546     // find pointers into the name:value field //
2547     /////////////////////////////////////////////
2548 
2549     /**
2550      * Fix for INKqa09141. The is_token function fails for '@' character.
2551      * Header names starting with '@' signs are valid headers. Hence we
2552      * have to add one more check to see if the first parameter is '@'
2553      * character then, the header name is valid.
2554      **/
2555     if ((!ParseRules::is_token(*parsed)) && (*parsed != '@')) {
2556       continue; // toss away garbage line
2557     }
2558 
2559     // find name last
2560     auto field_value = parsed; // need parsed as is later on.
2561     auto field_name  = field_value.split_prefix_at(':');
2562     if (field_name.empty()) {
2563       continue; // toss away garbage line
2564     }
2565 
2566     // RFC7230 section 3.2.4:
2567     // No whitespace is allowed between the header field-name and colon.  In
2568     // the past, differences in the handling of such whitespace have led to
2569     // security vulnerabilities in request routing and response handling.  A
2570     // server MUST reject any received request message that contains
2571     // whitespace between a header field-name and colon with a response code
2572     // of 400 (Bad Request).
2573     if (is_ws(field_name.back())) {
2574       return PARSE_RESULT_ERROR;
2575     }
2576 
2577     // find value first
2578     field_value.ltrim_if(&ParseRules::is_ws);
2579     field_value.rtrim_if(&ParseRules::is_wslfcr);
2580 
2581     // Make sure the name + value is not longer than configured max_hdr_field_size
2582     if (field_name.size() + field_value.size() > max_hdr_field_size) {
2583       return PARSE_RESULT_ERROR;
2584     }
2585 
2586     //    int total_line_length = (int)(field_line_last - field_line_first + 1);
2587 
2588     //////////////////////////////////////////////////////////////////////
2589     // if we can't leave the name & value in the real buffer, copy them //
2590     //////////////////////////////////////////////////////////////////////
2591 
2592     if (must_copy_strings || (!line_is_real)) {
2593       char *dup       = heap->duplicate_str(parsed.data(), parsed.size());
2594       ptrdiff_t delta = dup - parsed.data();
2595       field_name.assign(field_name.data() + delta, field_name.size());
2596       field_value.assign(field_value.data() + delta, field_value.size());
2597     }
2598     ///////////////////////
2599     // tokenize the name //
2600     ///////////////////////
2601 
2602     int field_name_wks_idx = hdrtoken_tokenize(field_name.data(), field_name.size());
2603 
2604     ///////////////////////////////////////////
2605     // build and insert the new field object //
2606     ///////////////////////////////////////////
2607 
2608     MIMEField *field = mime_field_create(heap, mh);
2609     mime_field_name_value_set(heap, mh, field, field_name_wks_idx, field_name.data(), field_name.size(), field_value.data(),
2610                               field_value.size(), true, parsed.size(), false);
2611     mime_hdr_field_attach(mh, field, 1, nullptr);
2612   }
2613 }
2614 
2615 void
mime_hdr_describe(HdrHeapObjImpl * raw,bool recurse)2616 mime_hdr_describe(HdrHeapObjImpl *raw, bool recurse)
2617 {
2618   MIMEFieldBlockImpl *fblock;
2619   MIMEHdrImpl *obj = (MIMEHdrImpl *)raw;
2620 
2621   Debug("http", "\t[PBITS: 0x%08X%08X, SLACC: 0x%04X%04X%04X%04X, HEADBLK: %p, TAILBLK: %p]",
2622         (uint32_t)((obj->m_presence_bits >> 32) & (TOK_64_CONST(0xFFFFFFFF))),
2623         (uint32_t)((obj->m_presence_bits >> 0) & (TOK_64_CONST(0xFFFFFFFF))), obj->m_slot_accelerators[0],
2624         obj->m_slot_accelerators[1], obj->m_slot_accelerators[2], obj->m_slot_accelerators[3], &(obj->m_first_fblock),
2625         obj->m_fblock_list_tail);
2626 
2627   Debug("http", "\t[CBITS: 0x%08X, T_MAXAGE: %d, T_SMAXAGE: %d, T_MAXSTALE: %d, T_MINFRESH: %d, PNO$: %d]",
2628         obj->m_cooked_stuff.m_cache_control.m_mask, obj->m_cooked_stuff.m_cache_control.m_secs_max_age,
2629         obj->m_cooked_stuff.m_cache_control.m_secs_s_maxage, obj->m_cooked_stuff.m_cache_control.m_secs_max_stale,
2630         obj->m_cooked_stuff.m_cache_control.m_secs_min_fresh, obj->m_cooked_stuff.m_pragma.m_no_cache);
2631   for (fblock = &(obj->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
2632     if (recurse || (fblock == &(obj->m_first_fblock))) {
2633       obj_describe((HdrHeapObjImpl *)fblock, recurse);
2634     }
2635   }
2636 }
2637 
2638 void
mime_field_block_describe(HdrHeapObjImpl * raw,bool)2639 mime_field_block_describe(HdrHeapObjImpl *raw, bool /* recurse ATS_UNUSED */)
2640 {
2641   unsigned int i;
2642   static const char *readiness_names[] = {"EMPTY", "DETACHED", "LIVE", "DELETED"};
2643 
2644   MIMEFieldBlockImpl *obj = (MIMEFieldBlockImpl *)raw;
2645 
2646   Debug("http", "[FREETOP: %d, NEXTBLK: %p]", obj->m_freetop, obj->m_next);
2647 
2648   for (i = 0; i < obj->m_freetop; i++) {
2649     MIMEField *f = &(obj->m_field_slots[i]);
2650     Debug("http", "\tSLOT #%2d (%p), %-8s", i, f, readiness_names[f->m_readiness]);
2651 
2652     switch (f->m_readiness) {
2653     case MIME_FIELD_SLOT_READINESS_EMPTY:
2654       break;
2655     case MIME_FIELD_SLOT_READINESS_DETACHED:
2656     case MIME_FIELD_SLOT_READINESS_LIVE:
2657     case MIME_FIELD_SLOT_READINESS_DELETED:
2658       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,
2659             f->m_wks_idx);
2660       Debug("http", "V: \"%.*s\", V_LEN: %d, ", f->m_len_value, (f->m_ptr_value ? f->m_ptr_value : "NULL"), f->m_len_value);
2661       Debug("http", "NEXTDUP: %p, RAW: %d, RAWLEN: %d, F: %d]", f->m_next_dup, f->m_n_v_raw_printable,
2662             f->m_len_name + f->m_len_value + f->m_n_v_raw_printable_pad, f->m_flags);
2663       break;
2664     }
2665     Debug("http", "\n");
2666   }
2667 }
2668 
2669 int
mime_hdr_print(HdrHeap *,MIMEHdrImpl * mh,char * buf_start,int buf_length,int * buf_index_inout,int * buf_chars_to_skip_inout)2670 mime_hdr_print(HdrHeap * /* heap ATS_UNUSED */, MIMEHdrImpl *mh, char *buf_start, int buf_length, int *buf_index_inout,
2671                int *buf_chars_to_skip_inout)
2672 {
2673   MIMEFieldBlockImpl *fblock;
2674   MIMEField *field;
2675   uint32_t index;
2676 
2677 #define SIMPLE_MIME_HDR_PRINT
2678 #ifdef SIMPLE_MIME_HDR_PRINT
2679   for (fblock = &(mh->m_first_fblock); fblock != nullptr; fblock = fblock->m_next) {
2680     for (index = 0; index < fblock->m_freetop; index++) {
2681       field = &(fblock->m_field_slots[index]);
2682       if (field->is_live()) {
2683         if (!mime_field_print(field, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout)) {
2684           return 0;
2685         }
2686       }
2687     }
2688   }
2689 #else
2690   // FIX: if not raw_printable, need to print with mime_field_print,
2691   //      not mime_mem_print
2692   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
2693     const char *contig_start = NULL;
2694     int this_length, contig_length = 0;
2695     for (index = 0; index < fblock->m_freetop; index++) {
2696       field       = &(fblock->m_field_slots[index]);
2697       this_length = field->m_len_name + field->m_len_value + field->m_n_v_raw_printable_pad;
2698       if (field->is_live()) {
2699         if ((field->m_ptr_name == contig_start + contig_length) && field->m_n_v_raw_printable &&
2700             ((buf_index_inout == NULL) || (contig_length + this_length <= buf_length - *buf_index_inout))) {
2701           contig_length += this_length;
2702         } else {
2703           if (contig_length > 0) {
2704             if (!mime_mem_print(contig_start, contig_length, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout))
2705               return 0;
2706           }
2707           contig_start  = field->m_ptr_name;
2708           contig_length = this_length;
2709         }
2710       }
2711     }
2712 
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   }
2718 #endif
2719 
2720   if (!mime_mem_print("\r\n", 2, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout)) {
2721     return 0;
2722   }
2723 
2724   return 1;
2725 }
2726 
2727 namespace
2728 {
2729 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))2730 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,
2731                 int (*char_transform)(int char_in))
2732 {
2733   if (buf_start == nullptr) { // this case should only be used by test_header
2734     ink_release_assert(buf_index_inout == nullptr);
2735     ink_release_assert(buf_chars_to_skip_inout == nullptr);
2736     while (src_l--) {
2737       putchar(*src_d++);
2738     }
2739     return 1;
2740   }
2741 
2742   ink_assert(src_d != nullptr);
2743 
2744   if (*buf_chars_to_skip_inout > 0) {
2745     if (*buf_chars_to_skip_inout >= src_l) {
2746       *buf_chars_to_skip_inout -= src_l;
2747       return 1;
2748     } else {
2749       src_l -= *buf_chars_to_skip_inout;
2750       src_d += *buf_chars_to_skip_inout;
2751       *buf_chars_to_skip_inout = 0;
2752     }
2753   }
2754 
2755   int copy_l = std::min(buf_length - *buf_index_inout, src_l);
2756   if (copy_l > 0) {
2757     buf_start += *buf_index_inout;
2758     std::transform(src_d, src_d + copy_l, buf_start, char_transform);
2759     *buf_index_inout += copy_l;
2760   }
2761   return (src_l == copy_l);
2762 }
2763 
2764 int
to_same_char(int ch)2765 to_same_char(int ch)
2766 {
2767   return ch;
2768 }
2769 
2770 } // end anonymous namespace
2771 
2772 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)2773 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)
2774 {
2775   return mime_mem_print_(src_d, src_l, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout, to_same_char);
2776 }
2777 
2778 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)2779 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)
2780 {
2781   return mime_mem_print_(src_d, src_l, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout, std::tolower);
2782 }
2783 
2784 int
mime_field_print(MIMEField * field,char * buf_start,int buf_length,int * buf_index_inout,int * buf_chars_to_skip_inout)2785 mime_field_print(MIMEField *field, char *buf_start, int buf_length, int *buf_index_inout, int *buf_chars_to_skip_inout)
2786 {
2787 #define TRY(x) \
2788   if (!x)      \
2789   return 0
2790 
2791   int total_len;
2792 
2793   // Don't print names that begin with an '@'.
2794   if (field->m_ptr_name[0] == '@') {
2795     return 1;
2796   }
2797 
2798   if (field->m_n_v_raw_printable) {
2799     total_len = field->m_len_name + field->m_len_value + field->m_n_v_raw_printable_pad;
2800 
2801     if ((buf_start != nullptr) && (*buf_chars_to_skip_inout == 0) && (total_len <= (buf_length - *buf_index_inout))) {
2802       buf_start += *buf_index_inout;
2803       memcpy(buf_start, field->m_ptr_name, total_len);
2804       *buf_index_inout += total_len;
2805 
2806     } else {
2807       TRY(mime_mem_print(field->m_ptr_name, total_len, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
2808     }
2809   } else {
2810     total_len = field->m_len_name + field->m_len_value + 2 + 2;
2811 
2812     // try to handle on fast path
2813 
2814     if ((buf_start != nullptr) && (*buf_chars_to_skip_inout == 0) && (total_len <= (buf_length - *buf_index_inout))) {
2815       buf_start += *buf_index_inout;
2816 
2817       memcpy(buf_start, field->m_ptr_name, field->m_len_name);
2818       buf_start += field->m_len_name;
2819 
2820       buf_start[0] = ':';
2821       buf_start[1] = ' ';
2822       buf_start += 2;
2823 
2824       memcpy(buf_start, field->m_ptr_value, field->m_len_value);
2825       buf_start += field->m_len_value;
2826 
2827       buf_start[0] = '\r';
2828       buf_start[1] = '\n';
2829 
2830       *buf_index_inout += total_len;
2831     } else {
2832       TRY(mime_mem_print(field->m_ptr_name, field->m_len_name, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
2833       TRY(mime_mem_print(": ", 2, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
2834       TRY(mime_mem_print(field->m_ptr_value, field->m_len_value, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
2835       TRY(mime_mem_print("\r\n", 2, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
2836     }
2837   }
2838 
2839   return 1;
2840 
2841 #undef TRY
2842 }
2843 
2844 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)2845 mime_str_u16_set(HdrHeap *heap, const char *s_str, int s_len, const char **d_str, uint16_t *d_len, bool must_copy)
2846 {
2847   ink_assert(s_len >= 0 && s_len < UINT16_MAX);
2848   // INKqa08287 - keep track of free string space.
2849   //  INVARIENT: passed in result pointers must be to
2850   //    either NULL or be valid ptr for a string already
2851   //    the string heaps
2852   heap->free_string(*d_str, *d_len);
2853 
2854   if (must_copy && s_str) {
2855     s_str = heap->duplicate_str(s_str, s_len);
2856   }
2857   *d_str = s_str;
2858   *d_len = s_len;
2859   return s_str;
2860 }
2861 
2862 int
mime_field_length_get(MIMEField * field)2863 mime_field_length_get(MIMEField *field)
2864 {
2865   if (