~ps10gel/ubuntu/xenial/trafficserver/6.2.0

« back to all changes in this revision

Viewing changes to proxy/hdrs/HTTP.cc

  • Committer: Bazaar Package Importer
  • Author(s): Arno Toell
  • Date: 2011-01-13 11:49:18 UTC
  • Revision ID: james.westby@ubuntu.com-20110113114918-vu422h8dknrgkj15
Tags: upstream-2.1.5-unstable
ImportĀ upstreamĀ versionĀ 2.1.5-unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 
 
3
  A brief file description
 
4
 
 
5
  @section license License
 
6
 
 
7
  Licensed to the Apache Software Foundation (ASF) under one
 
8
  or more contributor license agreements.  See the NOTICE file
 
9
  distributed with this work for additional information
 
10
  regarding copyright ownership.  The ASF licenses this file
 
11
  to you under the Apache License, Version 2.0 (the
 
12
  "License"); you may not use this file except in compliance
 
13
  with the License.  You may obtain a copy of the License at
 
14
 
 
15
      http://www.apache.org/licenses/LICENSE-2.0
 
16
 
 
17
  Unless required by applicable law or agreed to in writing, software
 
18
  distributed under the License is distributed on an "AS IS" BASIS,
 
19
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
20
  See the License for the specific language governing permissions and
 
21
  limitations under the License.
 
22
 */
 
23
 
 
24
#include "libts.h"
 
25
#include <assert.h>
 
26
#include <stdio.h>
 
27
#include <string.h>
 
28
#include "HTTP.h"
 
29
#include "HdrToken.h"
 
30
#include "Diags.h"
 
31
 
 
32
 
 
33
/***********************************************************************
 
34
 *                                                                     *
 
35
 *                    C O M P I L E    O P T I O N S                   *
 
36
 *                                                                     *
 
37
 ***********************************************************************/
 
38
 
 
39
#define ENABLE_PARSER_FAST_PATHS        1
 
40
 
 
41
/***********************************************************************
 
42
 *                                                                     *
 
43
 *                          C O N S T A N T S                          *
 
44
 *                                                                     *
 
45
 ***********************************************************************/
 
46
 
 
47
// TODO: We should enable the creation and use of these WKS. XXXX
 
48
#if 0
 
49
static const char *cache_control_values[SIZEOF(cache_control_names)];
 
50
#endif
 
51
 
 
52
const char *HTTP_METHOD_CONNECT;
 
53
const char *HTTP_METHOD_DELETE;
 
54
const char *HTTP_METHOD_GET;
 
55
const char *HTTP_METHOD_HEAD;
 
56
const char *HTTP_METHOD_ICP_QUERY;
 
57
const char *HTTP_METHOD_OPTIONS;
 
58
const char *HTTP_METHOD_POST;
 
59
const char *HTTP_METHOD_PURGE;
 
60
const char *HTTP_METHOD_PUT;
 
61
const char *HTTP_METHOD_TRACE;
 
62
const char *HTTP_METHOD_PUSH;
 
63
 
 
64
int HTTP_WKSIDX_CONNECT;
 
65
int HTTP_WKSIDX_DELETE;
 
66
int HTTP_WKSIDX_GET;
 
67
int HTTP_WKSIDX_HEAD;
 
68
int HTTP_WKSIDX_ICP_QUERY;
 
69
int HTTP_WKSIDX_OPTIONS;
 
70
int HTTP_WKSIDX_POST;
 
71
int HTTP_WKSIDX_PURGE;
 
72
int HTTP_WKSIDX_PUT;
 
73
int HTTP_WKSIDX_TRACE;
 
74
int HTTP_WKSIDX_PUSH;
 
75
int HTTP_WKSIDX_METHODS_CNT = 0;
 
76
 
 
77
int HTTP_LEN_CONNECT;
 
78
int HTTP_LEN_DELETE;
 
79
int HTTP_LEN_GET;
 
80
int HTTP_LEN_HEAD;
 
81
int HTTP_LEN_ICP_QUERY;
 
82
int HTTP_LEN_OPTIONS;
 
83
int HTTP_LEN_POST;
 
84
int HTTP_LEN_PURGE;
 
85
int HTTP_LEN_PUT;
 
86
int HTTP_LEN_TRACE;
 
87
int HTTP_LEN_PUSH;
 
88
 
 
89
const char *HTTP_VALUE_BYTES;
 
90
const char *HTTP_VALUE_CHUNKED;
 
91
const char *HTTP_VALUE_CLOSE;
 
92
const char *HTTP_VALUE_COMPRESS;
 
93
const char *HTTP_VALUE_DEFLATE;
 
94
const char *HTTP_VALUE_GZIP;
 
95
const char *HTTP_VALUE_IDENTITY;
 
96
const char *HTTP_VALUE_KEEP_ALIVE;
 
97
const char *HTTP_VALUE_MAX_AGE;
 
98
const char *HTTP_VALUE_MAX_STALE;
 
99
const char *HTTP_VALUE_MIN_FRESH;
 
100
const char *HTTP_VALUE_MUST_REVALIDATE;
 
101
const char *HTTP_VALUE_NONE;
 
102
const char *HTTP_VALUE_NO_CACHE;
 
103
const char *HTTP_VALUE_NO_STORE;
 
104
const char *HTTP_VALUE_NO_TRANSFORM;
 
105
const char *HTTP_VALUE_ONLY_IF_CACHED;
 
106
const char *HTTP_VALUE_PRIVATE;
 
107
const char *HTTP_VALUE_PROXY_REVALIDATE;
 
108
const char *HTTP_VALUE_PUBLIC;
 
109
const char *HTTP_VALUE_S_MAXAGE;
 
110
const char *HTTP_VALUE_NEED_REVALIDATE_ONCE;
 
111
// Cache-control: extension "need-revalidate-once" is used internally by T.S.
 
112
// to invalidate a document, and it is not returned/forwarded.
 
113
// If a cached document has this extension set (ie, is invalidated),
 
114
// then the T.S. needs to revalidate the document once before returning it.
 
115
// After a successful revalidation, the extension will be removed by T.S.
 
116
// To set or unset this directive should be done via the following two
 
117
// function:
 
118
//      set_cooked_cc_need_revalidate_once()
 
119
//      unset_cooked_cc_need_revalidate_once()
 
120
// To test, use regular Cache-control testing functions, eg,
 
121
//      is_cache_control_set(HTTP_VALUE_NEED_REVALIDATE_ONCE)
 
122
 
 
123
int HTTP_LEN_BYTES;
 
124
int HTTP_LEN_CHUNKED;
 
125
int HTTP_LEN_CLOSE;
 
126
int HTTP_LEN_COMPRESS;
 
127
int HTTP_LEN_DEFLATE;
 
128
int HTTP_LEN_GZIP;
 
129
int HTTP_LEN_IDENTITY;
 
130
int HTTP_LEN_KEEP_ALIVE;
 
131
int HTTP_LEN_MAX_AGE;
 
132
int HTTP_LEN_MAX_STALE;
 
133
int HTTP_LEN_MIN_FRESH;
 
134
int HTTP_LEN_MUST_REVALIDATE;
 
135
int HTTP_LEN_NONE;
 
136
int HTTP_LEN_NO_CACHE;
 
137
int HTTP_LEN_NO_STORE;
 
138
int HTTP_LEN_NO_TRANSFORM;
 
139
int HTTP_LEN_ONLY_IF_CACHED;
 
140
int HTTP_LEN_PRIVATE;
 
141
int HTTP_LEN_PROXY_REVALIDATE;
 
142
int HTTP_LEN_PUBLIC;
 
143
int HTTP_LEN_S_MAXAGE;
 
144
int HTTP_LEN_NEED_REVALIDATE_ONCE;
 
145
 
 
146
/***********************************************************************
 
147
 *                                                                     *
 
148
 *                 U T I L I T Y    R O U T I N E S                    *
 
149
 *                                                                     *
 
150
 ***********************************************************************/
 
151
 
 
152
inline static int
 
153
is_digit(char c)
 
154
{
 
155
  return ((c <= '9') && (c >= '0'));
 
156
}
 
157
 
 
158
/***********************************************************************
 
159
 *                                                                     *
 
160
 *                         M A I N    C O D E                          *
 
161
 *                                                                     *
 
162
 ***********************************************************************/
 
163
 
 
164
void
 
165
http_hdr_adjust(HTTPHdrImpl * hdrp, int32_t offset, int32_t length, int32_t delta)
 
166
{
 
167
  NOWARN_UNUSED(hdrp);
 
168
  NOWARN_UNUSED(offset);
 
169
  NOWARN_UNUSED(length);
 
170
  NOWARN_UNUSED(delta);
 
171
  ink_release_assert(!"http_hdr_adjust not implemented");
 
172
}
 
173
 
 
174
/*-------------------------------------------------------------------------
 
175
  -------------------------------------------------------------------------*/
 
176
 
 
177
void
 
178
http_init(const char *path)
 
