• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

MIME.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 #include "ink_defs.h"
00025 #include "libts.h"
00026 #include <assert.h>
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include "MIME.h"
00030 #include "HdrHeap.h"
00031 #include "HdrToken.h"
00032 #include "HdrUtils.h"
00033 #include "HttpCompat.h"
00034 
00035 /***********************************************************************
00036  *                                                                     *
00037  *                    C O M P I L E    O P T I O N S                   *
00038  *                                                                     *
00039  ***********************************************************************/
00040 #define TRACK_FIELD_FIND_CALLS                  0
00041 #define TRACK_COOKING                           0
00042 #define MIME_FORMAT_DATE_USE_LOOKUP_TABLE       1
00043 
00044 
00045 /***********************************************************************
00046  *                                                                     *
00047  *                          C O N S T A N T S                          *
00048  *                                                                     *
00049  ***********************************************************************/
00050 static DFA *day_names_dfa = NULL;
00051 static DFA *month_names_dfa = NULL;
00052 
00053 static const char *day_names[] = {
00054   "Sun",
00055   "Mon",
00056   "Tue",
00057   "Wed",
00058   "Thu",
00059   "Fri",
00060   "Sat",
00061 };
00062 
00063 static const char *month_names[] = {
00064   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00065   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
00066 };
00067 
00068 struct MDY
00069 {
00070   uint8_t m;
00071   uint8_t d;
00072   uint16_t y;
00073 };
00074 
00075 static MDY *_days_to_mdy_fast_lookup_table = NULL;
00076 static unsigned int _days_to_mdy_fast_lookup_table_first_day;
00077 static unsigned int _days_to_mdy_fast_lookup_table_last_day;
00078 
00079 
00080 /***********************************************************************
00081  *                                                                     *
00082  *                             G L O B A L S                           *
00083  *                                                                     *
00084  ***********************************************************************/
00085 const char *MIME_FIELD_ACCEPT;
00086 const char *MIME_FIELD_ACCEPT_CHARSET;
00087 const char *MIME_FIELD_ACCEPT_ENCODING;
00088 const char *MIME_FIELD_ACCEPT_LANGUAGE;
00089 const char *MIME_FIELD_ACCEPT_RANGES;
00090 const char *MIME_FIELD_AGE;
00091 const char *MIME_FIELD_ALLOW;
00092 const char *MIME_FIELD_APPROVED;
00093 const char *MIME_FIELD_AUTHORIZATION;
00094 const char *MIME_FIELD_BYTES;
00095 const char *MIME_FIELD_CACHE_CONTROL;
00096 const char *MIME_FIELD_CLIENT_IP;
00097 const char *MIME_FIELD_CONNECTION;
00098 const char *MIME_FIELD_CONTENT_BASE;
00099 const char *MIME_FIELD_CONTENT_ENCODING;
00100 const char *MIME_FIELD_CONTENT_LANGUAGE;
00101 const char *MIME_FIELD_CONTENT_LENGTH;
00102 const char *MIME_FIELD_CONTENT_LOCATION;
00103 const char *MIME_FIELD_CONTENT_MD5;
00104 const char *MIME_FIELD_CONTENT_RANGE;
00105 const char *MIME_FIELD_CONTENT_TYPE;
00106 const char *MIME_FIELD_CONTROL;
00107 const char *MIME_FIELD_COOKIE;
00108 const char *MIME_FIELD_DATE;
00109 const char *MIME_FIELD_DISTRIBUTION;
00110 const char *MIME_FIELD_ETAG;
00111 const char *MIME_FIELD_EXPECT;
00112 const char *MIME_FIELD_EXPIRES;
00113 const char *MIME_FIELD_FOLLOWUP_TO;
00114 const char *MIME_FIELD_FROM;
00115 const char *MIME_FIELD_HOST;
00116 const char *MIME_FIELD_IF_MATCH;
00117 const char *MIME_FIELD_IF_MODIFIED_SINCE;
00118 const char *MIME_FIELD_IF_NONE_MATCH;
00119 const char *MIME_FIELD_IF_RANGE;
00120 const char *MIME_FIELD_IF_UNMODIFIED_SINCE;
00121 const char *MIME_FIELD_KEEP_ALIVE;
00122 const char *MIME_FIELD_KEYWORDS;
00123 const char *MIME_FIELD_LAST_MODIFIED;
00124 const char *MIME_FIELD_LINES;
00125 const char *MIME_FIELD_LOCATION;
00126 const char *MIME_FIELD_MAX_FORWARDS;
00127 const char *MIME_FIELD_MESSAGE_ID;
00128 const char *MIME_FIELD_NEWSGROUPS;
00129 const char *MIME_FIELD_ORGANIZATION;
00130 const char *MIME_FIELD_PATH;
00131 const char *MIME_FIELD_PRAGMA;
00132 const char *MIME_FIELD_PROXY_AUTHENTICATE;
00133 const char *MIME_FIELD_PROXY_AUTHORIZATION;
00134 const char *MIME_FIELD_PROXY_CONNECTION;
00135 const char *MIME_FIELD_PUBLIC;
00136 const char *MIME_FIELD_RANGE;
00137 const char *MIME_FIELD_REFERENCES;
00138 const char *MIME_FIELD_REFERER;
00139 const char *MIME_FIELD_REPLY_TO;
00140 const char *MIME_FIELD_RETRY_AFTER;
00141 const char *MIME_FIELD_SENDER;
00142 const char *MIME_FIELD_SERVER;
00143 const char *MIME_FIELD_SET_COOKIE;
00144 const char *MIME_FIELD_STRICT_TRANSPORT_SECURITY;
00145 const char *MIME_FIELD_SUBJECT;
00146 const char *MIME_FIELD_SUMMARY;
00147 const char *MIME_FIELD_TE;
00148 const char *MIME_FIELD_TRANSFER_ENCODING;
00149 const char *MIME_FIELD_UPGRADE;
00150 const char *MIME_FIELD_USER_AGENT;
00151 const char *MIME_FIELD_VARY;
00152 const char *MIME_FIELD_VIA;
00153 const char *MIME_FIELD_WARNING;
00154 const char *MIME_FIELD_WWW_AUTHENTICATE;
00155 const char *MIME_FIELD_XREF;
00156 const char *MIME_FIELD_INT_DATA_INFO;
00157 const char *MIME_FIELD_X_ID;
00158 const char *MIME_FIELD_X_FORWARDED_FOR;
00159 const char *MIME_FIELD_SEC_WEBSOCKET_KEY;
00160 const char *MIME_FIELD_SEC_WEBSOCKET_VERSION;
00161 
00162 const char *MIME_VALUE_BYTES;
00163 const char *MIME_VALUE_CHUNKED;
00164 const char *MIME_VALUE_CLOSE;
00165 const char *MIME_VALUE_COMPRESS;
00166 const char *MIME_VALUE_DEFLATE;
00167 const char *MIME_VALUE_GZIP;
00168 const char *MIME_VALUE_IDENTITY;
00169 const char *MIME_VALUE_KEEP_ALIVE;
00170 const char *MIME_VALUE_MAX_AGE;
00171 const char *MIME_VALUE_MAX_STALE;
00172 const char *MIME_VALUE_MIN_FRESH;
00173 const char *MIME_VALUE_MUST_REVALIDATE;
00174 const char *MIME_VALUE_NONE;
00175 const char *MIME_VALUE_NO_CACHE;
00176 const char *MIME_VALUE_NO_STORE;
00177 const char *MIME_VALUE_NO_TRANSFORM;
00178 const char *MIME_VALUE_ONLY_IF_CACHED;
00179 const char *MIME_VALUE_PRIVATE;
00180 const char *MIME_VALUE_PROXY_REVALIDATE;
00181 const char *MIME_VALUE_PUBLIC;
00182 const char *MIME_VALUE_S_MAXAGE;
00183 const char *MIME_VALUE_NEED_REVALIDATE_ONCE;
00184 const char *MIME_VALUE_WEBSOCKET;
00185 
00186 // Cache-control: extension "need-revalidate-once" is used internally by T.S.
00187 // to invalidate a document, and it is not returned/forwarded.
00188 // If a cached document has this extension set (ie, is invalidated),
00189 // then the T.S. needs to revalidate the document once before returning it.
00190 // After a successful revalidation, the extension will be removed by T.S.
00191 // To set or unset this directive should be done via the following two
00192 // function:
00193 //      set_cooked_cc_need_revalidate_once()
00194 //      unset_cooked_cc_need_revalidate_once()
00195 // To test, use regular Cache-control testing functions, eg,
00196 //      is_cache_control_set(HTTP_VALUE_NEED_REVALIDATE_ONCE)
00197 
00198 int MIME_LEN_ACCEPT;
00199 int MIME_LEN_ACCEPT_CHARSET;
00200 int MIME_LEN_ACCEPT_ENCODING;
00201 int MIME_LEN_ACCEPT_LANGUAGE;
00202 int MIME_LEN_ACCEPT_RANGES;
00203 int MIME_LEN_AGE;
00204 int MIME_LEN_ALLOW;
00205 int MIME_LEN_APPROVED;
00206 int MIME_LEN_AUTHORIZATION;
00207 int MIME_LEN_BYTES;
00208 int MIME_LEN_CACHE_CONTROL;
00209 int MIME_LEN_CLIENT_IP;
00210 int MIME_LEN_CONNECTION;
00211 int MIME_LEN_CONTENT_BASE;
00212 int MIME_LEN_CONTENT_ENCODING;
00213 int MIME_LEN_CONTENT_LANGUAGE;
00214 int MIME_LEN_CONTENT_LENGTH;
00215 int MIME_LEN_CONTENT_LOCATION;
00216 int MIME_LEN_CONTENT_MD5;
00217 int MIME_LEN_CONTENT_RANGE;
00218 int MIME_LEN_CONTENT_TYPE;
00219 int MIME_LEN_CONTROL;
00220 int MIME_LEN_COOKIE;
00221 int MIME_LEN_DATE;
00222 int MIME_LEN_DISTRIBUTION;
00223 int MIME_LEN_ETAG;
00224 int MIME_LEN_EXPECT;
00225 int MIME_LEN_EXPIRES;
00226 int MIME_LEN_FOLLOWUP_TO;
00227 int MIME_LEN_FROM;
00228 int MIME_LEN_HOST;
00229 int MIME_LEN_IF_MATCH;
00230 int MIME_LEN_IF_MODIFIED_SINCE;
00231 int MIME_LEN_IF_NONE_MATCH;
00232 int MIME_LEN_IF_RANGE;
00233 int MIME_LEN_IF_UNMODIFIED_SINCE;
00234 int MIME_LEN_KEEP_ALIVE;
00235 int MIME_LEN_KEYWORDS;
00236 int MIME_LEN_LAST_MODIFIED;
00237 int MIME_LEN_LINES;
00238 int MIME_LEN_LOCATION;
00239 int MIME_LEN_MAX_FORWARDS;
00240 int MIME_LEN_MESSAGE_ID;
00241 int MIME_LEN_NEWSGROUPS;
00242 int MIME_LEN_ORGANIZATION;
00243 int MIME_LEN_PATH;
00244 int MIME_LEN_PRAGMA;
00245 int MIME_LEN_PROXY_AUTHENTICATE;
00246 int MIME_LEN_PROXY_AUTHORIZATION;
00247 int MIME_LEN_PROXY_CONNECTION;
00248 int MIME_LEN_PUBLIC;
00249 int MIME_LEN_RANGE;
00250 int MIME_LEN_REFERENCES;
00251 int MIME_LEN_REFERER;
00252 int MIME_LEN_REPLY_TO;
00253 int MIME_LEN_RETRY_AFTER;
00254 int MIME_LEN_SENDER;
00255 int MIME_LEN_SERVER;
00256 int MIME_LEN_SET_COOKIE;
00257 int MIME_LEN_STRICT_TRANSPORT_SECURITY;
00258 int MIME_LEN_SUBJECT;
00259 int MIME_LEN_SUMMARY;
00260 int MIME_LEN_TE;
00261 int MIME_LEN_TRANSFER_ENCODING;
00262 int MIME_LEN_UPGRADE;
00263 int MIME_LEN_USER_AGENT;
00264 int MIME_LEN_VARY;
00265 int MIME_LEN_VIA;
00266 int MIME_LEN_WARNING;
00267 int MIME_LEN_WWW_AUTHENTICATE;
00268 int MIME_LEN_XREF;
00269 int MIME_LEN_INT_DATA_INFO;
00270 int MIME_LEN_X_ID;
00271 int MIME_LEN_X_FORWARDED_FOR;
00272 int MIME_LEN_SEC_WEBSOCKET_KEY;
00273 int MIME_LEN_SEC_WEBSOCKET_VERSION;
00274 
00275 int MIME_WKSIDX_ACCEPT;
00276 int MIME_WKSIDX_ACCEPT_CHARSET;
00277 int MIME_WKSIDX_ACCEPT_ENCODING;
00278 int MIME_WKSIDX_ACCEPT_LANGUAGE;
00279 int MIME_WKSIDX_ACCEPT_RANGES;
00280 int MIME_WKSIDX_AGE;
00281 int MIME_WKSIDX_ALLOW;
00282 int MIME_WKSIDX_APPROVED;
00283 int MIME_WKSIDX_AUTHORIZATION;
00284 int MIME_WKSIDX_BYTES;
00285 int MIME_WKSIDX_CACHE_CONTROL;
00286 int MIME_WKSIDX_CLIENT_IP;
00287 int MIME_WKSIDX_CONNECTION;
00288 int MIME_WKSIDX_CONTENT_BASE;
00289 int MIME_WKSIDX_CONTENT_ENCODING;
00290 int MIME_WKSIDX_CONTENT_LANGUAGE;
00291 int MIME_WKSIDX_CONTENT_LENGTH;
00292 int MIME_WKSIDX_CONTENT_LOCATION;
00293 int MIME_WKSIDX_CONTENT_MD5;
00294 int MIME_WKSIDX_CONTENT_RANGE;
00295 int MIME_WKSIDX_CONTENT_TYPE;
00296 int MIME_WKSIDX_CONTROL;
00297 int MIME_WKSIDX_COOKIE;
00298 int MIME_WKSIDX_DATE;
00299 int MIME_WKSIDX_DISTRIBUTION;
00300 int MIME_WKSIDX_ETAG;
00301 int MIME_WKSIDX_EXPECT;
00302 int MIME_WKSIDX_EXPIRES;
00303 int MIME_WKSIDX_FOLLOWUP_TO;
00304 int MIME_WKSIDX_FROM;
00305 int MIME_WKSIDX_HOST;
00306 int MIME_WKSIDX_IF_MATCH;
00307 int MIME_WKSIDX_IF_MODIFIED_SINCE;
00308 int MIME_WKSIDX_IF_NONE_MATCH;
00309 int MIME_WKSIDX_IF_RANGE;
00310 int MIME_WKSIDX_IF_UNMODIFIED_SINCE;
00311 int MIME_WKSIDX_KEEP_ALIVE;
00312 int MIME_WKSIDX_KEYWORDS;
00313 int MIME_WKSIDX_LAST_MODIFIED;
00314 int MIME_WKSIDX_LINES;
00315 int MIME_WKSIDX_LOCATION;
00316 int MIME_WKSIDX_MAX_FORWARDS;
00317 int MIME_WKSIDX_MESSAGE_ID;
00318 int MIME_WKSIDX_NEWSGROUPS;
00319 int MIME_WKSIDX_ORGANIZATION;
00320 int MIME_WKSIDX_PATH;
00321 int MIME_WKSIDX_PRAGMA;
00322 int MIME_WKSIDX_PROXY_AUTHENTICATE;
00323 int MIME_WKSIDX_PROXY_AUTHORIZATION;
00324 int MIME_WKSIDX_PROXY_CONNECTION;
00325 int MIME_WKSIDX_PUBLIC;
00326 int MIME_WKSIDX_RANGE;
00327 int MIME_WKSIDX_REFERENCES;
00328 int MIME_WKSIDX_REFERER;
00329 int MIME_WKSIDX_REPLY_TO;
00330 int MIME_WKSIDX_RETRY_AFTER;
00331 int MIME_WKSIDX_SENDER;
00332 int MIME_WKSIDX_SERVER;
00333 int MIME_WKSIDX_SET_COOKIE;
00334 int MIME_WKSIDX_STRICT_TRANSPORT_SECURITY;
00335 int MIME_WKSIDX_SUBJECT;
00336 int MIME_WKSIDX_SUMMARY;
00337 int MIME_WKSIDX_TE;
00338 int MIME_WKSIDX_TRANSFER_ENCODING;
00339 int MIME_WKSIDX_UPGRADE;
00340 int MIME_WKSIDX_USER_AGENT;
00341 int MIME_WKSIDX_VARY;
00342 int MIME_WKSIDX_VIA;
00343 int MIME_WKSIDX_WARNING;
00344 int MIME_WKSIDX_WWW_AUTHENTICATE;
00345 int MIME_WKSIDX_XREF;
00346 int MIME_WKSIDX_INT_DATA_INFO;
00347 int MIME_WKSIDX_X_ID;
00348 int MIME_WKSIDX_X_FORWARDED_FOR;
00349 int MIME_WKSIDX_SEC_WEBSOCKET_KEY;
00350 int MIME_WKSIDX_SEC_WEBSOCKET_VERSION;
00351 
00352 /***********************************************************************
00353  *                                                                     *
00354  *                 U T I L I T Y    R O U T I N E S                    *
00355  *                                                                     *
00356  ***********************************************************************/
00357 inline static int
00358 is_digit(char c)
00359 {
00360   return ((c <= '9') && (c >= '0'));
00361 }
00362 
00363 inline static int
00364 is_ws(char c)
00365 {
00366   return ((c == ParseRules::CHAR_SP) || (c == ParseRules::CHAR_HT));
00367 }
00368 
00369 
00370 /***********************************************************************
00371  *                                                                     *
00372  *                    P R E S E N C E    B I T S                       *
00373  *                                                                     *
00374  ***********************************************************************/
00375 uint64_t
00376 mime_field_presence_mask(const char *well_known_str)
00377 {
00378   return hdrtoken_wks_to_mask(well_known_str);
00379 }
00380 
00381 uint64_t
00382 mime_field_presence_mask(int well_known_str_index)
00383 {
00384   return hdrtoken_index_to_mask(well_known_str_index);
00385 }
00386 
00387 int
00388 mime_field_presence_get(MIMEHdrImpl *h, const char *well_known_str)
00389 {
00390   uint64_t mask = mime_field_presence_mask(well_known_str);
00391   return ((mask == 0) ? 1 : ((h->m_presence_bits & mask) == 0 ? 0 : 1));
00392 }
00393 
00394 int
00395 mime_field_presence_get(MIMEHdrImpl *h, int well_known_str_index)
00396 {
00397   const char *wks = hdrtoken_index_to_wks(well_known_str_index);
00398   return mime_field_presence_get(h, wks);
00399 }
00400 
00401 void
00402 mime_hdr_presence_set(MIMEHdrImpl *h, const char *well_known_str)
00403 {
00404   uint64_t mask = mime_field_presence_mask(well_known_str);
00405   if (mask != 0)
00406     h->m_presence_bits |= mask;
00407 }
00408 
00409 void
00410 mime_hdr_presence_set(MIMEHdrImpl *h, int well_known_str_index)
00411 {
00412   const char *wks = hdrtoken_index_to_wks(well_known_str_index);
00413   mime_hdr_presence_set(h, wks);
00414 }
00415 
00416 void
00417 mime_hdr_presence_unset(MIMEHdrImpl *h, const char *well_known_str)
00418 {
00419   uint64_t mask = mime_field_presence_mask(well_known_str);
00420   if (mask != 0)
00421     h->m_presence_bits &= (~mask);
00422 }
00423 
00424 void
00425 mime_hdr_presence_unset(MIMEHdrImpl *h, int well_known_str_index)
00426 {
00427   const char *wks = hdrtoken_index_to_wks(well_known_str_index);
00428   mime_hdr_presence_unset(h, wks);
00429 }
00430 
00431 /***********************************************************************
00432  *                                                                     *
00433  *                  S L O T    A C C E L E R A T O R S                 *
00434  *                                                                     *
00435  ***********************************************************************/
00436 inline void
00437 mime_hdr_init_accelerators_and_presence_bits(MIMEHdrImpl* mh)
00438 {
00439   mh->m_presence_bits = 0;
00440   mh->m_slot_accelerators[0] = 0xFFFFFFFF;
00441   mh->m_slot_accelerators[1] = 0xFFFFFFFF;
00442   mh->m_slot_accelerators[2] = 0xFFFFFFFF;
00443   mh->m_slot_accelerators[3] = 0xFFFFFFFF;
00444 }
00445 
00446 inline uint32_t
00447 mime_hdr_get_accelerator_slotnum(MIMEHdrImpl *mh, int32_t slot_id)
00448 {
00449   ink_assert((slot_id != MIME_SLOTID_NONE) && (slot_id < 32));
00450 
00451   uint32_t word_index = slot_id / 8;      // 4 words of 8 slots
00452   uint32_t word = mh->m_slot_accelerators[word_index];    // 8 slots of 4 bits each
00453   uint32_t nybble = slot_id % 8;  // which of the 8 nybbles?
00454   uint32_t slot = ((word >> (nybble * 4)) & 15);  // grab the 4 bit slotnum
00455   return slot;
00456 }
00457 
00458 inline void
00459 mime_hdr_set_accelerator_slotnum(MIMEHdrImpl *mh, int32_t slot_id, uint32_t slot_num)
00460 {
00461   ink_assert((slot_id != MIME_SLOTID_NONE) && (slot_id < 32));
00462   ink_assert(slot_num < 16);
00463 
00464   uint32_t word_index = slot_id / 8;      // 4 words of 8 slots
00465   uint32_t word = mh->m_slot_accelerators[word_index];    // 8 slots of 4 bits each
00466   uint32_t nybble = slot_id % 8;  // which of the 8 nybbles?
00467   uint32_t shift = nybble * 4;    // shift in chunks of 4 bits
00468   uint32_t mask = ~(MIME_FIELD_SLOTNUM_MASK << shift);    // mask to zero out old slot
00469   uint32_t graft = (slot_num << shift);   // plug to insert into slot
00470   uint32_t new_word = (word & mask) | graft;      // new value
00471 
00472   mh->m_slot_accelerators[word_index] = new_word;
00473 }
00474 
00475 inline void
00476 mime_hdr_set_accelerators_and_presence_bits(MIMEHdrImpl *mh, MIMEField *field)
00477 {
00478   int slot_id, slot_num;
00479   if (field->m_wks_idx < 0)
00480     return;
00481 
00482   mime_hdr_presence_set(mh, field->m_wks_idx);
00483 
00484   slot_id = hdrtoken_index_to_slotid(field->m_wks_idx);
00485   if (slot_id != MIME_SLOTID_NONE) {
00486     slot_num = (field - &(mh->m_first_fblock.m_field_slots[0]));
00487     if ((slot_num >= 0) && (slot_num < MIME_FIELD_SLOTNUM_UNKNOWN))
00488       mime_hdr_set_accelerator_slotnum(mh, slot_id, slot_num);
00489     else
00490       mime_hdr_set_accelerator_slotnum(mh, slot_id, MIME_FIELD_SLOTNUM_UNKNOWN);
00491   }
00492 }
00493 
00494 inline void
00495 mime_hdr_unset_accelerators_and_presence_bits(MIMEHdrImpl *mh, MIMEField *field)
00496 {
00497   int slot_id;
00498   if (field->m_wks_idx < 0)
00499     return;
00500 
00501   mime_hdr_presence_unset(mh, field->m_wks_idx);
00502 
00503   slot_id = hdrtoken_index_to_slotid(field->m_wks_idx);
00504   if (slot_id != MIME_SLOTID_NONE)
00505     mime_hdr_set_accelerator_slotnum(mh, slot_id, MIME_FIELD_SLOTNUM_MAX);
00506 }
00507 
00508 /// Reset data in the header.
00509 /// Clear all the presence bits and accelerators.
00510 /// Update all the m_wks_idx values, presence bits and accelerators.
00511 inline void
00512 mime_hdr_reset_accelerators_and_presence_bits(MIMEHdrImpl* mh) {
00513   mime_hdr_init_accelerators_and_presence_bits(mh);
00514 
00515   for (MIMEFieldBlockImpl* fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
00516     for ( MIMEField *field = fblock->m_field_slots, *limit = field + fblock->m_freetop ; field < limit ; ++field) {
00517       if (field->is_live()) {
00518         field->m_wks_idx = hdrtoken_tokenize(field->m_ptr_name, field->m_len_name);
00519         if (field->is_dup_head())
00520           mime_hdr_set_accelerators_and_presence_bits(mh, field);
00521       }
00522     }
00523   }
00524 }
00525 
00526 int
00527 checksum_block(const char *s, int len)
00528 {
00529   int sum = 0;
00530   while (len--)
00531     sum ^= *s++;
00532   return sum;
00533 }
00534 
00535 
00536 #ifdef DEBUG
00537 void
00538 mime_hdr_sanity_check(MIMEHdrImpl *mh)
00539 {
00540   MIMEFieldBlockImpl *fblock, *blk, *last_fblock;
00541   MIMEField *field, *next_dup;
00542   uint32_t slot_index, index;
00543   uint64_t masksum;
00544 
00545   masksum = 0;
00546   slot_index = 0;
00547   last_fblock = NULL;
00548 
00549   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
00550     for (index = 0; index < fblock->m_freetop; index++) {
00551       field = &(fblock->m_field_slots[index]);
00552 
00553       if (field->is_live()) {
00554         // dummy operations just to make sure deref doesn't crash
00555         checksum_block(field->m_ptr_name, field->m_len_name);
00556         if (field->m_ptr_value)
00557           checksum_block(field->m_ptr_value, field->m_len_value);
00558 
00559         if (field->m_n_v_raw_printable) {
00560           int total_len = field->m_len_name + field->m_len_value + field->m_n_v_raw_printable_pad;
00561           checksum_block(field->m_ptr_name, total_len);
00562         }
00563         // walk the dup list, quickly checking each cell
00564         if (field->m_next_dup != NULL) {
00565           int field_slotnum = mime_hdr_field_slotnum(mh, field);
00566 
00567           for (next_dup = field->m_next_dup; next_dup; next_dup = next_dup->m_next_dup) {
00568             int next_slotnum = mime_hdr_field_slotnum(mh, next_dup);
00569             ink_release_assert((next_dup->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD) == 0);
00570             ink_release_assert((next_dup->m_readiness == MIME_FIELD_SLOT_READINESS_LIVE));
00571             ink_release_assert(next_dup->m_wks_idx == field->m_wks_idx);
00572             ink_release_assert(next_dup->m_len_name == field->m_len_name);
00573             ink_release_assert(strncasecmp(field->m_ptr_name, next_dup->m_ptr_name, field->m_len_name) == 0);
00574             ink_release_assert(next_slotnum > field_slotnum);
00575           }
00576         }
00577         // if this is a well known string, check presence bits & slot accelerators
00578         if (field->m_wks_idx >= 0) {
00579           const char *wks = hdrtoken_index_to_wks(field->m_wks_idx);
00580           int len = hdrtoken_index_to_length(field->m_wks_idx);
00581 
00582           if (field->m_len_name != len || strncasecmp(field->m_ptr_name, wks, field->m_len_name) != 0)
00583             Warning("Encountered WKS hash collision on '%.*s'", field->m_len_name, field->m_ptr_name);
00584 
00585           uint64_t mask = mime_field_presence_mask(field->m_wks_idx);
00586           masksum |= mask;
00587 
00588           int32_t slot_id = hdrtoken_index_to_slotid(field->m_wks_idx);
00589           if ((slot_id != MIME_SLOTID_NONE) &&
00590               (slot_index < MIME_FIELD_SLOTNUM_UNKNOWN) && (field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD)) {
00591             uint32_t slot_num = mime_hdr_get_accelerator_slotnum(mh, slot_id);
00592             if (slot_num <= 14)
00593               ink_release_assert(slot_num == slot_index);
00594           }
00595         } else {
00596           int idx = hdrtoken_tokenize(field->m_ptr_name, field->m_len_name, NULL);
00597           ink_release_assert(idx < 0);
00598         }
00599 
00600         // verify that the next dup pointer points to a block in this list
00601         if (field->m_next_dup) {
00602           bool found = false;
00603           for (blk = &(mh->m_first_fblock); blk != NULL; blk = blk->m_next) {
00604             const char *addr = (const char *) (field->m_next_dup);
00605             if ((addr >= (const char *) (blk)) && (addr < (const char *) (blk) + sizeof(MIMEFieldBlockImpl))) {
00606               found = true;
00607               break;
00608             }
00609           }
00610           ink_release_assert(found);
00611         }
00612         // re-find the field --- should always find the head dup
00613         MIMEField *mf = mime_hdr_field_find(mh, field->m_ptr_name, field->m_len_name);
00614         ink_release_assert(mf != NULL);
00615         if (mf == field)
00616           ink_release_assert((field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD) != 0);
00617         else
00618           ink_release_assert((field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD) == 0);
00619       }
00620 
00621       ++slot_index;
00622     }
00623     last_fblock = fblock;
00624   }
00625 
00626   ink_release_assert(last_fblock == mh->m_fblock_list_tail);
00627   ink_release_assert(masksum == mh->m_presence_bits);
00628 }
00629 #endif
00630 
00631 
00632 void
00633 mime_init()
00634 {
00635   static int init = 1;
00636 
00637   if (init) {
00638     init = 0;
00639     
00640     hdrtoken_init();
00641     day_names_dfa = new DFA;
00642     day_names_dfa->compile(day_names, SIZEOF(day_names), RE_CASE_INSENSITIVE);
00643     
00644     month_names_dfa = new DFA;
00645     month_names_dfa->compile(month_names, SIZEOF(month_names), RE_CASE_INSENSITIVE);
00646     
00647     MIME_FIELD_ACCEPT = hdrtoken_string_to_wks("Accept");
00648     MIME_FIELD_ACCEPT_CHARSET = hdrtoken_string_to_wks("Accept-Charset");
00649     MIME_FIELD_ACCEPT_ENCODING = hdrtoken_string_to_wks("Accept-Encoding");
00650     MIME_FIELD_ACCEPT_LANGUAGE = hdrtoken_string_to_wks("Accept-Language");
00651     MIME_FIELD_ACCEPT_RANGES = hdrtoken_string_to_wks("Accept-Ranges");
00652     MIME_FIELD_AGE = hdrtoken_string_to_wks("Age");
00653     MIME_FIELD_ALLOW = hdrtoken_string_to_wks("Allow");
00654     MIME_FIELD_APPROVED = hdrtoken_string_to_wks("Approved");
00655     MIME_FIELD_AUTHORIZATION = hdrtoken_string_to_wks("Authorization");
00656     MIME_FIELD_BYTES = hdrtoken_string_to_wks("Bytes");
00657     MIME_FIELD_CACHE_CONTROL = hdrtoken_string_to_wks("Cache-Control");
00658     MIME_FIELD_CLIENT_IP = hdrtoken_string_to_wks("Client-ip");
00659     MIME_FIELD_CONNECTION = hdrtoken_string_to_wks("Connection");
00660     MIME_FIELD_CONTENT_BASE = hdrtoken_string_to_wks("Content-Base");
00661     MIME_FIELD_CONTENT_ENCODING = hdrtoken_string_to_wks("Content-Encoding");
00662     MIME_FIELD_CONTENT_LANGUAGE = hdrtoken_string_to_wks("Content-Language");
00663     MIME_FIELD_CONTENT_LENGTH = hdrtoken_string_to_wks("Content-Length");
00664     MIME_FIELD_CONTENT_LOCATION = hdrtoken_string_to_wks("Content-Location");
00665     MIME_FIELD_CONTENT_MD5 = hdrtoken_string_to_wks("Content-MD5");
00666     MIME_FIELD_CONTENT_RANGE = hdrtoken_string_to_wks("Content-Range");
00667     MIME_FIELD_CONTENT_TYPE = hdrtoken_string_to_wks("Content-Type");
00668     MIME_FIELD_CONTROL = hdrtoken_string_to_wks("Control");
00669     MIME_FIELD_COOKIE = hdrtoken_string_to_wks("Cookie");
00670     MIME_FIELD_DATE = hdrtoken_string_to_wks("Date");
00671     MIME_FIELD_DISTRIBUTION = hdrtoken_string_to_wks("Distribution");
00672     MIME_FIELD_ETAG = hdrtoken_string_to_wks("Etag");
00673     MIME_FIELD_EXPECT = hdrtoken_string_to_wks("Expect");
00674     MIME_FIELD_EXPIRES = hdrtoken_string_to_wks("Expires");
00675     MIME_FIELD_FOLLOWUP_TO = hdrtoken_string_to_wks("Followup-To");
00676     MIME_FIELD_FROM = hdrtoken_string_to_wks("From");
00677     MIME_FIELD_HOST = hdrtoken_string_to_wks("Host");
00678     MIME_FIELD_IF_MATCH = hdrtoken_string_to_wks("If-Match");
00679     MIME_FIELD_IF_MODIFIED_SINCE = hdrtoken_string_to_wks("If-Modified-Since");
00680     MIME_FIELD_IF_NONE_MATCH = hdrtoken_string_to_wks("If-None-Match");
00681     MIME_FIELD_IF_RANGE = hdrtoken_string_to_wks("If-Range");
00682     MIME_FIELD_IF_UNMODIFIED_SINCE = hdrtoken_string_to_wks("If-Unmodified-Since");
00683     MIME_FIELD_KEEP_ALIVE = hdrtoken_string_to_wks("Keep-Alive");
00684     MIME_FIELD_KEYWORDS = hdrtoken_string_to_wks("Keywords");
00685     MIME_FIELD_LAST_MODIFIED = hdrtoken_string_to_wks("Last-Modified");
00686     MIME_FIELD_LINES = hdrtoken_string_to_wks("Lines");
00687     MIME_FIELD_LOCATION = hdrtoken_string_to_wks("Location");
00688     MIME_FIELD_MAX_FORWARDS = hdrtoken_string_to_wks("Max-Forwards");
00689     MIME_FIELD_MESSAGE_ID = hdrtoken_string_to_wks("Message-ID");
00690     MIME_FIELD_NEWSGROUPS = hdrtoken_string_to_wks("Newsgroups");
00691     MIME_FIELD_ORGANIZATION = hdrtoken_string_to_wks("Organization");
00692     MIME_FIELD_PATH = hdrtoken_string_to_wks("Path");
00693     MIME_FIELD_PRAGMA = hdrtoken_string_to_wks("Pragma");
00694     MIME_FIELD_PROXY_AUTHENTICATE = hdrtoken_string_to_wks("Proxy-Authenticate");
00695     MIME_FIELD_PROXY_AUTHORIZATION = hdrtoken_string_to_wks("Proxy-Authorization");
00696     MIME_FIELD_PROXY_CONNECTION = hdrtoken_string_to_wks("Proxy-Connection");
00697     MIME_FIELD_PUBLIC = hdrtoken_string_to_wks("Public");
00698     MIME_FIELD_RANGE = hdrtoken_string_to_wks("Range");
00699     MIME_FIELD_REFERENCES = hdrtoken_string_to_wks("References");
00700     MIME_FIELD_REFERER = hdrtoken_string_to_wks("Referer");
00701     MIME_FIELD_REPLY_TO = hdrtoken_string_to_wks("Reply-To");
00702     MIME_FIELD_RETRY_AFTER = hdrtoken_string_to_wks("Retry-After");
00703     MIME_FIELD_SENDER = hdrtoken_string_to_wks("Sender");
00704     MIME_FIELD_SERVER = hdrtoken_string_to_wks("Server");
00705     MIME_FIELD_SET_COOKIE = hdrtoken_string_to_wks("Set-Cookie");
00706     MIME_FIELD_STRICT_TRANSPORT_SECURITY = hdrtoken_string_to_wks("Strict-Transport-Security");
00707     MIME_FIELD_SUBJECT = hdrtoken_string_to_wks("Subject");
00708     MIME_FIELD_SUMMARY = hdrtoken_string_to_wks("Summary");
00709     MIME_FIELD_TE = hdrtoken_string_to_wks("TE");
00710     MIME_FIELD_TRANSFER_ENCODING = hdrtoken_string_to_wks("Transfer-Encoding");
00711     MIME_FIELD_UPGRADE = hdrtoken_string_to_wks("Upgrade");
00712     MIME_FIELD_USER_AGENT = hdrtoken_string_to_wks("User-Agent");
00713     MIME_FIELD_VARY = hdrtoken_string_to_wks("Vary");
00714     MIME_FIELD_VIA = hdrtoken_string_to_wks("Via");
00715     MIME_FIELD_WARNING = hdrtoken_string_to_wks("Warning");
00716     MIME_FIELD_WWW_AUTHENTICATE = hdrtoken_string_to_wks("Www-Authenticate");
00717     MIME_FIELD_XREF = hdrtoken_string_to_wks("Xref");
00718     MIME_FIELD_INT_DATA_INFO = hdrtoken_string_to_wks("@DataInfo");
00719     MIME_FIELD_X_ID = hdrtoken_string_to_wks("X-ID");
00720     MIME_FIELD_X_FORWARDED_FOR = hdrtoken_string_to_wks("X-Forwarded-For");
00721 
00722     MIME_FIELD_SEC_WEBSOCKET_KEY = hdrtoken_string_to_wks("Sec-WebSocket-Key");
00723     MIME_FIELD_SEC_WEBSOCKET_VERSION = hdrtoken_string_to_wks("Sec-WebSocket-Version");
00724 
00725 
00726     MIME_LEN_ACCEPT = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT);
00727     MIME_LEN_ACCEPT_CHARSET = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_CHARSET);
00728     MIME_LEN_ACCEPT_ENCODING = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_ENCODING);
00729     MIME_LEN_ACCEPT_LANGUAGE = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_LANGUAGE);
00730     MIME_LEN_ACCEPT_RANGES = hdrtoken_wks_to_length(MIME_FIELD_ACCEPT_RANGES);
00731     MIME_LEN_AGE = hdrtoken_wks_to_length(MIME_FIELD_AGE);
00732     MIME_LEN_ALLOW = hdrtoken_wks_to_length(MIME_FIELD_ALLOW);
00733     MIME_LEN_APPROVED = hdrtoken_wks_to_length(MIME_FIELD_APPROVED);
00734     MIME_LEN_AUTHORIZATION = hdrtoken_wks_to_length(MIME_FIELD_AUTHORIZATION);
00735     MIME_LEN_BYTES = hdrtoken_wks_to_length(MIME_FIELD_BYTES);
00736     MIME_LEN_CACHE_CONTROL = hdrtoken_wks_to_length(MIME_FIELD_CACHE_CONTROL);
00737     MIME_LEN_CLIENT_IP = hdrtoken_wks_to_length(MIME_FIELD_CLIENT_IP);
00738     MIME_LEN_CONNECTION = hdrtoken_wks_to_length(MIME_FIELD_CONNECTION);
00739     MIME_LEN_CONTENT_BASE = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_BASE);
00740     MIME_LEN_CONTENT_ENCODING = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_ENCODING);
00741     MIME_LEN_CONTENT_LANGUAGE = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_LANGUAGE);
00742     MIME_LEN_CONTENT_LENGTH = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_LENGTH);
00743     MIME_LEN_CONTENT_LOCATION = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_LOCATION);
00744     MIME_LEN_CONTENT_MD5 = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_MD5);
00745     MIME_LEN_CONTENT_RANGE = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_RANGE);
00746     MIME_LEN_CONTENT_TYPE = hdrtoken_wks_to_length(MIME_FIELD_CONTENT_TYPE);
00747     MIME_LEN_CONTROL = hdrtoken_wks_to_length(MIME_FIELD_CONTROL);
00748     MIME_LEN_COOKIE = hdrtoken_wks_to_length(MIME_FIELD_COOKIE);
00749     MIME_LEN_DATE = hdrtoken_wks_to_length(MIME_FIELD_DATE);
00750     MIME_LEN_DISTRIBUTION = hdrtoken_wks_to_length(MIME_FIELD_DISTRIBUTION);
00751     MIME_LEN_ETAG = hdrtoken_wks_to_length(MIME_FIELD_ETAG);
00752     MIME_LEN_EXPECT = hdrtoken_wks_to_length(MIME_FIELD_EXPECT);
00753     MIME_LEN_EXPIRES = hdrtoken_wks_to_length(MIME_FIELD_EXPIRES);
00754     MIME_LEN_FOLLOWUP_TO = hdrtoken_wks_to_length(MIME_FIELD_FOLLOWUP_TO);
00755     MIME_LEN_FROM = hdrtoken_wks_to_length(MIME_FIELD_FROM);
00756     MIME_LEN_HOST = hdrtoken_wks_to_length(MIME_FIELD_HOST);
00757     MIME_LEN_IF_MATCH = hdrtoken_wks_to_length(MIME_FIELD_IF_MATCH);
00758     MIME_LEN_IF_MODIFIED_SINCE = hdrtoken_wks_to_length(MIME_FIELD_IF_MODIFIED_SINCE);
00759     MIME_LEN_IF_NONE_MATCH = hdrtoken_wks_to_length(MIME_FIELD_IF_NONE_MATCH);
00760     MIME_LEN_IF_RANGE = hdrtoken_wks_to_length(MIME_FIELD_IF_RANGE);
00761     MIME_LEN_IF_UNMODIFIED_SINCE = hdrtoken_wks_to_length(MIME_FIELD_IF_UNMODIFIED_SINCE);
00762     MIME_LEN_KEEP_ALIVE = hdrtoken_wks_to_length(MIME_FIELD_KEEP_ALIVE);
00763     MIME_LEN_KEYWORDS = hdrtoken_wks_to_length(MIME_FIELD_KEYWORDS);
00764     MIME_LEN_LAST_MODIFIED = hdrtoken_wks_to_length(MIME_FIELD_LAST_MODIFIED);
00765     MIME_LEN_LINES = hdrtoken_wks_to_length(MIME_FIELD_LINES);
00766     MIME_LEN_LOCATION = hdrtoken_wks_to_length(MIME_FIELD_LOCATION);
00767     MIME_LEN_MAX_FORWARDS = hdrtoken_wks_to_length(MIME_FIELD_MAX_FORWARDS);
00768     MIME_LEN_MESSAGE_ID = hdrtoken_wks_to_length(MIME_FIELD_MESSAGE_ID);
00769     MIME_LEN_NEWSGROUPS = hdrtoken_wks_to_length(MIME_FIELD_NEWSGROUPS);
00770     MIME_LEN_ORGANIZATION = hdrtoken_wks_to_length(MIME_FIELD_ORGANIZATION);
00771     MIME_LEN_PATH = hdrtoken_wks_to_length(MIME_FIELD_PATH);
00772     MIME_LEN_PRAGMA = hdrtoken_wks_to_length(MIME_FIELD_PRAGMA);
00773     MIME_LEN_PROXY_AUTHENTICATE = hdrtoken_wks_to_length(MIME_FIELD_PROXY_AUTHENTICATE);
00774     MIME_LEN_PROXY_AUTHORIZATION = hdrtoken_wks_to_length(MIME_FIELD_PROXY_AUTHORIZATION);
00775     MIME_LEN_PROXY_CONNECTION = hdrtoken_wks_to_length(MIME_FIELD_PROXY_CONNECTION);
00776     MIME_LEN_PUBLIC = hdrtoken_wks_to_length(MIME_FIELD_PUBLIC);
00777     MIME_LEN_RANGE = hdrtoken_wks_to_length(MIME_FIELD_RANGE);
00778     MIME_LEN_REFERENCES = hdrtoken_wks_to_length(MIME_FIELD_REFERENCES);
00779     MIME_LEN_REFERER = hdrtoken_wks_to_length(MIME_FIELD_REFERER);
00780     MIME_LEN_REPLY_TO = hdrtoken_wks_to_length(MIME_FIELD_REPLY_TO);
00781     MIME_LEN_RETRY_AFTER = hdrtoken_wks_to_length(MIME_FIELD_RETRY_AFTER);
00782     MIME_LEN_SENDER = hdrtoken_wks_to_length(MIME_FIELD_SENDER);
00783     MIME_LEN_SERVER = hdrtoken_wks_to_length(MIME_FIELD_SERVER);
00784     MIME_LEN_SET_COOKIE = hdrtoken_wks_to_length(MIME_FIELD_SET_COOKIE);
00785     MIME_LEN_STRICT_TRANSPORT_SECURITY = hdrtoken_wks_to_length(MIME_FIELD_STRICT_TRANSPORT_SECURITY);
00786     MIME_LEN_SUBJECT = hdrtoken_wks_to_length(MIME_FIELD_SUBJECT);
00787     MIME_LEN_SUMMARY = hdrtoken_wks_to_length(MIME_FIELD_SUMMARY);
00788     MIME_LEN_TE = hdrtoken_wks_to_length(MIME_FIELD_TE);
00789     MIME_LEN_TRANSFER_ENCODING = hdrtoken_wks_to_length(MIME_FIELD_TRANSFER_ENCODING);
00790     MIME_LEN_UPGRADE = hdrtoken_wks_to_length(MIME_FIELD_UPGRADE);
00791     MIME_LEN_USER_AGENT = hdrtoken_wks_to_length(MIME_FIELD_USER_AGENT);
00792     MIME_LEN_VARY = hdrtoken_wks_to_length(MIME_FIELD_VARY);
00793     MIME_LEN_VIA = hdrtoken_wks_to_length(MIME_FIELD_VIA);
00794     MIME_LEN_WARNING = hdrtoken_wks_to_length(MIME_FIELD_WARNING);
00795     MIME_LEN_WWW_AUTHENTICATE = hdrtoken_wks_to_length(MIME_FIELD_WWW_AUTHENTICATE);
00796     MIME_LEN_XREF = hdrtoken_wks_to_length(MIME_FIELD_XREF);
00797     MIME_LEN_INT_DATA_INFO = hdrtoken_wks_to_length(MIME_FIELD_INT_DATA_INFO);
00798     MIME_LEN_X_ID = hdrtoken_wks_to_length(MIME_FIELD_X_ID);
00799     MIME_LEN_X_FORWARDED_FOR = hdrtoken_wks_to_length(MIME_FIELD_X_FORWARDED_FOR);
00800 
00801     MIME_LEN_SEC_WEBSOCKET_KEY = hdrtoken_wks_to_length(MIME_FIELD_SEC_WEBSOCKET_KEY);
00802     MIME_LEN_SEC_WEBSOCKET_VERSION = hdrtoken_wks_to_length(MIME_FIELD_SEC_WEBSOCKET_VERSION);
00803 
00804 
00805     MIME_WKSIDX_ACCEPT = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT);
00806     MIME_WKSIDX_ACCEPT_CHARSET = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_CHARSET);
00807     MIME_WKSIDX_ACCEPT_ENCODING = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_ENCODING);
00808     MIME_WKSIDX_ACCEPT_LANGUAGE = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_LANGUAGE);
00809     MIME_WKSIDX_ACCEPT_RANGES = hdrtoken_wks_to_index(MIME_FIELD_ACCEPT_RANGES);
00810     MIME_WKSIDX_AGE = hdrtoken_wks_to_index(MIME_FIELD_AGE);
00811     MIME_WKSIDX_ALLOW = hdrtoken_wks_to_index(MIME_FIELD_ALLOW);
00812     MIME_WKSIDX_APPROVED = hdrtoken_wks_to_index(MIME_FIELD_APPROVED);
00813     MIME_WKSIDX_AUTHORIZATION = hdrtoken_wks_to_index(MIME_FIELD_AUTHORIZATION);
00814     MIME_WKSIDX_BYTES = hdrtoken_wks_to_index(MIME_FIELD_BYTES);
00815     MIME_WKSIDX_CACHE_CONTROL = hdrtoken_wks_to_index(MIME_FIELD_CACHE_CONTROL);
00816     MIME_WKSIDX_CLIENT_IP = hdrtoken_wks_to_index(MIME_FIELD_CLIENT_IP);
00817     MIME_WKSIDX_CONNECTION = hdrtoken_wks_to_index(MIME_FIELD_CONNECTION);
00818     MIME_WKSIDX_CONTENT_BASE = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_BASE);
00819     MIME_WKSIDX_CONTENT_ENCODING = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_ENCODING);
00820     MIME_WKSIDX_CONTENT_LANGUAGE = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_LANGUAGE);
00821     MIME_WKSIDX_CONTENT_LENGTH = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_LENGTH);
00822     MIME_WKSIDX_CONTENT_LOCATION = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_LOCATION);
00823     MIME_WKSIDX_CONTENT_MD5 = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_MD5);
00824     MIME_WKSIDX_CONTENT_RANGE = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_RANGE);
00825     MIME_WKSIDX_CONTENT_TYPE = hdrtoken_wks_to_index(MIME_FIELD_CONTENT_TYPE);
00826     MIME_WKSIDX_CONTROL = hdrtoken_wks_to_index(MIME_FIELD_CONTROL);
00827     MIME_WKSIDX_COOKIE = hdrtoken_wks_to_index(MIME_FIELD_COOKIE);
00828     MIME_WKSIDX_DATE = hdrtoken_wks_to_index(MIME_FIELD_DATE);
00829     MIME_WKSIDX_DISTRIBUTION = hdrtoken_wks_to_index(MIME_FIELD_DISTRIBUTION);
00830     MIME_WKSIDX_ETAG = hdrtoken_wks_to_index(MIME_FIELD_ETAG);
00831     MIME_WKSIDX_EXPECT = hdrtoken_wks_to_index(MIME_FIELD_EXPECT);
00832     MIME_WKSIDX_EXPIRES = hdrtoken_wks_to_index(MIME_FIELD_EXPIRES);
00833     MIME_WKSIDX_FOLLOWUP_TO = hdrtoken_wks_to_index(MIME_FIELD_FOLLOWUP_TO);
00834     MIME_WKSIDX_FROM = hdrtoken_wks_to_index(MIME_FIELD_FROM);
00835     MIME_WKSIDX_HOST = hdrtoken_wks_to_index(MIME_FIELD_HOST);
00836     MIME_WKSIDX_IF_MATCH = hdrtoken_wks_to_index(MIME_FIELD_IF_MATCH);
00837     MIME_WKSIDX_IF_MODIFIED_SINCE = hdrtoken_wks_to_index(MIME_FIELD_IF_MODIFIED_SINCE);
00838     MIME_WKSIDX_IF_NONE_MATCH = hdrtoken_wks_to_index(MIME_FIELD_IF_NONE_MATCH);
00839     MIME_WKSIDX_IF_RANGE = hdrtoken_wks_to_index(MIME_FIELD_IF_RANGE);
00840     MIME_WKSIDX_IF_UNMODIFIED_SINCE = hdrtoken_wks_to_index(MIME_FIELD_IF_UNMODIFIED_SINCE);
00841     MIME_WKSIDX_KEEP_ALIVE = hdrtoken_wks_to_index(MIME_FIELD_KEEP_ALIVE);
00842     MIME_WKSIDX_KEYWORDS = hdrtoken_wks_to_index(MIME_FIELD_KEYWORDS);
00843     MIME_WKSIDX_LAST_MODIFIED = hdrtoken_wks_to_index(MIME_FIELD_LAST_MODIFIED);
00844     MIME_WKSIDX_LINES = hdrtoken_wks_to_index(MIME_FIELD_LINES);
00845     MIME_WKSIDX_LOCATION = hdrtoken_wks_to_index(MIME_FIELD_LOCATION);
00846     MIME_WKSIDX_MAX_FORWARDS = hdrtoken_wks_to_index(MIME_FIELD_MAX_FORWARDS);
00847     MIME_WKSIDX_MESSAGE_ID = hdrtoken_wks_to_index(MIME_FIELD_MESSAGE_ID);
00848     MIME_WKSIDX_NEWSGROUPS = hdrtoken_wks_to_index(MIME_FIELD_NEWSGROUPS);
00849     MIME_WKSIDX_ORGANIZATION = hdrtoken_wks_to_index(MIME_FIELD_ORGANIZATION);
00850     MIME_WKSIDX_PATH = hdrtoken_wks_to_index(MIME_FIELD_PATH);
00851     MIME_WKSIDX_PRAGMA = hdrtoken_wks_to_index(MIME_FIELD_PRAGMA);
00852     MIME_WKSIDX_PROXY_AUTHENTICATE = hdrtoken_wks_to_index(MIME_FIELD_PROXY_AUTHENTICATE);
00853     MIME_WKSIDX_PROXY_AUTHORIZATION = hdrtoken_wks_to_index(MIME_FIELD_PROXY_AUTHORIZATION);
00854     MIME_WKSIDX_PROXY_CONNECTION = hdrtoken_wks_to_index(MIME_FIELD_PROXY_CONNECTION);
00855     MIME_WKSIDX_PUBLIC = hdrtoken_wks_to_index(MIME_FIELD_PUBLIC);
00856     MIME_WKSIDX_RANGE = hdrtoken_wks_to_index(MIME_FIELD_RANGE);
00857     MIME_WKSIDX_REFERENCES = hdrtoken_wks_to_index(MIME_FIELD_REFERENCES);
00858     MIME_WKSIDX_REFERER = hdrtoken_wks_to_index(MIME_FIELD_REFERER);
00859     MIME_WKSIDX_REPLY_TO = hdrtoken_wks_to_index(MIME_FIELD_REPLY_TO);
00860     MIME_WKSIDX_RETRY_AFTER = hdrtoken_wks_to_index(MIME_FIELD_RETRY_AFTER);
00861     MIME_WKSIDX_SENDER = hdrtoken_wks_to_index(MIME_FIELD_SENDER);
00862     MIME_WKSIDX_SERVER = hdrtoken_wks_to_index(MIME_FIELD_SERVER);
00863     MIME_WKSIDX_SET_COOKIE = hdrtoken_wks_to_index(MIME_FIELD_SET_COOKIE);
00864     MIME_WKSIDX_STRICT_TRANSPORT_SECURITY = hdrtoken_wks_to_index(MIME_FIELD_STRICT_TRANSPORT_SECURITY);
00865     MIME_WKSIDX_SUBJECT = hdrtoken_wks_to_index(MIME_FIELD_SUBJECT);
00866     MIME_WKSIDX_SUMMARY = hdrtoken_wks_to_index(MIME_FIELD_SUMMARY);
00867     MIME_WKSIDX_TE = hdrtoken_wks_to_index(MIME_FIELD_TE);
00868     MIME_WKSIDX_TRANSFER_ENCODING = hdrtoken_wks_to_index(MIME_FIELD_TRANSFER_ENCODING);
00869     MIME_WKSIDX_UPGRADE = hdrtoken_wks_to_index(MIME_FIELD_UPGRADE);
00870     MIME_WKSIDX_USER_AGENT = hdrtoken_wks_to_index(MIME_FIELD_USER_AGENT);
00871     MIME_WKSIDX_VARY = hdrtoken_wks_to_index(MIME_FIELD_VARY);
00872     MIME_WKSIDX_VIA = hdrtoken_wks_to_index(MIME_FIELD_VIA);
00873     MIME_WKSIDX_WARNING = hdrtoken_wks_to_index(MIME_FIELD_WARNING);
00874     MIME_WKSIDX_WWW_AUTHENTICATE = hdrtoken_wks_to_index(MIME_FIELD_WWW_AUTHENTICATE);
00875     MIME_WKSIDX_XREF = hdrtoken_wks_to_index(MIME_FIELD_XREF);
00876     MIME_WKSIDX_X_ID = hdrtoken_wks_to_index(MIME_FIELD_X_ID);
00877     MIME_WKSIDX_X_FORWARDED_FOR = hdrtoken_wks_to_index(MIME_FIELD_X_FORWARDED_FOR);
00878     MIME_WKSIDX_SEC_WEBSOCKET_KEY = hdrtoken_wks_to_index(MIME_FIELD_SEC_WEBSOCKET_KEY);
00879     MIME_WKSIDX_SEC_WEBSOCKET_VERSION = hdrtoken_wks_to_index(MIME_FIELD_SEC_WEBSOCKET_VERSION);
00880 
00881     MIME_VALUE_BYTES = hdrtoken_string_to_wks("bytes");
00882     MIME_VALUE_CHUNKED = hdrtoken_string_to_wks("chunked");
00883     MIME_VALUE_CLOSE = hdrtoken_string_to_wks("close");
00884     MIME_VALUE_COMPRESS = hdrtoken_string_to_wks("compress");
00885     MIME_VALUE_DEFLATE = hdrtoken_string_to_wks("deflate");
00886     MIME_VALUE_GZIP = hdrtoken_string_to_wks("gzip");
00887     MIME_VALUE_IDENTITY = hdrtoken_string_to_wks("identity");
00888     MIME_VALUE_KEEP_ALIVE = hdrtoken_string_to_wks("keep-alive");
00889     MIME_VALUE_MAX_AGE = hdrtoken_string_to_wks("max-age");
00890     MIME_VALUE_MAX_STALE = hdrtoken_string_to_wks("max-stale");
00891     MIME_VALUE_MIN_FRESH = hdrtoken_string_to_wks("min-fresh");
00892     MIME_VALUE_MUST_REVALIDATE = hdrtoken_string_to_wks("must-revalidate");
00893     MIME_VALUE_NONE = hdrtoken_string_to_wks("none");
00894     MIME_VALUE_NO_CACHE = hdrtoken_string_to_wks("no-cache");
00895     MIME_VALUE_NO_STORE = hdrtoken_string_to_wks("no-store");
00896     MIME_VALUE_NO_TRANSFORM = hdrtoken_string_to_wks("no-transform");
00897     MIME_VALUE_ONLY_IF_CACHED = hdrtoken_string_to_wks("only-if-cached");
00898     MIME_VALUE_PRIVATE = hdrtoken_string_to_wks("private");
00899     MIME_VALUE_PROXY_REVALIDATE = hdrtoken_string_to_wks("proxy-revalidate");
00900     MIME_VALUE_PUBLIC = hdrtoken_string_to_wks("public");
00901     MIME_VALUE_S_MAXAGE = hdrtoken_string_to_wks("s-maxage");
00902     MIME_VALUE_NEED_REVALIDATE_ONCE = hdrtoken_string_to_wks("need-revalidate-once");
00903     MIME_VALUE_WEBSOCKET = hdrtoken_string_to_wks("websocket");
00904 
00905 
00906     mime_init_date_format_table();
00907     mime_init_cache_control_cooking_masks();
00908   }
00909 }
00910 
00911 void
00912 mime_init_cache_control_cooking_masks()
00913 {
00914   static struct
00915   {
00916     const char *name;
00917     uint32_t mask;
00918   } cc_mask_table[] = {
00919     {
00920     "max-age", MIME_COOKED_MASK_CC_MAX_AGE}, {
00921     "no-cache", MIME_COOKED_MASK_CC_NO_CACHE}, {
00922     "no-store", MIME_COOKED_MASK_CC_NO_STORE}, {
00923     "no-transform", MIME_COOKED_MASK_CC_NO_TRANSFORM}, {
00924     "max-stale", MIME_COOKED_MASK_CC_MAX_STALE}, {
00925     "min-fresh", MIME_COOKED_MASK_CC_MIN_FRESH}, {
00926     "only-if-cached", MIME_COOKED_MASK_CC_ONLY_IF_CACHED}, {
00927     "public", MIME_COOKED_MASK_CC_PUBLIC}, {
00928     "private", MIME_COOKED_MASK_CC_PRIVATE}, {
00929     "must-revalidate", MIME_COOKED_MASK_CC_MUST_REVALIDATE}, {
00930     "proxy-revalidate", MIME_COOKED_MASK_CC_PROXY_REVALIDATE}, {
00931     "s-maxage", MIME_COOKED_MASK_CC_S_MAXAGE}, {
00932     "need-revalidate-once", MIME_COOKED_MASK_CC_NEED_REVALIDATE_ONCE}, {
00933     NULL, 0}
00934   };
00935 
00936   for (int i = 0; cc_mask_table[i].name != NULL; i++) {
00937     const char *wks = hdrtoken_string_to_wks(cc_mask_table[i].name);
00938     HdrTokenHeapPrefix *p = hdrtoken_wks_to_prefix(wks);
00939     p->wks_type_specific.u.cache_control.cc_mask = cc_mask_table[i].mask;
00940   }
00941 }
00942 
00943 void
00944 mime_init_date_format_table()
00945 {
00946   ////////////////////////////////////////////////////////////////
00947   // to speed up the days_since_epoch to m/d/y conversion, we   //
00948   // use a pre-computed lookup table to support the common case //
00949   // of dates that are +/- one year from today --- this code    //
00950   // builds the lookup table during the first call.             //
00951   ////////////////////////////////////////////////////////////////
00952 
00953   time_t now_secs;
00954   int i, now_days, first_days, last_days, num_days;
00955   int m=0, d=0, y=0;
00956 
00957   time(&now_secs);
00958   now_days = (int) (now_secs / (60 * 60 * 24));
00959   first_days = now_days - 366;
00960   last_days = now_days + 366;
00961   num_days = last_days - first_days + 1;
00962 
00963   _days_to_mdy_fast_lookup_table = (MDY *)ats_malloc(num_days * sizeof(MDY));
00964   _days_to_mdy_fast_lookup_table_first_day = first_days;
00965   _days_to_mdy_fast_lookup_table_last_day = last_days;
00966 
00967   for (i = 0; i < num_days; i++) {
00968     mime_days_since_epoch_to_mdy_slowcase(first_days + i, &m, &d, &y);
00969     _days_to_mdy_fast_lookup_table[i].m = m;
00970     _days_to_mdy_fast_lookup_table[i].d = d;
00971     _days_to_mdy_fast_lookup_table[i].y = y;
00972   }
00973 }
00974 
00975 MIMEHdrImpl *
00976 mime_hdr_create(HdrHeap *heap)
00977 {
00978   MIMEHdrImpl *mh;
00979 
00980   mh = (MIMEHdrImpl *) heap->allocate_obj(sizeof(MIMEHdrImpl), HDR_HEAP_OBJ_MIME_HEADER);
00981   mime_hdr_init(mh);
00982   return mh;
00983 }
00984 
00985 void
00986 _mime_hdr_field_block_init(MIMEFieldBlockImpl *fblock)
00987 {
00988   fblock->m_freetop = 0;
00989   fblock->m_next = NULL;
00990 
00991 #ifdef BLOCK_INIT_PARANOIA
00992   int i;
00993 
00994   // FIX: Could eliminate this initialization loop if we assumed
00995   //      every slot above the freetop of the block was garbage;
00996   //      but to be safe, and help debugging, for now we are eating
00997   //      the cost of initializing all slots in a block.
00998 
00999   for (i = 0; i < MIME_FIELD_BLOCK_SLOTS; i++) {
01000     MIMEField *field = &(fblock->m_field_slots[i]);
01001     field->m_readiness = MIME_FIELD_SLOT_READINESS_EMPTY;
01002   }
01003 #endif
01004 }
01005 
01006 void
01007 mime_hdr_cooked_stuff_init(MIMEHdrImpl *mh, MIMEField *changing_field_or_null)
01008 {
01009 
01010   // to be safe, reinitialize unless you know this call is for other cooked field
01011   if ((changing_field_or_null == NULL) || (changing_field_or_null->m_wks_idx != MIME_WKSIDX_PRAGMA)) {
01012     mh->m_cooked_stuff.m_cache_control.m_mask = 0;
01013     mh->m_cooked_stuff.m_cache_control.m_secs_max_age = 0;
01014     mh->m_cooked_stuff.m_cache_control.m_secs_s_maxage = 0;
01015     mh->m_cooked_stuff.m_cache_control.m_secs_max_stale = 0;
01016     mh->m_cooked_stuff.m_cache_control.m_secs_min_fresh = 0;
01017   }
01018   if ((changing_field_or_null == NULL) || (changing_field_or_null->m_wks_idx != MIME_WKSIDX_CACHE_CONTROL)) {
01019     mh->m_cooked_stuff.m_pragma.m_no_cache = 0;
01020   }
01021 }
01022 
01023 void
01024 mime_hdr_init(MIMEHdrImpl *mh)
01025 {
01026   mime_hdr_init_accelerators_and_presence_bits(mh);
01027 
01028   mime_hdr_cooked_stuff_init(mh, NULL);
01029 
01030   // first header is inline: fake an object header for uniformity
01031   obj_init_header((HdrHeapObjImpl *) & (mh->m_first_fblock), HDR_HEAP_OBJ_FIELD_BLOCK, sizeof(MIMEFieldBlockImpl), 0);
01032 
01033   _mime_hdr_field_block_init(&(mh->m_first_fblock));
01034   mh->m_fblock_list_tail = &(mh->m_first_fblock);
01035 
01036   MIME_HDR_SANITY_CHECK(mh);
01037 }
01038 
01039 MIMEFieldBlockImpl *
01040 _mime_field_block_copy(MIMEFieldBlockImpl *s_fblock, HdrHeap * /* s_heap ATS_UNUSED */, HdrHeap *d_heap)
01041 {
01042   MIMEFieldBlockImpl *d_fblock;
01043 
01044   d_fblock = (MIMEFieldBlockImpl *)
01045     d_heap->allocate_obj(sizeof(MIMEFieldBlockImpl), HDR_HEAP_OBJ_FIELD_BLOCK);
01046   memcpy(d_fblock, s_fblock, sizeof(MIMEFieldBlockImpl));
01047   return d_fblock;
01048 }
01049 
01050 void
01051 _mime_field_block_destroy(HdrHeap *heap, MIMEFieldBlockImpl *fblock)
01052 {
01053   heap->deallocate_obj(fblock);
01054 }
01055 
01056 void
01057 mime_hdr_destroy_field_block_list(HdrHeap *heap, MIMEFieldBlockImpl *head)
01058 {
01059   MIMEFieldBlockImpl *next;
01060 
01061   while (head != NULL) {
01062     next = head->m_next;
01063     _mime_field_block_destroy(heap, head);
01064     head = next;
01065   }
01066 }
01067 
01068 void
01069 mime_hdr_destroy(HdrHeap *heap, MIMEHdrImpl *mh)
01070 {
01071   mime_hdr_destroy_field_block_list(heap, mh->m_first_fblock.m_next);
01072 
01073   // INKqa11458: if we deallocate mh here and call TSMLocRelease
01074   // again, the plugin fails in assert. We leave deallocating to
01075   // the plugin using TSMLocRelease
01076 
01077   //heap->deallocate_obj(mh);
01078 }
01079 
01080 void
01081 mime_hdr_copy_onto(MIMEHdrImpl *s_mh, HdrHeap *s_heap, MIMEHdrImpl *d_mh, HdrHeap *d_heap, bool inherit_strs)
01082 {
01083   int block_count;
01084   MIMEFieldBlockImpl *s_fblock, *d_fblock, *prev_d_fblock;
01085 
01086   // If there are chained field blocks beyond the first one, we're just going to
01087   //   destroy them.  Ideally, we'd use them if the copied in header needed
01088   //   extra blocks.  It's too late in the Tomcat code cycle to implement
01089   //   reuse.
01090   if (d_mh->m_first_fblock.m_next) {
01091     mime_hdr_destroy_field_block_list(d_heap, d_mh->m_first_fblock.m_next);
01092   }
01093 
01094   ink_assert(((char *) &(s_mh->m_first_fblock.m_field_slots[MIME_FIELD_BLOCK_SLOTS]) - (char *) s_mh) ==
01095                    sizeof(struct MIMEHdrImpl));
01096 
01097   int top = s_mh->m_first_fblock.m_freetop;
01098   char *end = (char *) &(s_mh->m_first_fblock.m_field_slots[top]);
01099   int bytes_below_top = end - (char *) s_mh;
01100 
01101   // copies useful part of enclosed first block too
01102   memcpy(d_mh, s_mh, bytes_below_top);
01103 
01104   if (d_mh->m_first_fblock.m_next == NULL)      // common case: no other block
01105   {
01106     d_mh->m_fblock_list_tail = &(d_mh->m_first_fblock);
01107     block_count = 1;
01108   } else                        // uncommon case: block list exists
01109   {
01110     prev_d_fblock = &(d_mh->m_first_fblock);
01111     block_count = 1;
01112     for (s_fblock = s_mh->m_first_fblock.m_next; s_fblock != NULL; s_fblock = s_fblock->m_next) {
01113       ++block_count;
01114       d_fblock = _mime_field_block_copy(s_fblock, s_heap, d_heap);
01115       prev_d_fblock->m_next = d_fblock;
01116       prev_d_fblock = d_fblock;
01117     }
01118     d_mh->m_fblock_list_tail = prev_d_fblock;
01119   }
01120 
01121   if (inherit_strs)
01122     d_heap->inherit_string_heaps(s_heap);
01123 
01124   mime_hdr_field_block_list_adjust(block_count, &(s_mh->m_first_fblock), &(d_mh->m_first_fblock));
01125 
01126   MIME_HDR_SANITY_CHECK(s_mh);
01127   MIME_HDR_SANITY_CHECK(d_mh);
01128 }
01129 
01130 MIMEHdrImpl *
01131 mime_hdr_clone(MIMEHdrImpl *s_mh, HdrHeap *s_heap, HdrHeap *d_heap, bool inherit_strs)
01132 {
01133   MIMEHdrImpl *d_mh;
01134 
01135   d_mh = mime_hdr_create(d_heap);
01136   mime_hdr_copy_onto(s_mh, s_heap, d_mh, d_heap, inherit_strs);
01137   return d_mh;
01138 }
01139 
01140 /** Move a pointer from one list to another, keeping the relative offset.
01141  * @return A pointer that has the same relative offset to @a dest_base as
01142  * @a dest_ptr does to @a src_base.
01143  */
01144 static inline MIMEField *rebase(
01145   MIMEField *dest_ptr, ///< Original pointer into @src_base memory.
01146   void *dest_base,     ///< New base pointer.
01147   void *src_base       ///< Original base pointer.
01148 ) {
01149   return reinterpret_cast<MIMEField *>
01150     (reinterpret_cast<char *>(dest_ptr) + (static_cast<char *>(dest_base) - static_cast<char *>(src_base)));
01151 }
01152 
01153 static inline void relocate(MIMEField *field, MIMEFieldBlockImpl *dest_block, MIMEFieldBlockImpl *src_block)
01154 {
01155   for ( ; src_block; src_block = src_block->m_next, dest_block = dest_block->m_next) {
01156     ink_release_assert(dest_block) ;
01157 
01158     if (field->m_next_dup >= src_block->m_field_slots &&
01159         field->m_next_dup < src_block->m_field_slots + src_block->m_freetop) {
01160       field->m_next_dup = rebase(field->m_next_dup, dest_block->m_field_slots, src_block->m_field_slots);
01161       return;
01162     }
01163   }
01164 }
01165 
01166 void
01167 mime_hdr_field_block_list_adjust(int /* block_count ATS_UNUSED */, MIMEFieldBlockImpl *old_list,
01168                                  MIMEFieldBlockImpl *new_list)
01169 {
01170   for (MIMEFieldBlockImpl *new_blk = new_list; new_blk; new_blk = new_blk->m_next) {
01171     for (MIMEField *field = new_blk->m_field_slots, *end=field + new_blk->m_freetop; field != end; ++field) {
01172       if (field->is_live() && field->m_next_dup) {
01173         relocate(field, new_list, old_list);
01174       }
01175     }
01176   }
01177 }
01178 
01179 int
01180 mime_hdr_length_get(MIMEHdrImpl *mh)
01181 {
01182   unsigned int length, index;
01183   MIMEFieldBlockImpl *fblock;
01184   MIMEField *field;
01185 
01186   length = 2;
01187 
01188   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
01189     for (index = 0; index < fblock->m_freetop; index++) {
01190       field = &(fblock->m_field_slots[index]);
01191       if (field->is_live()) {
01192         length += mime_field_length_get(field);
01193       }
01194     }
01195   }
01196 
01197   return length;
01198 }
01199 
01200 void
01201 mime_hdr_fields_clear(HdrHeap *heap, MIMEHdrImpl *mh)
01202 {
01203   mime_hdr_destroy_field_block_list(heap, mh->m_first_fblock.m_next);
01204   mime_hdr_init(mh);
01205 }
01206 
01207 MIMEField *
01208 _mime_hdr_field_list_search_by_wks(MIMEHdrImpl *mh, int wks_idx)
01209 {
01210   MIMEFieldBlockImpl *fblock;
01211   MIMEField *field, *too_far_field;
01212 
01213   ink_assert(hdrtoken_is_valid_wks_idx(wks_idx));
01214 
01215   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
01216     field = &(fblock->m_field_slots[0]);
01217 
01218     too_far_field = &(fblock->m_field_slots[fblock->m_freetop]);
01219     while (field < too_far_field) {
01220       if (field->is_live() && (field->m_wks_idx == wks_idx))
01221         return field;
01222       ++field;
01223     }
01224   }
01225 
01226   return NULL;
01227 }
01228 
01229 MIMEField *
01230 _mime_hdr_field_list_search_by_string(MIMEHdrImpl *mh, const char *field_name_str, int field_name_len)
01231 {
01232   MIMEFieldBlockImpl *fblock;
01233   MIMEField *field, *too_far_field;
01234 
01235   ink_assert(mh);
01236   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
01237     field = &(fblock->m_field_slots[0]);
01238 
01239     too_far_field = &(fblock->m_field_slots[fblock->m_freetop]);
01240     while (field < too_far_field) {
01241       if (field->is_live() &&
01242           (field_name_len == field->m_len_name) &&
01243           (strncasecmp(field->m_ptr_name, field_name_str, field_name_len) == 0)) {
01244         return field;
01245       }
01246       ++field;
01247     }
01248   }
01249 
01250   return NULL;
01251 }
01252 
01253 MIMEField *
01254 _mime_hdr_field_list_search_by_slotnum(MIMEHdrImpl *mh, int slotnum)
01255 {
01256   unsigned int block_num, block_index;
01257   MIMEFieldBlockImpl *fblock;
01258 
01259   if (slotnum < MIME_FIELD_BLOCK_SLOTS) {
01260     fblock = &(mh->m_first_fblock);
01261     block_index = slotnum;
01262     if (block_index >= fblock->m_freetop) {
01263       return NULL;
01264     } else {
01265       return &(fblock->m_field_slots[block_index]);
01266     }
01267   } else {
01268     block_num = slotnum / MIME_FIELD_BLOCK_SLOTS;
01269     block_index = slotnum % MIME_FIELD_BLOCK_SLOTS;
01270 
01271     fblock = &(mh->m_first_fblock);
01272     while (block_num-- && fblock)
01273       fblock = fblock->m_next;
01274     if ((fblock == NULL) || (block_index >= fblock->m_freetop))
01275       return NULL;
01276     else
01277       return &(fblock->m_field_slots[block_index]);
01278   }
01279 }
01280 
01281 MIMEField *
01282 mime_hdr_field_find(MIMEHdrImpl *mh, const char *field_name_str, int field_name_len)
01283 {
01284   int is_wks;
01285   HdrTokenHeapPrefix *token_info;
01286 
01287   ink_assert(field_name_len >= 0);
01288 
01289   ////////////////////////////////////////////
01290   // do presence check and slot accelerator //
01291   ////////////////////////////////////////////
01292 
01293   is_wks = hdrtoken_is_wks(field_name_str);
01294 #if TRACK_FIELD_FIND_CALLS
01295   Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): is_wks = %d\n", mh, field_name_len, field_name_str, is_wks);
01296 #endif
01297 
01298   if (is_wks) {
01299     token_info = hdrtoken_wks_to_prefix(field_name_str);
01300     if ((token_info->wks_info.mask) && ((mh->m_presence_bits & token_info->wks_info.mask) == 0)) {
01301 #if TRACK_FIELD_FIND_CALLS
01302       Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): MISS (due to presence bits)\n",
01303             mh, field_name_len, field_name_str);
01304 #endif
01305       return NULL;
01306     }
01307 
01308     int32_t slot_id = token_info->wks_info.slotid;
01309 
01310     if (slot_id != MIME_SLOTID_NONE) {
01311       uint32_t slotnum = mime_hdr_get_accelerator_slotnum(mh, slot_id);
01312 
01313       if (slotnum != MIME_FIELD_SLOTNUM_UNKNOWN) {
01314         MIMEField *f = _mime_hdr_field_list_search_by_slotnum(mh, slotnum);
01315         ink_assert((f == NULL) || f->is_live());
01316 #if TRACK_FIELD_FIND_CALLS
01317         Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): %s (due to slot accelerators)\n",
01318               mh, field_name_len, field_name_str, (f ? "HIT" : "MISS"));
01319 #endif
01320         return f;
01321       } else {
01322 #if TRACK_FIELD_FIND_CALLS
01323         Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): UNKNOWN (slot too big)\n",
01324               mh, field_name_len, field_name_str);
01325 #endif
01326       }
01327     }
01328   }
01329   ///////////////////////////////////////////////////////////////////////////
01330   // search by well-known string index or by case-insensitive string match //
01331   ///////////////////////////////////////////////////////////////////////////
01332 
01333   if (is_wks) {
01334     MIMEField *f = _mime_hdr_field_list_search_by_wks(mh, token_info->wks_idx);
01335     ink_assert((f == NULL) || f->is_live());
01336 #if TRACK_FIELD_FIND_CALLS
01337     Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): %s (due to WKS list walk)\n",
01338           mh, field_name_len, field_name_str, (f ? "HIT" : "MISS"));
01339 #endif
01340     return f;
01341   } else {
01342     MIMEField *f = _mime_hdr_field_list_search_by_string(mh, field_name_str, field_name_len);
01343 
01344     ink_assert((f == NULL) || f->is_live());
01345 #if TRACK_FIELD_FIND_CALLS
01346     Debug("http", "mime_hdr_field_find(hdr 0x%X, field %.*s): %s (due to strcmp list walk)\n",
01347           mh, field_name_len, field_name_str, (f ? "HIT" : "MISS"));
01348 #endif
01349     return f;
01350   }
01351 }
01352 
01353 MIMEField *
01354 mime_hdr_field_get(MIMEHdrImpl *mh, int idx)
01355 {
01356   unsigned int index;
01357   MIMEFieldBlockImpl *fblock;
01358   MIMEField *field;
01359   int got_idx;
01360 
01361   got_idx = -1;
01362 
01363   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
01364     for (index = 0; index < fblock->m_freetop; index++) {
01365       field = &(fblock->m_field_slots[index]);
01366       if (field->is_live())
01367         ++got_idx;
01368       if (got_idx == idx)
01369         return field;
01370     }
01371   }
01372 
01373   return NULL;
01374 }
01375 
01376 MIMEField *
01377 mime_hdr_field_get_slotnum(MIMEHdrImpl *mh, int slotnum)
01378 {
01379   return _mime_hdr_field_list_search_by_slotnum(mh, slotnum);
01380 }
01381 
01382 int
01383 mime_hdr_fields_count(MIMEHdrImpl *mh)
01384 {
01385   unsigned int index;
01386   MIMEFieldBlockImpl *fblock;
01387   MIMEField *field;
01388   int count;
01389 
01390   count = 0;
01391 
01392   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
01393     for (index = 0; index < fblock->m_freetop; index++) {
01394       field = &(fblock->m_field_slots[index]);
01395       if (field->is_live())
01396         ++count;
01397     }
01398   }
01399 
01400   return count;
01401 }
01402 
01403 void
01404 mime_field_init(MIMEField *field)
01405 {
01406   memset(field, 0, sizeof(MIMEField));
01407   field->m_readiness = MIME_FIELD_SLOT_READINESS_DETACHED;
01408   field->m_wks_idx = -1;
01409 }
01410 
01411 MIMEField *
01412 mime_field_create(HdrHeap *heap, MIMEHdrImpl *mh)
01413 {
01414   MIMEField *field;
01415   MIMEFieldBlockImpl *tail_fblock, *new_fblock;
01416 
01417   tail_fblock = mh->m_fblock_list_tail;
01418   if (tail_fblock->m_freetop >= MIME_FIELD_BLOCK_SLOTS) {
01419     new_fblock = (MIMEFieldBlockImpl *)
01420       heap->allocate_obj(sizeof(MIMEFieldBlockImpl), HDR_HEAP_OBJ_FIELD_BLOCK);
01421     _mime_hdr_field_block_init(new_fblock);
01422     tail_fblock->m_next = new_fblock;
01423     tail_fblock = new_fblock;
01424     mh->m_fblock_list_tail = new_fblock;
01425   }
01426 
01427   field = &(tail_fblock->m_field_slots[tail_fblock->m_freetop]);
01428   ++tail_fblock->m_freetop;
01429 
01430   mime_field_init(field);
01431 
01432   return field;
01433 }
01434 
01435 MIMEField *
01436 mime_field_create_named(HdrHeap *heap, MIMEHdrImpl *mh, const char *name, int length)
01437 {
01438   MIMEField *field = mime_field_create(heap, mh);
01439   int field_name_wks_idx = hdrtoken_tokenize(name, length);
01440   mime_field_name_set(heap, mh, field, field_name_wks_idx, name, length, 1);
01441   return field;
01442 }
01443 
01444 void
01445 mime_hdr_field_attach(MIMEHdrImpl *mh, MIMEField *field, int check_for_dups, MIMEField *prev_dup)
01446 {
01447   MIME_HDR_SANITY_CHECK(mh);
01448 
01449   if (!field->is_detached()) {
01450     return;
01451   }
01452 
01453   ink_assert(field->m_ptr_name != NULL);
01454 
01455   //////////////////////////////////////////////////
01456   // if we don't know the head dup, or are given  //
01457   // a non-head dup, then search for the head dup //
01458   //////////////////////////////////////////////////
01459 
01460   if (check_for_dups || (prev_dup && (!prev_dup->is_dup_head()))) {
01461     int length;
01462     const char *name = mime_field_name_get(field, &length);
01463     prev_dup = mime_hdr_field_find(mh, name, length);
01464     ink_assert((prev_dup == NULL) || (prev_dup->is_dup_head()));
01465   }
01466 
01467   field->m_readiness = MIME_FIELD_SLOT_READINESS_LIVE;
01468 
01469   ////////////////////////////////////////////////////////////////////
01470   // now, attach the new field --- if there are dups, make sure the //
01471   // field is patched into the dup list in increasing slot order to //
01472   // maintain the invariant that dups are chained in slot order     //
01473   ////////////////////////////////////////////////////////////////////
01474 
01475   if (prev_dup) {
01476     MIMEField *next_dup;
01477     int field_slotnum, prev_slotnum, next_slotnum;
01478 
01479     /////////////////////////////////////////////////////////////////
01480     // walk down dup list looking for the last dup in slot-order   //
01481     // before this field object --- meaning a dup before the field //
01482     // in slot order who either has no next dup, or whose next dup //
01483     // is numerically after the field in slot order.               //
01484     /////////////////////////////////////////////////////////////////
01485 
01486     field_slotnum = mime_hdr_field_slotnum(mh, field);
01487     prev_slotnum = mime_hdr_field_slotnum(mh, prev_dup);
01488     next_dup = prev_dup->m_next_dup;
01489     next_slotnum = (next_dup ? mime_hdr_field_slotnum(mh, next_dup) : -1);
01490 
01491     ink_assert(field_slotnum != prev_slotnum);
01492 
01493     while (prev_slotnum < field_slotnum)        // break if prev after field
01494     {
01495       if (next_dup == NULL)
01496         break;                  // no next dup, we're done
01497       if (next_slotnum > field_slotnum)
01498         break;                  // next dup is after us, we're done
01499       prev_dup = next_dup;
01500       prev_slotnum = next_slotnum;
01501       next_dup = prev_dup->m_next_dup;
01502     }
01503 
01504     /////////////////////////////////////////////////////
01505     // we get here if the prev_slotnum > field_slotnum //
01506     // (meaning we're now the first dup in the list),  //
01507     // or when we've found the correct prev and next   //
01508     /////////////////////////////////////////////////////
01509 
01510     if (prev_slotnum > field_slotnum)   // we are now the head
01511     {
01512       /////////////////////////////////////////////////////////////
01513       // here, it turns out that "prev_dup" is actually after    //
01514       // "field" in the list of fields --- so, prev_dup is a bit //
01515       // of a misnomer, it is actually, the NEXT field!          //
01516       /////////////////////////////////////////////////////////////
01517 
01518       field->m_flags = (field->m_flags | MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
01519       field->m_next_dup = prev_dup;
01520       prev_dup->m_flags = (prev_dup->m_flags & ~MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
01521       mime_hdr_set_accelerators_and_presence_bits(mh, field);
01522     } else                      // patch us after prev, and before next
01523     {
01524       ink_assert(prev_slotnum < field_slotnum);
01525       ink_assert((next_dup == NULL) || (next_slotnum > field_slotnum));
01526       field->m_flags = (field->m_flags & ~MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
01527       ink_assert((next_dup == NULL) || next_dup->is_live());
01528       prev_dup->m_next_dup = field;
01529       field->m_next_dup = next_dup;
01530     }
01531   } else {
01532     field->m_flags = (field->m_flags | MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
01533     mime_hdr_set_accelerators_and_presence_bits(mh, field);
01534   }
01535 
01536   // Now keep the cooked cache consistent
01537   ink_assert(field->is_live());
01538   if (field->m_ptr_value && field->is_cooked())
01539     mh->recompute_cooked_stuff(field);
01540 
01541   MIME_HDR_SANITY_CHECK(mh);
01542 }
01543 
01544 void
01545 mime_hdr_field_detach(MIMEHdrImpl *mh, MIMEField *field, bool detach_all_dups)
01546 {
01547   MIMEField *next_dup = field->m_next_dup;
01548 
01549   // If this field is already detached, there's nothing to do. There must
01550   // not be a dup list if we detached correctly.
01551   if (field->is_detached()) {
01552     ink_assert(next_dup == NULL);
01553     return;
01554   }
01555 
01556   ink_assert(field->is_live());
01557   MIME_HDR_SANITY_CHECK(mh);
01558 
01559   // Normally, this function is called with the current dup list head,
01560   // so, we need to update the accelerators after the patch out.  But, if
01561   // this function is ever called in the middle of a dup list, we need
01562   // to walk the list to find the previous dup in the list to patch out
01563   // the dup being detached.
01564 
01565   if (field->m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD)  // head of list?
01566   {
01567     if (!next_dup)              // only child
01568     {
01569       mime_hdr_unset_accelerators_and_presence_bits(mh, field);
01570     } else                      // next guy is dup head
01571     {
01572       next_dup->m_flags |= MIME_FIELD_SLOT_FLAGS_DUP_HEAD;
01573       mime_hdr_set_accelerators_and_presence_bits(mh, next_dup);
01574     }
01575   } else                        // need to walk list to find and patch out from predecessor
01576   {
01577     int name_length;
01578     const char *name = mime_field_name_get(field, &name_length);
01579     MIMEField *prev = mime_hdr_field_find(mh, name, name_length);
01580 
01581     while (prev && (prev->m_next_dup != field))
01582       prev = prev->m_next_dup;
01583     ink_assert(prev != NULL);
01584 
01585     if (prev->m_next_dup == field)
01586       prev->m_next_dup = next_dup;
01587   }
01588 
01589   // Field is now detached and alone
01590   field->m_readiness = MIME_FIELD_SLOT_READINESS_DETACHED;
01591   field->m_next_dup = NULL;
01592 
01593   // Because we changed the values through detaching,update the cooked cache
01594   if (field->is_cooked())
01595     mh->recompute_cooked_stuff(field);
01596 
01597   MIME_HDR_SANITY_CHECK(mh);
01598 
01599   // At this point, the list should be back to a valid state, either the
01600   // next dup detached and the accelerators set to the next dup (if any),
01601   // or an interior dup detached and patched around.  If we are requested
01602   // to delete the whole dup list, we tail-recurse to delete it.
01603 
01604   if (detach_all_dups && next_dup)
01605     mime_hdr_field_detach(mh, next_dup, detach_all_dups);
01606 }
01607 
01608 void
01609 mime_hdr_field_delete(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, bool delete_all_dups)
01610 {
01611   if (delete_all_dups) {
01612     while (field) {
01613       // NOTE: we pass zero to field_detach for detach_all_dups
01614       //       since this loop will already detach each dup
01615       MIMEField *next = field->m_next_dup;
01616 
01617       heap->free_string(field->m_ptr_name, field->m_len_name);
01618       heap->free_string(field->m_ptr_value, field->m_len_value);
01619 
01620       MIME_HDR_SANITY_CHECK(mh);
01621       mime_hdr_field_detach(mh, field, 0);
01622 
01623       MIME_HDR_SANITY_CHECK(mh);
01624       mime_field_destroy(mh, field);
01625 
01626       MIME_HDR_SANITY_CHECK(mh);
01627       field = next;
01628     }
01629   } else {
01630     heap->free_string(field->m_ptr_name, field->m_len_name);
01631     heap->free_string(field->m_ptr_value, field->m_len_value);
01632 
01633     MIME_HDR_SANITY_CHECK(mh);
01634     mime_hdr_field_detach(mh, field, 0);
01635 
01636     MIME_HDR_SANITY_CHECK(mh);
01637     mime_field_destroy(mh, field);
01638   }
01639 
01640   MIME_HDR_SANITY_CHECK(mh);
01641 }
01642 
01643 int
01644 mime_hdr_field_slotnum(MIMEHdrImpl *mh, MIMEField *field)
01645 {
01646   int slots_so_far;
01647   MIMEFieldBlockImpl *fblock;
01648 
01649   slots_so_far = 0;
01650   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
01651     MIMEField *first = &(fblock->m_field_slots[0]);
01652     int block_slot = (int) (field - first);     // in units of MIMEField
01653     if ((block_slot >= 0) && (block_slot < MIME_FIELD_BLOCK_SLOTS))
01654       return (slots_so_far + block_slot);
01655     slots_so_far += MIME_FIELD_BLOCK_SLOTS;
01656   }
01657   return -1;
01658 }
01659 
01660 MIMEField *
01661 mime_hdr_prepare_for_value_set(HdrHeap *heap, MIMEHdrImpl *mh, const char *name, int name_length)
01662 {
01663   int wks_idx;
01664   MIMEField *field;
01665 
01666   field = mime_hdr_field_find(mh, name, name_length);
01667 
01668   //////////////////////////////////////////////////////////////////////
01669   // this function returns with exactly one attached field created,   //
01670   // ready to have its value set.                                     //
01671   //                                                                  //
01672   // on return from field_find, there are 3 possibilities:            //
01673   //   no field found:      create attached, named field              //
01674   //   field found w/dups:  delete list, create attached, named field //
01675   //   dupless field found: return the field for mutation             //
01676   //////////////////////////////////////////////////////////////////////
01677 
01678   if (field == NULL)            // no fields of this name
01679   {
01680     wks_idx = hdrtoken_tokenize(name, name_length);
01681     field = mime_field_create(heap, mh);
01682     mime_field_name_set(heap, mh, field, wks_idx, name, name_length, 1);
01683     mime_hdr_field_attach(mh, field, 0, NULL);
01684 
01685   } else if (field->m_next_dup) // list of more than 1 field
01686   {
01687     wks_idx = field->m_wks_idx;
01688     mime_hdr_field_delete(heap, mh, field, true);
01689     field = mime_field_create(heap, mh);
01690     mime_field_name_set(heap, mh, field, wks_idx, name, name_length, 1);
01691     mime_hdr_field_attach(mh, field, 0, NULL);
01692   }
01693   return field;
01694 }
01695 
01696 void
01697 mime_field_destroy(MIMEHdrImpl */* mh ATS_UNUSED */, MIMEField *field)
01698 {
01699   ink_assert(field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED);
01700   field->m_readiness = MIME_FIELD_SLOT_READINESS_DELETED;
01701 }
01702 
01703 const char *
01704 mime_field_name_get(MIMEField *field, int *length)
01705 {
01706   *length = field->m_len_name;
01707   if (field->m_wks_idx >= 0)
01708     return hdrtoken_index_to_wks(field->m_wks_idx);
01709   else
01710     return field->m_ptr_name;
01711 }
01712 
01713 void
01714 mime_field_name_set(HdrHeap *heap, MIMEHdrImpl */* mh ATS_UNUSED */, MIMEField *field, int16_t name_wks_idx_or_neg1,
01715                     const char *name, int length, bool must_copy_string)
01716 {
01717   ink_assert(field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED);
01718 
01719   field->m_wks_idx = name_wks_idx_or_neg1;
01720   mime_str_u16_set(heap, name, length, &(field->m_ptr_name), &(field->m_len_name), must_copy_string);
01721 
01722   if ((name_wks_idx_or_neg1 == MIME_WKSIDX_CACHE_CONTROL) || (name_wks_idx_or_neg1 == MIME_WKSIDX_PRAGMA)) {
01723     field->m_flags |= MIME_FIELD_SLOT_FLAGS_COOKED;
01724   }
01725 }
01726 
01727 const char *
01728 mime_field_value_get(MIMEField *field, int *length)
01729 {
01730   *length = field->m_len_value;
01731   return field->m_ptr_value;
01732 }
01733 
01734 int32_t
01735 mime_field_value_get_int(MIMEField *field)
01736 {
01737   int length;
01738   const char *str = mime_field_value_get(field, &length);
01739 
01740   return mime_parse_int(str, str + length);
01741 }
01742 
01743 uint32_t
01744 mime_field_value_get_uint(MIMEField *field)
01745 {
01746   int length;
01747   const char *str = mime_field_value_get(field, &length);
01748   return mime_parse_uint(str, str + length);
01749 }
01750 
01751 int64_t
01752 mime_field_value_get_int64(MIMEField *field)
01753 {
01754   int length;
01755   const char *str = mime_field_value_get(field, &length);
01756 
01757   return mime_parse_int64(str, str + length);
01758 }
01759 
01760 time_t
01761 mime_field_value_get_date(MIMEField *field)
01762 {
01763   int length;
01764   const char *str = mime_field_value_get(field, &length);
01765   return mime_parse_date(str, str + length);
01766 }
01767 
01768 const char *
01769 mime_field_value_get_comma_val(MIMEField *field, int *length, int idx)
01770 {
01771   // some fields (like Date) contain commas but should not be ripped apart
01772   if (!field->supports_commas()) {
01773     if (idx == 0)
01774       return mime_field_value_get(field, length);
01775     else
01776       return NULL;
01777   } else {
01778     Str *str;
01779     StrList list(false);
01780 
01781     mime_field_value_get_comma_list(field, &list);
01782     str = list.get_idx(idx);
01783     if (str != NULL) {
01784       *length = (int) (str->len);
01785       return str->str;
01786     } else {
01787       *length = 0;
01788       return NULL;
01789     }
01790   }
01791 }
01792 
01793 int
01794 mime_field_value_get_comma_val_count(MIMEField *field)
01795 {
01796   // some fields (like Date) contain commas but should not be ripped apart
01797   if (!field->supports_commas()) {
01798     return ((field->m_len_value == 0) ? 0 : 1);
01799   } else {
01800     StrList list(false);
01801     int count = mime_field_value_get_comma_list(field, &list);
01802     return count;
01803   }
01804 }
01805 
01806 int
01807 mime_field_value_get_comma_list(MIMEField *field, StrList *list)
01808 {
01809   const char *str;
01810   int len;
01811 
01812   str = mime_field_value_get(field, &len);
01813 
01814   // if field doesn't support commas, don't rip apart.
01815   if (!field->supports_commas())
01816     list->append_string(str, len);
01817   else
01818     HttpCompat::parse_tok_list(list, 1, str, len, ',');
01819 
01820   return list->count;
01821 }
01822 
01823 const char *
01824 mime_field_value_str_from_strlist(HdrHeap *heap, int *new_str_len_return, StrList *list)
01825 {
01826   Str *cell;
01827   char *new_value, *dest;
01828   int i, new_value_len;
01829   // This works, because all strings are from the same heap when it is "split" into the list.
01830   HdrHeap::HeapGuard guard(heap, list->head->str);
01831 
01832   new_value_len = 0;
01833 
01834   // (1) walk the StrList cells, summing each cell's string lengths,
01835   //     and add 2 bytes for each ", " between cells
01836   cell = list->head;
01837   for (i = 0; i < list->count; i++) {
01838     new_value_len += cell->len;
01839     cell = cell->next;
01840   }
01841   if (list->count > 1)
01842     new_value_len += (2 * (list->count - 1));
01843 
01844   // (2) allocate new heap string
01845   new_value = heap->allocate_str(new_value_len);
01846 
01847   // (3) copy string pieces into new heap string
01848   dest = new_value;
01849   cell = list->head;
01850   for (i = 0; i < list->count; i++) {
01851     if (i != 0) {
01852       *dest++ = ',';
01853       *dest++ = ' ';
01854     }
01855     memcpy(dest, cell->str, cell->len);
01856     dest += cell->len;
01857     cell = cell->next;
01858   }
01859   ink_assert(dest - new_value == new_value_len);
01860 
01861   *new_str_len_return = new_value_len;
01862   return new_value;
01863 }
01864 
01865 void
01866 mime_field_value_set_comma_val(HdrHeap *heap, MIMEHdrImpl *mh,
01867                                MIMEField *field, int idx, const char *new_piece_str, int new_piece_len)
01868 {
01869   int len;
01870   Str *cell;
01871   StrList list(false);
01872 
01873   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
01874   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
01875 
01876   // (2) if desired index isn't valid, then don't change the field
01877   if ((idx<0) || (idx>= list.count))
01878     return;
01879 
01880   // (3) mutate cell idx
01881   cell = list.get_idx(idx);
01882   ink_assert(cell != NULL);
01883   cell->str = new_piece_str;
01884   cell->len = new_piece_len;
01885 
01886   // (4) reassemble the new string
01887   field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
01888   field->m_len_value = len;
01889 
01890   // (5) keep stuff fields consistent
01891   field->m_n_v_raw_printable = 0;
01892   if (field->is_live() && field->is_cooked())
01893     mh->recompute_cooked_stuff(field);
01894 }
01895 
01896 void
01897 mime_field_value_delete_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx)
01898 {
01899   int len;
01900   Str *cell;
01901   StrList list(false);
01902 
01903   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
01904   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
01905 
01906   // (2) if desired index isn't valid, then don't change the field
01907   if ((idx<0) || (idx>= list.count))
01908     return;
01909 
01910   // (3) delete cell idx
01911   cell = list.get_idx(idx);
01912   list.detach(cell);
01913 
01914     /**********************************************/
01915   /*   Fix for bug INKqa09752                   */
01916   /*                                            */
01917   /*   If this is the last value                */
01918   /*   in the field, set the m_ptr_val to NULL  */
01919     /**********************************************/
01920 
01921   if (list.count == 0) {
01922     field->m_ptr_value = 0;
01923     field->m_len_value = 0;
01924   } else {
01925       /************************************/
01926     /*   End Fix for bug INKqa09752     */
01927       /************************************/
01928 
01929 
01930     // (4) reassemble the new string
01931     field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
01932     field->m_len_value = len;
01933   }
01934 
01935   // (5) keep stuff fields consistent
01936   field->m_n_v_raw_printable = 0;
01937   if (field->is_live() && field->is_cooked())
01938     mh->recompute_cooked_stuff(field);
01939 }
01940 
01941 void
01942 mime_field_value_insert_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx,
01943                                   const char *new_piece_str, int new_piece_len)
01944 {
01945   int len;
01946   Str *cell, *prev;
01947   StrList list(false);
01948 
01949   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
01950   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
01951 
01952   // (2) if desired index isn't valid, then don't change the field
01953   if (idx < 0)
01954     idx = list.count;
01955   if (idx > list.count)
01956     return;
01957 
01958   // (3) create a new cell
01959   cell = list.new_cell(new_piece_str, new_piece_len);
01960 
01961   // (4) patch new cell into list at the right place
01962   if (idx == 0) {
01963     list.prepend(cell);
01964   } else {
01965     prev = list.get_idx(idx - 1);
01966     list.add_after(prev, cell);
01967   }
01968 
01969   // (5) reassemble the new string
01970   field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
01971   field->m_len_value = len;
01972 
01973   // (6) keep stuff fields consistent
01974   field->m_n_v_raw_printable = 0;
01975   if (field->is_live() && field->is_cooked())
01976     mh->recompute_cooked_stuff(field);
01977 }
01978 
01979 void
01980 mime_field_value_extend_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx,
01981                                   const char *new_piece_str, int new_piece_len)
01982 {
01983   Str *cell;
01984   StrList list(false);
01985   int trimmed, len;
01986   size_t extended_len;
01987   char *dest, *temp_ptr, temp_buf[128];
01988 
01989   // (1) rip the value into tokens, keeping surrounding quotes, but not whitespace
01990   HttpCompat::parse_tok_list(&list, 0, field->m_ptr_value, field->m_len_value, ',');
01991 
01992   // (2) if desired index isn't valid, then don't change the field
01993   if ((idx<0) || (idx>= list.count))
01994     return;
01995 
01996   // (3) get the cell we want to modify
01997   cell = list.get_idx(idx);
01998   ink_assert(cell != NULL);
01999 
02000   // (4) trim quotes if any
02001   if ((cell->len >= 2) && (cell->str[0] == '\"') && (cell->str[cell->len - 1] == '\"')) {
02002     trimmed = 1;
02003     cell->str += 1;
02004     cell->len -= 2;
02005   } else {
02006     trimmed = 0;
02007   }
02008 
02009   // (5) compute length of extended token
02010   extended_len = cell->len + new_piece_len + (trimmed ? 2 : 0);
02011 
02012   // (6) allocate temporary space to construct new value
02013   if (extended_len <= sizeof(temp_buf))
02014     temp_ptr = temp_buf;
02015   else
02016     temp_ptr = (char *)ats_malloc(extended_len);
02017 
02018   // (7) construct new extended token
02019   dest = temp_ptr;
02020   if (trimmed)
02021     *dest++ = '\"';
02022   memcpy(dest, cell->str, cell->len);
02023   dest += cell->len;
02024   memcpy(dest, new_piece_str, new_piece_len);
02025   dest += new_piece_len;
02026   if (trimmed)
02027     *dest++ = '\"';
02028   ink_assert((size_t) (dest - temp_ptr) == extended_len);
02029 
02030   // (8) assign the new token to the cell
02031   cell->str = temp_ptr;
02032   cell->len = extended_len;
02033 
02034   // (9) reassemble the new string
02035   field->m_ptr_value = mime_field_value_str_from_strlist(heap, &len, &list);
02036   field->m_len_value = len;
02037 
02038   // (10) keep stuff fields consistent
02039   field->m_n_v_raw_printable = 0;
02040   if (field->is_live() && field->is_cooked())
02041     mh->recompute_cooked_stuff(field);
02042 
02043   // (11) free up any temporary storage
02044   if (extended_len > sizeof(temp_buf))
02045     ats_free(temp_ptr);
02046 }
02047 
02048 void
02049 mime_field_value_set(HdrHeap *heap,
02050                      MIMEHdrImpl *mh, MIMEField *field, const char *value, int length, bool must_copy_string)
02051 {
02052 
02053   heap->free_string(field->m_ptr_value, field->m_len_value);
02054 
02055   if (must_copy_string && value)
02056     field->m_ptr_value = heap->duplicate_str(value, length);
02057   else
02058     field->m_ptr_value = value;
02059 
02060   field->m_len_value = length;
02061   field->m_n_v_raw_printable = 0;
02062 
02063   // Now keep the cooked cache consistent
02064   if (field->is_live() && field->is_cooked())
02065     mh->recompute_cooked_stuff(field);
02066 }
02067 
02068 void
02069 mime_field_value_set_int(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int32_t value)
02070 {
02071   char buf[16];
02072   int len = mime_format_int(buf, value, sizeof(buf));
02073   mime_field_value_set(heap, mh, field, buf, len, 1);
02074 }
02075 
02076 void
02077 mime_field_value_set_uint(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, uint32_t value)
02078 {
02079   char buf[16];
02080   int len = mime_format_uint(buf, value, sizeof(buf));
02081   mime_field_value_set(heap, mh, field, buf, len, 1);
02082 }
02083 
02084 void
02085 mime_field_value_set_int64(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int64_t value)
02086 {
02087   char buf[20];
02088   int len = mime_format_int64(buf, value, sizeof(buf));
02089   mime_field_value_set(heap, mh, field, buf, len, 1);
02090 }
02091 
02092 void
02093 mime_field_value_set_date(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, time_t value)
02094 {
02095   char buf[33];
02096   int len = mime_format_date(buf, value);
02097   mime_field_value_set(heap, mh, field, buf, len, 1);
02098 }
02099 
02100 void
02101 mime_field_name_value_set(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int16_t name_wks_idx_or_neg1,
02102                           const char *name, int name_length, const char *value, int value_length, int n_v_raw_printable,
02103                           int n_v_raw_length, bool must_copy_strings)
02104 {
02105   unsigned int n_v_raw_pad = n_v_raw_length - (name_length + value_length);
02106 
02107   ink_assert(field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED);
02108 
02109   if (must_copy_strings) {
02110     mime_field_name_set(heap, mh, field, name_wks_idx_or_neg1, name, name_length, 1);
02111     mime_field_value_set(heap, mh, field, value, value_length, 1);
02112   } else {
02113     field->m_wks_idx = name_wks_idx_or_neg1;
02114     field->m_ptr_name = name;
02115     field->m_ptr_value = value;
02116     field->m_len_name = name_length;
02117     field->m_len_value = value_length;
02118     if (n_v_raw_printable && (n_v_raw_pad <= 7)) {
02119       field->m_n_v_raw_printable = n_v_raw_printable;
02120       field->m_n_v_raw_printable_pad = n_v_raw_pad;
02121     } else {
02122       field->m_n_v_raw_printable = 0;
02123     }
02124 
02125     // Now keep the cooked cache consistent
02126     if ((name_wks_idx_or_neg1 == MIME_WKSIDX_CACHE_CONTROL) || (name_wks_idx_or_neg1 == MIME_WKSIDX_PRAGMA)) {
02127       field->m_flags |= MIME_FIELD_SLOT_FLAGS_COOKED;
02128     }
02129     if (field->is_live() && field->is_cooked())
02130       mh->recompute_cooked_stuff(field);
02131   }
02132 }
02133 
02134 void
02135 mime_field_value_append(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, const char *value, int length,
02136                         bool prepend_comma, const char separator)
02137 {
02138   int new_length = field->m_len_value + length;
02139   if (prepend_comma && field->m_len_value)
02140     new_length += 2;
02141 
02142   // Start by trying expand the string we already  have
02143   char *new_str = heap->expand_str(field->m_ptr_value, field->m_len_value, new_length);
02144 
02145   if (new_str == NULL) {
02146     // Expansion failed.  Create a new string and copy over the value contents
02147     new_str = heap->allocate_str(new_length);
02148     memcpy(new_str, field->m_ptr_value, field->m_len_value);
02149   }
02150 
02151   char *ptr = new_str + field->m_len_value;
02152   if (prepend_comma && field->m_len_value) {
02153     *ptr++ = separator;
02154     *ptr++ = ' ';
02155   }
02156 
02157   memcpy(ptr, value, length);
02158 
02159   field->m_ptr_value = new_str;
02160   field->m_len_value = new_length;
02161   field->m_n_v_raw_printable = 0;
02162 
02163   // Now keep the cooked cache consistent
02164   if (field->is_live() && field->is_cooked())
02165     mh->recompute_cooked_stuff(field);
02166 }
02167 
02168 MIMEField* MIMEHdr::get_host_port_values(
02169   char const** host_ptr, ///< Pointer to host.
02170   int* host_len, ///< Length of host.
02171   char const** port_ptr, ///< Pointer to port.
02172   int* port_len
02173   )
02174 {
02175   MIMEField* field = this->field_find(MIME_FIELD_HOST, MIME_LEN_HOST);
02176   if (host_ptr)
02177     *host_ptr = 0;
02178   if (host_len)
02179     *host_len = 0;
02180   if (port_ptr)
02181     *port_ptr = 0;
02182   if (port_len)
02183     *port_len = 0;
02184 
02185   if (field) {
02186     ts::ConstBuffer b(field->m_ptr_value, field->m_len_value);
02187     ts::ConstBuffer host, port;
02188 
02189     if (b) {
02190       char const* x;
02191 
02192       if ('[' == *b) {
02193         x = static_cast<char const*>(memchr(b._ptr, ']', b._size));
02194         if (x && b.contains(x+1) && ':' == x[1]) {
02195           host = b.splitOn(x+1);
02196           port = b;
02197         } else {
02198           host = b;
02199         }
02200       } else {
02201         x = static_cast<char const*>(memchr(b._ptr, ':', b._size));
02202         if (x) {
02203           host = b.splitOn(x);
02204           port = b;
02205         } else {
02206           host = b;
02207         }
02208       }
02209       
02210       if (host) {
02211         if (host_ptr) *host_ptr = host._ptr;
02212         if (host_len) *host_len = static_cast<int>(host._size);
02213       }
02214       if (port) {
02215         if (port_ptr) *port_ptr = port._ptr;
02216         if (port_len) *port_len = static_cast<int>(port._size);
02217       }
02218     } else {
02219       field = 0; // no value in field, signal fail.
02220     }
02221   }
02222   return field;
02223 }
02224 
02225 /***********************************************************************
02226  *                                                                     *
02227  *                          P A R S E R                                *
02228  *                                                                     *
02229  ***********************************************************************/
02230 void
02231 _mime_scanner_init(MIMEScanner *scanner)
02232 {
02233   scanner->m_line = NULL;
02234   scanner->m_line_size = 0;
02235   scanner->m_line_length = 0;
02236   scanner->m_state = MIME_PARSE_BEFORE;
02237 
02238 }
02239 
02240 //////////////////////////////////////////////////////
02241 // init     first time structure setup              //
02242 // clear    resets an already-initialized structure //
02243 //////////////////////////////////////////////////////
02244 void
02245 mime_scanner_init(MIMEScanner *scanner)
02246 {
02247   _mime_scanner_init(scanner);
02248 }
02249 
02250 // clear is to reset an already initialized structure
02251 void
02252 mime_scanner_clear(MIMEScanner *scanner)
02253 {
02254   ats_free(scanner->m_line);
02255   _mime_scanner_init(scanner);
02256 }
02257 
02258 void
02259 mime_scanner_append(MIMEScanner *scanner, const char *data, int data_size)
02260 {
02261   int free_size = scanner->m_line_size - scanner->m_line_length;
02262 
02263   //////////////////////////////////////////////////////
02264   // if not enough space, allocate or grow the buffer //
02265   //////////////////////////////////////////////////////
02266   if (data_size > free_size) {    // need to allocate/grow the buffer
02267     if (scanner->m_line_size == 0)      // buffer should be at least 128 bytes
02268       scanner->m_line_size = 128;
02269 
02270     while (free_size < data_size) {      // grow buffer by powers of 2
02271       scanner->m_line_size *= 2;
02272       free_size = scanner->m_line_size - scanner->m_line_length;
02273     }
02274 
02275     if (scanner->m_line == NULL) {       // if no buffer yet, allocate one
02276       scanner->m_line = (char *)ats_malloc(scanner->m_line_size);
02277     } else {
02278       scanner->m_line = (char *)ats_realloc(scanner->m_line, scanner->m_line_size);
02279     }
02280   }
02281   ////////////////////////////////////////////////
02282   // append new data onto the end of the buffer //
02283   ////////////////////////////////////////////////
02284 
02285   memcpy(&(scanner->m_line[scanner->m_line_length]), data, data_size);
02286   scanner->m_line_length += data_size;
02287 }
02288 
02289 MIMEParseResult
02290 mime_scanner_get(MIMEScanner *S,
02291                  const char **raw_input_s,
02292                  const char *raw_input_e,
02293                  const char **output_s,
02294                  const char **output_e,
02295                  bool *output_shares_raw_input,
02296                  bool raw_input_eof, ///< All data has been received for this header.
02297                  int raw_input_scan_type)
02298 {
02299   const char *raw_input_c, *lf_ptr;
02300   MIMEParseResult zret = PARSE_CONT;
02301   // Need this for handling dangling CR.
02302   static char const RAW_CR = ParseRules::CHAR_CR;
02303 
02304   ink_assert((raw_input_s != NULL) && (*raw_input_s != NULL));
02305   ink_assert(raw_input_e != NULL);
02306 
02307   raw_input_c = *raw_input_s;
02308 
02309   while (PARSE_CONT == zret && raw_input_c < raw_input_e) {
02310     ptrdiff_t runway = raw_input_e - raw_input_c; // remaining input.
02311     switch (S->m_state) {
02312     case MIME_PARSE_BEFORE: // waiting to find a field.
02313       if (ParseRules::is_cr(*raw_input_c)) {
02314         ++raw_input_c;
02315         if (runway >= 2 && ParseRules::is_lf(*raw_input_c)) {
02316           // optimize a bit - this happens >99% of the time after a CR.
02317           ++raw_input_c;
02318           zret = PARSE_DONE;
02319         } else {
02320           S->m_state = MIME_PARSE_FOUND_CR;
02321         }
02322       } else if (ParseRules::is_lf(*raw_input_c)) {
02323         ++raw_input_c;
02324         zret = PARSE_DONE; // Required by regression test.
02325       } else {
02326         // consume this character in the next state.
02327         S->m_state = MIME_PARSE_INSIDE;
02328       }
02329       break;
02330     case MIME_PARSE_FOUND_CR:
02331       // Looking for a field and found a CR, which should mean terminating
02332       // the header. Note that we've left the CR in the input so we have
02333       // to skip over it.
02334       if (ParseRules::is_lf(*raw_input_c)) {
02335         // Header terminated.
02336         ++raw_input_c;
02337         zret = PARSE_DONE;
02338       } else {
02339         // This really should be an error (spec doesn't permit lone CR)
02340         // but the regression tests require it.
02341         mime_scanner_append(S, &RAW_CR, 1);
02342         S->m_state = MIME_PARSE_INSIDE;
02343       }
02344       break;
02345     case MIME_PARSE_INSIDE:
02346       lf_ptr = static_cast<char const*>(memchr(raw_input_c, ParseRules::CHAR_LF, runway));
02347       if (lf_ptr) {
02348         raw_input_c = lf_ptr + 1;
02349         if (MIME_SCANNER_TYPE_LINE == raw_input_scan_type) {
02350           zret = PARSE_OK;
02351           S->m_state = MIME_PARSE_BEFORE;
02352         } else {
02353           S->m_state = MIME_PARSE_AFTER;
02354         }
02355       } else {
02356         raw_input_c = raw_input_e; // grab all that's available.
02357       }
02358       break;
02359     case MIME_PARSE_AFTER:
02360       // After a LF. Might be the end or a continuation.
02361       if (ParseRules::is_ws(*raw_input_c)) {
02362         S->m_state = MIME_PARSE_INSIDE; // back inside the field.
02363       } else {
02364         S->m_state = MIME_PARSE_BEFORE; // field terminated.
02365         zret = PARSE_OK;
02366       }
02367       break;
02368     }
02369   }
02370 
02371   ptrdiff_t data_size = raw_input_c - *raw_input_s;
02372 
02373   if (PARSE_CONT == zret) {
02374     // data ran out before we got a clear final result.
02375     // There a number of things we need to check and possibly adjust
02376     // that result. It's less complex to do this cleanup than handle
02377     // in the parser state machine.
02378     if (raw_input_eof) {
02379       // Should never return PARSE_CONT if we've hit EOF.
02380       if (0 == data_size) {
02381         // all input previously consumed. If we're between fields, that's cool.
02382         if (MIME_PARSE_INSIDE != S->m_state) {
02383           S->m_state = MIME_PARSE_BEFORE; // probably not needed...
02384           zret = PARSE_DONE;
02385         } else {
02386           zret = PARSE_ERROR; // unterminated field.
02387         }
02388       } else if (MIME_PARSE_AFTER == S->m_state) {
02389         // Special case it seems - need to accept the final field
02390         // even if there's no header terminating CR LF. We check for
02391         // absolute end of input because otherwise this might be
02392         // a multiline field where we haven't seen the next leading space.
02393         S->m_state = MIME_PARSE_BEFORE;
02394         zret = PARSE_OK;
02395       } else {
02396         // Partial input, no field / line CR LF
02397         zret = PARSE_ERROR; // Unterminated field.
02398       }
02399     } else if (data_size) {
02400       // Inside a field but more data is expected. Save what we've got.
02401       mime_scanner_append(S, *raw_input_s, data_size);
02402       data_size = 0; // Don't append again.
02403     }
02404   } 
02405 
02406   if (data_size && S->m_line_length) {
02407     // If we're already accumulating, continue to do so if we have data.
02408     mime_scanner_append(S, *raw_input_s, data_size);
02409   }
02410 
02411   // adjust out arguments.
02412   if (PARSE_CONT != zret) {
02413     if (0 != S->m_line_length) {
02414       *output_s = S->m_line;
02415       *output_e = *output_s + S->m_line_length;
02416       *output_shares_raw_input = false;
02417       S->m_line_length = 0;
02418     } else {
02419       *output_s = *raw_input_s;
02420       *output_e = raw_input_c;
02421       *output_shares_raw_input = true;
02422     }
02423   }
02424   
02425   *raw_input_s = raw_input_c; // mark input consumed.
02426   return zret;
02427 }
02428 
02429 void
02430 _mime_parser_init(MIMEParser *parser)
02431 {
02432   parser->m_field = 0;
02433   parser->m_field_flags = 0;
02434   parser->m_value = -1;
02435 }
02436 //////////////////////////////////////////////////////
02437 // init     first time structure setup              //
02438 // clear    resets an already-initialized structure //
02439 //////////////////////////////////////////////////////
02440 void
02441 mime_parser_init(MIMEParser *parser)
02442 {
02443   mime_scanner_init(&parser->m_scanner);
02444   _mime_parser_init(parser);
02445 }
02446 
02447 void
02448 mime_parser_clear(MIMEParser *parser)
02449 {
02450   mime_scanner_clear(&parser->m_scanner);
02451   _mime_parser_init(parser);
02452 }
02453 
02454 MIMEParseResult
02455 mime_parser_parse(MIMEParser *parser, HdrHeap *heap, MIMEHdrImpl *mh, const char **real_s, const char *real_e,
02456                   bool must_copy_strings, bool eof)
02457 {
02458   MIMEParseResult err;
02459   bool line_is_real;
02460   const char *colon;
02461   const char *line_c;
02462   const char *line_s;
02463   const char *line_e;
02464   const char *field_name_first;
02465   const char *field_name_last;
02466   const char *field_value_first;
02467   const char *field_value_last;
02468   const char *field_line_first;
02469   const char *field_line_last;
02470   int field_name_length, field_value_length;
02471 
02472   MIMEScanner *scanner = &parser->m_scanner;
02473 
02474   while (1) {
02475     ////////////////////////////////////////////////////////////////////////////
02476     // get a name:value line, with all continuation lines glued into one line //
02477     ////////////////////////////////////////////////////////////////////////////
02478 
02479     err = mime_scanner_get(scanner, real_s, real_e, &line_s, &line_e, &line_is_real, eof, MIME_SCANNER_TYPE_FIELD);
02480     if (err != PARSE_OK)
02481       return err;
02482 
02483     line_c = line_s;
02484 
02485     //////////////////////////////////////////////////
02486     // if got a LF or CR on its own, end the header //
02487     //////////////////////////////////////////////////
02488 
02489     if ((line_e - line_c >= 2) && (line_c[0] == ParseRules::CHAR_CR) && (line_c[1] == ParseRules::CHAR_LF))
02490       return PARSE_DONE;
02491 
02492     if ((line_e - line_c >= 1) && (line_c[0] == ParseRules::CHAR_LF))
02493       return PARSE_DONE;
02494 
02495     /////////////////////////////////////////////
02496     // find pointers into the name:value field //
02497     /////////////////////////////////////////////
02498 
02499     field_line_first = line_c;
02500     field_line_last = line_e - 1;
02501 
02502     // find name first
02503     field_name_first = line_c;
02504         /**
02505          * Fix for INKqa09141. The is_token function fails for '@' character.
02506          * Header names starting with '@' signs are valid headers. Hence we
02507          * have to add one more check to see if the first parameter is '@'
02508          * character then, the header name is valid.
02509          **/
02510     if ((!ParseRules::is_token(*field_name_first)) && (*field_name_first != '@'))
02511       continue;                 // toss away garbage line
02512 
02513     // find name last
02514     colon = (char *) memchr(line_c, ':', (line_e - line_c));
02515     if (!colon)
02516       continue;                 // toss away garbage line
02517     field_name_last = colon - 1;
02518     while ((field_name_last >= field_name_first) && is_ws(*field_name_last))
02519       --field_name_last;
02520 
02521     // find value first
02522     field_value_first = colon + 1;
02523     while ((field_value_first < line_e) && is_ws(*field_value_first))
02524       ++field_value_first;
02525 
02526     // find_value_last
02527     field_value_last = line_e - 1;
02528     while ((field_value_last >= field_value_first) && ParseRules::is_wslfcr(*field_value_last))
02529       --field_value_last;
02530 
02531     field_name_length = (int) (field_name_last - field_name_first + 1);
02532     field_value_length = (int) (field_value_last - field_value_first + 1);
02533 
02534     // Make sure the name or value is not longer than 64K
02535     if (field_name_length >= UINT16_MAX || field_value_length >= UINT16_MAX)
02536       return PARSE_ERROR;
02537 
02538     int total_line_length = (int) (field_line_last - field_line_first + 1);
02539 
02540     //////////////////////////////////////////////////////////////////////
02541     // if we can't leave the name & value in the real buffer, copy them //
02542     //////////////////////////////////////////////////////////////////////
02543 
02544     if (must_copy_strings || (!line_is_real)) {
02545       int length = total_line_length;
02546       char *dup = heap->duplicate_str(field_name_first, length);
02547       intptr_t delta = dup - field_name_first;
02548 
02549       field_name_first += delta;
02550       field_value_first += delta;
02551     }
02552     ///////////////////////
02553     // tokenize the name //
02554     ///////////////////////
02555 
02556     int field_name_wks_idx = hdrtoken_tokenize(field_name_first, field_name_length);
02557 
02558     ///////////////////////////////////////////
02559     // build and insert the new field object //
02560     ///////////////////////////////////////////
02561 
02562 
02563     MIMEField *field = mime_field_create(heap, mh);
02564     mime_field_name_value_set(heap, mh, field,
02565                               field_name_wks_idx,
02566                               field_name_first, field_name_length,
02567                               field_value_first, field_value_length, true, total_line_length, 0);
02568     mime_hdr_field_attach(mh, field, 1, NULL);
02569   }
02570 }
02571 
02572 void
02573 mime_hdr_describe(HdrHeapObjImpl *raw, bool recurse)
02574 {
02575   MIMEFieldBlockImpl *fblock;
02576   MIMEHdrImpl *obj = (MIMEHdrImpl *) raw;
02577 
02578   Debug("http", "\n\t[PBITS: 0x%08X%08X, SLACC: 0x%04X%04X%04X%04X, HEADBLK: %p, TAILBLK: %p]\n",
02579         (uint32_t) ((obj->m_presence_bits >> 32) & (TOK_64_CONST(0xFFFFFFFF))),
02580         (uint32_t) ((obj->m_presence_bits >> 0) & (TOK_64_CONST(0xFFFFFFFF))),
02581         obj->m_slot_accelerators[0], obj->m_slot_accelerators[1],
02582         obj->m_slot_accelerators[2], obj->m_slot_accelerators[3], &(obj->m_first_fblock), obj->m_fblock_list_tail);
02583 
02584   Debug("http", "\t[CBITS: 0x%08X, T_MAXAGE: %d, T_SMAXAGE: %d, T_MAXSTALE: %d, T_MINFRESH: %d, PNO$: %d]\n",
02585         obj->m_cooked_stuff.m_cache_control.m_mask,
02586         obj->m_cooked_stuff.m_cache_control.m_secs_max_age,
02587         obj->m_cooked_stuff.m_cache_control.m_secs_s_maxage,
02588         obj->m_cooked_stuff.m_cache_control.m_secs_max_stale,
02589         obj->m_cooked_stuff.m_cache_control.m_secs_min_fresh, obj->m_cooked_stuff.m_pragma.m_no_cache);
02590   for (fblock = &(obj->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
02591     if (recurse || (fblock == &(obj->m_first_fblock)))
02592       obj_describe((HdrHeapObjImpl *) fblock, recurse);
02593   }
02594 }
02595 
02596 void
02597 mime_field_block_describe(HdrHeapObjImpl *raw, bool /* recurse ATS_UNUSED */)
02598 {
02599   unsigned int i;
02600   static const char *readiness_names[] = { "EMPTY", "DETACHED", "LIVE", "DELETED" };
02601 
02602   MIMEFieldBlockImpl *obj = (MIMEFieldBlockImpl *) raw;
02603 
02604   Debug("http", "[FREETOP: %d, NEXTBLK: %p]\n", obj->m_freetop, obj->m_next);
02605 
02606   for (i = 0; i < obj->m_freetop; i++) {
02607     MIMEField *f = &(obj->m_field_slots[i]);
02608     Debug("http", "\tSLOT #%2d (%p), %-8s", i, f, readiness_names[f->m_readiness]);
02609 
02610     switch (f->m_readiness) {
02611     case MIME_FIELD_SLOT_READINESS_EMPTY:
02612       break;
02613     case MIME_FIELD_SLOT_READINESS_DETACHED:
02614     case MIME_FIELD_SLOT_READINESS_LIVE:
02615     case MIME_FIELD_SLOT_READINESS_DELETED:
02616       Debug("http", "[N: \"%.*s\", N_LEN: %d, N_IDX: %d, ",
02617             f->m_len_name, (f->m_ptr_name ? f->m_ptr_name : "NULL"), f->m_len_name, f->m_wks_idx);
02618       Debug("http", "V: \"%.*s\", V_LEN: %d, ",
02619             f->m_len_value, (f->m_ptr_value ? f->m_ptr_value : "NULL"), f->m_len_value);
02620       Debug("http", "NEXTDUP: %p, RAW: %d, RAWLEN: %d, F: %d]",
02621             f->m_next_dup, f->m_n_v_raw_printable,
02622             f->m_len_name + f->m_len_value + f->m_n_v_raw_printable_pad, f->m_flags);
02623       break;
02624     }
02625     Debug("http", "\n");
02626   }
02627 }
02628 
02629 int
02630 mime_hdr_print(HdrHeap * /* heap ATS_UNUSED */, MIMEHdrImpl *mh, char *buf_start, int buf_length, int *buf_index_inout,
02631                int *buf_chars_to_skip_inout)
02632 {
02633   MIMEFieldBlockImpl *fblock;
02634   MIMEField *field;
02635   uint32_t index;
02636 
02637 #define SIMPLE_MIME_HDR_PRINT
02638 #ifdef SIMPLE_MIME_HDR_PRINT
02639   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
02640     for (index = 0; index < fblock->m_freetop; index++) {
02641       field = &(fblock->m_field_slots[index]);
02642       if (field->is_live()) {
02643         if (!mime_field_print(field, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout))
02644           return 0;
02645       }
02646     }
02647   }
02648 #else
02649   // FIX: if not raw_printable, need to print with mime_field_print,
02650   //      not mime_mem_print
02651   for (fblock = &(mh->m_first_fblock); fblock != NULL; fblock = fblock->m_next) {
02652     const char *contig_start = NULL;
02653     int this_length, contig_length = 0;
02654     for (index = 0; index < fblock->m_freetop; index++) {
02655       field = &(fblock->m_field_slots[index]);
02656       this_length = field->m_len_name + field->m_len_value + field->m_n_v_raw_printable_pad;
02657       if (field->is_live()) {
02658         if ((field->m_ptr_name == contig_start + contig_length)
02659             && field->m_n_v_raw_printable
02660             && ((buf_index_inout == NULL) || (contig_length + this_length <= buf_length - *buf_index_inout))) {
02661 
02662           contig_length += this_length;
02663         } else {
02664           if (contig_length > 0) {
02665             if (!mime_mem_print(contig_start, contig_length, buf_start, buf_length,
02666                                 buf_index_inout, buf_chars_to_skip_inout))
02667               return 0;
02668           }
02669           contig_start = field->m_ptr_name;
02670           contig_length = this_length;
02671         }
02672       }
02673     }
02674 
02675     if (contig_length > 0) {
02676       if (!mime_mem_print(contig_start, contig_length, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout))
02677         return 0;
02678     }
02679   }
02680 #endif
02681 
02682   if (!mime_mem_print("\r\n", 2, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout)) {
02683     return 0;
02684   }
02685 
02686   return 1;
02687 }
02688 
02689 int
02690 mime_mem_print(const char *src_d, int src_l, char *buf_start, int buf_length, int *buf_index_inout,
02691                int *buf_chars_to_skip_inout)
02692 {
02693   int copy_l;
02694 
02695   if (buf_start == NULL) {      // this case should only be used by test_header
02696     ink_release_assert(buf_index_inout == NULL);
02697     ink_release_assert(buf_chars_to_skip_inout == NULL);
02698     while (src_l--)
02699       putchar(*src_d++);
02700     return 1;
02701   }
02702 
02703   ink_assert(buf_start != NULL);
02704   ink_assert(src_d != NULL);
02705 
02706   if (*buf_chars_to_skip_inout > 0) {
02707     if (*buf_chars_to_skip_inout >= src_l) {
02708       *buf_chars_to_skip_inout -= src_l;
02709       return 1;
02710     } else {
02711       src_l -= *buf_chars_to_skip_inout;
02712       src_d += *buf_chars_to_skip_inout;
02713       *buf_chars_to_skip_inout = 0;
02714     }
02715   }
02716 
02717   copy_l = min(buf_length - *buf_index_inout, src_l);
02718   if (copy_l > 0) {
02719     memcpy(buf_start + *buf_index_inout, src_d, copy_l);
02720     *buf_index_inout += copy_l;
02721   }
02722   return (src_l == copy_l);
02723 }
02724 
02725 int
02726 mime_field_print(MIMEField *field, char *buf_start, int buf_length, int *buf_index_inout, int *buf_chars_to_skip_inout)
02727 {
02728 #define TRY(x)  if (!x) return 0
02729 
02730   int total_len;
02731 
02732   // Don't print names that begin with an '@'.
02733   if (field->m_ptr_name[0] == '@') {
02734     return 1;
02735   }
02736 
02737   if (field->m_n_v_raw_printable) {
02738 
02739     total_len = field->m_len_name + field->m_len_value + field->m_n_v_raw_printable_pad;
02740 
02741     if ((buf_start != NULL) && (*buf_chars_to_skip_inout == 0) && (total_len <= (buf_length - *buf_index_inout))) {
02742 
02743       buf_start += *buf_index_inout;
02744       memcpy(buf_start, field->m_ptr_name, total_len);
02745       *buf_index_inout += total_len;
02746 
02747     } else {
02748       TRY(mime_mem_print(field->m_ptr_name, total_len, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
02749     }
02750   } else {
02751     total_len = field->m_len_name + field->m_len_value + 2 + 2;
02752 
02753     // try to handle on fast path
02754 
02755     if ((buf_start != NULL) && (*buf_chars_to_skip_inout == 0) && (total_len <= (buf_length - *buf_index_inout))) {
02756       buf_start += *buf_index_inout;
02757 
02758       memcpy(buf_start, field->m_ptr_name, field->m_len_name);
02759       buf_start += field->m_len_name;
02760 
02761       buf_start[0] = ':';
02762       buf_start[1] = ' ';
02763       buf_start += 2;
02764 
02765       memcpy(buf_start, field->m_ptr_value, field->m_len_value);
02766       buf_start += field->m_len_value;
02767 
02768       buf_start[0] = '\r';
02769       buf_start[1] = '\n';
02770 
02771       *buf_index_inout += total_len;
02772     } else {
02773       TRY(mime_mem_print(field->m_ptr_name, field->m_len_name, buf_start, buf_length, buf_index_inout,
02774                          buf_chars_to_skip_inout));
02775       TRY(mime_mem_print(": ", 2, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
02776       TRY(mime_mem_print(field->m_ptr_value, field->m_len_value, buf_start, buf_length, buf_index_inout,
02777                          buf_chars_to_skip_inout));
02778       TRY(mime_mem_print("\r\n", 2, buf_start, buf_length, buf_index_inout, buf_chars_to_skip_inout));
02779     }
02780   }
02781 
02782   return 1;
02783 
02784 #undef TRY
02785 }
02786 
02787 const char *
02788 mime_str_u16_set(HdrHeap *heap, const char *s_str, int s_len, const char **d_str, uint16_t *d_len, bool must_copy)
02789 {
02790   ink_assert(s_len >= 0 && s_len < UINT16_MAX);
02791   // INKqa08287 - keep track of free string space.
02792   //  INVARIENT: passed in result pointers must be to
02793   //    either NULL or be valid ptr for a string already
02794   //    the string heaps
02795   heap->free_string(*d_str, *d_len);
02796 
02797   if (must_copy && s_str) {
02798     s_str = heap->duplicate_str(s_str, s_len);
02799   }
02800   *d_str = s_str;
02801   *d_len = s_len;
02802   return s_str;
02803 }
02804 
02805 int
02806 mime_field_length_get(MIMEField *field)
02807 {
02808   if (field->m_n_v_raw_printable) {
02809     return (field->m_len_name + field->m_len_value + field->m_n_v_raw_printable_pad);
02810   } else {
02811     return (field->m_len_name + field->m_len_value + 4);        // add ": \r\n"
02812   }
02813 }
02814 
02815 int
02816 mime_format_int(char *buf, int32_t val, size_t buf_len)
02817 {
02818   return ink_fast_itoa(val, buf, buf_len);
02819 }
02820 
02821 int
02822 mime_format_uint(char *buf, uint32_t val, size_t buf_len)
02823 {
02824   return ink_fast_uitoa(val, buf, buf_len);
02825 }
02826 
02827 int
02828 mime_format_int64(char *buf, int64_t val, size_t buf_len)
02829 {
02830   return ink_fast_ltoa(val, buf, buf_len);
02831 }
02832 
02833 void
02834 mime_days_since_epoch_to_mdy_slowcase(unsigned int days_since_jan_1_1970, int *m_return, int *d_return, int *y_return)
02835 {
02836   static const int DAYS_OFFSET = 25508;
02837 
02838   static const char months[] = {
02839     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
02840     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
02841     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
02842     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4,
02843     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
02844     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
02845     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
02846     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6,
02847     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
02848     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7,
02849     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
02850     7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8,
02851     8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
02852     8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9,
02853     9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
02854     9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
02855     10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
02856     10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
02857     11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
02858     11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02859     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02860     0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
02861     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
02862   };
02863 
02864   static const int days[12] = {
02865     305, 336, -1, 30, 60, 91, 121, 152, 183, 213, 244, 274
02866   };
02867 
02868   int mday, year, month, d, dp;
02869 
02870   mday = days_since_jan_1_1970;
02871 
02872   /* guess the year and refine the guess */
02873   year = mday / 365 + 69;
02874   d = dp = (year * 365) + (year / 4) - (year / 100) + (year / 100 + 3) / 4 - DAYS_OFFSET - 1;
02875 
02876   while (dp < mday) {
02877     d = dp;
02878     year += 1;
02879     dp = (year * 365) + (year / 4) - (year / 100) + (year / 100 + 3) / 4 - DAYS_OFFSET - 1;
02880   }
02881 
02882   /* convert the days */
02883   d = mday - d;
02884   if ((d<0) || (d> 366))
02885     ink_assert(!"bad date");
02886   else {
02887     month = months[d];
02888     if (month > 1)
02889       year -= 1;
02890 
02891     mday = d - days[month] - 1;
02892     year += 1900;
02893 
02894     *m_return = month;
02895     *d_return = mday;
02896     *y_return = year;
02897   }
02898 }
02899 
02900 void
02901 mime_days_since_epoch_to_mdy(unsigned int days_since_jan_1_1970, int *m_return, int *d_return, int *y_return)
02902 {
02903   ink_assert(_days_to_mdy_fast_lookup_table != NULL);
02904 
02905   /////////////////////////////////////////////////////////////
02906   // if we have a fast lookup entry for this date, return it //
02907   /////////////////////////////////////////////////////////////
02908 
02909   if ((days_since_jan_1_1970 >= _days_to_mdy_fast_lookup_table_first_day) &&
02910       (days_since_jan_1_1970 <= _days_to_mdy_fast_lookup_table_last_day)) {
02911     ////////////////////////////////////////////////////////////////
02912     // to speed up the days_since_epoch to m/d/y conversion, we   //
02913     // use a pre-computed lookup table to support the common case //
02914     // of dates that are +/- one year from today.                 //
02915     ////////////////////////////////////////////////////////////////
02916 
02917     int i = days_since_jan_1_1970 - _days_to_mdy_fast_lookup_table_first_day;
02918     *m_return = _days_to_mdy_fast_lookup_table[i].m;
02919     *d_return = _days_to_mdy_fast_lookup_table[i].d;
02920     *y_return = _days_to_mdy_fast_lookup_table[i].y;
02921     return;
02922   }
02923   ////////////////////////////////////
02924   // otherwise, return the slow way //
02925   ////////////////////////////////////
02926 
02927   mime_days_since_epoch_to_mdy_slowcase(days_since_jan_1_1970, m_return, d_return, y_return);
02928 }
02929 
02930 int
02931 mime_format_date(char *buffer, time_t value)
02932 {
02933   // must be 3 characters!
02934   static const char *daystrs[] = {
02935     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
02936   };
02937 
02938   // must be 3 characters!
02939   static const char *monthstrs[] = {
02940     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
02941     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
02942   };
02943 
02944   static const char *digitstrs[] = {
02945     "00", "01", "02", "03", "04", "05", "06", "07", "08", "09",
02946     "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
02947     "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
02948     "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
02949     "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
02950     "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
02951     "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
02952     "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
02953     "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
02954     "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
02955   };
02956 
02957   char *buf;
02958   int sec, min, hour, wday, mday=0, year=0, month=0;
02959 
02960   buf = buffer;
02961 
02962   sec = (int) (value % 60);
02963   value /= 60;
02964   min = (int) (value % 60);
02965   value /= 60;
02966   hour = (int) (value % 24);
02967   value /= 24;
02968 
02969   /* Jan 1, 1970 was a Thursday */
02970   wday = (int) ((4 + value) % 7);
02971 
02972   /* value is days since Jan 1, 1970 */
02973 #if MIME_FORMAT_DATE_USE_LOOKUP_TABLE
02974   mime_days_since_epoch_to_mdy(value, &month, &mday, &year);
02975 #else
02976   mime_days_since_epoch_to_mdy_slowcase(value, &month, &mday, &year);
02977 #endif
02978 
02979   /* arrange the date in the buffer */
02980   ink_assert((mday >= 0) && (mday <= 99));
02981   ink_assert((hour >= 0) && (hour <= 99));
02982   ink_assert((min >= 0) && (min <= 99));
02983   ink_assert((sec >= 0) && (sec <= 99));
02984 
02985   /* the day string */
02986   const char *three_char_day = daystrs[wday];
02987   buf[0] = three_char_day[0];
02988   buf[1] = three_char_day[1];
02989   buf[2] = three_char_day[2];
02990   buf += 3;
02991 
02992   buf[0] = ',';
02993   buf[1] = ' ';
02994   buf += 2;
02995 
02996   /* the day of month */
02997   buf[0] = digitstrs[mday][0];
02998   buf[1] = digitstrs[mday][1];
02999   buf[2] = ' ';
03000   buf += 3;
03001 
03002   /* the month string */
03003   const char *three_char_month = monthstrs[month];
03004   buf[0] = three_char_month[0];
03005   buf[1] = three_char_month[1];
03006   buf[2] = three_char_month[2];
03007   buf += 3;
03008 
03009   /* the year */
03010   buf[0] = ' ';
03011 
03012   if ((year >= 2000) && (year <= 2009)) {
03013     buf[1] = '2';
03014     buf[2] = '0';
03015     buf[3] = '0';
03016     buf[4] = (year - 2000) + '0';
03017   } else if ((year >= 1990) && (year <= 1999)) {
03018     buf[1] = '1';
03019     buf[2] = '9';
03020     buf[3] = '9';
03021     buf[4] = (year - 1990) + '0';
03022   } else {
03023     buf[4] = (year % 10) + '0';
03024     year /= 10;
03025     buf[3] = (year % 10) + '0';
03026     year /= 10;
03027     buf[2] = (year % 10) + '0';
03028     year /= 10;
03029     buf[1] = (year % 10) + '0';
03030   }
03031   buf[5] = ' ';
03032   buf += 6;
03033 
03034   /* the hour */
03035   buf[0] = digitstrs[hour][0];
03036   buf[1] = digitstrs[hour][1];
03037   buf[2] = ':';
03038   buf += 3;
03039 
03040   /* the minute */
03041   buf[0] = digitstrs[min][0];
03042   buf[1] = digitstrs[min][1];
03043   buf[2] = ':';
03044   buf += 3;
03045 
03046   /* the second */
03047   buf[0] = digitstrs[sec][0];
03048   buf[1] = digitstrs[sec][1];
03049   buf[2] = ' ';
03050   buf += 3;
03051 
03052   /* the timezone string */
03053   buf[0] = 'G';
03054   buf[1] = 'M';
03055   buf[2] = 'T';
03056   buf[3] = '\0';
03057   buf += 3;
03058 
03059   return buf - buffer;                    // not counting NUL
03060 }
03061 
03062 int32_t
03063 mime_parse_int(const char *buf, const char *end)
03064 {
03065   int32_t num;
03066   bool negative;
03067 
03068   if (!buf || (buf == end))
03069     return 0;
03070 
03071   if (is_digit(*buf))           // fast case
03072   {
03073     num = *buf++ - '0';
03074     while ((buf != end) && is_digit(*buf))
03075       num = (num * 10) + (*buf++ - '0');
03076     return num;
03077   } else {
03078     num = 0;
03079     negative = false;
03080 
03081     while ((buf != end) && ParseRules::is_space(*buf))
03082       buf += 1;
03083 
03084     if ((buf != end) && (*buf == '-')) {
03085       negative = true;
03086       buf += 1;
03087     }
03088     // NOTE: we first compute the value as negative then correct the
03089     // sign back to positive. This enables us to correctly parse MININT.
03090     while ((buf != end) && is_digit(*buf))
03091       num = (num * 10) - (*buf++ - '0');
03092 
03093     if (!negative)
03094       num = -num;
03095 
03096     return num;
03097   }
03098 }
03099 
03100 uint32_t
03101 mime_parse_uint(const char *buf, const char *end)
03102 {
03103   uint32_t num;
03104 
03105   if (!buf || (buf == end))
03106     return 0;
03107 
03108   if (is_digit(*buf))           // fast case
03109   {
03110     num = *buf++ - '0';
03111     while ((buf != end) && is_digit(*buf))
03112       num = (num * 10) + (*buf++ - '0');
03113     return num;
03114   } else {
03115     num = 0;
03116     while ((buf != end) && ParseRules::is_space(*buf))
03117       buf += 1;
03118     while ((buf != end) && is_digit(*buf))
03119       num = (num * 10) + (*buf++ - '0');
03120     return num;
03121   }
03122 }
03123 
03124 int64_t
03125 mime_parse_int64(const char *buf, const char *end)
03126 {
03127   int64_t num;
03128   bool negative;
03129 
03130   if (!buf || (buf == end))
03131     return 0;
03132 
03133   if (is_digit(*buf))           // fast case
03134     {
03135       num = *buf++ - '0';
03136       while ((buf != end) && is_digit(*buf))
03137         num = (num * 10) + (*buf++ - '0');
03138       return num;
03139     } else {
03140     num = 0;
03141     negative = false;
03142 
03143     while ((buf != end) && ParseRules::is_space(*buf))
03144       buf += 1;
03145 
03146     if ((buf != end) && (*buf == '-')) {
03147       negative = true;
03148       buf += 1;
03149     }
03150     // NOTE: we first compute the value as negative then correct the
03151     // sign back to positive. This enables us to correctly parse MININT.
03152     while ((buf != end) && is_digit(*buf))
03153       num = (num * 10) - (*buf++ - '0');
03154 
03155     if (!negative)
03156       num = -num;
03157 
03158     return num;
03159   }
03160 }
03161 
03162 
03163 /*-------------------------------------------------------------------------
03164 
03165   mime_parse_rfc822_date_fastcase (const char *buf, int length, struct tm *tp)
03166 
03167   This routine is a fast case parser for date strings that are guaranteed
03168   to be in the rfc822/rfc1123 format.  It uses integer binary searches to
03169   convert daya and month names into integral indices.
03170 
03171   This routine only supports rfc822/rfc1123 dates.  It must be called
03172   with NO leading whitespace, with a length >= 29 characters, and with
03173   a comma in buf[3].  The caller MUST ensure these conditions.
03174 
03175         Sun, 06 Nov 1994 08:49:37 GMT
03176         01234567890123456789012345678
03177 
03178   This function handles the common case dates fast.  The day and month
03179   are processed as 3 character integers before falling to DFA.  This
03180   table shows string, hash (24 bit values of 3 characters), and the
03181   resulting string index.
03182 
03183         Fri 0x467269 5    Apr 0x417072 3
03184         Mon 0x4D6F6E 1    Aug 0x417567 7
03185         Sat 0x536174 6    Dec 0x446563 11
03186         Sun 0x53756E 0    Feb 0x466562 1
03187         Thu 0x546875 4    Jan 0x4A616E 0
03188         Tue 0x547565 2    Jul 0x4A756C 6
03189         Wed 0x576564 3    Jun 0x4A756E 5
03190                           Mar 0x4D6172 2
03191                           May 0x4D6179 4
03192                           Nov 0x4E6F76 10
03193                           Oct 0x4F6374 9
03194                           Sep 0x536570 8
03195 
03196   -------------------------------------------------------------------------*/
03197 int
03198 mime_parse_rfc822_date_fastcase(const char *buf, int length, struct tm *tp)
03199 {
03200   unsigned int three_char_wday, three_char_mon;
03201 
03202   ink_assert(length >= 29);
03203   ink_assert(!is_ws(buf[0]));
03204   ink_assert(buf[3] == ',');
03205 
03206   ////////////////////////////
03207   // binary search for wday //
03208   ////////////////////////////
03209   tp->tm_wday = -1;
03210   three_char_wday = (buf[0] << 16) | (buf[1] << 8) | buf[2];
03211   if (three_char_wday <= 0x53756E) {
03212     if (three_char_wday == 0x467269)
03213       tp->tm_wday = 5;
03214     else if (three_char_wday == 0x4D6F6E)
03215       tp->tm_wday = 1;
03216     else if (three_char_wday == 0x536174)
03217       tp->tm_wday = 6;
03218     else if (three_char_wday == 0x53756E)
03219       tp->tm_wday = 0;
03220   } else {
03221     if (three_char_wday == 0x546875)
03222       tp->tm_wday = 4;
03223     else if (three_char_wday == 0x547565)
03224       tp->tm_wday = 2;
03225     else if (three_char_wday == 0x576564)
03226       tp->tm_wday = 3;
03227   }
03228   if (tp->tm_wday < 0) {
03229     tp->tm_wday = day_names_dfa->match(buf, length);
03230     if (tp->tm_wday < 0)
03231       return 0;
03232   }
03233   //////////////////////////
03234   // extract day of month //
03235   //////////////////////////
03236   tp->tm_mday = (buf[5] - '0') * 10 + (buf[6] - '0');
03237 
03238   /////////////////////////////
03239   // binary search for month //
03240   /////////////////////////////
03241   tp->tm_mon = -1;
03242   three_char_mon = (buf[8] << 16) | (buf[9] << 8) | buf[10];
03243   if (three_char_mon <= 0x4A756C) {
03244     if (three_char_mon <= 0x446563) {
03245       if (three_char_mon == 0x417072)
03246         tp->tm_mon = 3;
03247       else if (three_char_mon == 0x417567)
03248         tp->tm_mon = 7;
03249       else if (three_char_mon == 0x446563)
03250         tp->tm_mon = 11;
03251     } else {
03252       if (three_char_mon == 0x466562)
03253         tp->tm_mon = 1;
03254       else if (three_char_mon == 0x4A616E)
03255         tp->tm_mon = 0;
03256       else if (three_char_mon == 0x4A756C)
03257         tp->tm_mon = 6;
03258     }
03259   } else {
03260     if (three_char_mon <= 0x4D6179) {
03261       if (three_char_mon == 0x4A756E)
03262         tp->tm_mon = 5;
03263       else if (three_char_mon == 0x4D6172)
03264         tp->tm_mon = 2;
03265       else if (three_char_mon == 0x4D6179)
03266         tp->tm_mon = 4;
03267     } else {
03268       if (three_char_mon == 0x4E6F76)
03269         tp->tm_mon = 10;
03270       else if (three_char_mon == 0x4F6374)
03271         tp->tm_mon = 9;
03272       else if (three_char_mon == 0x536570)
03273         tp->tm_mon = 8;
03274     }
03275   }
03276   if (tp->tm_mon < 0) {
03277     tp->tm_mon = month_names_dfa->match(buf, length);
03278     if (tp->tm_mon < 0)
03279       return 0;
03280   }
03281   //////////////////
03282   // extract year //
03283   //////////////////
03284   tp->tm_year = ((buf[12] - '0') * 1000 + (buf[13] - '0') * 100 + (buf[14] - '0') * 10 + (buf[15] - '0')) - 1900;
03285 
03286   //////////////////
03287   // extract time //
03288   //////////////////
03289   tp->tm_hour = (buf[17] - '0') * 10 + (buf[18] - '0');
03290   tp->tm_min = (buf[20] - '0') * 10 + (buf[21] - '0');
03291   tp->tm_sec = (buf[23] - '0') * 10 + (buf[24] - '0');
03292   if ((buf[19] != ':') || (buf[22] != ':'))
03293     return 0;
03294   return 1;
03295 }
03296 
03297 /*-------------------------------------------------------------------------
03298    Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
03299    Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
03300    Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
03301    6 Nov 1994 08:49:37 GMT        ; NNTP-style date
03302   -------------------------------------------------------------------------*/
03303 time_t
03304 mime_parse_date(const char *buf, const char *end)
03305 {
03306   static const int DAYS_OFFSET = 25508;
03307   static const int days[12] = {
03308     305, 336, -1, 30, 60, 91, 121, 152, 183, 213, 244, 274
03309   };
03310 
03311   struct tm tp;
03312   time_t t;
03313   int year;
03314   int month;
03315   int mday;
03316 
03317   if (!buf)
03318     return (time_t)0;
03319 
03320   while ((buf != end) && is_ws(*buf))
03321     buf += 1;
03322 
03323   if ((buf != end) && is_digit(*buf)) { // NNTP date
03324     if (!mime_parse_mday(buf, end, &tp.tm_mday)) {
03325       return (time_t)0;
03326     }
03327     if (!mime_parse_month(buf, end, &tp.tm_mon)) {
03328       return (time_t)0;
03329     }
03330     if (!mime_parse_year(buf, end, &tp.tm_year)) {
03331       return (time_t)0;
03332     }
03333     if (!mime_parse_time(buf, end, &tp.tm_hour, &tp.tm_min, &tp.tm_sec)) {
03334       return (time_t)0;
03335     }
03336   } else if (end && (end - buf >= 29) && (buf[3] == ',')) {
03337     if (!mime_parse_rfc822_date_fastcase(buf, end - buf, &tp))
03338       return (time_t)0;
03339   } else {
03340     if (!mime_parse_day(buf, end, &tp.tm_wday)) {
03341       return (time_t)0;
03342     }
03343 
03344     while ((buf != end) && is_ws(*buf)) {
03345       buf += 1;
03346     }
03347 
03348     if ((buf != end) && ((*buf == ',') || is_digit(*buf))) {
03349       // RFC 822 or RFC 850 time format
03350       if (!mime_parse_mday(buf, end, &tp.tm_mday)) {
03351         return (time_t)0;
03352       }
03353       if (!mime_parse_month(buf, end, &tp.tm_mon)) {
03354         return (time_t)0;
03355       }
03356       if (!mime_parse_year(buf, end, &tp.tm_year)) {
03357         return (time_t)0;
03358       }
03359       if (!mime_parse_time(buf, end, &tp.tm_hour, &tp.tm_min, &tp.tm_sec)) {
03360         return (time_t)0;
03361       }
03362       // ignore timezone specifier...should always be GMT anways
03363     } else {
03364       // ANSI C's asctime format
03365       if (!mime_parse_month(buf, end, &tp.tm_mon)) {
03366         return (time_t)0;
03367       }
03368       if (!mime_parse_mday(buf, end, &tp.tm_mday)) {
03369         return (time_t)0;
03370       }
03371       if (!mime_parse_time(buf, end, &tp.tm_hour, &tp.tm_min, &tp.tm_sec)) {
03372         return (time_t)0;
03373       }
03374       if (!mime_parse_year(buf, end, &tp.tm_year)) {
03375         return (time_t)0;
03376       }
03377     }
03378   }
03379 
03380   year = tp.tm_year;
03381   month = tp.tm_mon;
03382   mday = tp.tm_mday;
03383 
03384   // what should we do?
03385   if (year > 137) {
03386     return (time_t)INT_MAX;
03387   }
03388   if (year < 70) {
03389     return (time_t)0;
03390   }
03391 
03392   mday += days[month];
03393   /* month base == march */
03394   if (month < 2) {
03395     year -= 1;
03396   }
03397   mday += (year * 365) + (year / 4) - (year / 100) + (year / 100 + 3) / 4;
03398   mday -= DAYS_OFFSET;
03399 
03400   t = ((mday * 24 + tp.tm_hour) * 60 + tp.tm_min) * 60 + tp.tm_sec;
03401 
03402   return t;
03403 }
03404 
03405 int
03406 mime_parse_day(const char *&buf, const char *end, int *day)
03407 {
03408   const char *e;
03409 
03410   while ((buf != end) && *buf && !ParseRules::is_alpha(*buf)) {
03411     buf += 1;
03412   }
03413 
03414   e = buf;
03415   while ((e != end) && *e && ParseRules::is_alpha(*e)) {
03416     e += 1;
03417   }
03418 
03419   *day = day_names_dfa->match(buf, e - buf);
03420   if (*day < 0) {
03421     return 0;
03422   } else {
03423     buf = e;
03424     return 1;
03425   }
03426 }
03427 
03428 int
03429 mime_parse_month(const char *&buf, const char *end, int *month)
03430 {
03431   const char *e;
03432 
03433   while ((buf != end) && *buf && !ParseRules::is_alpha(*buf)) {
03434     buf += 1;
03435   }
03436 
03437   e = buf;
03438   while ((e != end) && *e && ParseRules::is_alpha(*e)) {
03439     e += 1;
03440   }
03441 
03442   *month = month_names_dfa->match(buf, e - buf);
03443   if (*month < 0) {
03444     return 0;
03445   } else {
03446     buf = e;
03447     return 1;
03448   }
03449 }
03450 
03451 int
03452 mime_parse_mday(const char *&buf, const char *end, int *mday)
03453 {
03454   return mime_parse_integer(buf, end, mday);
03455 }
03456 
03457 int
03458 mime_parse_year(const char *&buf, const char *end, int *year)
03459 {
03460   int val;
03461 
03462   while ((buf != end) && *buf && !is_digit(*buf)) {
03463     buf += 1;
03464   }
03465 
03466   if ((buf == end) || (*buf == '\0')) {
03467     return 0;
03468   }
03469 
03470   val = 0;
03471 
03472   while ((buf != end) && *buf && is_digit(*buf)) {
03473     val = (val * 10) + (*buf++ - '0');
03474   }
03475 
03476   if (val >= 1900) {
03477     val -= 1900;
03478   } else if (val < 70) {
03479     val += 100;
03480   }
03481 
03482   *year = val;
03483 
03484   return 1;
03485 }
03486 
03487 int
03488 mime_parse_time(const char *&buf, const char *end, int *hour, int *min, int *sec)
03489 {
03490   if (!mime_parse_integer(buf, end, hour)) {
03491     return 0;
03492   }
03493   if (!mime_parse_integer(buf, end, min)) {
03494     return 0;
03495   }
03496   if (!mime_parse_integer(buf, end, sec)) {
03497     return 0;
03498   }
03499   return 1;
03500 }
03501 
03502 // TODO: Do we really need mime_parse_int() and mime_parse_integer() ? I know
03503 // they have slightly different prototypes, but still...
03504 int
03505 mime_parse_integer(const char *&buf, const char *end, int *integer)
03506 {
03507   int val;
03508   bool negative;
03509 
03510   negative = false;
03511 
03512   while ((buf != end) && *buf && !is_digit(*buf) && (*buf != '-')) {
03513     buf += 1;
03514   }
03515 
03516   if ((buf == end) || (*buf == '\0')) {
03517     return 0;
03518   }
03519 
03520   if (*buf == '-') {
03521     negative = true;
03522     buf += 1;
03523   }
03524 
03525   val = 0;
03526   while ((buf != end) && is_digit(*buf)) {
03527     val = (val * 10) + (*buf++ - '0');
03528   }
03529 
03530   if (negative) {
03531     *integer = -val;
03532   } else {
03533     *integer = val;
03534   }
03535 
03536   return 1;
03537 }
03538 
03539 
03540 /***********************************************************************
03541  *                                                                     *
03542  *                        M A R S H A L I N G                          *
03543  *                                                                     *
03544  ***********************************************************************/
03545 int
03546 MIMEFieldBlockImpl::marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str)
03547 {
03548 // printf("FieldBlockImpl:marshal  num_ptr = %d  num_str = %d\n", num_ptr, num_str);
03549   HDR_MARSHAL_PTR(m_next, MIMEFieldBlockImpl, ptr_xlate, num_ptr);
03550 
03551   if ((num_str == 1) && (num_ptr == 1)) {
03552     for (uint32_t index = 0; index < m_freetop; index++) {
03553       MIMEField *field = &(m_field_slots[index]);
03554 
03555       if (field->is_live()) {
03556         HDR_MARSHAL_STR_1(field->m_ptr_name, str_xlate);
03557         HDR_MARSHAL_STR_1(field->m_ptr_value, str_xlate);
03558         if (field->m_next_dup) {
03559           HDR_MARSHAL_PTR_1(field->m_next_dup, MIMEField, ptr_xlate);
03560         }
03561       }
03562     }
03563   } else {
03564     for (uint32_t index = 0; index < m_freetop; index++) {
03565       MIMEField *field = &(m_field_slots[index]);
03566 
03567       if (field->is_live()) {
03568         HDR_MARSHAL_STR(field->m_ptr_name, str_xlate, num_str);
03569         HDR_MARSHAL_STR(field->m_ptr_value, str_xlate, num_str);
03570         if (field->m_next_dup) {
03571           HDR_MARSHAL_PTR(field->m_next_dup, MIMEField, ptr_xlate, num_ptr);
03572         }
03573       }
03574     }
03575   }
03576   return 0;
03577 }
03578 
03579 void
03580 MIMEFieldBlockImpl::unmarshal(intptr_t offset)
03581 {
03582   HDR_UNMARSHAL_PTR(m_next, MIMEFieldBlockImpl, offset);
03583 
03584 
03585   for (uint32_t index = 0; index < m_freetop; index++) {
03586     MIMEField *field = &(m_field_slots[index]);
03587 
03588     // FIX ME - DO I NEED TO DEAL WITH OTHER READINESSES?
03589     if (field->is_live()) {
03590       HDR_UNMARSHAL_STR(field->m_ptr_name, offset);
03591       HDR_UNMARSHAL_STR(field->m_ptr_value, offset);
03592       if (field->m_next_dup) {
03593         HDR_UNMARSHAL_PTR(field->m_next_dup, MIMEField, offset);
03594       }
03595     }
03596 
03597   }
03598 }
03599 
03600 void
03601 MIMEFieldBlockImpl::move_strings(HdrStrHeap *new_heap)
03602 {
03603   for (uint32_t index = 0; index < m_freetop; index++) {
03604     MIMEField *field = &(m_field_slots[index]);
03605 
03606     if (field->is_live() || field->is_detached()) {
03607       // FIX ME - Should do the field in one shot and preserve
03608       //   raw_printable if it's set
03609       field->m_n_v_raw_printable = 0;
03610 
03611       HDR_MOVE_STR(field->m_ptr_name, field->m_len_name);
03612       HDR_MOVE_STR(field->m_ptr_value, field->m_len_value);
03613     }
03614   }
03615 }
03616 
03617 size_t
03618 MIMEFieldBlockImpl::strings_length()
03619 {
03620   size_t ret = 0;
03621 
03622   for (uint32_t index = 0; index < m_freetop; index++) {
03623     MIMEField *field = &(m_field_slots[index]);
03624 
03625     if (field->m_readiness == MIME_FIELD_SLOT_READINESS_LIVE ||
03626         field->m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED) {
03627       ret += field->m_len_name;
03628       ret += field->m_len_value;
03629     }
03630   }
03631   return ret;
03632 }
03633 
03634 void
03635 MIMEFieldBlockImpl::check_strings(HeapCheck *heaps, int num_heaps)
03636 {
03637   for (uint32_t index = 0; index < m_freetop; index++) {
03638     MIMEField *field = &(m_field_slots[index]);
03639 
03640     if (field->is_live() || field->is_detached()) {
03641       // FIX ME - Should check raw printing characters as well
03642       CHECK_STR(field->m_ptr_name, field->m_len_name, heaps, num_heaps);
03643       CHECK_STR(field->m_ptr_value, field->m_len_value, heaps, num_heaps);
03644     }
03645   }
03646 }
03647 
03648 int
03649 MIMEHdrImpl::marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str)
03650 {
03651   // printf("MIMEHdrImpl:marshal  num_ptr = %d  num_str = %d\n", num_ptr, num_str);
03652   HDR_MARSHAL_PTR(m_fblock_list_tail, MIMEFieldBlockImpl, ptr_xlate, num_ptr);
03653   return m_first_fblock.marshal(ptr_xlate, num_ptr, str_xlate, num_str);
03654 }
03655 
03656 void
03657 MIMEHdrImpl::unmarshal(intptr_t offset)
03658 {
03659   HDR_UNMARSHAL_PTR(m_fblock_list_tail, MIMEFieldBlockImpl, offset);
03660   m_first_fblock.unmarshal(offset);
03661 }
03662 
03663 void
03664 MIMEHdrImpl::move_strings(HdrStrHeap *new_heap)
03665 {
03666   m_first_fblock.move_strings(new_heap);
03667 }
03668 
03669 size_t
03670 MIMEHdrImpl::strings_length()
03671 {
03672   return m_first_fblock.strings_length();
03673 }
03674 
03675 void
03676 MIMEHdrImpl::check_strings(HeapCheck *heaps, int num_heaps)
03677 {
03678   m_first_fblock.check_strings(heaps, num_heaps);
03679 }
03680 
03681 void
03682 MIMEHdrImpl::recompute_accelerators_and_presence_bits() {
03683   mime_hdr_reset_accelerators_and_presence_bits(this);
03684 }
03685 
03686 
03687 /***********************************************************************
03688  *                                                                     *
03689  *                 C O O K E D    V A L U E    C A C H E               *
03690  *                                                                     *
03691  ***********************************************************************/
03692 
03693 ////////////////////////////////////////////////////////
03694 // we need to recook the cooked values cache when:    //
03695 //                                                    //
03696 //      setting the value and the field is live       //
03697 //      attaching the field and the field isn't empty //
03698 //      detaching the field                           //
03699 ////////////////////////////////////////////////////////
03700 
03701 
03702 void
03703 MIMEHdrImpl::recompute_cooked_stuff(MIMEField *changing_field_or_null)
03704 {
03705   int len, tlen;
03706   const char *s;
03707   const char *c;
03708   const char *e;
03709   const char *token_wks;
03710   MIMEField *field;
03711   uint32_t mask = 0;
03712 
03713   mime_hdr_cooked_stuff_init(this, changing_field_or_null);
03714 
03715   //////////////////////////////////////////////////
03716   // (1) cook the Cache-Control header if present //
03717   //////////////////////////////////////////////////
03718 
03719   // to be safe, recompute unless you know this call is for other cooked field
03720   if ((changing_field_or_null == NULL) || (changing_field_or_null->m_wks_idx != MIME_WKSIDX_PRAGMA)) {
03721 
03722     field = mime_hdr_field_find(this, MIME_FIELD_CACHE_CONTROL, MIME_LEN_CACHE_CONTROL);
03723 
03724     if (field) {
03725       // try pathpaths first -- unlike most other fastpaths, this one
03726       // is probably more useful for polygraph than for the real world
03727       if (!field->has_dups()) {
03728         s = field->value_get(&len);
03729         if (ptr_len_casecmp(s, len, "public", 6) == 0) {
03730           mask = MIME_COOKED_MASK_CC_PUBLIC;
03731           m_cooked_stuff.m_cache_control.m_mask |= mask;
03732         } else if (ptr_len_casecmp(s, len, "private,no-cache", 16) == 0) {
03733           mask = MIME_COOKED_MASK_CC_PRIVATE | MIME_COOKED_MASK_CC_NO_CACHE;
03734           m_cooked_stuff.m_cache_control.m_mask |= mask;
03735         }
03736       }
03737 
03738       if (mask == 0) {
03739         HdrCsvIter csv_iter;
03740 
03741         for (s = csv_iter.get_first(field, &len); s != NULL; s = csv_iter.get_next(&len)) {
03742           e = s + len;
03743           for (c = s; (c < e) && (ParseRules::is_token(*c)); c++);
03744           tlen = c - s;
03745 
03746           // If >= 0 then this is a well known token
03747           if (hdrtoken_tokenize(s, tlen, &token_wks) >= 0) {
03748 #if TRACK_COOKING
03749             Debug("http", "recompute_cooked_stuff: got field '%s'\n", token_wks);
03750 #endif
03751 
03752             HdrTokenHeapPrefix *p = hdrtoken_wks_to_prefix(token_wks);
03753             mask = p->wks_type_specific.u.cache_control.cc_mask;
03754             m_cooked_stuff.m_cache_control.m_mask |= mask;
03755 
03756 #if TRACK_COOKING
03757             Debug("http", "                        set mask 0x%0X\n", mask);
03758 #endif
03759 
03760             if (mask & (MIME_COOKED_MASK_CC_MAX_AGE |
03761                         MIME_COOKED_MASK_CC_S_MAXAGE | MIME_COOKED_MASK_CC_MAX_STALE | MIME_COOKED_MASK_CC_MIN_FRESH)) {
03762               int value;
03763 
03764               if (mime_parse_integer(c, e, &value)) {
03765 #if TRACK_COOKING
03766                 Debug("http", "                        set integer value %d\n", value);
03767 #endif
03768                 if (token_wks == MIME_VALUE_MAX_AGE)
03769                   m_cooked_stuff.m_cache_control.m_secs_max_age = value;
03770                 else if (token_wks == MIME_VALUE_MIN_FRESH)
03771                   m_cooked_stuff.m_cache_control.m_secs_min_fresh = value;
03772                 else if (token_wks == MIME_VALUE_MAX_STALE)
03773                   m_cooked_stuff.m_cache_control.m_secs_max_stale = value;
03774                 else if (token_wks == MIME_VALUE_S_MAXAGE)
03775                   m_cooked_stuff.m_cache_control.m_secs_s_maxage = value;
03776               } else {
03777 #if TRACK_COOKING
03778                 Debug("http", "                        set integer value %d\n", INT_MAX);
03779 #endif
03780                 if (token_wks == MIME_VALUE_MAX_STALE)
03781                   m_cooked_stuff.m_cache_control.m_secs_max_stale = INT_MAX;
03782               }
03783             }
03784           }
03785         }
03786       }
03787     }
03788   }
03789   ///////////////////////////////////////////
03790   // (2) cook the Pragma header if present //
03791   ///////////////////////////////////////////
03792 
03793   if ((changing_field_or_null == NULL) || (changing_field_or_null->m_wks_idx != MIME_WKSIDX_CACHE_CONTROL)) {
03794 
03795     field = mime_hdr_field_find(this, MIME_FIELD_PRAGMA, MIME_LEN_PRAGMA);
03796     if (field) {
03797       if (!field->has_dups()) { // try fastpath first
03798         s = field->value_get(&len);
03799         if (ptr_len_casecmp(s, len, "no-cache", 8) == 0) {
03800           m_cooked_stuff.m_pragma.m_no_cache = 1;
03801           return;
03802         }
03803       }
03804 
03805       {
03806         HdrCsvIter csv_iter;
03807 
03808         for (s = csv_iter.get_first(field, &len); s != NULL; s = csv_iter.get_next(&len)) {
03809           e = s + len;
03810           for (c = s; (c < e) && (ParseRules::is_token(*c)); c++);
03811           tlen = c - s;
03812 
03813           if (hdrtoken_tokenize(s, tlen, &token_wks) >= 0) {
03814             if (token_wks == MIME_VALUE_NO_CACHE)
03815               m_cooked_stuff.m_pragma.m_no_cache = 1;
03816           }
03817         }
03818       }
03819     }
03820   }
03821 }

Generated by  doxygen 1.7.1