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