179
{
 
180
  static int init = 1;
 
181
 
 
182
  if (init) {
 
183
    init = 0;
 
184
 
 
185
    mime_init(path);
 
186
    url_init(path);
 
187
 
 
188
    HTTP_METHOD_CONNECT = hdrtoken_string_to_wks("CONNECT");
 
189
    HTTP_METHOD_DELETE = hdrtoken_string_to_wks("DELETE");
 
190
    HTTP_METHOD_GET = hdrtoken_string_to_wks("GET");
 
191
    HTTP_METHOD_HEAD = hdrtoken_string_to_wks("HEAD");
 
192
    HTTP_METHOD_ICP_QUERY = hdrtoken_string_to_wks("ICP_QUERY");
 
193
    HTTP_METHOD_OPTIONS = hdrtoken_string_to_wks("OPTIONS");
 
194
    HTTP_METHOD_POST = hdrtoken_string_to_wks("POST");
 
195
    HTTP_METHOD_PURGE = hdrtoken_string_to_wks("PURGE");
 
196
    HTTP_METHOD_PUT = hdrtoken_string_to_wks("PUT");
 
197
    HTTP_METHOD_TRACE = hdrtoken_string_to_wks("TRACE");
 
198
    HTTP_METHOD_PUSH = hdrtoken_string_to_wks("PUSH");
 
199
 
 
200
    // HTTP methods index calculation. Don't forget to count them!
 
201
    // Don't change the order of calculation! Each index has related bitmask (see http quick filter)
 
202
    HTTP_WKSIDX_CONNECT = hdrtoken_wks_to_index(HTTP_METHOD_CONNECT);
 
203
    HTTP_WKSIDX_METHODS_CNT++;
 
204
    HTTP_WKSIDX_DELETE = hdrtoken_wks_to_index(HTTP_METHOD_DELETE);
 
205
    HTTP_WKSIDX_METHODS_CNT++;
 
206
    HTTP_WKSIDX_GET = hdrtoken_wks_to_index(HTTP_METHOD_GET);
 
207
    HTTP_WKSIDX_METHODS_CNT++;
 
208
    HTTP_WKSIDX_HEAD = hdrtoken_wks_to_index(HTTP_METHOD_HEAD);
 
209
    HTTP_WKSIDX_METHODS_CNT++;
 
210
    HTTP_WKSIDX_ICP_QUERY = hdrtoken_wks_to_index(HTTP_METHOD_ICP_QUERY);
 
211
    HTTP_WKSIDX_METHODS_CNT++;
 
212
    HTTP_WKSIDX_OPTIONS = hdrtoken_wks_to_index(HTTP_METHOD_OPTIONS);
 
213
    HTTP_WKSIDX_METHODS_CNT++;
 
214
    HTTP_WKSIDX_POST = hdrtoken_wks_to_index(HTTP_METHOD_POST);
 
215
    HTTP_WKSIDX_METHODS_CNT++;
 
216
    HTTP_WKSIDX_PURGE = hdrtoken_wks_to_index(HTTP_METHOD_PURGE);
 
217
    HTTP_WKSIDX_METHODS_CNT++;
 
218
    HTTP_WKSIDX_PUT = hdrtoken_wks_to_index(HTTP_METHOD_PUT);
 
219
    HTTP_WKSIDX_METHODS_CNT++;
 
220
    HTTP_WKSIDX_TRACE = hdrtoken_wks_to_index(HTTP_METHOD_TRACE);
 
221
    HTTP_WKSIDX_METHODS_CNT++;
 
222
    HTTP_WKSIDX_PUSH = hdrtoken_wks_to_index(HTTP_METHOD_PUSH);
 
223
    HTTP_WKSIDX_METHODS_CNT++;
 
224
 
 
225
 
 
226
    HTTP_LEN_CONNECT = hdrtoken_wks_to_length(HTTP_METHOD_CONNECT);
 
227
    HTTP_LEN_DELETE = hdrtoken_wks_to_length(HTTP_METHOD_DELETE);
 
228
    HTTP_LEN_GET = hdrtoken_wks_to_length(HTTP_METHOD_GET);
 
229
    HTTP_LEN_HEAD = hdrtoken_wks_to_length(HTTP_METHOD_HEAD);
 
230
    HTTP_LEN_ICP_QUERY = hdrtoken_wks_to_length(HTTP_METHOD_ICP_QUERY);
 
231
    HTTP_LEN_OPTIONS = hdrtoken_wks_to_length(HTTP_METHOD_OPTIONS);
 
232
    HTTP_LEN_POST = hdrtoken_wks_to_length(HTTP_METHOD_POST);
 
233
    HTTP_LEN_PURGE = hdrtoken_wks_to_length(HTTP_METHOD_PURGE);
 
234
    HTTP_LEN_PUT = hdrtoken_wks_to_length(HTTP_METHOD_PUT);
 
235
    HTTP_LEN_TRACE = hdrtoken_wks_to_length(HTTP_METHOD_TRACE);
 
236
    HTTP_LEN_PUSH = hdrtoken_wks_to_length(HTTP_METHOD_PUSH);
 
237
 
 
238
    HTTP_VALUE_BYTES = hdrtoken_string_to_wks("bytes");
 
239
    HTTP_VALUE_CHUNKED = hdrtoken_string_to_wks("chunked");
 
240
    HTTP_VALUE_CLOSE = hdrtoken_string_to_wks("close");
 
241
    HTTP_VALUE_COMPRESS = hdrtoken_string_to_wks("compress");
 
242
    HTTP_VALUE_DEFLATE = hdrtoken_string_to_wks("deflate");
 
243
    HTTP_VALUE_GZIP = hdrtoken_string_to_wks("gzip");
 
244
    HTTP_VALUE_IDENTITY = hdrtoken_string_to_wks("identity");
 
245
    HTTP_VALUE_KEEP_ALIVE = hdrtoken_string_to_wks("keep-alive");
 
246
    HTTP_VALUE_MAX_AGE = hdrtoken_string_to_wks("max-age");
 
247
    HTTP_VALUE_MAX_STALE = hdrtoken_string_to_wks("max-stale");
 
248
    HTTP_VALUE_MIN_FRESH = hdrtoken_string_to_wks("min-fresh");
 
249
    HTTP_VALUE_MUST_REVALIDATE = hdrtoken_string_to_wks("must-revalidate");
 
250
    HTTP_VALUE_NONE = hdrtoken_string_to_wks("none");
 
251
    HTTP_VALUE_NO_CACHE = hdrtoken_string_to_wks("no-cache");
 
252
    HTTP_VALUE_NO_STORE = hdrtoken_string_to_wks("no-store");
 
253
    HTTP_VALUE_NO_TRANSFORM = hdrtoken_string_to_wks("no-transform");
 
254
    HTTP_VALUE_ONLY_IF_CACHED = hdrtoken_string_to_wks("only-if-cached");
 
255
    HTTP_VALUE_PRIVATE = hdrtoken_string_to_wks("private");
 
256
    HTTP_VALUE_PROXY_REVALIDATE = hdrtoken_string_to_wks("proxy-revalidate");
 
257
    HTTP_VALUE_PUBLIC = hdrtoken_string_to_wks("public");
 
258
    HTTP_VALUE_S_MAXAGE = hdrtoken_string_to_wks("s-maxage");
 
259
    HTTP_VALUE_NEED_REVALIDATE_ONCE = hdrtoken_string_to_wks("need-revalidate-once");
 
260
 
 
261
    HTTP_LEN_BYTES = hdrtoken_wks_to_length(HTTP_VALUE_BYTES);
 
262
    HTTP_LEN_CHUNKED = hdrtoken_wks_to_length(HTTP_VALUE_CHUNKED);
 
263
    HTTP_LEN_CLOSE = hdrtoken_wks_to_length(HTTP_VALUE_CLOSE);
 
264
    HTTP_LEN_COMPRESS = hdrtoken_wks_to_length(HTTP_VALUE_COMPRESS);
 
265
    HTTP_LEN_DEFLATE = hdrtoken_wks_to_length(HTTP_VALUE_DEFLATE);
 
266
    HTTP_LEN_GZIP = hdrtoken_wks_to_length(HTTP_VALUE_GZIP);
 
267
    HTTP_LEN_IDENTITY = hdrtoken_wks_to_length(HTTP_VALUE_IDENTITY);
 
268
    HTTP_LEN_KEEP_ALIVE = hdrtoken_wks_to_length(HTTP_VALUE_KEEP_ALIVE);
 
269
    HTTP_LEN_MAX_AGE = hdrtoken_wks_to_length(HTTP_VALUE_MAX_AGE);
 
270
    HTTP_LEN_MAX_STALE = hdrtoken_wks_to_length(HTTP_VALUE_MAX_STALE);
 
271
    HTTP_LEN_MIN_FRESH = hdrtoken_wks_to_length(HTTP_VALUE_MIN_FRESH);
 
272
    HTTP_LEN_MUST_REVALIDATE = hdrtoken_wks_to_length(HTTP_VALUE_MUST_REVALIDATE);
 
273
    HTTP_LEN_NONE = hdrtoken_wks_to_length(HTTP_VALUE_NONE);
 
274
    HTTP_LEN_NO_CACHE = hdrtoken_wks_to_length(HTTP_VALUE_NO_CACHE);
 
275
    HTTP_LEN_NO_STORE = hdrtoken_wks_to_length(HTTP_VALUE_NO_STORE);
 
276
    HTTP_LEN_NO_TRANSFORM = hdrtoken_wks_to_length(HTTP_VALUE_NO_TRANSFORM);
 
277
    HTTP_LEN_ONLY_IF_CACHED = hdrtoken_wks_to_length(HTTP_VALUE_ONLY_IF_CACHED);
 
278
    HTTP_LEN_PRIVATE = hdrtoken_wks_to_length(HTTP_VALUE_PRIVATE);
 
279
    HTTP_LEN_PROXY_REVALIDATE = hdrtoken_wks_to_length(HTTP_VALUE_PROXY_REVALIDATE);
 
280
    HTTP_LEN_PUBLIC = hdrtoken_wks_to_length(HTTP_VALUE_PUBLIC);
 
281
    HTTP_LEN_S_MAXAGE = hdrtoken_wks_to_length(HTTP_VALUE_S_MAXAGE);
 
282
    HTTP_LEN_NEED_REVALIDATE_ONCE = hdrtoken_wks_to_length(HTTP_VALUE_NEED_REVALIDATE_ONCE);
 
283
 
 
284
    // TODO: We need to look into enable these CC values as WKS XXX
 
285
#if 0
 
286
    for (int i = 0; i < (int) SIZEOF(cache_control_values); i++) {
 
287
      cache_control_values[i] = hdrtoken_string_to_wks(cache_control_names[i]);
 
288
    }
 
289
#endif
 
290
  }
 
291
}
 
292
 
 
293
/*-------------------------------------------------------------------------
 
294
  -------------------------------------------------------------------------*/
 
295
 
 
296
HTTPHdrImpl *
 
297
http_hdr_create(HdrHeap * heap, HTTPType polarity)
 
298
{
 
299
  HTTPHdrImpl *hh;
 
300
 
 
301
  hh = (HTTPHdrImpl *) heap->allocate_obj(sizeof(HTTPHdrImpl), HDR_HEAP_OBJ_HTTP_HEADER);
 
302
  http_hdr_init(heap, hh, polarity);
 
303
  return (hh);
 
304
}
 
305
 
 
306
/*-------------------------------------------------------------------------
 
307
  -------------------------------------------------------------------------*/
 
308
 
 
309
void
 
310
http_hdr_init(HdrHeap * heap, HTTPHdrImpl * hh, HTTPType polarity)
 
311
{
 
312
  memset(&(hh->u), 0, sizeof(hh->u));
 
313
  hh->m_polarity = polarity;
 
314
  hh->m_version = HTTP_VERSION(0, 9);
 
315
  hh->m_fields_impl = mime_hdr_create(heap);
 
316
  if (polarity == HTTP_TYPE_REQUEST) {
 
317
    hh->u.req.m_url_impl = url_create(heap);
 
318
    hh->u.req.m_method_wks_idx = -1;
 
319
  }
 
320
}
 
321
 
 
322
/*-------------------------------------------------------------------------
 
323
  -------------------------------------------------------------------------*/
 
324
 
 
325
void
 
326
http_hdr_copy_onto(HTTPHdrImpl * s_hh, HdrHeap * s_heap, HTTPHdrImpl * d_hh, HdrHeap * d_heap, bool inherit_strs)
 
327
{
 
328
  MIMEHdrImpl *s_mh, *d_mh;
 
329
  URLImpl *s_url, *d_url;
 
330
  HTTPType d_polarity;
 
331
 
 
332
  s_mh = s_hh->m_fields_impl;
 
333
  s_url = s_hh->u.req.m_url_impl;
 
334
  d_mh = d_hh->m_fields_impl;
 
335
  d_url = d_hh->u.req.m_url_impl;
 
336
  d_polarity = d_hh->m_polarity;
 
337
 
 
338
  ink_assert(s_hh->m_polarity != HTTP_TYPE_UNKNOWN);
 
339
  ink_assert(s_mh != NULL);
 
340
  ink_assert(d_mh != NULL);
 
341
 
 
342
  memcpy(d_hh, s_hh, sizeof(HTTPHdrImpl));
 
343
  d_hh->m_fields_impl = d_mh;   // restore pre-memcpy mime impl
 
344
 
 
345
  if (s_hh->m_polarity == HTTP_TYPE_REQUEST) {
 
346
    if (d_polarity == HTTP_TYPE_REQUEST) {
 
347
      d_hh->u.req.m_url_impl = d_url;   // restore pre-memcpy url impl
 
348
    } else {
 
349
      d_url = d_hh->u.req.m_url_impl = url_create(d_heap);      // create url
 
350
    }
 
351
    url_copy_onto(s_url, s_heap, d_url, d_heap, false);
 
352
  } else if (d_polarity == HTTP_TYPE_REQUEST) {
 
353
    // gender bender.  Need to kill off old url
 
354
    url_clear(d_url);
 
355
  }
 
356
 
 
357
  mime_hdr_copy_onto(s_mh, s_heap, d_mh, d_heap, false);
 
358
  if (inherit_strs)
 
359
    d_heap->inherit_string_heaps(s_heap);
 
360
}
 
