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

HTTP.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 "HTTP.h"
00030 #include "HdrToken.h"
00031 #include "Diags.h"
00032 
00033 
00034 /***********************************************************************
00035  *                                                                     *
00036  *                    C O M P I L E    O P T I O N S                   *
00037  *                                                                     *
00038  ***********************************************************************/
00039 
00040 #define ENABLE_PARSER_FAST_PATHS        1
00041 
00042 /***********************************************************************
00043  *                                                                     *
00044  *                          C O N S T A N T S                          *
00045  *                                                                     *
00046  ***********************************************************************/
00047 
00048 // TODO: We should enable the creation and use of these WKS. XXXX
00049 #if 0
00050 static const char *cache_control_values[SIZEOF(cache_control_names)];
00051 #endif
00052 
00053 const char *HTTP_METHOD_CONNECT;
00054 const char *HTTP_METHOD_DELETE;
00055 const char *HTTP_METHOD_GET;
00056 const char *HTTP_METHOD_HEAD;
00057 const char *HTTP_METHOD_ICP_QUERY;
00058 const char *HTTP_METHOD_OPTIONS;
00059 const char *HTTP_METHOD_POST;
00060 const char *HTTP_METHOD_PURGE;
00061 const char *HTTP_METHOD_PUT;
00062 const char *HTTP_METHOD_TRACE;
00063 const char *HTTP_METHOD_PUSH;
00064 
00065 int HTTP_WKSIDX_CONNECT;
00066 int HTTP_WKSIDX_DELETE;
00067 int HTTP_WKSIDX_GET;
00068 int HTTP_WKSIDX_HEAD;
00069 int HTTP_WKSIDX_ICP_QUERY;
00070 int HTTP_WKSIDX_OPTIONS;
00071 int HTTP_WKSIDX_POST;
00072 int HTTP_WKSIDX_PURGE;
00073 int HTTP_WKSIDX_PUT;
00074 int HTTP_WKSIDX_TRACE;
00075 int HTTP_WKSIDX_PUSH;
00076 int HTTP_WKSIDX_METHODS_CNT = 0;
00077 
00078 int HTTP_LEN_CONNECT;
00079 int HTTP_LEN_DELETE;
00080 int HTTP_LEN_GET;
00081 int HTTP_LEN_HEAD;
00082 int HTTP_LEN_ICP_QUERY;
00083 int HTTP_LEN_OPTIONS;
00084 int HTTP_LEN_POST;
00085 int HTTP_LEN_PURGE;
00086 int HTTP_LEN_PUT;
00087 int HTTP_LEN_TRACE;
00088 int HTTP_LEN_PUSH;
00089 
00090 const char *HTTP_VALUE_BYTES;
00091 const char *HTTP_VALUE_CHUNKED;
00092 const char *HTTP_VALUE_CLOSE;
00093 const char *HTTP_VALUE_COMPRESS;
00094 const char *HTTP_VALUE_DEFLATE;
00095 const char *HTTP_VALUE_GZIP;
00096 const char *HTTP_VALUE_IDENTITY;
00097 const char *HTTP_VALUE_KEEP_ALIVE;
00098 const char *HTTP_VALUE_MAX_AGE;
00099 const char *HTTP_VALUE_MAX_STALE;
00100 const char *HTTP_VALUE_MIN_FRESH;
00101 const char *HTTP_VALUE_MUST_REVALIDATE;
00102 const char *HTTP_VALUE_NONE;
00103 const char *HTTP_VALUE_NO_CACHE;
00104 const char *HTTP_VALUE_NO_STORE;
00105 const char *HTTP_VALUE_NO_TRANSFORM;
00106 const char *HTTP_VALUE_ONLY_IF_CACHED;
00107 const char *HTTP_VALUE_PRIVATE;
00108 const char *HTTP_VALUE_PROXY_REVALIDATE;
00109 const char *HTTP_VALUE_PUBLIC;
00110 const char *HTTP_VALUE_S_MAXAGE;
00111 const char *HTTP_VALUE_NEED_REVALIDATE_ONCE;
00112 const char *HTTP_VALUE_100_CONTINUE;
00113 // Cache-control: extension "need-revalidate-once" is used internally by T.S.
00114 // to invalidate a document, and it is not returned/forwarded.
00115 // If a cached document has this extension set (ie, is invalidated),
00116 // then the T.S. needs to revalidate the document once before returning it.
00117 // After a successful revalidation, the extension will be removed by T.S.
00118 // To set or unset this directive should be done via the following two
00119 // function:
00120 //      set_cooked_cc_need_revalidate_once()
00121 //      unset_cooked_cc_need_revalidate_once()
00122 // To test, use regular Cache-control testing functions, eg,
00123 //      is_cache_control_set(HTTP_VALUE_NEED_REVALIDATE_ONCE)
00124 
00125 int HTTP_LEN_BYTES;
00126 int HTTP_LEN_CHUNKED;
00127 int HTTP_LEN_CLOSE;
00128 int HTTP_LEN_COMPRESS;
00129 int HTTP_LEN_DEFLATE;
00130 int HTTP_LEN_GZIP;
00131 int HTTP_LEN_IDENTITY;
00132 int HTTP_LEN_KEEP_ALIVE;
00133 int HTTP_LEN_MAX_AGE;
00134 int HTTP_LEN_MAX_STALE;
00135 int HTTP_LEN_MIN_FRESH;
00136 int HTTP_LEN_MUST_REVALIDATE;
00137 int HTTP_LEN_NONE;
00138 int HTTP_LEN_NO_CACHE;
00139 int HTTP_LEN_NO_STORE;
00140 int HTTP_LEN_NO_TRANSFORM;
00141 int HTTP_LEN_ONLY_IF_CACHED;
00142 int HTTP_LEN_PRIVATE;
00143 int HTTP_LEN_PROXY_REVALIDATE;
00144 int HTTP_LEN_PUBLIC;
00145 int HTTP_LEN_S_MAXAGE;
00146 int HTTP_LEN_NEED_REVALIDATE_ONCE;
00147 int HTTP_LEN_100_CONTINUE;
00148 
00149 Arena* const HTTPHdr::USE_HDR_HEAP_MAGIC = reinterpret_cast<Arena*>(1);
00150 
00151 /***********************************************************************
00152  *                                                                     *
00153  *                 U T I L I T Y    R O U T I N E S                    *
00154  *                                                                     *
00155  ***********************************************************************/
00156 
00157 inline static int
00158 is_digit(char c)
00159 {
00160   return ((c <= '9') && (c >= '0'));
00161 }
00162 
00163 /***********************************************************************
00164  *                                                                     *
00165  *                         M A I N    C O D E                          *
00166  *                                                                     *
00167  ***********************************************************************/
00168 
00169 void
00170 http_hdr_adjust(HTTPHdrImpl */* hdrp ATS_UNUSED */, int32_t /* offset ATS_UNUSED */, int32_t /* length ATS_UNUSED */,
00171                 int32_t /* delta ATS_UNUSED */)
00172 {
00173   ink_release_assert(!"http_hdr_adjust not implemented");
00174 }
00175 
00176 /*-------------------------------------------------------------------------
00177   -------------------------------------------------------------------------*/
00178 
00179 void
00180 http_init()
00181 {
00182   static int init = 1;
00183 
00184   if (init) {
00185     init = 0;
00186 
00187     mime_init();
00188     url_init();
00189 
00190     HTTP_METHOD_CONNECT = hdrtoken_string_to_wks("CONNECT");
00191     HTTP_METHOD_DELETE = hdrtoken_string_to_wks("DELETE");
00192     HTTP_METHOD_GET = hdrtoken_string_to_wks("GET");
00193     HTTP_METHOD_HEAD = hdrtoken_string_to_wks("HEAD");
00194     HTTP_METHOD_ICP_QUERY = hdrtoken_string_to_wks("ICP_QUERY");
00195     HTTP_METHOD_OPTIONS = hdrtoken_string_to_wks("OPTIONS");
00196     HTTP_METHOD_POST = hdrtoken_string_to_wks("POST");
00197     HTTP_METHOD_PURGE = hdrtoken_string_to_wks("PURGE");
00198     HTTP_METHOD_PUT = hdrtoken_string_to_wks("PUT");
00199     HTTP_METHOD_TRACE = hdrtoken_string_to_wks("TRACE");
00200     HTTP_METHOD_PUSH = hdrtoken_string_to_wks("PUSH");
00201 
00202     // HTTP methods index calculation. Don't forget to count them!
00203     // Don't change the order of calculation! Each index has related bitmask (see http quick filter)
00204     HTTP_WKSIDX_CONNECT = hdrtoken_wks_to_index(HTTP_METHOD_CONNECT);
00205     HTTP_WKSIDX_METHODS_CNT++;
00206     HTTP_WKSIDX_DELETE = hdrtoken_wks_to_index(HTTP_METHOD_DELETE);
00207     HTTP_WKSIDX_METHODS_CNT++;
00208     HTTP_WKSIDX_GET = hdrtoken_wks_to_index(HTTP_METHOD_GET);
00209     HTTP_WKSIDX_METHODS_CNT++;
00210     HTTP_WKSIDX_HEAD = hdrtoken_wks_to_index(HTTP_METHOD_HEAD);
00211     HTTP_WKSIDX_METHODS_CNT++;
00212     HTTP_WKSIDX_ICP_QUERY = hdrtoken_wks_to_index(HTTP_METHOD_ICP_QUERY);
00213     HTTP_WKSIDX_METHODS_CNT++;
00214     HTTP_WKSIDX_OPTIONS = hdrtoken_wks_to_index(HTTP_METHOD_OPTIONS);
00215     HTTP_WKSIDX_METHODS_CNT++;
00216     HTTP_WKSIDX_POST = hdrtoken_wks_to_index(HTTP_METHOD_POST);
00217     HTTP_WKSIDX_METHODS_CNT++;
00218     HTTP_WKSIDX_PURGE = hdrtoken_wks_to_index(HTTP_METHOD_PURGE);
00219     HTTP_WKSIDX_METHODS_CNT++;
00220     HTTP_WKSIDX_PUT = hdrtoken_wks_to_index(HTTP_METHOD_PUT);
00221     HTTP_WKSIDX_METHODS_CNT++;
00222     HTTP_WKSIDX_TRACE = hdrtoken_wks_to_index(HTTP_METHOD_TRACE);
00223     HTTP_WKSIDX_METHODS_CNT++;
00224     HTTP_WKSIDX_PUSH = hdrtoken_wks_to_index(HTTP_METHOD_PUSH);
00225     HTTP_WKSIDX_METHODS_CNT++;
00226 
00227 
00228     HTTP_LEN_CONNECT = hdrtoken_wks_to_length(HTTP_METHOD_CONNECT);
00229     HTTP_LEN_DELETE = hdrtoken_wks_to_length(HTTP_METHOD_DELETE);
00230     HTTP_LEN_GET = hdrtoken_wks_to_length(HTTP_METHOD_GET);
00231     HTTP_LEN_HEAD = hdrtoken_wks_to_length(HTTP_METHOD_HEAD);
00232     HTTP_LEN_ICP_QUERY = hdrtoken_wks_to_length(HTTP_METHOD_ICP_QUERY);
00233     HTTP_LEN_OPTIONS = hdrtoken_wks_to_length(HTTP_METHOD_OPTIONS);
00234     HTTP_LEN_POST = hdrtoken_wks_to_length(HTTP_METHOD_POST);
00235     HTTP_LEN_PURGE = hdrtoken_wks_to_length(HTTP_METHOD_PURGE);
00236     HTTP_LEN_PUT = hdrtoken_wks_to_length(HTTP_METHOD_PUT);
00237     HTTP_LEN_TRACE = hdrtoken_wks_to_length(HTTP_METHOD_TRACE);
00238     HTTP_LEN_PUSH = hdrtoken_wks_to_length(HTTP_METHOD_PUSH);
00239 
00240     HTTP_VALUE_BYTES = hdrtoken_string_to_wks("bytes");
00241     HTTP_VALUE_CHUNKED = hdrtoken_string_to_wks("chunked");
00242     HTTP_VALUE_CLOSE = hdrtoken_string_to_wks("close");
00243     HTTP_VALUE_COMPRESS = hdrtoken_string_to_wks("compress");
00244     HTTP_VALUE_DEFLATE = hdrtoken_string_to_wks("deflate");
00245     HTTP_VALUE_GZIP = hdrtoken_string_to_wks("gzip");
00246     HTTP_VALUE_IDENTITY = hdrtoken_string_to_wks("identity");
00247     HTTP_VALUE_KEEP_ALIVE = hdrtoken_string_to_wks("keep-alive");
00248     HTTP_VALUE_MAX_AGE = hdrtoken_string_to_wks("max-age");
00249     HTTP_VALUE_MAX_STALE = hdrtoken_string_to_wks("max-stale");
00250     HTTP_VALUE_MIN_FRESH = hdrtoken_string_to_wks("min-fresh");
00251     HTTP_VALUE_MUST_REVALIDATE = hdrtoken_string_to_wks("must-revalidate");
00252     HTTP_VALUE_NONE = hdrtoken_string_to_wks("none");
00253     HTTP_VALUE_NO_CACHE = hdrtoken_string_to_wks("no-cache");
00254     HTTP_VALUE_NO_STORE = hdrtoken_string_to_wks("no-store");
00255     HTTP_VALUE_NO_TRANSFORM = hdrtoken_string_to_wks("no-transform");
00256     HTTP_VALUE_ONLY_IF_CACHED = hdrtoken_string_to_wks("only-if-cached");
00257     HTTP_VALUE_PRIVATE = hdrtoken_string_to_wks("private");
00258     HTTP_VALUE_PROXY_REVALIDATE = hdrtoken_string_to_wks("proxy-revalidate");
00259     HTTP_VALUE_PUBLIC = hdrtoken_string_to_wks("public");
00260     HTTP_VALUE_S_MAXAGE = hdrtoken_string_to_wks("s-maxage");
00261     HTTP_VALUE_NEED_REVALIDATE_ONCE = hdrtoken_string_to_wks("need-revalidate-once");
00262     HTTP_VALUE_100_CONTINUE = hdrtoken_string_to_wks("100-continue");
00263 
00264     HTTP_LEN_BYTES = hdrtoken_wks_to_length(HTTP_VALUE_BYTES);
00265     HTTP_LEN_CHUNKED = hdrtoken_wks_to_length(HTTP_VALUE_CHUNKED);
00266     HTTP_LEN_CLOSE = hdrtoken_wks_to_length(HTTP_VALUE_CLOSE);
00267     HTTP_LEN_COMPRESS = hdrtoken_wks_to_length(HTTP_VALUE_COMPRESS);
00268     HTTP_LEN_DEFLATE = hdrtoken_wks_to_length(HTTP_VALUE_DEFLATE);
00269     HTTP_LEN_GZIP = hdrtoken_wks_to_length(HTTP_VALUE_GZIP);
00270     HTTP_LEN_IDENTITY = hdrtoken_wks_to_length(HTTP_VALUE_IDENTITY);
00271     HTTP_LEN_KEEP_ALIVE = hdrtoken_wks_to_length(HTTP_VALUE_KEEP_ALIVE);
00272     HTTP_LEN_MAX_AGE = hdrtoken_wks_to_length(HTTP_VALUE_MAX_AGE);
00273     HTTP_LEN_MAX_STALE = hdrtoken_wks_to_length(HTTP_VALUE_MAX_STALE);
00274     HTTP_LEN_MIN_FRESH = hdrtoken_wks_to_length(HTTP_VALUE_MIN_FRESH);
00275     HTTP_LEN_MUST_REVALIDATE = hdrtoken_wks_to_length(HTTP_VALUE_MUST_REVALIDATE);
00276     HTTP_LEN_NONE = hdrtoken_wks_to_length(HTTP_VALUE_NONE);
00277     HTTP_LEN_NO_CACHE = hdrtoken_wks_to_length(HTTP_VALUE_NO_CACHE);
00278     HTTP_LEN_NO_STORE = hdrtoken_wks_to_length(HTTP_VALUE_NO_STORE);
00279     HTTP_LEN_NO_TRANSFORM = hdrtoken_wks_to_length(HTTP_VALUE_NO_TRANSFORM);
00280     HTTP_LEN_ONLY_IF_CACHED = hdrtoken_wks_to_length(HTTP_VALUE_ONLY_IF_CACHED);
00281     HTTP_LEN_PRIVATE = hdrtoken_wks_to_length(HTTP_VALUE_PRIVATE);
00282     HTTP_LEN_PROXY_REVALIDATE = hdrtoken_wks_to_length(HTTP_VALUE_PROXY_REVALIDATE);
00283     HTTP_LEN_PUBLIC = hdrtoken_wks_to_length(HTTP_VALUE_PUBLIC);
00284     HTTP_LEN_S_MAXAGE = hdrtoken_wks_to_length(HTTP_VALUE_S_MAXAGE);
00285     HTTP_LEN_NEED_REVALIDATE_ONCE = hdrtoken_wks_to_length(HTTP_VALUE_NEED_REVALIDATE_ONCE);
00286     HTTP_LEN_100_CONTINUE = hdrtoken_wks_to_length(HTTP_VALUE_100_CONTINUE);
00287 
00288     // TODO: We need to look into enable these CC values as WKS XXX
00289 #if 0
00290     for (int i = 0; i < (int) SIZEOF(cache_control_values); i++) {
00291       cache_control_values[i] = hdrtoken_string_to_wks(cache_control_names[i]);
00292     }
00293 #endif
00294   }
00295 }
00296 
00297 /*-------------------------------------------------------------------------
00298   -------------------------------------------------------------------------*/
00299 
00300 HTTPHdrImpl *
00301 http_hdr_create(HdrHeap *heap, HTTPType polarity)
00302 {
00303   HTTPHdrImpl *hh;
00304 
00305   hh = (HTTPHdrImpl *) heap->allocate_obj(sizeof(HTTPHdrImpl), HDR_HEAP_OBJ_HTTP_HEADER);
00306   http_hdr_init(heap, hh, polarity);
00307   return (hh);
00308 }
00309 
00310 /*-------------------------------------------------------------------------
00311   -------------------------------------------------------------------------*/
00312 
00313 void
00314 http_hdr_init(HdrHeap *heap, HTTPHdrImpl *hh, HTTPType polarity)
00315 {
00316   memset(&(hh->u), 0, sizeof(hh->u));
00317   hh->m_polarity = polarity;
00318   hh->m_version = HTTP_VERSION(0, 9);
00319   hh->m_fields_impl = mime_hdr_create(heap);
00320   if (polarity == HTTP_TYPE_REQUEST) {
00321     hh->u.req.m_url_impl = url_create(heap);
00322     hh->u.req.m_method_wks_idx = -1;
00323   }
00324 }
00325 
00326 /*-------------------------------------------------------------------------
00327   -------------------------------------------------------------------------*/
00328 
00329 void
00330 http_hdr_copy_onto(HTTPHdrImpl *s_hh, HdrHeap *s_heap, HTTPHdrImpl *d_hh, HdrHeap *d_heap, bool inherit_strs)
00331 {
00332   MIMEHdrImpl *s_mh, *d_mh;
00333   URLImpl *s_url, *d_url;
00334   HTTPType d_polarity;
00335 
00336   s_mh = s_hh->m_fields_impl;
00337   s_url = s_hh->u.req.m_url_impl;
00338   d_mh = d_hh->m_fields_impl;
00339   d_url = d_hh->u.req.m_url_impl;
00340   d_polarity = d_hh->m_polarity;
00341 
00342   ink_assert(s_hh->m_polarity != HTTP_TYPE_UNKNOWN);
00343   ink_assert(s_mh != NULL);
00344   ink_assert(d_mh != NULL);
00345 
00346   memcpy(d_hh, s_hh, sizeof(HTTPHdrImpl));
00347   d_hh->m_fields_impl = d_mh;   // restore pre-memcpy mime impl
00348 
00349   if (s_hh->m_polarity == HTTP_TYPE_REQUEST) {
00350     if (d_polarity == HTTP_TYPE_REQUEST) {
00351       d_hh->u.req.m_url_impl = d_url;   // restore pre-memcpy url impl
00352     } else {
00353       d_url = d_hh->u.req.m_url_impl = url_create(d_heap);      // create url
00354     }
00355     url_copy_onto(s_url, s_heap, d_url, d_heap, false);
00356   } else if (d_polarity == HTTP_TYPE_REQUEST) {
00357     // gender bender.  Need to kill off old url
00358     url_clear(d_url);
00359   }
00360 
00361   mime_hdr_copy_onto(s_mh, s_heap, d_mh, d_heap, false);
00362   if (inherit_strs)
00363     d_heap->inherit_string_heaps(s_heap);
00364 }
00365 
00366 /*-------------------------------------------------------------------------
00367   -------------------------------------------------------------------------*/
00368 
00369 HTTPHdrImpl *
00370 http_hdr_clone(HTTPHdrImpl *s_hh, HdrHeap *s_heap, HdrHeap *d_heap)
00371 {
00372   HTTPHdrImpl *d_hh;
00373 
00374   // FIX: A future optimization is to copy contiguous objects with
00375   //      one single memcpy.  For this first optimization, we just
00376   //      copy each object separately.
00377 
00378   d_hh = http_hdr_create(d_heap, s_hh->m_polarity);
00379   http_hdr_copy_onto(s_hh, s_heap, d_hh, d_heap, ((s_heap != d_heap) ? true : false));
00380   return (d_hh);
00381 }
00382 
00383 /*-------------------------------------------------------------------------
00384   -------------------------------------------------------------------------*/
00385 
00386 static inline char *
00387 http_hdr_version_to_string(int32_t version, char *buf9)
00388 {
00389   ink_assert(HTTP_MAJOR(version) < 10);
00390   ink_assert(HTTP_MINOR(version) < 10);
00391 
00392   buf9[0] = 'H';
00393   buf9[1] = 'T';
00394   buf9[2] = 'T';
00395   buf9[3] = 'P';
00396   buf9[4] = '/';
00397   buf9[5] = '0' + HTTP_MAJOR(version);
00398   buf9[6] = '.';
00399   buf9[7] = '0' + HTTP_MINOR(version);
00400   buf9[8] = '\0';
00401 
00402   return (buf9);
00403 }
00404 
00405 /*-------------------------------------------------------------------------
00406   -------------------------------------------------------------------------*/
00407 
00408 int
00409 http_version_print(int32_t version, char *buf, int bufsize, int *bufindex, int *dumpoffset)
00410 {
00411 #define TRY(x)  if (!x) return 0
00412 
00413   char tmpbuf[16];
00414   http_hdr_version_to_string(version, tmpbuf);
00415   TRY(mime_mem_print(tmpbuf, 8, buf, bufsize, bufindex, dumpoffset));
00416   return 1;
00417 
00418 #undef TRY
00419 }
00420 
00421 /*-------------------------------------------------------------------------
00422   -------------------------------------------------------------------------*/
00423 
00424 int
00425 http_hdr_print(HdrHeap *heap, HTTPHdrImpl *hdr, char *buf, int bufsize, int *bufindex, int *dumpoffset)
00426 {
00427 #define TRY(x)  if (!x) return 0
00428 
00429   int tmplen, hdrstat;
00430   char tmpbuf[32];
00431   char *p;
00432 
00433   ink_assert((hdr->m_polarity == HTTP_TYPE_REQUEST) || (hdr->m_polarity == HTTP_TYPE_RESPONSE));
00434 
00435   if (hdr->m_polarity == HTTP_TYPE_REQUEST) {
00436 
00437     if (hdr->u.req.m_ptr_method == NULL)
00438       return 1;
00439 
00440     if ((buf != NULL) && (*dumpoffset == 0) && (bufsize - *bufindex >= hdr->u.req.m_len_method + 1)) {  // fastpath
00441 
00442       p = buf + *bufindex;
00443       memcpy(p, hdr->u.req.m_ptr_method, hdr->u.req.m_len_method);
00444       p += hdr->u.req.m_len_method;
00445       *p++ = ' ';
00446       *bufindex += hdr->u.req.m_len_method + 1;
00447 
00448       if (hdr->u.req.m_url_impl) {
00449         TRY(url_print(hdr->u.req.m_url_impl, buf, bufsize, bufindex, dumpoffset));
00450         if (bufsize - *bufindex >= 1) {
00451           if (hdr->u.req.m_method_wks_idx == HTTP_WKSIDX_CONNECT) {
00452               *bufindex -= 1; // remove trailing slash for CONNECT request
00453           }
00454           p = buf + *bufindex;
00455           *p++ = ' ';
00456           *bufindex += 1;
00457         } else {
00458           return 0;
00459         }
00460       }
00461 
00462       if (bufsize - *bufindex >= 9) {
00463         http_hdr_version_to_string(hdr->m_version, p);
00464         *bufindex += 9 - 1;     // overwrite '\0';
00465       } else {
00466         TRY(http_version_print(hdr->m_version, buf, bufsize, bufindex, dumpoffset));
00467       }
00468 
00469       if (bufsize - *bufindex >= 2) {
00470         p = buf + *bufindex;
00471         *p++ = '\r';
00472         *p++ = '\n';
00473         *bufindex += 2;
00474       } else {
00475         TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
00476       }
00477 
00478       TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
00479 
00480     } else {
00481 
00482       TRY(mime_mem_print(hdr->u.req.m_ptr_method, hdr->u.req.m_len_method, buf, bufsize, bufindex, dumpoffset));
00483 
00484       TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
00485 
00486       if (hdr->u.req.m_url_impl) {
00487         TRY(url_print(hdr->u.req.m_url_impl, buf, bufsize, bufindex, dumpoffset));
00488         TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
00489       }
00490 
00491       TRY(http_version_print(hdr->m_version, buf, bufsize, bufindex, dumpoffset));
00492 
00493       TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
00494 
00495       TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
00496     }
00497 
00498   } else {                      //  hdr->m_polarity == HTTP_TYPE_RESPONSE
00499 
00500     if ((buf != NULL) && (*dumpoffset == 0) && (bufsize - *bufindex >= 9 + 6 + 1)) {    // fastpath
00501 
00502       p = buf + *bufindex;
00503       http_hdr_version_to_string(hdr->m_version, p);
00504       p += 8;                   // overwrite '\0' with space
00505       *p++ = ' ';
00506       *bufindex += 9;
00507 
00508       hdrstat = http_hdr_status_get(hdr);
00509       if (hdrstat == 200) {
00510         *p++ = '2';
00511         *p++ = '0';
00512         *p++ = '0';
00513         tmplen = 3;
00514       } else {
00515         tmplen = mime_format_int(p, hdrstat, (bufsize - (p - buf)));
00516         ink_assert(tmplen <= 6);
00517         p += tmplen;
00518       }
00519       *p++ = ' ';
00520       *bufindex += tmplen + 1;
00521 
00522       if (hdr->u.resp.m_ptr_reason) {
00523         TRY(mime_mem_print(hdr->u.resp.m_ptr_reason, hdr->u.resp.m_len_reason, buf, bufsize, bufindex, dumpoffset));
00524       }
00525 
00526       if (bufsize - *bufindex >= 2) {
00527         p = buf + *bufindex;
00528         *p++ = '\r';
00529         *p++ = '\n';
00530         *bufindex += 2;
00531       } else {
00532         TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
00533       }
00534 
00535       TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
00536 
00537     } else {
00538 
00539       TRY(http_version_print(hdr->m_version, buf, bufsize, bufindex, dumpoffset));
00540 
00541       TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
00542 
00543       tmplen = mime_format_int(tmpbuf, http_hdr_status_get(hdr), sizeof(tmpbuf));
00544 
00545       TRY(mime_mem_print(tmpbuf, tmplen, buf, bufsize, bufindex, dumpoffset));
00546 
00547       TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
00548 
00549       if (hdr->u.resp.m_ptr_reason) {
00550         TRY(mime_mem_print(hdr->u.resp.m_ptr_reason, hdr->u.resp.m_len_reason, buf, bufsize, bufindex, dumpoffset));
00551       }
00552 
00553       TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
00554 
00555       TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
00556 
00557     }
00558   }
00559 
00560   return 1;
00561 
00562 #undef TRY
00563 }
00564 
00565 /*-------------------------------------------------------------------------
00566   -------------------------------------------------------------------------*/
00567 
00568 void
00569 http_hdr_describe(HdrHeapObjImpl *raw, bool recurse)
00570 {
00571   HTTPHdrImpl *obj = (HTTPHdrImpl *) raw;
00572 
00573   if (obj->m_polarity == HTTP_TYPE_REQUEST) {
00574     Debug("http", "[TYPE: REQ, V: %04X, URL: %p, METHOD: \"%.*s\", METHOD_LEN: %d, FIELDS: %p]\n",
00575           obj->m_version, obj->u.req.m_url_impl,
00576           obj->u.req.m_len_method, (obj->u.req.m_ptr_method ? obj->u.req.m_ptr_method : "NULL"),
00577           obj->u.req.m_len_method, obj->m_fields_impl);
00578     if (recurse) {
00579       if (obj->u.req.m_url_impl)
00580         obj_describe(obj->u.req.m_url_impl, recurse);
00581       if (obj->m_fields_impl)
00582         obj_describe(obj->m_fields_impl, recurse);
00583     }
00584   } else {
00585     Debug("http", "[TYPE: RSP, V: %04X, STATUS: %d, REASON: \"%.*s\", REASON_LEN: %d, FIELDS: %p]\n",
00586           obj->m_version, obj->u.resp.m_status,
00587           obj->u.resp.m_len_reason, (obj->u.resp.m_ptr_reason ? obj->u.resp.m_ptr_reason : "NULL"),
00588           obj->u.resp.m_len_reason, obj->m_fields_impl);
00589     if (recurse) {
00590       if (obj->m_fields_impl)
00591         obj_describe(obj->m_fields_impl, recurse);
00592     }
00593   }
00594 }
00595 
00596 /*-------------------------------------------------------------------------
00597   -------------------------------------------------------------------------*/
00598 
00599 int
00600 http_hdr_length_get(HTTPHdrImpl *hdr)
00601 {
00602   int length = 0;
00603 
00604   if (hdr->m_polarity == HTTP_TYPE_REQUEST) {
00605     if (hdr->u.req.m_ptr_method) {
00606       length = hdr->u.req.m_len_method;
00607     } else {
00608       length = 0;
00609     }
00610 
00611     length += 1;                // " "
00612 
00613     if (hdr->u.req.m_url_impl) {
00614       length += url_length_get(hdr->u.req.m_url_impl);
00615     }
00616 
00617     length += 1;                // " "
00618 
00619     length += 8;                // HTTP/%d.%d
00620 
00621     length += 2;                // "\r\n"
00622   } else if (hdr->m_polarity == HTTP_TYPE_RESPONSE) {
00623     if (hdr->u.resp.m_ptr_reason) {
00624       length = hdr->u.resp.m_len_reason;
00625     } else {
00626       length = 0;
00627 
00628     }
00629 
00630     length += 8;                // HTTP/%d.%d
00631 
00632     length += 1;                // " "
00633 
00634     length += 3;                // status
00635 
00636     length += 1;                // " "
00637 
00638     length += 2;                // "\r\n"
00639   }
00640 
00641   length += mime_hdr_length_get(hdr->m_fields_impl);
00642 
00643   return length;
00644 }
00645 
00646 
00647 /*-------------------------------------------------------------------------
00648   -------------------------------------------------------------------------*/
00649 
00650 void
00651 http_hdr_type_set(HTTPHdrImpl *hh, HTTPType type)
00652 {
00653   hh->m_polarity = type;
00654 }
00655 
00656 /*-------------------------------------------------------------------------
00657   -------------------------------------------------------------------------*/
00658 
00659 void
00660 http_hdr_version_set(HTTPHdrImpl *hh, int32_t ver)
00661 {
00662   hh->m_version = ver;
00663 }
00664 
00665 /*-------------------------------------------------------------------------
00666   -------------------------------------------------------------------------*/
00667 
00668 const char *
00669 http_hdr_method_get(HTTPHdrImpl *hh, int *length)
00670 {
00671   const char *str;
00672 
00673   ink_assert(hh->m_polarity == HTTP_TYPE_REQUEST);
00674 
00675   if (hh->u.req.m_method_wks_idx >= 0) {
00676     str = hdrtoken_index_to_wks(hh->u.req.m_method_wks_idx);
00677     *length = hdrtoken_index_to_length(hh->u.req.m_method_wks_idx);
00678   } else {
00679     str = hh->u.req.m_ptr_method;
00680     *length = hh->u.req.m_len_method;
00681   }
00682 
00683   return (str);
00684 }
00685 
00686 /*-------------------------------------------------------------------------
00687   -------------------------------------------------------------------------*/
00688 
00689 void
00690 http_hdr_method_set(HdrHeap *heap, HTTPHdrImpl *hh, const char *method, int16_t method_wks_idx, int method_length,
00691                     bool must_copy)
00692 {
00693   ink_assert(hh->m_polarity == HTTP_TYPE_REQUEST);
00694 
00695   hh->u.req.m_method_wks_idx = method_wks_idx;
00696   mime_str_u16_set(heap, method, method_length, &(hh->u.req.m_ptr_method), &(hh->u.req.m_len_method), must_copy);
00697 }
00698 
00699 /*-------------------------------------------------------------------------
00700   -------------------------------------------------------------------------*/
00701 
00702 void
00703 http_hdr_url_set(HdrHeap *heap, HTTPHdrImpl *hh, URLImpl *url)
00704 {
00705   ink_assert(hh->m_polarity == HTTP_TYPE_REQUEST);
00706   if (hh->u.req.m_url_impl != url) {
00707     if (hh->u.req.m_url_impl != NULL) {
00708       heap->deallocate_obj(hh->u.req.m_url_impl);
00709     }
00710     hh->u.req.m_url_impl = url;
00711   }
00712 }
00713 
00714 
00715 /*-------------------------------------------------------------------------
00716   -------------------------------------------------------------------------*/
00717 
00718 void
00719 http_hdr_status_set(HTTPHdrImpl *hh, HTTPStatus status)
00720 {
00721   ink_assert(hh->m_polarity == HTTP_TYPE_RESPONSE);
00722   hh->u.resp.m_status = status;
00723 }
00724 
00725 /*-------------------------------------------------------------------------
00726   -------------------------------------------------------------------------*/
00727 
00728 const char *
00729 http_hdr_reason_get(HTTPHdrImpl *hh, int *length)
00730 {
00731   ink_assert(hh->m_polarity == HTTP_TYPE_RESPONSE);
00732   *length = hh->u.resp.m_len_reason;
00733   return (hh->u.resp.m_ptr_reason);
00734 }
00735 
00736 /*-------------------------------------------------------------------------
00737   -------------------------------------------------------------------------*/
00738 
00739 void
00740 http_hdr_reason_set(HdrHeap *heap, HTTPHdrImpl *hh, const char *value, int length, bool must_copy)
00741 {
00742   ink_assert(hh->m_polarity == HTTP_TYPE_RESPONSE);
00743   mime_str_u16_set(heap, value, length, &(hh->u.resp.m_ptr_reason), &(hh->u.resp.m_len_reason), must_copy);
00744 }
00745 
00746 /*-------------------------------------------------------------------------
00747   -------------------------------------------------------------------------*/
00748 
00749 const char *
00750 http_hdr_reason_lookup(unsigned status)
00751 {
00752 #define HTTP_STATUS_ENTRY(value, reason) \
00753     case value: return #reason
00754 
00755   switch (status) {
00756     HTTP_STATUS_ENTRY(0, None);                                       // TS_HTTP_STATUS_NONE
00757     HTTP_STATUS_ENTRY(100, Continue);                                 // [RFC2616]
00758     HTTP_STATUS_ENTRY(101, Switching Protocols);                      // [RFC2616]
00759     HTTP_STATUS_ENTRY(102, Processing);                               // [RFC2518]
00760     // 103-199 Unassigned
00761     HTTP_STATUS_ENTRY(200, OK);                                       // [RFC2616]
00762     HTTP_STATUS_ENTRY(201, Created);                                  // [RFC2616]
00763     HTTP_STATUS_ENTRY(202, Accepted);                                 // [RFC2616]
00764     HTTP_STATUS_ENTRY(203, Non-Authoritative Information);            // [RFC2616]
00765     HTTP_STATUS_ENTRY(204, No Content);                               // [RFC2616]
00766     HTTP_STATUS_ENTRY(205, Reset Content);                            // [RFC2616]
00767     HTTP_STATUS_ENTRY(206, Partial Content);                          // [RFC2616]
00768     HTTP_STATUS_ENTRY(207, Multi-Status);                             // [RFC4918]
00769     HTTP_STATUS_ENTRY(208, Already Reported);                         // [RFC5842]
00770     // 209-225 Unassigned
00771     HTTP_STATUS_ENTRY(226, IM Used);                                  // [RFC3229]
00772     // 227-299 Unassigned
00773     HTTP_STATUS_ENTRY(300, Multiple Choices);                         // [RFC2616]
00774     HTTP_STATUS_ENTRY(301, Moved Permanently);                        // [RFC2616]
00775     HTTP_STATUS_ENTRY(302, Found);                                    // [RFC2616]
00776     HTTP_STATUS_ENTRY(303, See Other);                                // [RFC2616]
00777     HTTP_STATUS_ENTRY(304, Not Modified);                             // [RFC2616]
00778     HTTP_STATUS_ENTRY(305, Use Proxy);                                // [RFC2616]
00779     // 306 Reserved                                                   // [RFC2616]
00780     HTTP_STATUS_ENTRY(307, Temporary Redirect);                       // [RFC2616]
00781     HTTP_STATUS_ENTRY(308, Permanent Redirect);                       // [RFC-reschke-http-status-308-07]
00782     // 309-399 Unassigned
00783     HTTP_STATUS_ENTRY(400, Bad Request);                              // [RFC2616]
00784     HTTP_STATUS_ENTRY(401, Unauthorized);                             // [RFC2616]
00785     HTTP_STATUS_ENTRY(402, Payment Required);                         // [RFC2616]
00786     HTTP_STATUS_ENTRY(403, Forbidden);                                // [RFC2616]
00787     HTTP_STATUS_ENTRY(404, Not Found);                                // [RFC2616]
00788     HTTP_STATUS_ENTRY(405, Method Not Allowed);                       // [RFC2616]
00789     HTTP_STATUS_ENTRY(406, Not Acceptable);                           // [RFC2616]
00790     HTTP_STATUS_ENTRY(407, Proxy Authentication Required);            // [RFC2616]
00791     HTTP_STATUS_ENTRY(408, Request Timeout);                          // [RFC2616]
00792     HTTP_STATUS_ENTRY(409, Conflict);                                 // [RFC2616]
00793     HTTP_STATUS_ENTRY(410, Gone);                                     // [RFC2616]
00794     HTTP_STATUS_ENTRY(411, Length Required);                          // [RFC2616]
00795     HTTP_STATUS_ENTRY(412, Precondition Failed);                      // [RFC2616]
00796     HTTP_STATUS_ENTRY(413, Request Entity Too Large);                 // [RFC2616]
00797     HTTP_STATUS_ENTRY(414, Request-URI Too Long);                     // [RFC2616]
00798     HTTP_STATUS_ENTRY(415, Unsupported Media Type);                   // [RFC2616]
00799     HTTP_STATUS_ENTRY(416, Requested Range Not Satisfiable);          // [RFC2616]
00800     HTTP_STATUS_ENTRY(417, Expectation Failed);                       // [RFC2616]
00801     HTTP_STATUS_ENTRY(422, Unprocessable Entity);                     // [RFC4918]
00802     HTTP_STATUS_ENTRY(423, Locked);                                   // [RFC4918]
00803     HTTP_STATUS_ENTRY(424, Failed Dependency);                        // [RFC4918]
00804     // 425 Reserved                                                   // [RFC2817]
00805     HTTP_STATUS_ENTRY(426, Upgrade Required);                         // [RFC2817]
00806     // 427 Unassigned
00807     HTTP_STATUS_ENTRY(428, Precondition Required);                    // [RFC6585]
00808     HTTP_STATUS_ENTRY(429, Too Many Requests);                        // [RFC6585]
00809     // 430 Unassigned
00810     HTTP_STATUS_ENTRY(431, Request Header Fields Too Large);          // [RFC6585]
00811     // 432-499 Unassigned
00812     HTTP_STATUS_ENTRY(500, Internal Server Error);                    // [RFC2616]
00813     HTTP_STATUS_ENTRY(501, Not Implemented);                          // [RFC2616]
00814     HTTP_STATUS_ENTRY(502, Bad Gateway);                              // [RFC2616]
00815     HTTP_STATUS_ENTRY(503, Service Unavailable);                      // [RFC2616]
00816     HTTP_STATUS_ENTRY(504, Gateway Timeout);                          // [RFC2616]
00817     HTTP_STATUS_ENTRY(505, HTTP Version Not Supported);               // [RFC2616]
00818     HTTP_STATUS_ENTRY(506, Variant Also Negotiates);                  // [RFC2295]
00819     HTTP_STATUS_ENTRY(507, Insufficient Storage);                     // [RFC4918]
00820     HTTP_STATUS_ENTRY(508, Loop Detected);                            // [RFC5842]
00821     // 509 Unassigned
00822     HTTP_STATUS_ENTRY(510, Not Extended);                             // [RFC2774]
00823     HTTP_STATUS_ENTRY(511, Network Authentication Required);          // [RFC6585]
00824     // 512-599 Unassigned
00825   }
00826 
00827 #undef HTTP_STATUS_ENTRY
00828 
00829   return NULL;
00830 }
00831 
00832 /*-------------------------------------------------------------------------
00833   -------------------------------------------------------------------------*/
00834 
00835 void
00836 _http_parser_init(HTTPParser *parser)
00837 {
00838   parser->m_parsing_http = true;
00839 }
00840 
00841 //////////////////////////////////////////////////////
00842 // init     first time structure setup              //
00843 // clear    resets an already-initialized structure //
00844 //////////////////////////////////////////////////////
00845 
00846 void
00847 http_parser_init(HTTPParser *parser)
00848 {
00849   _http_parser_init(parser);
00850   mime_parser_init(&parser->m_mime_parser);
00851 }
00852 
00853 void
00854 http_parser_clear(HTTPParser *parser)
00855 {
00856   _http_parser_init(parser);
00857   mime_parser_clear(&parser->m_mime_parser);
00858 }
00859 
00860 /*-------------------------------------------------------------------------
00861   -------------------------------------------------------------------------*/
00862 
00863 #define GETNEXT(label) { \
00864     cur += 1;            \
00865     if (cur >= end) {    \
00866         goto label;      \
00867     }                    \
00868 }
00869 
00870 #define GETPREV(label) {    \
00871     cur -= 1;               \
00872     if (cur < line_start) { \
00873         goto label;         \
00874     }                       \
00875 }
00876 
00877 // NOTE: end is ONE CHARACTER PAST end of string!
00878 
00879 MIMEParseResult
00880 http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end,
00881                       bool must_copy_strings, bool eof)
00882 {
00883   if (parser->m_parsing_http) {
00884     MIMEScanner *scanner = &parser->m_mime_parser.m_scanner;
00885     URLImpl *url;
00886 
00887     MIMEParseResult err;
00888     bool line_is_real;
00889     const char *cur;
00890     const char *line_start;
00891     const char *real_end;
00892     const char *method_start;
00893     const char *method_end;
00894     const char *url_start;
00895     const char *url_end;
00896     const char *version_start;
00897     const char *version_end;
00898 
00899     real_end = end;
00900 
00901   start:
00902     hh->m_polarity = HTTP_TYPE_REQUEST;
00903 
00904     // Make sure the line is not longer than 64K
00905     if (scanner->m_line_length >= UINT16_MAX)
00906       return PARSE_ERROR;
00907 
00908     err = mime_scanner_get(scanner, start, real_end, &line_start, &end, &line_is_real, eof, MIME_SCANNER_TYPE_LINE);
00909     if (err < 0)
00910       return err;
00911     // We have to get a request line.  If we get parse done here,
00912     //   that meas we got an empty request
00913     if (err == PARSE_DONE)
00914       return PARSE_ERROR;
00915     if (err == PARSE_CONT)
00916       return err;
00917 
00918     cur = line_start;
00919     ink_assert((end - cur) >= 0);
00920     ink_assert((end - cur) < UINT16_MAX);
00921 
00922     must_copy_strings = (must_copy_strings || (!line_is_real));
00923 
00924 #if (ENABLE_PARSER_FAST_PATHS)
00925     // first try fast path
00926     if (end - cur >= 16) {
00927       if (((cur[0] ^ 'G') | (cur[1] ^ 'E') | (cur[2] ^ 'T')) != 0)
00928         goto slow_case;
00929       if (((end[-10] ^ 'H') | (end[-9] ^ 'T') | (end[-8] ^ 'T') | (end[-7] ^ 'P') |
00930            (end[-6] ^ '/') | (end[-4] ^ '.') | (end[-2] ^ '\r') | (end[-1] ^ '\n')) != 0)
00931         goto slow_case;
00932       if (!(is_digit(end[-5]) && is_digit(end[-3])))
00933         goto slow_case;
00934       if (!(ParseRules::is_space(cur[3]) && (!ParseRules::is_space(cur[4])) &&
00935             (!ParseRules::is_space(end[-12])) && ParseRules::is_space(end[-11])))
00936         goto slow_case;
00937       if (&(cur[4]) >= &(end[-11]))
00938         goto slow_case;
00939 
00940       int32_t version = HTTP_VERSION(end[-5] - '0', end[-3] - '0');
00941 
00942       http_hdr_method_set(heap, hh, &(cur[0]), hdrtoken_wks_to_index(HTTP_METHOD_GET), 3, must_copy_strings);
00943       ink_assert(hh->u.req.m_url_impl != NULL);
00944       url = hh->u.req.m_url_impl;
00945       url_start = &(cur[4]);
00946       err =::url_parse(heap, url, &url_start, &(end[-11]), must_copy_strings);
00947       if (err < 0)
00948         return err;
00949       http_hdr_version_set(hh, version);
00950 
00951       end = real_end;
00952       parser->m_parsing_http = false;
00953       if (version == HTTP_VERSION(0, 9))
00954         return PARSE_DONE;
00955 
00956       return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
00957     }
00958 #endif
00959 
00960   slow_case:
00961 
00962     method_start = NULL;
00963     method_end = NULL;
00964     url_start = NULL;
00965     url_end = NULL;
00966     version_start = NULL;
00967     version_end = NULL;
00968     url = NULL;
00969 
00970     if (ParseRules::is_cr(*cur))
00971       GETNEXT(done);
00972     if (ParseRules::is_lf(*cur))
00973       goto start;
00974 
00975   parse_method1:
00976     if (ParseRules::is_ws(*cur)) {
00977       GETNEXT(done);
00978       goto parse_method1;
00979     }
00980     method_start = cur;
00981     GETNEXT(done);
00982   parse_method2:
00983     if (ParseRules::is_ws(*cur)) {
00984       method_end = cur;
00985       goto parse_version1;
00986     }
00987     GETNEXT(done);
00988     goto parse_method2;
00989 
00990   parse_version1:
00991     cur = end - 1;
00992     if (ParseRules::is_lf(*cur) && (cur >= line_start)) {
00993       cur -= 1;
00994     }
00995     if (ParseRules::is_cr(*cur) && (cur >= line_start)) {
00996       cur -= 1;
00997     }
00998     // A client may add extra white spaces after the HTTP version.
00999     // So, skip white spaces.
01000     while (ParseRules::is_ws(*cur) && (cur >= line_start)) {
01001       cur -= 1;
01002     }
01003     version_end = cur + 1;
01004   parse_version2:
01005     if (ParseRules::is_digit(*cur)) {
01006       GETPREV(parse_url);
01007       goto parse_version2;
01008     }
01009     if (*cur == '.') {
01010       GETPREV(parse_url);
01011       goto parse_version3;
01012     }
01013     goto parse_url;
01014   parse_version3:
01015     if (ParseRules::is_digit(*cur)) {
01016       GETPREV(parse_url);
01017       goto parse_version3;
01018     }
01019     if (*cur == '/') {
01020       GETPREV(parse_url);
01021       goto parse_version4;
01022     }
01023     goto parse_url;
01024   parse_version4:
01025     if ((*cur != 'P') && (*cur != 'p')) {
01026       goto parse_url;
01027     }
01028     GETPREV(parse_url);
01029     if ((*cur != 'T') && (*cur != 't')) {
01030       goto parse_url;
01031     }
01032     GETPREV(parse_url);
01033     if ((*cur != 'T') && (*cur != 't')) {
01034       goto parse_url;
01035     }
01036     GETPREV(parse_url);
01037     if ((*cur != 'H') && (*cur != 'h')) {
01038       goto parse_url;
01039     }
01040     version_start = cur;
01041 
01042   parse_url:
01043     url_start = method_end + 1;
01044     if (version_start) {
01045       url_end = version_start - 1;
01046     } else {
01047       url_end = end - 1;
01048     }
01049     while ((url_start < end) && ParseRules::is_ws(*url_start)) {
01050       url_start += 1;
01051     }
01052     while ((url_end >= line_start) && ParseRules::is_wslfcr(*url_end)) {
01053       url_end -= 1;
01054     }
01055     url_end += 1;
01056 
01057   done:
01058     if (!method_start || !method_end)
01059       return PARSE_ERROR;
01060 
01061     int method_wks_idx = hdrtoken_tokenize(method_start,
01062                                            (int) (method_end - method_start));
01063     http_hdr_method_set(heap, hh, method_start, method_wks_idx, (int) (method_end - method_start), must_copy_strings);
01064 
01065     if (!url_start || !url_end)
01066       return PARSE_ERROR;
01067 
01068     ink_assert(hh->u.req.m_url_impl != NULL);
01069 
01070     url = hh->u.req.m_url_impl;
01071     err =::url_parse(heap, url, &url_start, url_end, must_copy_strings);
01072 
01073     if (err < 0)
01074       return err;
01075 
01076     int32_t version;
01077     if (version_start && version_end) {
01078       version = http_parse_version(version_start, version_end);
01079     } else
01080       version = HTTP_VERSION(0, 9);
01081     http_hdr_version_set(hh, version);
01082 
01083     end = real_end;
01084     parser->m_parsing_http = false;
01085     if (version == HTTP_VERSION(0, 9))
01086       return PARSE_DONE;
01087   }
01088 
01089   return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
01090 }
01091 
01092 /*-------------------------------------------------------------------------
01093   -------------------------------------------------------------------------*/
01094 
01095 MIMEParseResult
01096 http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end,
01097                        bool must_copy_strings, bool eof)
01098 {
01099   if (parser->m_parsing_http) {
01100     MIMEScanner *scanner = &parser->m_mime_parser.m_scanner;
01101 
01102     MIMEParseResult err;
01103     bool line_is_real;
01104     const char *cur;
01105     const char *line_start;
01106     const char *real_end;
01107     const char *version_start;
01108     const char *version_end;
01109     const char *status_start;
01110     const char *status_end;
01111     const char *reason_start;
01112     const char *reason_end;
01113     const char *old_start;
01114 
01115     real_end = end;
01116     old_start = *start;
01117 
01118     hh->m_polarity = HTTP_TYPE_RESPONSE;
01119 
01120     // Make sure the line is not longer than 64K
01121     if (scanner->m_line_length >= UINT16_MAX)
01122       return PARSE_ERROR;
01123 
01124     err = mime_scanner_get(scanner, start, real_end, &line_start, &end, &line_is_real, eof, MIME_SCANNER_TYPE_LINE);
01125     if (err < 0)
01126       return err;
01127     if ((err == PARSE_DONE) || (err == PARSE_CONT))
01128       return err;
01129 
01130     cur = line_start;
01131     ink_assert((end - cur) >= 0);
01132     ink_assert((end - cur) < UINT16_MAX);
01133 
01134     must_copy_strings = (must_copy_strings || (!line_is_real));
01135 
01136 #if (ENABLE_PARSER_FAST_PATHS)
01137     // first try fast path
01138     if (end - cur >= 16) {
01139       int http_match = ((cur[0] ^ 'H') | (cur[1] ^ 'T') | (cur[2] ^ 'T') | (cur[3] ^ 'P') |
01140                         (cur[4] ^ '/') | (cur[6] ^ '.') | (cur[8] ^ ' '));
01141       if ((http_match != 0) ||
01142           (!(is_digit(cur[5]) && is_digit(cur[7]) &&
01143              is_digit(cur[9]) && is_digit(cur[10]) && is_digit(cur[11]) && (!ParseRules::is_space(cur[13]))))) {
01144         goto slow_case;
01145       }
01146 
01147       reason_start = &(cur[13]);
01148       reason_end = end - 1;
01149       while ((reason_end > reason_start + 1) && (ParseRules::is_space(reason_end[-1])))
01150         --reason_end;
01151 
01152       int32_t version = HTTP_VERSION(cur[5] - '0', cur[7] - '0');
01153       HTTPStatus status = (HTTPStatus) ((cur[9] - '0') * 100 + (cur[10] - '0') * 10 + (cur[11] - '0'));
01154 
01155       http_hdr_version_set(hh, version);
01156       http_hdr_status_set(hh, status);
01157       http_hdr_reason_set(heap, hh, reason_start, (int) (reason_end - reason_start), must_copy_strings);
01158 
01159       end = real_end;
01160       parser->m_parsing_http = false;
01161       return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
01162     }
01163 #endif
01164 
01165   slow_case:
01166     version_start = NULL;
01167     version_end = NULL;
01168     status_start = NULL;
01169     status_end = NULL;
01170     reason_start = NULL;
01171     reason_end = NULL;
01172 
01173     version_start = cur = line_start;
01174     if ((*cur != 'H') && (*cur != 'h')) {
01175       goto eoh;
01176     }
01177     GETNEXT(eoh);
01178     if ((*cur != 'T') && (*cur != 't')) {
01179       goto eoh;
01180     }
01181     GETNEXT(eoh);
01182     if ((*cur != 'T') && (*cur != 't')) {
01183       goto eoh;
01184     }
01185     GETNEXT(eoh);
01186     if ((*cur != 'P') && (*cur != 'p')) {
01187       goto eoh;
01188     }
01189     GETNEXT(eoh);
01190     if (*cur != '/') {
01191       goto eoh;
01192     }
01193     GETNEXT(eoh);
01194   parse_version2:
01195     if (ParseRules::is_digit(*cur)) {
01196       GETNEXT(eoh);
01197       goto parse_version2;
01198     }
01199     if (*cur == '.') {
01200       GETNEXT(eoh);
01201       goto parse_version3;
01202     }
01203     goto eoh;
01204   parse_version3:
01205     if (ParseRules::is_digit(*cur)) {
01206       GETNEXT(eoh);
01207       goto parse_version3;
01208     }
01209     if (ParseRules::is_ws(*cur)) {
01210       version_end = cur;
01211       GETNEXT(eoh);
01212       goto parse_status1;
01213     }
01214     goto eoh;
01215 
01216   parse_status1:
01217     if (ParseRules::is_ws(*cur)) {
01218       GETNEXT(done);
01219       goto parse_status1;
01220     }
01221     status_start = cur;
01222   parse_status2:
01223     status_end = cur;
01224     if (ParseRules::is_digit(*cur)) {
01225       GETNEXT(done);
01226       goto parse_status2;
01227     }
01228     if (ParseRules::is_ws(*cur)) {
01229       GETNEXT(done);
01230       goto parse_reason1;
01231     }
01232     goto done;
01233 
01234   parse_reason1:
01235     if (ParseRules::is_ws(*cur)) {
01236       GETNEXT(done);
01237       goto parse_reason1;
01238     }
01239     reason_start = cur;
01240     reason_end = end - 1;
01241     while ((reason_end >= line_start) && (ParseRules::is_cr(*reason_end) || ParseRules::is_lf(*reason_end))) {
01242       reason_end -= 1;
01243     }
01244     reason_end += 1;
01245     goto done;
01246 
01247   eoh:
01248     *start = old_start;
01249     return PARSE_DONE;
01250 
01251   done:
01252     if (!version_start || !version_end) {
01253       return PARSE_DONE;
01254     }
01255 
01256     http_hdr_version_set(hh, http_parse_version(version_start, version_end));
01257 
01258     if (status_start && status_end)
01259       http_hdr_status_set(hh, http_parse_status(status_start, status_end));
01260 
01261     if (reason_start && reason_end) {
01262       http_hdr_reason_set(heap, hh, reason_start, (int) (reason_end - reason_start), must_copy_strings);
01263     }
01264 
01265     end = real_end;
01266     parser->m_parsing_http = false;
01267   }
01268 
01269   return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
01270 }
01271 
01272 /*-------------------------------------------------------------------------
01273   -------------------------------------------------------------------------*/
01274 
01275 HTTPStatus
01276 http_parse_status(const char *start, const char *end)
01277 {
01278   int status = 0;
01279 
01280   while ((start != end) && ParseRules::is_space(*start)) {
01281     start += 1;
01282   }
01283 
01284   while ((start != end) && ParseRules::is_digit(*start)) {
01285     status = (status * 10) + (*start++ - '0');
01286   }
01287 
01288   return (HTTPStatus) status;
01289 }
01290 
01291 /*-------------------------------------------------------------------------
01292   -------------------------------------------------------------------------*/
01293 
01294 int32_t
01295 http_parse_version(const char *start, const char *end)
01296 {
01297   int maj;
01298   int min;
01299 
01300   if ((end - start) < 8) {
01301     return HTTP_VERSION(0, 9);
01302   }
01303 
01304   if (((start[0] == 'H') || (start[0] == 'h')) &&
01305       ((start[1] == 'T') || (start[1] == 't')) &&
01306       ((start[2] == 'T') || (start[2] == 't')) && ((start[3] == 'P') || (start[3] == 'p')) && (start[4] == '/')) {
01307     start += 5;
01308 
01309     maj = 0;
01310     min = 0;
01311 
01312     while ((start != end) && ParseRules::is_digit(*start)) {
01313       maj = (maj * 10) + (*start - '0');
01314       start += 1;
01315     }
01316 
01317     if (*start == '.') {
01318       start += 1;
01319     }
01320 
01321     while ((start != end) && ParseRules::is_digit(*start)) {
01322       min = (min * 10) + (*start - '0');
01323       start += 1;
01324     }
01325 
01326     return HTTP_VERSION(maj, min);
01327   }
01328 
01329   return HTTP_VERSION(0, 9);
01330 }
01331 
01332 /*-------------------------------------------------------------------------
01333   -------------------------------------------------------------------------*/
01334 
01335 static char *
01336 http_str_store(Arena *arena, const char *str, int length)
01337 {
01338   const char *wks;
01339   int idx = hdrtoken_tokenize(str, length, &wks);
01340   if (idx < 0) {
01341     return arena->str_store(str, length);
01342   } else {
01343     return (char *) wks;
01344   }
01345 }
01346 
01347 /*-------------------------------------------------------------------------
01348   -------------------------------------------------------------------------*/
01349 
01350 static void
01351 http_skip_ws(const char *&buf, int &len)
01352 {
01353   while (len > 0 && *buf && ParseRules::is_ws(*buf)) {
01354     buf += 1;
01355     len -= 1;
01356   }
01357 }
01358 
01359 /*-------------------------------------------------------------------------
01360   -------------------------------------------------------------------------*/
01361 
01362 static double
01363 http_parse_qvalue(const char *&buf, int &len)
01364 {
01365   double val = 1.0;
01366 
01367   if (*buf != ';') {
01368     return val;
01369   }
01370 
01371   buf += 1;
01372   len -= 1;
01373 
01374   while (len > 0 && *buf) {
01375     http_skip_ws(buf, len);
01376 
01377     if (*buf == 'q') {
01378       buf += 1;
01379       len -= 1;
01380       http_skip_ws(buf, len);
01381 
01382       if (*buf == '=') {
01383         double n;
01384         int f;
01385 
01386         buf += 1;
01387         len -= 1;
01388         http_skip_ws(buf, len);
01389 
01390         n = 0.0;
01391         while (len > 0 && *buf && ParseRules::is_digit(*buf)) {
01392           n = (n * 10) + (*buf++ - '0');
01393           len -= 1;
01394         }
01395 
01396         if (*buf == '.') {
01397           buf += 1;
01398           len -= 1;
01399 
01400           f = 10;
01401           while (len > 0 && *buf && ParseRules::is_digit(*buf)) {
01402             n += (*buf++ - '0') / (double) f;
01403             f *= 10;
01404             len -= 1;
01405           }
01406         }
01407 
01408         val = n;
01409       }
01410     } else {
01411       // The current parameter is not a q-value, so go to the next param.
01412       while (len > 0 && *buf) {
01413         if (*buf != ';') {
01414           buf += 1;
01415           len -= 1;
01416         } else {
01417           // Move to the character after the semicolon.
01418           buf += 1;
01419           len -= 1;
01420           break;
01421         }
01422       }
01423     }
01424   }
01425 
01426   return val;
01427 }
01428 
01429 /*-------------------------------------------------------------------------
01430   -------------------------------------------------------------------------*/
01431 
01432 
01433 /*-------------------------------------------------------------------------
01434   TE        = "TE" ":" #( t-codings )
01435   t-codings = "trailers" | ( transfer-extension [ accept-params ] )
01436   -------------------------------------------------------------------------*/
01437 
01438 HTTPValTE *
01439 http_parse_te(const char *buf, int len, Arena *arena)
01440 {
01441   HTTPValTE *val;
01442   const char *s;
01443 
01444   http_skip_ws(buf, len);
01445 
01446   s = buf;
01447 
01448   while (len > 0 && *buf && (*buf != ';')) {
01449     buf += 1;
01450     len -= 1;
01451   }
01452 
01453   val = (HTTPValTE *) arena->alloc(sizeof(HTTPValTE));
01454   val->encoding = http_str_store(arena, s, (int) (buf - s));
01455   val->qvalue = http_parse_qvalue(buf, len);
01456 
01457   return val;
01458 }
01459 
01460 void
01461 HTTPHdr::_fill_target_cache() const
01462 {
01463   URL* url = this->url_get();
01464   char const* port_ptr;
01465 
01466   m_target_in_url = false;
01467   m_port_in_header = false;
01468   m_host_mime = NULL;
01469   // Check in the URL first, then the HOST field.
01470   if (0 != url->host_get(&m_host_length)) {
01471     m_target_in_url = true;
01472     m_port = url->port_get();
01473     m_port_in_header = 0 != url->port_get_raw();
01474     m_host_mime = NULL;
01475   } else if (0 != (m_host_mime = const_cast<HTTPHdr*>(this)->get_host_port_values(0, &m_host_length, &port_ptr, 0))) {
01476     if (port_ptr) {
01477       m_port = 0;
01478       for ( ; is_digit(*port_ptr) ; ++port_ptr )
01479         m_port = m_port * 10 + *port_ptr - '0';
01480       m_port_in_header = (0 != m_port);
01481     }
01482     m_port = url_canonicalize_port(url->m_url_impl->m_url_type, m_port);
01483   }
01484 
01485   m_target_cached = true;
01486 }
01487 
01488 void
01489 HTTPHdr::set_url_target_from_host_field(URL* url) {
01490   this->_test_and_fill_target_cache();
01491 
01492   if (!url) {
01493     // Use local cached URL and don't copy if the target
01494     // is already there.
01495     if (!m_target_in_url && m_host_mime && m_host_length) {
01496       m_url_cached.host_set(m_host_mime->m_ptr_value, m_host_length);
01497       if (m_port_in_header) m_url_cached.port_set(m_port);
01498       m_target_in_url = true; // it's there now.
01499     }
01500   } else {
01501     int host_len = 0;
01502     char const *host = NULL;
01503     host = host_get(&host_len);
01504     url->host_set(host, host_len);
01505     if (m_port_in_header) url->port_set(m_port);
01506   }
01507 }
01508 
01509 // Very ugly, but a proper implementation will require
01510 // rewriting the URL class and all of its clients so that
01511 // clients access the URL through the HTTP header instance
01512 // unless they really need low level access. The header would
01513 // need to either keep two versions of the URL (pristine
01514 // and effective) or URl would have to provide access to
01515 // the URL printer.
01516 
01517 /// Hack the URL in the HTTP header to be 1.0 compliant, saving the
01518 /// original values so they can be restored.
01519 class UrlPrintHack {
01520   friend class HTTPHdr;
01521   UrlPrintHack(HTTPHdr* hdr) {
01522     hdr->_test_and_fill_target_cache();
01523     if (hdr->m_url_cached.valid()) {
01524       URLImpl* ui = hdr->m_url_cached.m_url_impl;
01525       char port_buff[10];
01526 
01527       m_hdr = hdr; // mark as potentially having modified values.
01528 
01529       /* Get dirty. We reach in to the URL implementation to
01530          set the host and port if
01531          1) They are not already set
01532          AND
01533          2) The values were in a HTTP header.
01534       */
01535       if (!hdr->m_target_in_url && hdr->m_host_length && hdr->m_host_mime) {
01536         ink_assert(0 == ui->m_ptr_host); // shouldn't be non-zero if not in URL.
01537         ui->m_ptr_host = hdr->m_host_mime->m_ptr_value;
01538         ui->m_len_host = hdr->m_host_length;
01539         m_host_modified_p = true;
01540       } else {
01541         m_host_modified_p = false;
01542       }
01543 
01544       if (0 == hdr->m_url_cached.port_get_raw() && hdr->m_port_in_header) {
01545         ink_assert(0 == ui->m_ptr_port); // shouldn't be set if not in URL.
01546         ui->m_ptr_port = port_buff;
01547         ui->m_len_port = sprintf(port_buff, "%.5d", hdr->m_port);
01548         m_port_modified_p = true;
01549       } else {
01550         m_port_modified_p = false;
01551       }
01552     } else {
01553       m_hdr = 0;
01554     }
01555   }
01556 
01557   /// Destructor.
01558   ~UrlPrintHack() {
01559     if (m_hdr) { // There was a potentially modified header.
01560       URLImpl* ui = m_hdr->m_url_cached.m_url_impl;
01561       // Because we only modified if not set, we can just set these values
01562       // back to zero if modified. We want to be careful because if a
01563       // heap re-allocation happened while this was active, then a saved value
01564       // is wrong and will break things if restored. We don't have to worry
01565       // about these because, if modified, they were originally NULL and should
01566       // still be NULL after a re-allocate.
01567       if (m_port_modified_p) {
01568         ui->m_len_port = 0;
01569         ui->m_ptr_port = 0;
01570       }
01571       if (m_host_modified_p) {
01572         ui->m_len_host = 0;
01573         ui->m_ptr_host = 0;
01574       }
01575     }
01576   }
01577 
01578   /// Check if the hack worked
01579   bool is_valid() const {
01580     return 0 != m_hdr;
01581   }
01582    
01583   /// Saved values.
01584   ///@{
01585   bool m_host_modified_p;
01586   bool m_port_modified_p;
01587   HTTPHdr* m_hdr;
01588   ///@}
01589 };
01590 
01591 char*
01592 HTTPHdr::url_string_get(Arena* arena, int* length)
01593 {
01594   char* zret = 0;
01595   UrlPrintHack hack(this);
01596 
01597   if (hack.is_valid()) {
01598     // The use of a magic value for Arena to indicate the internal heap is
01599     // even uglier but it's less so than duplicating this entire method to
01600     // change that one thing.
01601 
01602     zret = (arena == USE_HDR_HEAP_MAGIC)
01603       ? m_url_cached.string_get_ref(length)
01604       : m_url_cached.string_get(arena, length)
01605       ;
01606   }
01607   return zret;
01608 }
01609 
01610 int
01611 HTTPHdr::url_print(char* buff, int length, int* offset, int* skip)
01612 {
01613   ink_release_assert(offset);
01614   ink_release_assert(skip);
01615 
01616   int zret = 0;
01617   UrlPrintHack hack(this);
01618   if (hack.is_valid()) {
01619     zret = m_url_cached.print(buff, length, offset, skip);
01620   }
01621   return zret;
01622 }
01623 
01624 /***********************************************************************
01625  *                                                                     *
01626  *                        M A R S H A L I N G                          *
01627  *                                                                     *
01628  ***********************************************************************/
01629 
01630 int
01631 HTTPHdr::unmarshal(char *buf, int len, RefCountObj *block_ref)
01632 {
01633   m_heap = (HdrHeap *)buf;
01634 
01635   int res = m_heap->unmarshal(len, HDR_HEAP_OBJ_HTTP_HEADER, (HdrHeapObjImpl **) & m_http, block_ref);
01636 
01637   if (res > 0) {
01638     m_mime = m_http->m_fields_impl;
01639   } else {
01640     clear();
01641   }
01642 
01643   return res;
01644 }
01645 
01646 int
01647 HTTPHdrImpl::marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str)
01648 {
01649 
01650   if (m_polarity == HTTP_TYPE_REQUEST) {
01651     HDR_MARSHAL_STR(u.req.m_ptr_method, str_xlate, num_str);
01652     HDR_MARSHAL_PTR(u.req.m_url_impl, URLImpl, ptr_xlate, num_ptr);
01653   } else if (m_polarity == HTTP_TYPE_RESPONSE) {
01654     HDR_MARSHAL_STR(u.resp.m_ptr_reason, str_xlate, num_str);
01655   } else {
01656     ink_release_assert(!"unknown m_polarity");
01657   }
01658 
01659   HDR_MARSHAL_PTR(m_fields_impl, MIMEHdrImpl, ptr_xlate, num_ptr);
01660 
01661   return 0;
01662 }
01663 
01664 
01665 void
01666 HTTPHdrImpl::unmarshal(intptr_t offset)
01667 {
01668 
01669   if (m_polarity == HTTP_TYPE_REQUEST) {
01670     HDR_UNMARSHAL_STR(u.req.m_ptr_method, offset);
01671     HDR_UNMARSHAL_PTR(u.req.m_url_impl, URLImpl, offset);
01672   } else if (m_polarity == HTTP_TYPE_RESPONSE) {
01673     HDR_UNMARSHAL_STR(u.resp.m_ptr_reason, offset);
01674   } else {
01675     ink_release_assert(!"unknown m_polarity");
01676   }
01677 
01678   HDR_UNMARSHAL_PTR(m_fields_impl, MIMEHdrImpl, offset);
01679 }
01680 
01681 
01682 void
01683 HTTPHdrImpl::move_strings(HdrStrHeap *new_heap)
01684 {
01685   if (m_polarity == HTTP_TYPE_REQUEST) {
01686     HDR_MOVE_STR(u.req.m_ptr_method, u.req.m_len_method);
01687   } else if (m_polarity == HTTP_TYPE_RESPONSE) {
01688     HDR_MOVE_STR(u.resp.m_ptr_reason, u.resp.m_len_reason);
01689   } else {
01690     ink_release_assert(!"unknown m_polarity");
01691   }
01692 }
01693 
01694 size_t
01695 HTTPHdrImpl::strings_length()
01696 {
01697   size_t ret = 0;
01698 
01699   if (m_polarity == HTTP_TYPE_REQUEST) {
01700    ret += u.req.m_len_method;
01701   } else if (m_polarity == HTTP_TYPE_RESPONSE) {
01702    ret += u.resp.m_len_reason;
01703   }
01704   return ret;
01705 }
01706 
01707 void
01708 HTTPHdrImpl::check_strings(HeapCheck *heaps, int num_heaps)
01709 {
01710 
01711   if (m_polarity == HTTP_TYPE_REQUEST) {
01712     CHECK_STR(u.req.m_ptr_method, u.req.m_len_method, heaps, num_heaps);
01713   } else if (m_polarity == HTTP_TYPE_RESPONSE) {
01714     CHECK_STR(u.resp.m_ptr_reason, u.resp.m_len_reason, heaps, num_heaps);
01715   } else {
01716     ink_release_assert(!"unknown m_polarity");
01717   }
01718 }
01719 
01720 ClassAllocator<HTTPCacheAlt> httpCacheAltAllocator("httpCacheAltAllocator");
01721 
01722 /*-------------------------------------------------------------------------
01723   -------------------------------------------------------------------------*/
01724 HTTPCacheAlt::HTTPCacheAlt():
01725 m_magic(CACHE_ALT_MAGIC_ALIVE), m_writeable(1),
01726 m_unmarshal_len(-1),
01727 m_id(-1), m_rid(-1), m_request_hdr(),
01728 m_response_hdr(), m_request_sent_time(0), m_response_received_time(0),
01729 m_frag_offset_count(0), m_frag_offsets(0),
01730 m_ext_buffer(NULL)
01731 {
01732 
01733   m_object_key[0] = 0;
01734   m_object_key[1] = 0;
01735   m_object_key[2] = 0;
01736   m_object_key[3] = 0;
01737   m_object_size[0] = 0;
01738   m_object_size[1] = 0;
01739 }
01740 
01741 void
01742 HTTPCacheAlt::destroy()
01743 {
01744   ink_assert(m_magic == CACHE_ALT_MAGIC_ALIVE);
01745   ink_assert(m_writeable);
01746   m_magic = CACHE_ALT_MAGIC_DEAD;
01747   m_writeable = 0;
01748   m_request_hdr.destroy();
01749   m_response_hdr.destroy();
01750   m_frag_offset_count = 0;
01751   if (m_frag_offsets && m_frag_offsets != m_integral_frag_offsets) {
01752     ats_free(m_frag_offsets);
01753     m_frag_offsets = 0;
01754   }
01755   httpCacheAltAllocator.free(this);
01756 }
01757 
01758 void
01759 HTTPCacheAlt::copy(HTTPCacheAlt *to_copy)
01760 {
01761 
01762   m_magic = to_copy->m_magic;
01763   // m_writeable =      to_copy->m_writeable;
01764   m_unmarshal_len = to_copy->m_unmarshal_len;
01765   m_id = to_copy->m_id;
01766   m_rid = to_copy->m_rid;
01767   m_object_key[0] = to_copy->m_object_key[0];
01768   m_object_key[1] = to_copy->m_object_key[1];
01769   m_object_key[2] = to_copy->m_object_key[2];
01770   m_object_key[3] = to_copy->m_object_key[3];
01771   m_object_size[0] = to_copy->m_object_size[0];
01772   m_object_size[1] = to_copy->m_object_size[1];
01773 
01774   if (to_copy->m_request_hdr.valid()) {
01775     m_request_hdr.copy(&to_copy->m_request_hdr);
01776   }
01777 
01778   if (to_copy->m_response_hdr.valid()) {
01779     m_response_hdr.copy(&to_copy->m_response_hdr);
01780   }
01781 
01782   m_request_sent_time = to_copy->m_request_sent_time;
01783   m_response_received_time = to_copy->m_response_received_time;
01784   this->copy_frag_offsets_from(to_copy);
01785 }
01786 
01787 void
01788 HTTPCacheAlt::copy_frag_offsets_from(HTTPCacheAlt *src)
01789 {
01790   m_frag_offset_count = src->m_frag_offset_count;
01791   if (m_frag_offset_count > 0) {
01792     if (m_frag_offset_count > N_INTEGRAL_FRAG_OFFSETS) {
01793       /* Mixed feelings about this - technically we don't need it to be a
01794          power of two when copied because currently that means it is frozen.
01795          But that could change later and it would be a nasty bug to find.
01796          So we'll do it for now. The relative overhead is tiny.
01797       */
01798       int bcount = HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS * 2;
01799       while (bcount < m_frag_offset_count) bcount *= 2;
01800       m_frag_offsets = static_cast<FragOffset*>(ats_malloc(sizeof(FragOffset) * bcount));
01801     } else {
01802       m_frag_offsets = m_integral_frag_offsets;
01803     }
01804     memcpy(m_frag_offsets, src->m_frag_offsets, sizeof(FragOffset) * m_frag_offset_count);
01805   }
01806 }
01807 
01808 const int HTTP_ALT_MARSHAL_SIZE = ROUND(sizeof(HTTPCacheAlt), HDR_PTR_SIZE);
01809 
01810 void
01811 HTTPInfo::create()
01812 {
01813   m_alt = httpCacheAltAllocator.alloc();
01814 }
01815 
01816 void
01817 HTTPInfo::copy(HTTPInfo *hi)
01818 {
01819 
01820   if (m_alt && m_alt->m_writeable) {
01821     destroy();
01822   }
01823 
01824   create();
01825   m_alt->copy(hi->m_alt);
01826 }
01827 
01828 void
01829 HTTPInfo::copy_frag_offsets_from(HTTPInfo* src) {
01830   if (m_alt && src->m_alt)
01831     m_alt->copy_frag_offsets_from(src->m_alt);
01832 }
01833 
01834 
01835 int
01836 HTTPInfo::marshal_length()
01837 {
01838   int len = HTTP_ALT_MARSHAL_SIZE;
01839 
01840   if (m_alt->m_request_hdr.valid()) {
01841     len += m_alt->m_request_hdr.m_heap->marshal_length();
01842   }
01843 
01844   if (m_alt->m_response_hdr.valid()) {
01845     len += m_alt->m_response_hdr.m_heap->marshal_length();
01846   }
01847 
01848   if (m_alt->m_frag_offset_count > HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS) {
01849     len -= sizeof(m_alt->m_integral_frag_offsets);
01850     len += sizeof(FragOffset) * m_alt->m_frag_offset_count;
01851   }
01852 
01853   return len;
01854 }
01855 
01856 int
01857 HTTPInfo::marshal(char *buf, int len)
01858 {
01859   int tmp;
01860   int used = 0;
01861   HTTPCacheAlt *marshal_alt = (HTTPCacheAlt *) buf;
01862   // non-zero only if the offsets are external. Otherwise they get
01863   // marshalled along with the alt struct.
01864   int frag_len = (0 == m_alt->m_frag_offset_count || m_alt->m_frag_offsets == m_alt->m_integral_frag_offsets) ? 0 : sizeof(HTTPCacheAlt::FragOffset) * m_alt->m_frag_offset_count;
01865 
01866   ink_assert(m_alt->m_magic == CACHE_ALT_MAGIC_ALIVE);
01867 
01868   // Make sure the buffer is aligned
01869 //    ink_assert(((intptr_t)buf) & 0x3 == 0);
01870 
01871   // If we have external fragment offsets, copy the initial ones
01872   // into the integral data.
01873   if (frag_len) {
01874     memcpy(m_alt->m_integral_frag_offsets, m_alt->m_frag_offsets, sizeof(m_alt->m_integral_frag_offsets));
01875     frag_len -= sizeof(m_alt->m_integral_frag_offsets);
01876     // frag_len should never be non-zero at this point, as the offsets
01877     // should be external only if too big for the internal table.
01878   }
01879   // Memcpy the whole object so that we can use it
01880   //   live later.  This involves copying a few
01881   //   extra bytes now but will save copying any
01882   //   bytes on the way out of the cache
01883   memcpy(buf, m_alt, sizeof(HTTPCacheAlt));
01884   marshal_alt->m_magic = CACHE_ALT_MAGIC_MARSHALED;
01885   marshal_alt->m_writeable = 0;
01886   marshal_alt->m_unmarshal_len = -1;
01887   marshal_alt->m_ext_buffer = NULL;
01888   buf += HTTP_ALT_MARSHAL_SIZE;
01889   used += HTTP_ALT_MARSHAL_SIZE;
01890 
01891   if (frag_len > 0) {
01892     marshal_alt->m_frag_offsets = static_cast<FragOffset*>(reinterpret_cast<void*>(used));
01893     memcpy(buf, m_alt->m_frag_offsets + HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS, frag_len);
01894     buf += frag_len;
01895     used += frag_len;
01896   } else {
01897     marshal_alt->m_frag_offsets = 0;
01898   }
01899 
01900   // The m_{request,response}_hdr->m_heap pointers are converted
01901   //    to zero based offsets from the start of the buffer we're
01902   //    marshalling in to
01903   if (m_alt->m_request_hdr.valid()) {
01904     tmp = m_alt->m_request_hdr.m_heap->marshal(buf, len - used);
01905     marshal_alt->m_request_hdr.m_heap = (HdrHeap *)(intptr_t)used;
01906     ink_assert(((intptr_t) marshal_alt->m_request_hdr.m_heap) < len);
01907     buf += tmp;
01908     used += tmp;
01909   } else {
01910     marshal_alt->m_request_hdr.m_heap = NULL;
01911   }
01912 
01913   if (m_alt->m_response_hdr.valid()) {
01914     tmp = m_alt->m_response_hdr.m_heap->marshal(buf, len - used);
01915     marshal_alt->m_response_hdr.m_heap = (HdrHeap *)(intptr_t)used;
01916     ink_assert(((intptr_t) marshal_alt->m_response_hdr.m_heap) < len);
01917     used += tmp;
01918   } else {
01919     marshal_alt->m_response_hdr.m_heap = NULL;
01920   }
01921 
01922   // The prior system failed the marshal if there wasn't
01923   //   enough space by measuring the space for every
01924   //   component. Seems much faster to check once to
01925   //   see if we spammed memory
01926   ink_release_assert(used <= len);
01927 
01928   return used;
01929 }
01930 
01931 int
01932 HTTPInfo::unmarshal(char *buf, int len, RefCountObj *block_ref)
01933 {
01934   HTTPCacheAlt *alt = (HTTPCacheAlt *) buf;
01935   int orig_len = len;
01936 
01937   if (alt->m_magic == CACHE_ALT_MAGIC_ALIVE) {
01938     // Already unmarshaled, must be a ram cache
01939     //  it
01940     ink_assert(alt->m_unmarshal_len > 0);
01941     ink_assert(alt->m_unmarshal_len <= len);
01942     return alt->m_unmarshal_len;
01943   } else if (alt->m_magic != CACHE_ALT_MAGIC_MARSHALED) {
01944     ink_assert(!"HTTPInfo::unmarshal bad magic");
01945     return -1;
01946   }
01947 
01948   ink_assert(alt->m_unmarshal_len < 0);
01949   alt->m_magic = CACHE_ALT_MAGIC_ALIVE;
01950   ink_assert(alt->m_writeable == 0);
01951   len -= HTTP_ALT_MARSHAL_SIZE;
01952 
01953   if (alt->m_frag_offset_count > HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS) {
01954     // stuff that didn't fit in the integral slots.
01955     int extra = sizeof(FragOffset) * alt->m_frag_offset_count - sizeof(alt->m_integral_frag_offsets);
01956     char* extra_src = buf + reinterpret_cast<intptr_t>(alt->m_frag_offsets);
01957     // Actual buffer size, which must be a power of two.
01958     // Well, technically not, because we never modify an unmarshalled fragment
01959     // offset table, but it would be a nasty bug should that be done in the
01960     // future.
01961     int bcount = HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS * 2;
01962 
01963     while (bcount < alt->m_frag_offset_count) bcount *= 2;
01964     alt->m_frag_offsets = static_cast<FragOffset*>(ats_malloc(bcount * sizeof(FragOffset))); // WRONG - must round up to next power of 2.
01965     memcpy(alt->m_frag_offsets, alt->m_integral_frag_offsets, sizeof(alt->m_integral_frag_offsets));
01966     memcpy(alt->m_frag_offsets + HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS, extra_src, extra);
01967     len -= extra;
01968   } else if (alt->m_frag_offset_count > 0) {
01969     alt->m_frag_offsets = alt->m_integral_frag_offsets;
01970   } else {
01971     alt->m_frag_offsets = 0; // should really already be zero.
01972   }
01973 
01974   HdrHeap *heap = (HdrHeap *) (alt->m_request_hdr.m_heap ? (buf + (intptr_t) alt->m_request_hdr.m_heap) : 0);
01975   HTTPHdrImpl *hh = NULL;
01976   int tmp;
01977   if (heap != NULL) {
01978 
01979     tmp = heap->unmarshal(len, HDR_HEAP_OBJ_HTTP_HEADER, (HdrHeapObjImpl **) & hh, block_ref);
01980     if (hh == NULL || tmp < 0) {
01981       ink_assert(!"HTTPInfo::request unmarshal failed");
01982       return -1;
01983     }
01984     len -= tmp;
01985     alt->m_request_hdr.m_heap = heap;
01986     alt->m_request_hdr.m_http = hh;
01987     alt->m_request_hdr.m_mime = hh->m_fields_impl;
01988     alt->m_request_hdr.m_url_cached.m_heap = heap;
01989   }
01990 
01991   heap = (HdrHeap *) (alt->m_response_hdr.m_heap ? (buf + (intptr_t) alt->m_response_hdr.m_heap) : 0);
01992   if (heap != NULL) {
01993     tmp = heap->unmarshal(len, HDR_HEAP_OBJ_HTTP_HEADER, (HdrHeapObjImpl **) & hh, block_ref);
01994     if (hh == NULL || tmp < 0) {
01995       ink_assert(!"HTTPInfo::response unmarshal failed");
01996       return -1;
01997     }
01998     len -= tmp;
01999 
02000     alt->m_response_hdr.m_heap = heap;
02001     alt->m_response_hdr.m_http = hh;
02002     alt->m_response_hdr.m_mime = hh->m_fields_impl;
02003   }
02004 
02005   alt->m_unmarshal_len = orig_len - len;
02006 
02007   return alt->m_unmarshal_len;
02008 }
02009 
02010 // bool HTTPInfo::check_marshalled(char* buf, int len)
02011 //  Checks a marhshalled HTTPInfo buffer to make
02012 //    sure it's sane.  Returns true if sane, false otherwise
02013 //
02014 bool
02015 HTTPInfo::check_marshalled(char *buf, int len)
02016 {
02017   HTTPCacheAlt *alt = (HTTPCacheAlt *) buf;
02018 
02019   if (alt->m_magic != CACHE_ALT_MAGIC_MARSHALED) {
02020     return false;
02021   }
02022 
02023   if (alt->m_writeable != false) {
02024     return false;
02025   }
02026 
02027   if (len < HTTP_ALT_MARSHAL_SIZE) {
02028     return false;
02029   }
02030 
02031   if (alt->m_request_hdr.m_heap == NULL) {
02032     return false;
02033   }
02034 
02035   if ((intptr_t) alt->m_request_hdr.m_heap > len) {
02036     return false;
02037   }
02038 
02039   HdrHeap *heap = (HdrHeap *) (buf + (intptr_t) alt->m_request_hdr.m_heap);
02040   if (heap->check_marshalled(len) == false) {
02041     return false;
02042   }
02043 
02044   if (alt->m_response_hdr.m_heap == NULL) {
02045     return false;
02046   }
02047 
02048   if ((intptr_t) alt->m_response_hdr.m_heap > len) {
02049     return false;
02050   }
02051 
02052   heap = (HdrHeap *) (buf + (intptr_t) alt->m_response_hdr.m_heap);
02053   if (heap->check_marshalled(len) == false) {
02054     return false;
02055   }
02056 
02057   return true;
02058 }
02059 
02060 
02061 // void HTTPInfo::set_buffer_reference(RefCountObj* block_ref)
02062 //
02063 //    Setting a buffer reference for the alt is separate from
02064 //     the unmarshalling operation because the clustering
02065 //     utilizes the system differently than cache does
02066 //    The cache maintains external refcounting of the buffer that
02067 //     the alt is in & doesn't always destroy the alt when its
02068 //     done with it because it figures it doesn't need to since
02069 //     it is managing the buffer
02070 //    The receiver of ClusterRPC system has the alt manage the
02071 //     buffer itself and therefore needs to call this function
02072 //     to set up the reference
02073 //
02074 void
02075 HTTPInfo::set_buffer_reference(RefCountObj *block_ref)
02076 {
02077   ink_assert(m_alt->m_magic == CACHE_ALT_MAGIC_ALIVE);
02078 
02079   // Free existing reference
02080   if (m_alt->m_ext_buffer != NULL) {
02081     if (m_alt->m_ext_buffer->refcount_dec() == 0) {
02082       m_alt->m_ext_buffer->free();
02083     }
02084   }
02085   // Set up the ref count for the external buffer
02086   //   if there is one
02087   if (block_ref) {
02088     block_ref->refcount_inc();
02089   }
02090 
02091   m_alt->m_ext_buffer = block_ref;
02092 }
02093 
02094 int
02095 HTTPInfo::get_handle(char *buf, int len)
02096 {
02097 
02098   // All the offsets have already swizzled to pointers.  All we
02099   //  need to do is set m_alt and make sure things are sane
02100   HTTPCacheAlt *a = (HTTPCacheAlt *) buf;
02101 
02102   if (a->m_magic == CACHE_ALT_MAGIC_ALIVE) {
02103     m_alt = a;
02104     ink_assert(m_alt->m_unmarshal_len > 0);
02105     ink_assert(m_alt->m_unmarshal_len <= len);
02106     return m_alt->m_unmarshal_len;
02107   }
02108 
02109   clear();
02110   return -1;
02111 }
02112 
02113 void
02114 HTTPInfo::push_frag_offset(FragOffset offset) {
02115   ink_assert(m_alt);
02116   if (0 == m_alt->m_frag_offsets) {
02117     m_alt->m_frag_offsets = m_alt->m_integral_frag_offsets;
02118   } else if (m_alt->m_frag_offset_count >= HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS && 0 == (m_alt->m_frag_offset_count & (m_alt->m_frag_offset_count-1))) {
02119     // need more space than in integral storage and we're at an upgrade
02120     // size (power of 2).
02121     FragOffset* nf = static_cast<FragOffset*>(ats_malloc(sizeof(FragOffset) * (m_alt->m_frag_offset_count * 2)));
02122     memcpy(nf, m_alt->m_frag_offsets, sizeof(FragOffset) * m_alt->m_frag_offset_count);
02123     if (m_alt->m_frag_offsets != m_alt->m_integral_frag_offsets)
02124       ats_free(m_alt->m_frag_offsets);
02125     m_alt->m_frag_offsets = nf;
02126   }
02127 
02128   m_alt->m_frag_offsets[m_alt->m_frag_offset_count++] = offset;
02129 }

Generated by  doxygen 1.7.1