361
 
 
362
/*-------------------------------------------------------------------------
 
363
  -------------------------------------------------------------------------*/
 
364
 
 
365
HTTPHdrImpl *
 
366
http_hdr_clone(HTTPHdrImpl * s_hh, HdrHeap * s_heap, HdrHeap * d_heap)
 
367
{
 
368
  HTTPHdrImpl *d_hh;
 
369
 
 
370
  // FIX: A future optimization is to copy contiguous objects with
 
371
  //      one single memcpy.  For this first optimization, we just
 
372
  //      copy each object separately.
 
373
 
 
374
  d_hh = http_hdr_create(d_heap, s_hh->m_polarity);
 
375
  http_hdr_copy_onto(s_hh, s_heap, d_hh, d_heap, ((s_heap != d_heap) ? true : false));
 
376
  return (d_hh);
 
377
}
 
378
 
 
379
/*-------------------------------------------------------------------------
 
380
  -------------------------------------------------------------------------*/
 
381
 
 
382
static inline char *
 
383
http_hdr_version_to_string(int32_t version, char *buf9)
 
384
{
 
385
  ink_debug_assert(HTTP_MAJOR(version) < 10);
 
386
  ink_debug_assert(HTTP_MINOR(version) < 10);
 
387
 
 
388
  buf9[0] = 'H';
 
389
  buf9[1] = 'T';
 
390
  buf9[2] = 'T';
 
391
  buf9[3] = 'P';
 
392
  buf9[4] = '/';
 
393
  buf9[5] = '0' + HTTP_MAJOR(version);
 
394
  buf9[6] = '.';
 
395
  buf9[7] = '0' + HTTP_MINOR(version);
 
396
  buf9[8] = '\0';
 
397
 
 
398
  return (buf9);
 
399
}
 
400
 
 
401
/*-------------------------------------------------------------------------
 
402
  -------------------------------------------------------------------------*/
 
403
 
 
404
int
 
405
http_version_print(int32_t version, char *buf, int bufsize, int *bufindex, int *dumpoffset)
 
406
{
 
407
#define TRY(x)  if (!x) return 0
 
408
 
 
409
  char tmpbuf[16];
 
410
  http_hdr_version_to_string(version, tmpbuf);
 
411
  TRY(mime_mem_print(tmpbuf, 8, buf, bufsize, bufindex, dumpoffset));
 
412
  return 1;
 
413
 
 
414
#undef TRY
 
415
}
 
416
 
 
417
/*-------------------------------------------------------------------------
 
418
  -------------------------------------------------------------------------*/
 
419
 
 
420
int
 
421
http_hdr_print(HdrHeap * heap, HTTPHdrImpl * hdr, char *buf, int bufsize, int *bufindex, int *dumpoffset)
 
422
{
 
423
#define TRY(x)  if (!x) return 0
 
424
 
 
425
  int tmplen, hdrstat;
 
426
  char tmpbuf[32];
 
427
  char *p;
 
428
 
 
429
  ink_debug_assert((hdr->m_polarity == HTTP_TYPE_REQUEST) || (hdr->m_polarity == HTTP_TYPE_RESPONSE));
 
430
 
 
431
  if (hdr->m_polarity == HTTP_TYPE_REQUEST) {
 
432
 
 
433
    if (hdr->u.req.m_ptr_method == NULL)
 
434
      return 1;
 
435
 
 
436
    if ((buf != NULL) && (*dumpoffset == 0) && (bufsize - *bufindex >= hdr->u.req.m_len_method + 1)) {  // fastpath
 
437
 
 
438
      p = buf + *bufindex;
 
439
      memcpy(p, hdr->u.req.m_ptr_method, hdr->u.req.m_len_method);
 
440
      p += hdr->u.req.m_len_method;
 
441
      *p++ = ' ';
 
442
      *bufindex += hdr->u.req.m_len_method + 1;
 
443
 
 
444
      if (hdr->u.req.m_url_impl) {
 
445
        TRY(url_print(hdr->u.req.m_url_impl, buf, bufsize, bufindex, dumpoffset));
 
446
        if (bufsize - *bufindex >= 1) {
 
447
          p = buf + *bufindex;
 
448
          *p++ = ' ';
 
449
          *bufindex += 1;
 
450
        } else {
 
451
          return 0;
 
452
        }
 
453
      }
 
454
 
 
455
      if (bufsize - *bufindex >= 9) {
 
456
        http_hdr_version_to_string(hdr->m_version, p);
 
457
        *bufindex += 9 - 1;     // overwrite '\0';
 
458
      } else {
 
459
        TRY(http_version_print(hdr->m_version, buf, bufsize, bufindex, dumpoffset));
 
460
      }
 
461
 
 
462
      if (bufsize - *bufindex >= 2) {
 
463
        p = buf + *bufindex;
 
464
        *p++ = '\r';
 
465
        *p++ = '\n';
 
466
        *bufindex += 2;
 
467
      } else {
 
468
        TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
 
469
      }
 
470
 
 
471
      TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
 
472
 
 
473
    } else {
 
474
 
 
475
      TRY(mime_mem_print(hdr->u.req.m_ptr_method, hdr->u.req.m_len_method, buf, bufsize, bufindex, dumpoffset));
 
476
 
 
477
      TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
 
478
 
 
479
      if (hdr->u.req.m_url_impl) {
 
480
        TRY(url_print(hdr->u.req.m_url_impl, buf, bufsize, bufindex, dumpoffset));
 
481
        TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
 
482
      }
 
483
 
 
484
      TRY(http_version_print(hdr->m_version, buf, bufsize, bufindex, dumpoffset));
 
485
 
 
486
      TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
 
487
 
 
488
      TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
 
489
    }
 
490
 
 
491
  } else {                      //  hdr->m_polarity == HTTP_TYPE_RESPONSE
 
492
 
 
493
    if ((buf != NULL) && (*dumpoffset == 0) && (bufsize - *bufindex >= 9 + 6 + 1)) {    // fastpath
 
494
 
 
495
      p = buf + *bufindex;
 
496
      http_hdr_version_to_string(hdr->m_version, p);
 
497
      p += 8;                   // overwrite '\0' with space
 
498
      *p++ = ' ';
 
499
      *bufindex += 9;
 
500
 
 
501
      hdrstat = http_hdr_status_get(hdr);
 
502
      if (hdrstat == 200) {
 
503
        *p++ = '2';
 
504
        *p++ = '0';
 
505
        *p++ = '0';
 
506
        tmplen = 3;
 
507
      } else {
 
508
        tmplen = mime_format_int(p, hdrstat, (bufsize - (p - buf)));
 
509
        ink_debug_assert(tmplen <= 6);
 
510
        p += tmplen;
 
511
      }
 
512
      *p++ = ' ';
 
513
      *bufindex += tmplen + 1;
 
514
 
 
515
      if (hdr->u.resp.m_ptr_reason) {
 
516
        TRY(mime_mem_print(hdr->u.resp.m_ptr_reason, hdr->u.resp.m_len_reason, buf, bufsize, bufindex, dumpoffset));
 
517
      }
 
518
 
 
519
      if (bufsize - *bufindex >= 2) {
 
520
        p = buf + *bufindex;
 
521
        *p++ = '\r';
 
522
        *p++ = '\n';
 
523
        *bufindex += 2;
 
524
      } else {
 
525
        TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
 
526
      }
 
527
 
 
528
      TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
 
529
 
 
530
    } else {
 
531
 
 
532
      TRY(http_version_print(hdr->m_version, buf, bufsize, bufindex, dumpoffset));
 
533
 
 
534
      TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
 
535
 
 
536
      tmplen = mime_format_int(tmpbuf, http_hdr_status_get(hdr), sizeof(tmpbuf));
 
537
 
 
538
      TRY(mime_mem_print(tmpbuf, tmplen, buf, bufsize, bufindex, dumpoffset));
 
539
 
 
540
      TRY(mime_mem_print(" ", 1, buf, bufsize, bufindex, dumpoffset));
 
541
 
 
542
      if (hdr->u.resp.m_ptr_reason) {
 
543
        TRY(mime_mem_print(hdr->u.resp.m_ptr_reason, hdr->u.resp.m_len_reason, buf, bufsize, bufindex, dumpoffset));
 
544
      }
 
545
 
 
546
      TRY(mime_mem_print("\r\n", 2, buf, bufsize, bufindex, dumpoffset));
 
547
 
 
548
      TRY(mime_hdr_print(heap, hdr->m_fields_impl, buf, bufsize, bufindex, dumpoffset));
 
549
 
 
550
    }
 
551
  }
 
552
 
 
553
  return 1;
 
554
 
 
555
#undef TRY
 
556
}
 
557
 
 
558
/*-------------------------------------------------------------------------
 
559
  -------------------------------------------------------------------------*/
 
560
 
 
561
void
 
562
http_hdr_describe(HdrHeapObjImpl * raw, bool recurse)
 
563
{
 
564
  HTTPHdrImpl *obj = (HTTPHdrImpl *) raw;
 
565
 
 
566
  if (obj->m_polarity == HTTP_TYPE_REQUEST) {
 
567
    Debug("http", "[TYPE: REQ, V: %04X, URL: 0x%04X, METHOD: \"%.*s\", METHOD_LEN: %d, FIELDS: 0x%04X]\n",
 
568
          obj->m_version, obj->u.req.m_url_impl,
 
569
          obj->u.req.m_len_method, (obj->u.req.m_ptr_method ? obj->u.req.m_ptr_method : "NULL"),
 
570
          obj->u.req.m_len_method, obj->m_fields_impl);
 
571
    if (recurse) {
 
572
      if (obj->u.req.m_url_impl)
 
573
        obj_describe(obj->u.req.m_url_impl, recurse);
 
574
      if (obj->m_fields_impl)
 
575
        obj_describe(obj->m_fields_impl, recurse);
 
576
    }
 
577
  } else {
 
578
    Debug("http", "[TYPE: RSP, V: %04X, STATUS: %d, REASON: \"%.*s\", REASON_LEN: %d, FIELDS: 0x%04X]\n",
 
579
          obj->m_version, obj->u.resp.m_status,
 
580
          obj->u.resp.m_len_reason, (obj->u.resp.m_ptr_reason ? obj->u.resp.m_ptr_reason : "NULL"),
 
581
          obj->u.resp.m_len_reason, obj->m_fields_impl);
 
582
    if (recurse) {
 
583
      if (obj->m_fields_impl)
 
584
        obj_describe(obj->m_fields_impl, recurse);
 
585
    }
 
586
  }
 
587
}
 
588
 
 
589
/*-------------------------------------------------------------------------
 
590
  -------------------------------------------------------------------------*/
 
591
 
 
592
int
 
593
http_hdr_length_get(HTTPHdrImpl * hdr)
 
594
{
 
595
  int length = 0;
 
596
 
 
597
  if (hdr->m_polarity == HTTP_TYPE_REQUEST) {
 
598
    if (hdr->u.req.m_ptr_method) {
 
599
      length = hdr->u.req.m_len_method;
 
600
    } else {
 
601
      length = 0;
 
602
    }
 
603
 
 
604
    length += 1;                // " "
 
605
 
 
606
    if (hdr->u.req.m_url_impl) {
 
607
      length += url_length_get(hdr->u.req.m_url_impl);
 
608
    }
 
609
 
 
610
    length += 1;                // " "
 
611
 
 
612
    length += 8;                // HTTP/%d.%d
 
613
 
 
614
    length += 2;                // "\r\n"
 
615
  } else if (hdr->m_polarity == HTTP_TYPE_RESPONSE) {
 
616
    if (hdr->u.resp.m_ptr_reason) {
 
617
      length = hdr->u.resp.m_len_reason;
 
618
    } else {
 
619
      length = 0;
 
620
 
 
621
    }
 
622
 
 
623
    length += 8;                // HTTP/%d.%d
 
624
 
 
625
    length += 1;                // " "
 
626
 
 
627
    length += 3;                // status
 
628
 
 
629
    length += 1;                // " "
 
630
 
 
631
    length += 2;                // "\r\n"
 
632
  }
 
633
 
 
634
  length += mime_hdr_length_get(hdr->m_fields_impl);
 
635
 
 
636
  return length;
 
637
}
 
638
 
 
639
 
 
640
/*-------------------------------------------------------------------------
 
641
  -------------------------------------------------------------------------*/
 
642
 
 
643
void
 
644
http_hdr_type_set(HTTPHdrImpl * hh, HTTPType type)
 
645
{
 
646
  hh->m_polarity = type;
 
647
}
 
648
 
 
649
/*-------------------------------------------------------------------------
 
650
  -------------------------------------------------------------------------*/
 
651
 
 
652
void
 
653
http_hdr_version_set(HTTPHdrImpl * hh, int32_t ver)
 
654
{
 
655
  hh->m_version = ver;
 
656
}
 
657
 
 
658
/*-------------------------------------------------------------------------
 
659
  -------------------------------------------------------------------------*/
 
660
 
 
661
const char *
 
662
http_hdr_method_get(HTTPHdrImpl * hh, int *length)
 
663
{
 
664
  const char *str;
 
665
 
 
666
  ink_debug_assert(hh->m_polarity == HTTP_TYPE_REQUEST);
 
667
 
 
668
  if (hh->u.req.m_method_wks_idx >= 0) {
 
669
    str = hdrtoken_index_to_wks(hh->u.req.m_method_wks_idx);
 
670
    *length = hdrtoken_index_to_length(hh->u.req.m_method_wks_idx);
 
671
  } else {
 
672
    str = hh->u.req.m_ptr_method;
 
673
    *length = hh->u.req.m_len_method;
 
674
  }
 
675
 
 
676
  return (str);
 
677
}
 
678
 
 
679
/*-------------------------------------------------------------------------
 
680
  -------------------------------------------------------------------------*/
 
681
 
 
682
void
 
683
http_hdr_method_set(HdrHeap * heap,
 
684
                    HTTPHdrImpl * hh, const char *method, int16_t method_wks_idx, int method_length, bool must_copy)
 
685
{
 
686
  ink_debug_assert(hh->m_polarity == HTTP_TYPE_REQUEST);
 
687
 
 
688
  hh->u.req.m_method_wks_idx = method_wks_idx;
 
689
  mime_str_u16_set(heap, method, method_length, &(hh->u.req.m_ptr_method), &(hh->u.req.m_len_method), must_copy);
 
690
}
 
691
 
 
692
/*-------------------------------------------------------------------------
 
693
  -------------------------------------------------------------------------*/
 
694
 
 
695
void
 
696
http_hdr_url_set(HdrHeap * heap, HTTPHdrImpl * hh, URLImpl * url)
 
697
{
 
698
  ink_debug_assert(hh->m_polarity == HTTP_TYPE_REQUEST);
 
699
  if (hh->u.req.m_url_impl != url) {
 
700
    if (hh->u.req.m_url_impl != NULL) {
 
701
      heap->deallocate_obj(hh->u.req.m_url_impl);
 
702
    }
 
703
    hh->u.req.m_url_impl = url;
 
704
  }
 
705
}
 
706
 
 
707
 
 
708
/*-------------------------------------------------------------------------
 
709
  -------------------------------------------------------------------------*/
 
710
 
 
711
void
 
712
http_hdr_status_set(HTTPHdrImpl * hh, HTTPStatus status)
 
713
{
 
714
  ink_debug_assert(hh->m_polarity == HTTP_TYPE_RESPONSE);
 
715
  hh->u.resp.m_status = status;
 
716
}
 
717
 
 
718
/*-------------------------------------------------------------------------
 
719
  -------------------------------------------------------------------------*/
 
720
 
 
721
const char *
 
722
http_hdr_reason_get(HTTPHdrImpl * hh, int *length)
 
723
{
 
724
  ink_debug_assert(hh->m_polarity == HTTP_TYPE_RESPONSE);
 
725
  *length = hh->u.resp.m_len_reason;
 
726
  return (hh->u.resp.m_ptr_reason);
 
727
}
 
728
 
 
729
/*-------------------------------------------------------------------------
 
730
  -------------------------------------------------------------------------*/
 
731
 
 
732
void
 
733
http_hdr_reason_set(HdrHeap * heap, HTTPHdrImpl * hh, const char *value, int length, bool must_copy)
 
734
{
 
735
  ink_debug_assert(hh->m_polarity == HTTP_TYPE_RESPONSE);
 
736
  mime_str_u16_set(heap, value, length, &(hh->u.resp.m_ptr_reason), &(hh->u.resp.m_len_reason), must_copy);
 
737
}
 
738
 
 
739
/*-------------------------------------------------------------------------
 
740
  -------------------------------------------------------------------------*/
 
741
 
 
742
const char *
 
743
http_hdr_reason_lookup(HTTPStatus status)
 
744
{
 
745
  switch (status) {
 
746
  case HTTP_STATUS_NONE:
 
747
    return "None";
 
748
  case HTTP_STATUS_CONTINUE:
 
749
    return "Continue";
 
750
  case HTTP_STATUS_SWITCHING_PROTOCOL:
 
751
    return "Switching Protocol";
 
752
  case HTTP_STATUS_OK:
 
753
    return "Ok";
 
754
  case HTTP_STATUS_CREATED:
 
755
    return "Created";
 
756
  case HTTP_STATUS_ACCEPTED:
 
757
    return "Accepted";
 
758
  case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION:
 
759
    return "Non Authoritative Information";
 
760
  case HTTP_STATUS_NO_CONTENT:
 
761
    return "No Content";
 
762
  case HTTP_STATUS_RESET_CONTENT:
 
763
    return "Reset Content";
 
764
  case HTTP_STATUS_PARTIAL_CONTENT:
 
765
    return "Partial Content";
 
766
  case HTTP_STATUS_MULTIPLE_CHOICES:
 
767
    return "Multiple Choices";
 
768
  case HTTP_STATUS_MOVED_PERMANENTLY:
 
769
    return "Moved Permanently";
 
770
  case HTTP_STATUS_MOVED_TEMPORARILY:
 
771
    return "Moved Temporarily";
 
772
  case HTTP_STATUS_SEE_OTHER:
 
773
    return "See Other";
 
774
  case HTTP_STATUS_NOT_MODIFIED:
 
775
    return "Not Modified";
 
776
  case HTTP_STATUS_USE_PROXY:
 
777
    return "Use Proxy";
 
778
  case HTTP_STATUS_TEMPORARY_REDIRECT:
 
779
    return "Temporary Redirect";
 
780
  case HTTP_STATUS_BAD_REQUEST:
 
781
    return "Bad Request";
 
782
  case HTTP_STATUS_UNAUTHORIZED:
 
783
    return "Unauthorized";
 
784
  case HTTP_STATUS_PAYMENT_REQUIRED:
 
785
    return "Payment Required";
 
786
  case HTTP_STATUS_FORBIDDEN:
 
787
    return "Forbidden";
 
788
  case HTTP_STATUS_NOT_FOUND:
 
789
    return "Not Found";
 
790
  case HTTP_STATUS_METHOD_NOT_ALLOWED:
 
791
    return "Method Not Allowed";
 
792
  case HTTP_STATUS_NOT_ACCEPTABLE:
 
793
    return "Not Acceptable";
 
794
  case HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED:
 
795
    return "Proxy Authentication Required";
 
796
  case HTTP_STATUS_REQUEST_TIMEOUT:
 
797
    return "Request Timeout";
 
798
  case HTTP_STATUS_CONFLICT:
 
799
    return "Conflict";
 
800
  case HTTP_STATUS_GONE:
 
801
    return "Gone";
 
802
  case HTTP_STATUS_LENGTH_REQUIRED:
 
803
    return "Length Required";
 
804
  case HTTP_STATUS_PRECONDITION_FAILED:
 
805
    return "Precondition Failed";
 
806
  case HTTP_STATUS_RANGE_NOT_SATISFIABLE:
 
807
    return "Requested Range Not Satisfiable";
 
808
  case HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE:
 
809
    return "Request Entity Too Large";
 
810
  case HTTP_STATUS_REQUEST_URI_TOO_LONG:
 
811
    return "Request URI Too Long";
 
812
  case HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE:
 
813
    return "Unsupported Media Type";
 
814
  case HTTP_STATUS_INTERNAL_SERVER_ERROR:
 
815
    return "Internal Server Error";
 
816
  case HTTP_STATUS_NOT_IMPLEMENTED:
 
817
    return "Not Implemented";
 
818
  case HTTP_STATUS_BAD_GATEWAY:
 
819
    return "Bad Gateway";
 
820
  case HTTP_STATUS_SERVICE_UNAVAILABLE:
 
821
    return "Service Unavailable";
 
822
  case HTTP_STATUS_GATEWAY_TIMEOUT:
 
823
    return "Gateway Timeout";
 
824
  case HTTP_STATUS_HTTPVER_NOT_SUPPORTED:
 
825
    return "HTTP Version Not Supported";
 
826
  }
 
827
 
 
828
  return (NULL);
 
829
}
 
830
 
 
831
/*-------------------------------------------------------------------------
 
832
  -------------------------------------------------------------------------*/
 
833
 
 
834
void
 
835
_http_parser_init(HTTPParser * parser)
 
836
{
 
837
  parser->m_parsing_http = true;
 
838
}
 
839
 
 
840
//////////////////////////////////////////////////////
 
841
// init     first time structure setup              //
 
842
// clear    resets an already-initialized structure //
 
843
//////////////////////////////////////////////////////
 
844
 
 
845
void
 
846
http_parser_init(HTTPParser * parser)
 
847
{
 
848
  _http_parser_init(parser);
 
849
  mime_parser_init(&parser->m_mime_parser);
 
850
}
 
851
 
 
852
void
 
853
http_parser_clear(HTTPParser * parser)
 
854
{
 
855
  _http_parser_init(parser);
 
856
  mime_parser_clear(&parser->m_mime_parser);
 
857
}
 
858
 
 
859
/*-------------------------------------------------------------------------
 
860
  -------------------------------------------------------------------------*/
 
861
 
 
862
#define GETNEXT(label) { \
 
863
    cur += 1;            \
 
864
    if (cur >= end) {    \
 
865
        goto label;      \
 
866
    }                    \
 
867
}
 
868
 
 
869
#define GETPREV(label) {    \
 
870
    cur -= 1;               \
 
871
    if (cur < line_start) { \
 
872
        goto label;         \
 
873
    }                       \
 
874
}
 
875
 
 
876
// NOTE: end is ONE CHARACTER PAST end of string!
 
877
 
 
878
MIMEParseResult
 
879
http_parser_parse_req(HTTPParser * parser,
 
880
                      HdrHeap * heap,
 
881
                      HTTPHdrImpl * hh, const char **start, const char *end, bool must_copy_strings, bool eof)
 
882
{
 
883
  if (parser->m_parsing_http) {
 
884
    MIMEScanner *scanner = &parser->m_mime_parser.m_scanner;
 
885
    URLImpl *url;
 
886
 
 
887
    MIMEParseResult err;
 
888
    bool line_is_real;
 
889
    const char *cur;
 
890
    const char *line_start;
 
891
    const char *real_end;
 
892
    const char *method_start;
 
893
    const char *method_end;
 
894
    const char *url_start;
 
895
    const char *url_end;
 
896
    const char *version_start;
 
897
    const char *version_end;
 
898
 
 
899
    real_end = end;
 
900
 
 
901
  start:
 
902
    hh->m_polarity = HTTP_TYPE_REQUEST;
 
903
 
 
904
    err = mime_scanner_get(scanner, start, real_end, &line_start, &end, &line_is_real, eof, MIME_SCANNER_TYPE_LINE);
 
905
    if (err < 0)
 
906
      return err;
 
907
    // We have to get a request line.  If we get parse done here,
 
908
    //   that meas we got an empty request
 
909
    if (err == PARSE_DONE)
 
910
      return PARSE_ERROR;
 
911
    if (err == PARSE_CONT)
 
912
      return err;
 
913
 
 
914
    cur = line_start;
 
915
    must_copy_strings = (must_copy_strings || (!line_is_real));
 
916
 
 
917
#if (ENABLE_PARSER_FAST_PATHS)
 
918
    // first try fast path
 
919
    if (end - cur >= 16) {
 
920
      if (((cur[0] ^ 'G') | (cur[1] ^ 'E') | (cur[2] ^ 'T')) != 0)
 
921
        goto slow_case;
 
922
      if (((end[-10] ^ 'H') | (end[-9] ^ 'T') | (end[-8] ^ 'T') | (end[-7] ^ 'P') |
 
923
           (end[-6] ^ '/') | (end[-4] ^ '.') | (end[-2] ^ '\r') | (end[-1] ^ '\n')) != 0)
 
924
        goto slow_case;
 
925
      if (!(is_digit(end[-5]) && is_digit(end[-3])))
 
926
        goto slow_case;
 
927
      if (!(ParseRules::is_space(cur[3]) && (!ParseRules::is_space(cur[4])) &&
 
928
            (!ParseRules::is_space(end[-12])) && ParseRules::is_space(end[-11])))
 
929
        goto slow_case;
 
930
      if (&(cur[4]) >= &(end[-11]))
 
931
        goto slow_case;
 
932
 
 
933
      int32_t version = HTTP_VERSION(end[-5] - '0', end[-3] - '0');
 
934
 
 
935
      http_hdr_method_set(heap, hh, &(cur[0]), hdrtoken_wks_to_index(HTTP_METHOD_GET), 3, must_copy_strings);
 
936
      ink_debug_assert(hh->u.req.m_url_impl != NULL);
 
937
      url = hh->u.req.m_url_impl;
 
938
      url_start = &(cur[4]);
 
939
      err =::url_parse(heap, url, &url_start, &(end[-11]), must_copy_strings);
 
940
      if (err < 0)
 
941
        return err;
 
942
      http_hdr_version_set(hh, version);
 
943
 
 
944
      end = real_end;
 
945
      parser->m_parsing_http = false;
 
946
      if (version == HTTP_VERSION(0, 9))
 
947
        return PARSE_DONE;
 
948
 
 
949
      return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
 
950
    }
 
951
#endif
 
952
 
 
953
  slow_case:
 
954
 
 
955
    method_start = NULL;
 
956
    method_end = NULL;
 
957
    url_start = NULL;
 
958
    url_end = NULL;
 
959
    version_start = NULL;
 
960
    version_end = NULL;
 
961
    url = NULL;
 
962
 
 
963
    if (ParseRules::is_cr(*cur))
 
964
      GETNEXT(done);
 
965
    if (ParseRules::is_lf(*cur))
 
966
      goto start;
 
967
 
 
968
  parse_method1:
 
969
    if (ParseRules::is_ws(*cur)) {
 
970
      GETNEXT(done);
 
971
      goto parse_method1;
 
972
    }
 
973
    method_start = cur;
 
974
    GETNEXT(done);
 
975
  parse_method2:
 
976
    if (ParseRules::is_ws(*cur)) {
 
977
      method_end = cur;
 
978
      goto parse_version1;
 
979
    }
 
980
    GETNEXT(done);
 
981
    goto parse_method2;
 
982
 
 
983
  parse_version1:
 
984
    cur = end - 1;
 
985
    if (ParseRules::is_lf(*cur) && (cur >= line_start)) {
 
986
      cur -= 1;
 
987
    }
 
988
    if (ParseRules::is_cr(*cur) && (cur >= line_start)) {
 
989
      cur -= 1;
 
990
    }
 
991
    // A client may add extra white spaces after the HTTP version.
 
992
    // So, skip white spaces.
 
993
    while (ParseRules::is_ws(*cur) && (cur >= line_start)) {
 
994
      cur -= 1;
 
995
    }
 
996
    version_end = cur + 1;
 
997
  parse_version2:
 
998
    if (ParseRules::is_digit(*cur)) {
 
999
      GETPREV(parse_url);
 
1000
      goto parse_version2;
 
1001
    }
 
1002
    if (*cur == '.') {
 
1003
      GETPREV(parse_url);
 
1004
      goto parse_version3;
 
1005
    }
 
1006
    goto parse_url;
 
1007
  parse_version3:
 
1008
    if (ParseRules::is_digit(*cur)) {
 
1009
      GETPREV(parse_url);
 
1010
      goto parse_version3;
 
1011
    }
 
1012
    if (*cur == '/') {
 
1013
      GETPREV(parse_url);
 
1014
      goto parse_version4;
 
1015
    }
 
1016
    goto parse_url;
 
1017
  parse_version4:
 
1018
    if ((*cur != 'P') && (*cur != 'p')) {
 
1019
      goto parse_url;
 
1020
    }
 
1021
    GETPREV(parse_url);
 
1022
    if ((*cur != 'T') && (*cur != 't')) {
 
1023
      goto parse_url;
 
1024
    }
 
1025
    GETPREV(parse_url);
 
1026
    if ((*cur != 'T') && (*cur != 't')) {
 
1027
      goto parse_url;
 
1028
    }
 
1029
    GETPREV(parse_url);
 
1030
    if ((*cur != 'H') && (*cur != 'h')) {
 
1031
      goto parse_url;
 
1032
    }
 
1033
    version_start = cur;
 
1034
 
 
1035
  parse_url:
 
1036
    url_start = method_end + 1;
 
1037
    if (version_start) {
 
1038
      url_end = version_start - 1;
 
1039
    } else {
 
1040
      url_end = end - 1;
 
1041
    }
 
1042
    while ((url_start < end) && ParseRules::is_ws(*url_start)) {
 
1043
      url_start += 1;
 
1044
    }
 
1045
    while ((url_end >= line_start) && ParseRules::is_wslfcr(*url_end)) {
 
1046
      url_end -= 1;
 
1047
    }
 
1048
    url_end += 1;
 
1049
 
 
1050
  done:
 
1051
    if (!method_start || !method_end)
 
1052
      return PARSE_ERROR;
 
1053
 
 
1054
    int method_wks_idx = hdrtoken_tokenize(method_start,
 
1055
                                           (int) (method_end - method_start));
 
1056
    http_hdr_method_set(heap, hh, method_start, method_wks_idx, (int) (method_end - method_start), must_copy_strings);
 
1057
 
 
1058
    if (!url_start || !url_end)
 
1059
      return PARSE_ERROR;
 
1060
 
 
1061
    ink_debug_assert(hh->u.req.m_url_impl != NULL);
 
1062
 
 
1063
    url = hh->u.req.m_url_impl;
 
1064
    err =::url_parse(heap, url, &url_start, url_end, must_copy_strings);
 
1065
 
 
1066
    if (err < 0)
 
1067
      return err;
 
1068
 
 
1069
    int32_t version;
 
1070
    if (version_start && version_end) {
 
1071
      version = http_parse_version(version_start, version_end);
 
1072
    } else
 
1073
      version = HTTP_VERSION(0, 9);
 
1074
    http_hdr_version_set(hh, version);
 
1075
 
 
1076
    end = real_end;
 
1077
    parser->m_parsing_http = false;
 
1078
    if (version == HTTP_VERSION(0, 9))
 
1079
      return PARSE_DONE;
 
1080
  }
 
1081
 
 
1082
  return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
 
1083
}
 
1084
 
 
1085
/*-------------------------------------------------------------------------
 
1086
  -------------------------------------------------------------------------*/
 
1087
 
 
1088
MIMEParseResult
 
1089
http_parser_parse_resp(HTTPParser * parser,
 
1090
                       HdrHeap * heap,
 
1091
                       HTTPHdrImpl * hh, const char **start, const char *end, bool must_copy_strings, bool eof)
 
1092
{
 
1093
  if (parser->m_parsing_http) {
 
1094
    MIMEScanner *scanner = &parser->m_mime_parser.m_scanner;
 
1095
 
 
1096
    MIMEParseResult err;
 
1097
    bool line_is_real;
 
1098
    const char *cur;
 
1099
    const char *line_start;
 
1100
    const char *real_end;
 
1101
    const char *version_start;
 
1102
    const char *version_end;
 
1103
    const char *status_start;
 
1104
    const char *status_end;
 
1105
    const char *reason_start;
 
1106
    const char *reason_end;
 
1107
    const char *old_start;
 
1108
 
 
1109
    real_end = end;
 
1110
    old_start = *start;
 
1111
 
 
1112
    hh->m_polarity = HTTP_TYPE_RESPONSE;
 
1113
 
 
1114
    err = mime_scanner_get(scanner, start, real_end, &line_start, &end, &line_is_real, eof, MIME_SCANNER_TYPE_LINE);
 
1115
    if (err < 0)
 
1116
      return err;
 
1117
    if ((err == PARSE_DONE) || (err == PARSE_CONT))
 
1118
      return err;
 
1119
 
 
1120
    cur = line_start;
 
1121
    must_copy_strings = (must_copy_strings || (!line_is_real));
 
1122
 
 
1123
#if (ENABLE_PARSER_FAST_PATHS)
 
1124
    // first try fast path
 
1125
    if (end - cur >= 16) {
 
1126
      int http_match = ((cur[0] ^ 'H') | (cur[1] ^ 'T') | (cur[2] ^ 'T') | (cur[3] ^ 'P') |
 
1127
                        (cur[4] ^ '/') | (cur[6] ^ '.') | (cur[8] ^ ' '));
 
1128
      if ((http_match != 0) ||
 
1129
          (!(is_digit(cur[5]) && is_digit(cur[7]) &&
 
1130
             is_digit(cur[9]) && is_digit(cur[10]) && is_digit(cur[11]) && (!ParseRules::is_space(cur[13]))))) {
 
1131
        goto slow_case;
 
1132
      }
 
1133
 
 
1134
      reason_start = &(cur[13]);
 
1135
      reason_end = end - 1;
 
1136
      while ((reason_end > reason_start + 1) && (ParseRules::is_space(reason_end[-1])))
 
1137
        --reason_end;
 
1138
 
 
1139
      int32_t version = HTTP_VERSION(cur[5] - '0', cur[7] - '0');
 
1140
      HTTPStatus status = (HTTPStatus) ((cur[9] - '0') * 100 + (cur[10] - '0') * 10 + (cur[11] - '0'));
 
1141
 
 
1142
      http_hdr_version_set(hh, version);
 
1143
      http_hdr_status_set(hh, status);
 
1144
      http_hdr_reason_set(heap, hh, reason_start, (int) (reason_end - reason_start), must_copy_strings);
 
1145
 
 
1146
      end = real_end;
 
1147
      parser->m_parsing_http = false;
 
1148
      return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
 
1149
    }
 
1150
#endif
 
1151
 
 
1152
  slow_case:
 
1153
    version_start = NULL;
 
1154
    version_end = NULL;
 
1155
    status_start = NULL;
 
1156
    status_end = NULL;
 
1157
    reason_start = NULL;
 
1158
    reason_end = NULL;
 
1159
 
 
1160
    version_start = cur = line_start;
 
1161
    if ((*cur != 'H') && (*cur != 'h')) {
 
1162
      goto eoh;
 
1163
    }
 
1164
    GETNEXT(eoh);
 
1165
    if ((*cur != 'T') && (*cur != 't')) {
 
1166
      goto eoh;
 
1167
    }
 
1168
    GETNEXT(eoh);
 
1169
    if ((*cur != 'T') && (*cur != 't')) {
 
1170
      goto eoh;
 
1171
    }
 
1172
    GETNEXT(eoh);
 
1173
    if ((*cur != 'P') && (*cur != 'p')) {
 
1174
      goto eoh;
 
1175
    }
 
1176
    GETNEXT(eoh);
 
1177
    if (*cur != '/') {
 
1178
      goto eoh;
 
1179
    }
 
1180
    GETNEXT(eoh);
 
1181
  parse_version2:
 
1182
    if (ParseRules::is_digit(*cur)) {
 
1183
      GETNEXT(eoh);
 
1184
      goto parse_version2;
 
1185
    }
 
1186
    if (*cur == '.') {
 
1187
      GETNEXT(eoh);
 
1188
      goto parse_version3;
 
1189
    }
 
1190
    goto eoh;
 
1191
  parse_version3:
 
1192
    if (ParseRules::is_digit(*cur)) {
 
1193
      GETNEXT(eoh);
 
1194
      goto parse_version3;
 
1195
    }
 
1196
    if (ParseRules::is_ws(*cur)) {
 
1197
      version_end = cur;
 
1198
      GETNEXT(eoh);
 
1199
      goto parse_status1;
 
1200
    }
 
1201
    goto eoh;
 
1202
 
 
1203
  parse_status1:
 
1204
    if (ParseRules::is_ws(*cur)) {
 
1205
      GETNEXT(done);
 
1206
      goto parse_status1;
 
1207
    }
 
1208
    status_start = cur;
 
1209
  parse_status2:
 
1210
    status_end = cur;
 
1211
    if (ParseRules::is_digit(*cur)) {
 
1212
      GETNEXT(done);
 
1213
      goto parse_status2;
 
1214
    }
 
1215
    if (ParseRules::is_ws(*cur)) {
 
1216
      GETNEXT(done);
 
1217
      goto parse_reason1;
 
1218
    }
 
1219
    goto done;
 
1220
 
 
1221
  parse_reason1:
 
1222
    if (ParseRules::is_ws(*cur)) {
 
1223
      GETNEXT(done);
 
1224
      goto parse_reason1;
 
1225
    }
 
1226
    reason_start = cur;
 
1227
    reason_end = end - 1;
 
1228
    while ((reason_end >= line_start) && (ParseRules::is_cr(*reason_end) || ParseRules::is_lf(*reason_end))) {
 
1229
      reason_end -= 1;
 
1230
    }
 
1231
    reason_end += 1;
 
1232
    goto done;
 
1233
 
 
1234
  eoh:
 
1235
    *start = old_start;
 
1236
    return PARSE_DONE;
 
1237
 
 
1238
  done:
 
1239
    if (!version_start || !version_end) {
 
1240
      return PARSE_DONE;
 
1241
    }
 
1242
 
 
1243
    http_hdr_version_set(hh, http_parse_version(version_start, version_end));
 
1244
 
 
1245
    if (status_start && status_end)
 
1246
      http_hdr_status_set(hh, http_parse_status(status_start, status_end));
 
1247
 
 
1248
    if (reason_start && reason_end) {
 
1249
      http_hdr_reason_set(heap, hh, reason_start, (int) (reason_end - reason_start), must_copy_strings);
 
1250
    }
 
1251
 
 
1252
    end = real_end;
 
1253
    parser->m_parsing_http = false;
 
1254
  }
 
1255
 
 
1256
  return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
 
1257
}
 
1258
 
 
1259
/*-------------------------------------------------------------------------
 
1260
  -------------------------------------------------------------------------*/
 
1261
 
 
1262
HTTPStatus
 
1263
http_parse_status(const char *start, const char *end)
 
1264
{
 
1265
  int status = 0;
 
1266
 
 
1267
  while ((start != end) && ParseRules::is_space(*start)) {
 
1268
    start += 1;
 
1269
  }
 
1270
 
 
1271
  while ((start != end) && ParseRules::is_digit(*start)) {
 
1272
    status = (status * 10) + (*start++ - '0');
 
1273
  }
 
1274
 
 
1275
  return (HTTPStatus) status;
 
1276
}
 
1277
 
 
1278
/*-------------------------------------------------------------------------
 
1279
  -------------------------------------------------------------------------*/
 
1280
 
 
1281
int32_t
 
1282
http_parse_version(const char *start, const char *end)
 
1283
{
 
1284
  int maj;
 
1285
  int min;
 
1286
 
 
1287
  if ((end - start) < 8) {
 
1288
    return HTTP_VERSION(0, 9);
 
1289
  }
 
1290
 
 
1291
  if (((start[0] == 'H') || (start[0] == 'h')) &&
 
1292
      ((start[1] == 'T') || (start[1] == 't')) &&
 
1293
      ((start[2] == 'T') || (start[2] == 't')) && ((start[3] == 'P') || (start[3] == 'p')) && (start[4] == '/')) {
 
1294
    start += 5;
 
1295
 
 
1296
    maj = 0;
 
1297
    min = 0;
 
1298
 
 
1299
    while ((start != end) && ParseRules::is_digit(*start)) {
 
1300
      maj = (maj * 10) + (*start - '0');
 
1301
      start += 1;
 
1302
    }
 
1303
 
 
1304
    if (*start == '.') {
 
1305
      start += 1;
 
1306
    }
 
1307
 
 
1308
    while ((start != end) && ParseRules::is_digit(*start)) {
 
1309
      min = (min * 10) + (*start - '0');
 
1310
      start += 1;
 
1311
    }
 
1312
 
 
1313
    return HTTP_VERSION(maj, min);
 
1314
  }
 
1315
 
 
1316
  return HTTP_VERSION(0, 9);
 
1317
}
 
1318
 
 
1319
/*-------------------------------------------------------------------------
 
1320
  -------------------------------------------------------------------------*/
 
1321
 
 
1322
static char *
 
1323
http_str_store(Arena * arena, const char *str, int length)
 
1324
{
 
1325
  const char *wks;
 
1326
  int idx = hdrtoken_tokenize(str, length, &wks);
 
1327
  if (idx < 0) {
 
1328
    return arena->str_store(str, length);
 
1329
  } else {
 
1330
    return (char *) wks;
 
1331
  }
 
1332
}
 
1333
 
 
1334
/*-------------------------------------------------------------------------
 
1335
  -------------------------------------------------------------------------*/
 
1336
 
 
1337
static void
 
1338
http_skip_ws(const char *&buf, int &len)
 
1339
{
 
1340
  while (len > 0 && *buf && ParseRules::is_ws(*buf)) {
 
1341
    buf += 1;
 
1342
    len -= 1;
 
1343
  }
 
1344
}
 
1345
 
 
1346
/*-------------------------------------------------------------------------
 
1347
  -------------------------------------------------------------------------*/
 
1348
 
 
1349
static double
 
1350
http_parse_qvalue(const char *&buf, int &len)
 
1351
{
 
1352
  double val = 1.0;
 
1353
 
 
1354
  if (*buf != ';') {
 
1355
    return val;
 
1356
  }
 
1357
 
 
1358
  buf += 1;
 
1359
  len -= 1;
 
1360
 
 
1361
  while (len > 0 && *buf) {
 
1362
    http_skip_ws(buf, len);
 
1363
 
 
1364
    if (*buf == 'q') {
 
1365
      buf += 1;
 
1366
      len -= 1;
 
1367
      http_skip_ws(buf, len);
 
1368
 
 
1369
      if (*buf == '=') {
 
1370
        double n;
 
1371
        int f;
 
1372
 
 
1373
        buf += 1;
 
1374
        len -= 1;
 
1375
        http_skip_ws(buf, len);
 
1376
 
 
1377
        n = 0.0;
 
1378
        while (len > 0 && *buf && ParseRules::is_digit(*buf)) {
 
1379
          n = (n * 10) + (*buf++ - '0');
 
1380
          len -= 1;
 
1381
        }
 
1382
 
 
1383
        if (*buf == '.') {
 
1384
          buf += 1;
 
1385
          len -= 1;
 
1386
 
 
1387
          f = 10;
 
1388
          while (len > 0 && *buf && ParseRules::is_digit(*buf)) {
 
1389
            n += (*buf++ - '0') / (double) f;
 
1390
            f *= 10;
 
1391
            len -= 1;
 
1392
          }
 
1393
        }
 
1394
 
 
1395
        val = n;
 
1396
      }
 
1397
    } else {
 
1398
      // The current parameter is not a q-value, so go to the next param.
 
1399
      while (len > 0 && *buf) {
 
1400
        if (*buf != ';') {
 
1401
          buf += 1;
 
1402
          len -= 1;
 
1403
        } else {
 
1404
          // Move to the character after the semicolon.
 
1405
          buf += 1;
 
1406
          len -= 1;
 
1407
          break;
 
1408
        }
 
1409
      }
 
1410
    }
 
1411
  }
 
1412
 
 
1413
  return val;
 
1414
}
 
1415
 
 
1416
/*-------------------------------------------------------------------------
 
1417
  -------------------------------------------------------------------------*/
 
1418
 
 
1419
 
 
1420
/*-------------------------------------------------------------------------
 
1421
  TE        = "TE" ":" #( t-codings )
 
1422
  t-codings = "trailers" | ( transfer-extension [ accept-params ] )
 
1423
  -------------------------------------------------------------------------*/
 
1424
 
 
1425
HTTPValTE *
 
1426
http_parse_te(const char *buf, int len, Arena * arena)
 
1427
{
 
1428
  HTTPValTE *val;
 
1429
  const char *s;
 
1430
 
 
1431
  http_skip_ws(buf, len);
 
1432
 
 
1433
  s = buf;
 
1434
 
 
1435
  while (len > 0 && *buf && (*buf != ';')) {
 
1436
    buf += 1;
 
1437
    len -= 1;
 
1438
  }
 
1439
 
 
1440
  val = (HTTPValTE *) arena->alloc(sizeof(HTTPValTE));
 
1441
  val->encoding = http_str_store(arena, s, (int) (buf - s));
 
1442
  val->qvalue = http_parse_qvalue(buf, len);
 
1443
 
 
1444
  return val;
 
1445
}
 
1446
 
 
1447
void
 
1448
HTTPHdr::_fill_target_cache() const
 
1449
{
 
1450
  URL* url = this->url_get();
 
1451
  m_target_in_url = false;
 
1452
  m_port_in_header = false;
 
1453
  // Check in the URL first, then the HOST field.
 
1454
  if (0 != (m_host = url->host_get(&m_host_length))) {
 
1455
    m_target_in_url = true;
 
1456
    m_port = url->port_get();
 
1457
    m_port_in_header = 0 != url->port_get_raw();
 
1458
  } else if (0 != (m_host = const_cast<HTTPHdr*>(this)->value_get(MIME_FIELD_HOST, MIME_LEN_HOST, &m_host_length))) {
 
1459
    // Check for port in the host.
 
1460
    char const* colon = static_cast<char const*>(memchr(m_host, ':', m_host_length));
 
1461
    
 
1462
    if (colon) {
 
1463
      m_host_length = colon - m_host; // Length of just the host in the value.
 
1464
      m_port = 0;
 
1465
      for ( ++colon ; is_digit(*colon) ; ++colon )
 
1466
        m_port = m_port * 10 + *colon - '0';
 
1467
      m_port_in_header = 0 != m_port;
 
1468
    }
 
1469
    m_port = url_canonicalize_port(url->m_url_impl->m_url_type, m_port);
 
1470
  } else {
 
1471
    m_host_length = 0; // reset in case any earlier check corrupted it
 
1472
  }
 
1473
  m_target_cached = true;
 
1474
}
 
1475
 
 
1476
void
 
1477
HTTPHdr::set_url_target_from_host_field(URL* url) {
 
1478
  this->_test_and_fill_target_cache();
 
1479
 
 
1480
  if (!url) {
 
1481
    // Use local cached URL and don't copy if the target
 
1482
    // is already there.
 
1483
    if (!m_target_in_url && m_host_length) {
 
1484
      m_url_cached.host_set(m_host, m_host_length);
 
1485
      if (m_port_in_header) m_url_cached.port_set(m_port);
 
1486
      m_target_in_url = true; // it's there now.
 
1487
    }
 
1488
  } else {
 
1489
    url->host_set(m_host, m_host_length);
 
1490
    if (m_port_in_header) url->port_set(m_port);
 
1491
  }
 
1492
}
 
1493
 
 
1494
// Very ugly, but a proper implementation will require
 
1495
// rewriting the URL class and all of its clients so that
 
1496
// clients access the URL through the HTTP header instance
 
1497
// unless they really need low level access. The header would
 
1498
// need to either keep two versions of the URL (pristine
 
1499
// and effective) or URl would have to provide access to
 
1500
// the URL printer.
 
1501
char*
 
1502
HTTPHdr::url_string_get(Arena* arena, int* length) {
 
1503
  char *zret = 0;
 
1504
 
 
1505
  if (length) *length = 0;
 
1506
  this->_test_and_fill_target_cache();
 
1507
  if (m_url_cached.valid()) {
 
1508
    URLImpl* ui = m_url_cached.m_url_impl;
 
1509
    bool should_reset_host = false;
 
1510
    bool should_reset_port = false;
 
1511
    char port_buff[10];
 
1512
 
 
1513
    /* Get dirty. We reach in to the URL implementation to
 
1514
       set the host and port if
 
1515
       1) They are not already set and
 
1516
       2) The values were in a HTTP header field.
 
1517
    */
 
1518
 
 
1519
    if (!m_target_in_url && m_host_length) {
 
1520
      assert(0 == ui->m_ptr_host); // shouldn't be non-zero if not in URL.
 
1521
      ui->m_ptr_host = m_host;
 
1522
      ui->m_len_host = m_host_length;
 
1523
      should_reset_host = true;
 
1524
    }
 
1525
 
 
1526
    if (0 == m_url_cached.port_get_raw() && m_port_in_header) {
 
1527
      assert(0 == ui->m_ptr_port); // shouldn't be set if not in URL.
 
1528
      ui->m_ptr_port = port_buff;
 
1529
      ui->m_len_port = sprintf(port_buff, "%.5d", m_port);
 
1530
      should_reset_port = true;
 
1531
    }
 
1532
 
 
1533
    zret = m_url_cached.string_get(arena, length);
 
1534
    if (should_reset_host) { ui->m_ptr_host = 0; ui->m_len_host = 0; }
 
1535
    if (should_reset_port) { ui->m_ptr_port = 0; ui->m_len_port = 0; }
 
1536
 }
 
1537
 
 
1538
  return zret;
 
1539
}
 
1540
 
 
1541
/***********************************************************************
 
1542
 *                                                                     *
 
1543
 *                        M A R S H A L I N G                          *
 
1544
 *                                                                     *
 
1545
 ***********************************************************************/
 
1546
 
 
1547
int
 
1548
HTTPHdr::unmarshal(char *buf, int len, RefCountObj * block_ref)
 
1549
{
 
1550
  m_heap = (HdrHeap *) buf;
 
1551
 
 
1552
  int res = m_heap->unmarshal(len,
 
1553
                              HDR_HEAP_OBJ_HTTP_HEADER,
 
1554
                              (HdrHeapObjImpl **) & m_http,
 
1555
                              block_ref);
 
1556
 
 
1557
  if (res > 0) {
 
1558
    m_mime = m_http->m_fields_impl;
 
1559
  } else {
 
1560
    clear();
 
1561
  }
 
1562
 
 
1563
  return res;
 
1564
}
 
1565
 
 
1566
int
 
1567
HTTPHdrImpl::marshal(MarshalXlate * ptr_xlate, int num_ptr, MarshalXlate * str_xlate, int num_str)
 
1568
{
 
1569
 
 
1570
  if (m_polarity == HTTP_TYPE_REQUEST) {
 
1571
    HDR_MARSHAL_STR(u.req.m_ptr_method, str_xlate, num_str);
 
1572
    HDR_MARSHAL_PTR(u.req.m_url_impl, URLImpl, ptr_xlate, num_ptr);
 
1573
  } else if (m_polarity == HTTP_TYPE_RESPONSE) {
 
1574
    HDR_MARSHAL_STR(u.resp.m_ptr_reason, str_xlate, num_str);
 
1575
  } else {
 
1576
    ink_release_assert(!"unknown m_polarity");
 
1577
  }
 
1578
 
 
1579
  HDR_MARSHAL_PTR(m_fields_impl, MIMEHdrImpl, ptr_xlate, num_ptr);
 
1580
 
 
1581
  return 0;
 
1582
}
 
1583
 
 
1584
 
 
1585
void
 
1586
HTTPHdrImpl::unmarshal(intptr_t offset)
 
1587
{
 
1588
 
 
1589
  if (m_polarity == HTTP_TYPE_REQUEST) {
 
1590
    HDR_UNMARSHAL_STR(u.req.m_ptr_method, offset);
 
1591
    HDR_UNMARSHAL_PTR(u.req.m_url_impl, URLImpl, offset);
 
1592
  } else if (m_polarity == HTTP_TYPE_RESPONSE) {
 
1593
    HDR_UNMARSHAL_STR(u.resp.m_ptr_reason, offset);
 
1594
  } else {
 
1595
    ink_release_assert(!"unknown m_polarity");
 
1596
  }
 
1597
 
 
1598
  HDR_UNMARSHAL_PTR(m_fields_impl, MIMEHdrImpl, offset);
 
1599
}
 
1600
 
 
1601
 
 
1602
void
 
1603
HTTPHdrImpl::move_strings(HdrStrHeap * new_heap)
 
1604
{
 
1605
  if (m_polarity == HTTP_TYPE_REQUEST) {
 
1606
    HDR_MOVE_STR(u.req.m_ptr_method, u.req.m_len_method);
 
1607
  } else if (m_polarity == HTTP_TYPE_RESPONSE) {
 
1608
    HDR_MOVE_STR(u.resp.m_ptr_reason, u.resp.m_len_reason);
 
1609
  } else {
 
1610
    ink_release_assert(!"unknown m_polarity");
 
1611
  }
 
1612
}
 
1613
 
 
1614
void
 
1615
HTTPHdrImpl::check_strings(HeapCheck * heaps, int num_heaps)
 
1616
{
 
1617
 
 
1618
  if (m_polarity == HTTP_TYPE_REQUEST) {
 
1619
    CHECK_STR(u.req.m_ptr_method, u.req.m_len_method, heaps, num_heaps);
 
1620
  } else if (m_polarity == HTTP_TYPE_RESPONSE) {
 
1621
    CHECK_STR(u.resp.m_ptr_reason, u.resp.m_len_reason, heaps, num_heaps);
 
1622
  } else {
 
1623
    ink_release_assert(!"unknown m_polarity");
 
1624
  }
 
1625
}
 
1626
 
 
1627
ClassAllocator<HTTPCacheAlt> httpCacheAltAllocator("httpCacheAltAllocator");
 
1628
 
 
1629
/*-------------------------------------------------------------------------
 
1630
  -------------------------------------------------------------------------*/
 
1631
HTTPCacheAlt::HTTPCacheAlt():
 
1632
m_magic(CACHE_ALT_MAGIC_ALIVE), m_writeable(1),
 
1633
m_unmarshal_len(-1),
 
1634
m_id(-1), m_rid(-1), m_request_hdr(),
 
1635
m_response_hdr(), m_request_sent_time(0), m_response_received_time(0), m_ext_buffer(NULL)
 
1636
{
 
1637
 
 
1638
  m_object_key[0] = 0;
 
1639
  m_object_key[1] = 0;
 
1640
  m_object_key[2] = 0;
 
1641
  m_object_key[3] = 0;
 
1642
  m_object_size[0] = 0;
 
1643
  m_object_size[1] = 0;
 
1644
}
 
1645
 
 
1646
void
 
1647
HTTPCacheAlt::destroy()
 
1648
{
 
1649
  ink_assert(m_magic == CACHE_ALT_MAGIC_ALIVE);
 
1650
  ink_assert(m_writeable);
 
1651
  m_magic = CACHE_ALT_MAGIC_DEAD;
 
1652
  m_writeable = 0;
 
1653
  m_request_hdr.destroy();
 
1654
  m_response_hdr.destroy();
 
1655
  httpCacheAltAllocator.free(this);
 
1656
}
 
1657
 
 
1658
void
 
1659
HTTPCacheAlt::copy(HTTPCacheAlt * to_copy)
 
1660
{
 
1661
 
 
1662
  m_magic = to_copy->m_magic;
 
1663
  // m_writeable =      to_copy->m_writeable;
 
1664
  m_unmarshal_len = to_copy->m_unmarshal_len;
 
1665
  m_id = to_copy->m_id;
 
1666
  m_rid = to_copy->m_rid;
 
1667
  m_object_key[0] = to_copy->m_object_key[0];
 
1668
  m_object_key[1] = to_copy->m_object_key[1];
 
1669
  m_object_key[2] = to_copy->m_object_key[2];
 
1670
  m_object_key[3] = to_copy->m_object_key[3];
 
1671
  m_object_size[0] = to_copy->m_object_size[0];
 
1672
  m_object_size[1] = to_copy->m_object_size[1];
 
1673
 
 
1674
  if (to_copy->m_request_hdr.valid()) {
 
1675
    m_request_hdr.copy(&to_copy->m_request_hdr);
 
1676
  }
 
1677
 
 
1678
  if (to_copy->m_response_hdr.valid()) {
 
1679
    m_response_hdr.copy(&to_copy->m_response_hdr);
 
1680
  }
 
1681
 
 
1682
  m_request_sent_time = to_copy->m_request_sent_time;
 
1683
  m_response_received_time = to_copy->m_response_received_time;
 
1684
}
 
1685
 
 
1686
const int HTTP_ALT_MARSHAL_SIZE = ROUND(sizeof(HTTPCacheAlt), HDR_PTR_SIZE);
 
1687
 
 
1688
void
 
1689
HTTPInfo::create()
 
1690
{
 
1691
  m_alt = httpCacheAltAllocator.alloc();
 
1692
}
 
1693
 
 
1694
void
 
1695
HTTPInfo::copy(HTTPInfo * hi)
 
1696
{
 
1697
 
 
1698
  if (m_alt && m_alt->m_writeable) {
 
1699
    destroy();
 
1700
  }
 
1701
 
 
1702
  create();
 
1703
  m_alt->copy(hi->m_alt);
 
1704
}
 
1705
 
 
1706
 
 
1707
int
 
1708
HTTPInfo::marshal_length()
 
1709
{
 
1710
  int len = HTTP_ALT_MARSHAL_SIZE;
 
1711
 
 
1712
  if (m_alt->m_request_hdr.valid()) {
 
1713
    len += m_alt->m_request_hdr.m_heap->marshal_length();
 
1714
  }
 
1715
 
 
1716
  if (m_alt->m_response_hdr.valid()) {
 
1717
    len += m_alt->m_response_hdr.m_heap->marshal_length();
 
1718
  }
 
1719
 
 
1720
  return len;
 
1721
}
 
1722
 
 
1723
int
 
1724
HTTPInfo::marshal(char *buf, int len)
 
1725
{
 
1726
  int tmp;
 
1727
  int used = 0;
 
1728
  HTTPCacheAlt *marshal_alt = (HTTPCacheAlt *) buf;
 
1729
 
 
1730
  ink_debug_assert(m_alt->m_magic == CACHE_ALT_MAGIC_ALIVE);
 
1731
 
 
1732
  // Make sure the buffer is aligned
 
1733
//    ink_debug_assert(((intptr_t)buf) & 0x3 == 0);
 
1734
 
 
1735
  // Memcpy the whole object so that we can use it
 
1736
  //   live later.  This involves copying a few
 
1737
  //   extra bytes now but will save copying any
 
1738
  //   bytes on the way out of the cache
 
1739
  memcpy(buf, m_alt, sizeof(HTTPCacheAlt));
 
1740
  marshal_alt->m_magic = CACHE_ALT_MAGIC_MARSHALED;
 
1741
  marshal_alt->m_writeable = 0;
 
1742
  marshal_alt->m_unmarshal_len = -1;
 
1743
  marshal_alt->m_ext_buffer = NULL;
 
1744
  buf += HTTP_ALT_MARSHAL_SIZE;
 
1745
  used += HTTP_ALT_MARSHAL_SIZE;
 
1746
 
 
1747
  // The m_{request,response}_hdr->m_heap pointers are converted
 
1748
  //    to zero based offsets from the start of the buffer we're
 
1749
  //    marshalling in to
 
1750
  if (m_alt->m_request_hdr.valid()) {
 
1751
    tmp = m_alt->m_request_hdr.m_heap->marshal(buf, len - used);
 
1752
    marshal_alt->m_request_hdr.m_heap = (HdrHeap *)(intptr_t)used;
 
1753
    ink_assert(((intptr_t) marshal_alt->m_request_hdr.m_heap) < len);
 
1754
    buf += tmp;
 
1755
    used += tmp;
 
1756
  } else {
 
1757
    marshal_alt->m_request_hdr.m_heap = NULL;
 
1758
 
 
1759
  }
 
1760
 
 
1761
  if (m_alt->m_response_hdr.valid()) {
 
1762
    tmp = m_alt->m_response_hdr.m_heap->marshal(buf, len - used);
 
1763
    marshal_alt->m_response_hdr.m_heap = (HdrHeap *)(intptr_t)used;
 
1764
    ink_assert(((intptr_t) marshal_alt->m_response_hdr.m_heap) < len);
 
1765
    used += tmp;
 
1766
  } else {
 
1767
    marshal_alt->m_response_hdr.m_heap = NULL;
 
1768
  }
 
1769
 
 
1770
  // The prior system failed the marshal if there wasn't
 
1771
  //   enough space by measuring the space for every
 
1772
  //   component. Seems much faster to check once to
 
1773
  //   see if we spammed memory
 
1774
  ink_release_assert(used <= len);
 
1775
 
 
1776
  return used;
 
1777
}
 
1778
 
 
1779
int
 
1780
HTTPInfo::unmarshal(char *buf, int len, RefCountObj * block_ref)
 
1781
{
 
1782
  HTTPCacheAlt *alt = (HTTPCacheAlt *) buf;
 
1783
  int orig_len = len;
 
1784
 
 
1785
  if (alt->m_magic == CACHE_ALT_MAGIC_ALIVE) {
 
1786
    // Already unmarshaled, must be a ram cache
 
1787
    //  it
 
1788
    ink_assert(alt->m_unmarshal_len > 0);
 
1789
    ink_assert(alt->m_unmarshal_len <= len);
 
1790
    return alt->m_unmarshal_len;
 
1791
  } else if (alt->m_magic != CACHE_ALT_MAGIC_MARSHALED) {
 
1792
    ink_assert(!"HTTPInfo::unmarshal bad magic");
 
1793
    return -1;
 
1794
  }
 
1795
 
 
1796
  ink_assert(alt->m_unmarshal_len < 0);
 
1797
  alt->m_magic = CACHE_ALT_MAGIC_ALIVE;
 
1798
  ink_assert(alt->m_writeable == 0);
 
1799
  len -= HTTP_ALT_MARSHAL_SIZE;
 
1800
 
 
1801
  HdrHeap *heap = (HdrHeap *) (alt->m_request_hdr.m_heap ? (buf + (intptr_t) alt->m_request_hdr.m_heap) : 0);
 
1802
  HTTPHdrImpl *hh = NULL;
 
1803
  int tmp;
 
1804
  if (heap != NULL) {
 
1805
 
 
1806
    tmp = heap->unmarshal(len, HDR_HEAP_OBJ_HTTP_HEADER, (HdrHeapObjImpl **) & hh, block_ref);
 
1807
    if (hh == NULL || tmp < 0) {
 
1808
      ink_assert(!"HTTPInfo::request unmarshal failed");
 
1809
      return -1;
 
1810
    }
 
1811
    len -= tmp;
 
1812
    alt->m_request_hdr.m_heap = heap;
 
1813
    alt->m_request_hdr.m_http = hh;
 
1814
    alt->m_request_hdr.m_mime = hh->m_fields_impl;
 
1815
    alt->m_request_hdr.m_url_cached.m_heap = heap;
 
1816
  }
 
1817
 
 
1818
  heap = (HdrHeap *) (alt->m_response_hdr.m_heap ? (buf + (intptr_t) alt->m_response_hdr.m_heap) : 0);
 
1819
  if (heap != NULL) {
 
1820
    tmp = heap->unmarshal(len, HDR_HEAP_OBJ_HTTP_HEADER, (HdrHeapObjImpl **) & hh, block_ref);
 
1821
    if (hh == NULL || tmp < 0) {
 
1822
      ink_assert(!"HTTPInfo::response unmarshal failed");
 
1823
      return -1;
 
1824
    }
 
1825
    len -= tmp;
 
1826
 
 
1827
    alt->m_response_hdr.m_heap = heap;
 
1828
    alt->m_response_hdr.m_http = hh;
 
1829
    alt->m_response_hdr.m_mime = hh->m_fields_impl;
 
1830
  }
 
1831
 
 
1832
  alt->m_unmarshal_len = orig_len - len;
 
1833
 
 
1834
  return alt->m_unmarshal_len;
 
1835
}
 
1836
 
 
1837
// bool HTTPInfo::check_marshalled(char* buf, int len)
 
1838
//  Checks a marhshalled HTTPInfo buffer to make
 
1839
//    sure it's sane.  Returns true if sane, false otherwise
 
1840
//
 
1841
bool
 
1842
HTTPInfo::check_marshalled(char *buf, int len)
 
1843
{
 
1844
  HTTPCacheAlt *alt = (HTTPCacheAlt *) buf;
 
1845
 
 
1846
  if (alt->m_magic != CACHE_ALT_MAGIC_MARSHALED) {
 
1847
    return false;
 
1848
  }
 
1849
 
 
1850
  if (alt->m_writeable != false) {
 
1851
    return false;
 
1852
  }
 
1853
 
 
1854
  if (len < HTTP_ALT_MARSHAL_SIZE) {
 
1855
    return false;
 
1856
  }
 
1857
 
 
1858
  if (alt->m_request_hdr.m_heap == NULL) {
 
1859
    return false;
 
1860
  }
 
1861
 
 
1862
  if ((intptr_t) alt->m_request_hdr.m_heap > len) {
 
1863
    return false;
 
1864
  }
 
1865
 
 
1866
  HdrHeap *heap = (HdrHeap *) (buf + (intptr_t) alt->m_request_hdr.m_heap);
 
1867
  if (heap->check_marshalled(len) == false) {
 
1868
    return false;
 
1869
  }
 
1870
 
 
1871
  if (alt->m_response_hdr.m_heap == NULL) {
 
1872
    return false;
 
1873
  }
 
1874
 
 
1875
  if ((intptr_t) alt->m_response_hdr.m_heap > len) {
 
1876
    return false;
 
1877
  }
 
1878
 
 
1879
  heap = (HdrHeap *) (buf + (intptr_t) alt->m_response_hdr.m_heap);
 
1880
  if (heap->check_marshalled(len) == false) {
 
1881
    return false;
 
1882
  }
 
1883
 
 
1884
  return true;
 
1885
}
 
1886
 
 
1887
 
 
1888
// void HTTPInfo::set_buffer_reference(RefCountObj* block_ref)
 
1889
//
 
1890
//    Setting a buffer reference for the alt is separate from
 
1891
//     the unmarshalling operation because the clustering
 
1892
//     utilizes the system differently than cache does
 
1893
//    The cache maintains external refcounting of the buffer that
 
1894
//     the alt is in & doesn't always destroy the alt when its
 
1895
//     done with it because it figures it doesn't need to since
 
1896
//     it is managing the buffer
 
1897
//    The receiver of ClusterRPC system has the alt manage the
 
1898
//     buffer itself and therefore needs to call this function
 
1899
//     to set up the reference
 
1900
//
 
1901
void
 
1902
HTTPInfo::set_buffer_reference(RefCountObj * block_ref)
 
1903
{
 
1904
  ink_assert(m_alt->m_magic == CACHE_ALT_MAGIC_ALIVE);
 
1905
 
 
1906
  // Free existing reference
 
1907
  if (m_alt->m_ext_buffer != NULL) {
 
1908
    if (m_alt->m_ext_buffer->refcount_dec() == 0) {
 
1909
      m_alt->m_ext_buffer->free();
 
1910
    }
 
1911
  }
 
1912
  // Set up the ref count for the external buffer
 
1913
  //   if there is one
 
1914
  if (block_ref) {
 
1915
    block_ref->refcount_inc();
 
1916
  }
 
1917
 
 
1918
  m_alt->m_ext_buffer = block_ref;
 
1919
}
 
1920
 
 
1921
int
 
1922
HTTPInfo::get_handle(char *buf, int len)
 
1923
{
 
1924
 
 
1925
  // All the offsets have already swizzled to pointers.  All we
 
1926
  //  need to do is set m_alt and make sure things are sane
 
1927
  HTTPCacheAlt *a = (HTTPCacheAlt *) buf;
 
1928
 
 
1929
  if (a->m_magic == CACHE_ALT_MAGIC_ALIVE) {
 
1930
    m_alt = a;
 
1931
    ink_assert(m_alt->m_unmarshal_len > 0);
 
1932
    ink_assert(m_alt->m_unmarshal_len <= len);
 
1933
    return m_alt->m_unmarshal_len;
 
1934
  }
 
1935
 
 
1936
  clear();
 
1937
  return -1;
 
1938
}