PageRenderTime 100ms CodeModel.GetById 18ms app.highlight 72ms RepoModel.GetById 2ms app.codeStats 0ms

/http-parser/http_parser.c

http://github.com/nicolasff/webdis
C | 1591 lines | 1265 code | 222 blank | 104 comment | 401 complexity | 905d5bb8563c67c64c366984ff508ae6 MD5 | raw file
   1/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
   2 *
   3 * Permission is hereby granted, free of charge, to any person obtaining a copy
   4 * of this software and associated documentation files (the "Software"), to
   5 * deal in the Software without restriction, including without limitation the
   6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   7 * sell copies of the Software, and to permit persons to whom the Software is
   8 * furnished to do so, subject to the following conditions:
   9 *
  10 * The above copyright notice and this permission notice shall be included in
  11 * all copies or substantial portions of the Software.
  12 *
  13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19 * IN THE SOFTWARE.
  20 */
  21#include <http_parser.h>
  22#include <assert.h>
  23#include <stddef.h>
  24
  25
  26#ifndef MIN
  27# define MIN(a,b) ((a) < (b) ? (a) : (b))
  28#endif
  29
  30
  31#define CALLBACK2(FOR)                                               \
  32do {                                                                 \
  33  if (settings->on_##FOR) {                                          \
  34    if (0 != settings->on_##FOR(parser)) return (p - data);          \
  35  }                                                                  \
  36} while (0)
  37
  38
  39#define MARK(FOR)                                                    \
  40do {                                                                 \
  41  FOR##_mark = p;                                                    \
  42} while (0)
  43
  44#define CALLBACK_NOCLEAR(FOR)                                        \
  45do {                                                                 \
  46  if (FOR##_mark) {                                                  \
  47    if (settings->on_##FOR) {                                        \
  48      if (0 != settings->on_##FOR(parser,                            \
  49                                 FOR##_mark,                         \
  50                                 p - FOR##_mark))                    \
  51      {                                                              \
  52        return (p - data);                                           \
  53      }                                                              \
  54    }                                                                \
  55  }                                                                  \
  56} while (0)
  57
  58
  59#define CALLBACK(FOR)                                                \
  60do {                                                                 \
  61  CALLBACK_NOCLEAR(FOR);                                             \
  62  FOR##_mark = NULL;                                                 \
  63} while (0)
  64
  65
  66#define PROXY_CONNECTION "proxy-connection"
  67#define CONNECTION "connection"
  68#define CONTENT_LENGTH "content-length"
  69#define TRANSFER_ENCODING "transfer-encoding"
  70#define UPGRADE "upgrade"
  71#define CHUNKED "chunked"
  72#define KEEP_ALIVE "keep-alive"
  73#define CLOSE "close"
  74
  75
  76static const char *method_strings[] =
  77  { "DELETE"
  78  , "GET"
  79  , "HEAD"
  80  , "POST"
  81  , "PUT"
  82  , "CONNECT"
  83  , "OPTIONS"
  84  , "TRACE"
  85  , "COPY"
  86  , "LOCK"
  87  , "MKCOL"
  88  , "MOVE"
  89  , "PROPFIND"
  90  , "PROPPATCH"
  91  , "UNLOCK"
  92  , "REPORT"
  93  , "MKACTIVITY"
  94  , "CHECKOUT"
  95  , "MERGE"
  96  , "M-SEARCH"
  97  , "NOTIFY"
  98  , "SUBSCRIBE"
  99  , "UNSUBSCRIBE"
 100  };
 101
 102
 103/* Tokens as defined by rfc 2616. Also lowercases them.
 104 *        token       = 1*<any CHAR except CTLs or separators>
 105 *     separators     = "(" | ")" | "<" | ">" | "@"
 106 *                    | "," | ";" | ":" | "\" | <">
 107 *                    | "/" | "[" | "]" | "?" | "="
 108 *                    | "{" | "}" | SP | HT
 109 */
 110static const char tokens[256] = {
 111/*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */
 112        0,       0,       0,       0,       0,       0,       0,       0,
 113/*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */
 114        0,       0,       0,       0,       0,       0,       0,       0,
 115/*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */
 116        0,       0,       0,       0,       0,       0,       0,       0,
 117/*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */
 118        0,       0,       0,       0,       0,       0,       0,       0,
 119/*  32 sp    33  !    34  "    35  #    36  $    37  %    38  &    39  '  */
 120       ' ',      '!',     '"',     '#',     '$',     '%',     '&',    '\'',
 121/*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */
 122        0,       0,      '*',     '+',      0,      '-',     '.',     '/',
 123/*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */
 124       '0',     '1',     '2',     '3',     '4',     '5',     '6',     '7',
 125/*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */
 126       '8',     '9',      0,       0,       0,       0,       0,       0,
 127/*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */
 128        0,      'a',     'b',     'c',     'd',     'e',     'f',     'g',
 129/*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */
 130       'h',     'i',     'j',     'k',     'l',     'm',     'n',     'o',
 131/*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */
 132       'p',     'q',     'r',     's',     't',     'u',     'v',     'w',
 133/*  88  X    89  Y    90  Z    91  [    92  \    93  ]    94  ^    95  _  */
 134       'x',     'y',     'z',      0,       0,       0,      '^',     '_',
 135/*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */
 136       '`',     'a',     'b',     'c',     'd',     'e',     'f',     'g',
 137/* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */
 138       'h',     'i',     'j',     'k',     'l',     'm',     'n',     'o',
 139/* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */
 140       'p',     'q',     'r',     's',     't',     'u',     'v',     'w',
 141/* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */
 142       'x',     'y',     'z',      0,      '|',     '}',     '~',       0 };
 143
 144
 145static const int8_t unhex[256] =
 146  {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
 147  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
 148  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
 149  , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
 150  ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
 151  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
 152  ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
 153  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
 154  };
 155
 156
 157static const uint8_t normal_url_char[256] = {
 158/*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */
 159        0,       0,       0,       0,       0,       0,       0,       0,
 160/*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */
 161        0,       0,       0,       0,       0,       0,       0,       0,
 162/*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */
 163        0,       0,       0,       0,       0,       0,       0,       0,
 164/*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */
 165        0,       0,       0,       0,       0,       0,       0,       0,
 166/*  32 sp    33  !    34  "    35  #    36  $    37  %    38  &    39  '  */
 167        0,       1,       1,       0,       1,       1,       1,       1,
 168/*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */
 169        1,       1,       1,       1,       1,       1,       1,       1,
 170/*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */
 171        1,       1,       1,       1,       1,       1,       1,       1,
 172/*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */
 173        1,       1,       1,       1,       1,       1,       1,       0,
 174/*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */
 175        1,       1,       1,       1,       1,       1,       1,       1,
 176/*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */
 177        1,       1,       1,       1,       1,       1,       1,       1,
 178/*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */
 179        1,       1,       1,       1,       1,       1,       1,       1,
 180/*  88  X    89  Y    90  Z    91  [    92  \    93  ]    94  ^    95  _  */
 181        1,       1,       1,       1,       1,       1,       1,       1,
 182/*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */
 183        1,       1,       1,       1,       1,       1,       1,       1,
 184/* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */
 185        1,       1,       1,       1,       1,       1,       1,       1,
 186/* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */
 187        1,       1,       1,       1,       1,       1,       1,       1,
 188/* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */
 189        1,       1,       1,       1,       1,       1,       1,       0 };
 190
 191
 192enum state
 193  { s_dead = 1 /* important that this is > 0 */
 194
 195  , s_start_req_or_res
 196  , s_res_or_resp_H
 197  , s_start_res
 198  , s_res_H
 199  , s_res_HT
 200  , s_res_HTT
 201  , s_res_HTTP
 202  , s_res_first_http_major
 203  , s_res_http_major
 204  , s_res_first_http_minor
 205  , s_res_http_minor
 206  , s_res_first_status_code
 207  , s_res_status_code
 208  , s_res_status
 209  , s_res_line_almost_done
 210
 211  , s_start_req
 212
 213  , s_req_method
 214  , s_req_spaces_before_url
 215  , s_req_schema
 216  , s_req_schema_slash
 217  , s_req_schema_slash_slash
 218  , s_req_host
 219  , s_req_port
 220  , s_req_path
 221  , s_req_query_string_start
 222  , s_req_query_string
 223  , s_req_fragment_start
 224  , s_req_fragment
 225  , s_req_http_start
 226  , s_req_http_H
 227  , s_req_http_HT
 228  , s_req_http_HTT
 229  , s_req_http_HTTP
 230  , s_req_first_http_major
 231  , s_req_http_major
 232  , s_req_first_http_minor
 233  , s_req_http_minor
 234  , s_req_line_almost_done
 235
 236  , s_header_field_start
 237  , s_header_field
 238  , s_header_value_start
 239  , s_header_value
 240
 241  , s_header_almost_done
 242
 243  , s_headers_almost_done
 244  /* Important: 's_headers_almost_done' must be the last 'header' state. All
 245   * states beyond this must be 'body' states. It is used for overflow
 246   * checking. See the PARSING_HEADER() macro.
 247   */
 248  , s_chunk_size_start
 249  , s_chunk_size
 250  , s_chunk_size_almost_done
 251  , s_chunk_parameters
 252  , s_chunk_data
 253  , s_chunk_data_almost_done
 254  , s_chunk_data_done
 255
 256  , s_body_identity
 257  , s_body_identity_eof
 258  };
 259
 260
 261#define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING))
 262
 263
 264enum header_states
 265  { h_general = 0
 266  , h_C
 267  , h_CO
 268  , h_CON
 269
 270  , h_matching_connection
 271  , h_matching_proxy_connection
 272  , h_matching_content_length
 273  , h_matching_transfer_encoding
 274  , h_matching_upgrade
 275
 276  , h_connection
 277  , h_content_length
 278  , h_transfer_encoding
 279  , h_upgrade
 280
 281  , h_matching_transfer_encoding_chunked
 282  , h_matching_connection_keep_alive
 283  , h_matching_connection_close
 284
 285  , h_transfer_encoding_chunked
 286  , h_connection_keep_alive
 287  , h_connection_close
 288  };
 289
 290
 291#define CR '\r'
 292#define LF '\n'
 293#define LOWER(c) (unsigned char)(c | 0x20)
 294#define TOKEN(c) tokens[(unsigned char)c]
 295
 296
 297#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
 298
 299
 300#if HTTP_PARSER_STRICT
 301# define STRICT_CHECK(cond) if (cond) goto error
 302# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
 303#else
 304# define STRICT_CHECK(cond)
 305# define NEW_MESSAGE() start_state
 306#endif
 307
 308
 309size_t http_parser_execute (http_parser *parser,
 310                            const http_parser_settings *settings,
 311                            const char *data,
 312                            size_t len)
 313{
 314  char c, ch;
 315  const char *p = data, *pe;
 316  int64_t to_read;
 317
 318  enum state state = (enum state) parser->state;
 319  enum header_states header_state = (enum header_states) parser->header_state;
 320  uint64_t index = parser->index;
 321  uint64_t nread = parser->nread;
 322
 323  if (len == 0) {
 324    if (state == s_body_identity_eof) {
 325      CALLBACK2(message_complete);
 326    }
 327    return 0;
 328  }
 329
 330  /* technically we could combine all of these (except for url_mark) into one
 331     variable, saving stack space, but it seems more clear to have them
 332     separated. */
 333  const char *header_field_mark = 0;
 334  const char *header_value_mark = 0;
 335  const char *fragment_mark = 0;
 336  const char *query_string_mark = 0;
 337  const char *path_mark = 0;
 338  const char *url_mark = 0;
 339
 340  if (state == s_header_field)
 341    header_field_mark = data;
 342  if (state == s_header_value)
 343    header_value_mark = data;
 344  if (state == s_req_fragment)
 345    fragment_mark = data;
 346  if (state == s_req_query_string)
 347    query_string_mark = data;
 348  if (state == s_req_path)
 349    path_mark = data;
 350  if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash
 351      || state == s_req_schema_slash_slash || state == s_req_port
 352      || state == s_req_query_string_start || state == s_req_query_string
 353      || state == s_req_host
 354      || state == s_req_fragment_start || state == s_req_fragment)
 355    url_mark = data;
 356
 357  for (p=data, pe=data+len; p != pe; p++) {
 358    ch = *p;
 359
 360    if (PARSING_HEADER(state)) {
 361      ++nread;
 362      /* Buffer overflow attack */
 363      if (nread > HTTP_MAX_HEADER_SIZE) goto error;
 364    }
 365
 366    switch (state) {
 367
 368      case s_dead:
 369        /* this state is used after a 'Connection: close' message
 370         * the parser will error out if it reads another message
 371         */
 372        goto error;
 373
 374      case s_start_req_or_res:
 375      {
 376        if (ch == CR || ch == LF)
 377          break;
 378        parser->flags = 0;
 379        parser->content_length = -1;
 380
 381        CALLBACK2(message_begin);
 382
 383        if (ch == 'H')
 384          state = s_res_or_resp_H;
 385        else {
 386          parser->type = HTTP_REQUEST;
 387          goto start_req_method_assign;
 388        }
 389        break;
 390      }
 391
 392      case s_res_or_resp_H:
 393        if (ch == 'T') {
 394          parser->type = HTTP_RESPONSE;
 395          state = s_res_HT;
 396        } else {
 397          if (ch != 'E') goto error;
 398          parser->type = HTTP_REQUEST;
 399          parser->method = HTTP_HEAD;
 400          index = 2;
 401          state = s_req_method;
 402        }
 403        break;
 404
 405      case s_start_res:
 406      {
 407        parser->flags = 0;
 408        parser->content_length = -1;
 409
 410        CALLBACK2(message_begin);
 411
 412        switch (ch) {
 413          case 'H':
 414            state = s_res_H;
 415            break;
 416
 417          case CR:
 418          case LF:
 419            break;
 420
 421          default:
 422            goto error;
 423        }
 424        break;
 425      }
 426
 427      case s_res_H:
 428        STRICT_CHECK(ch != 'T');
 429        state = s_res_HT;
 430        break;
 431
 432      case s_res_HT:
 433        STRICT_CHECK(ch != 'T');
 434        state = s_res_HTT;
 435        break;
 436
 437      case s_res_HTT:
 438        STRICT_CHECK(ch != 'P');
 439        state = s_res_HTTP;
 440        break;
 441
 442      case s_res_HTTP:
 443        STRICT_CHECK(ch != '/');
 444        state = s_res_first_http_major;
 445        break;
 446
 447      case s_res_first_http_major:
 448        if (ch < '1' || ch > '9') goto error;
 449        parser->http_major = ch - '0';
 450        state = s_res_http_major;
 451        break;
 452
 453      /* major HTTP version or dot */
 454      case s_res_http_major:
 455      {
 456        if (ch == '.') {
 457          state = s_res_first_http_minor;
 458          break;
 459        }
 460
 461        if (ch < '0' || ch > '9') goto error;
 462
 463        parser->http_major *= 10;
 464        parser->http_major += ch - '0';
 465
 466        if (parser->http_major > 999) goto error;
 467        break;
 468      }
 469
 470      /* first digit of minor HTTP version */
 471      case s_res_first_http_minor:
 472        if (ch < '0' || ch > '9') goto error;
 473        parser->http_minor = ch - '0';
 474        state = s_res_http_minor;
 475        break;
 476
 477      /* minor HTTP version or end of request line */
 478      case s_res_http_minor:
 479      {
 480        if (ch == ' ') {
 481          state = s_res_first_status_code;
 482          break;
 483        }
 484
 485        if (ch < '0' || ch > '9') goto error;
 486
 487        parser->http_minor *= 10;
 488        parser->http_minor += ch - '0';
 489
 490        if (parser->http_minor > 999) goto error;
 491        break;
 492      }
 493
 494      case s_res_first_status_code:
 495      {
 496        if (ch < '0' || ch > '9') {
 497          if (ch == ' ') {
 498            break;
 499          }
 500          goto error;
 501        }
 502        parser->status_code = ch - '0';
 503        state = s_res_status_code;
 504        break;
 505      }
 506
 507      case s_res_status_code:
 508      {
 509        if (ch < '0' || ch > '9') {
 510          switch (ch) {
 511            case ' ':
 512              state = s_res_status;
 513              break;
 514            case CR:
 515              state = s_res_line_almost_done;
 516              break;
 517            case LF:
 518              state = s_header_field_start;
 519              break;
 520            default:
 521              goto error;
 522          }
 523          break;
 524        }
 525
 526        parser->status_code *= 10;
 527        parser->status_code += ch - '0';
 528
 529        if (parser->status_code > 999) goto error;
 530        break;
 531      }
 532
 533      case s_res_status:
 534        /* the human readable status. e.g. "NOT FOUND"
 535         * we are not humans so just ignore this */
 536        if (ch == CR) {
 537          state = s_res_line_almost_done;
 538          break;
 539        }
 540
 541        if (ch == LF) {
 542          state = s_header_field_start;
 543          break;
 544        }
 545        break;
 546
 547      case s_res_line_almost_done:
 548        STRICT_CHECK(ch != LF);
 549        state = s_header_field_start;
 550        break;
 551
 552      case s_start_req:
 553      {
 554        if (ch == CR || ch == LF)
 555          break;
 556        parser->flags = 0;
 557        parser->content_length = -1;
 558
 559        CALLBACK2(message_begin);
 560
 561        if (ch < 'A' || 'Z' < ch) goto error;
 562
 563      start_req_method_assign:
 564        parser->method = (enum http_method) 0;
 565        index = 1;
 566        switch (ch) {
 567          case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
 568          case 'D': parser->method = HTTP_DELETE; break;
 569          case 'G': parser->method = HTTP_GET; break;
 570          case 'H': parser->method = HTTP_HEAD; break;
 571          case 'L': parser->method = HTTP_LOCK; break;
 572          case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
 573          case 'N': parser->method = HTTP_NOTIFY; break;
 574          case 'O': parser->method = HTTP_OPTIONS; break;
 575          case 'P': parser->method = HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break;
 576          case 'R': parser->method = HTTP_REPORT; break;
 577          case 'S': parser->method = HTTP_SUBSCRIBE; break;
 578          case 'T': parser->method = HTTP_TRACE; break;
 579          case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
 580          default: goto error;
 581        }
 582        state = s_req_method;
 583        break;
 584      }
 585
 586      case s_req_method:
 587      {
 588        if (ch == '\0')
 589          goto error;
 590
 591        const char *matcher = method_strings[parser->method];
 592        if (ch == ' ' && matcher[index] == '\0') {
 593          state = s_req_spaces_before_url;
 594        } else if (ch == matcher[index]) {
 595          ; /* nada */
 596        } else if (parser->method == HTTP_CONNECT) {
 597          if (index == 1 && ch == 'H') {
 598            parser->method = HTTP_CHECKOUT;
 599          } else if (index == 2  && ch == 'P') {
 600            parser->method = HTTP_COPY;
 601          }
 602        } else if (parser->method == HTTP_MKCOL) {
 603          if (index == 1 && ch == 'O') {
 604            parser->method = HTTP_MOVE;
 605          } else if (index == 1 && ch == 'E') {
 606            parser->method = HTTP_MERGE;
 607          } else if (index == 1 && ch == '-') {
 608            parser->method = HTTP_MSEARCH;
 609          } else if (index == 2 && ch == 'A') {
 610            parser->method = HTTP_MKACTIVITY;
 611          }
 612        } else if (index == 1 && parser->method == HTTP_POST && ch == 'R') {
 613          parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
 614        } else if (index == 1 && parser->method == HTTP_POST && ch == 'U') {
 615          parser->method = HTTP_PUT;
 616        } else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') {
 617          parser->method = HTTP_UNSUBSCRIBE;
 618        } else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
 619          parser->method = HTTP_PROPPATCH;
 620        } else {
 621          goto error;
 622        }
 623
 624        ++index;
 625        break;
 626      }
 627      case s_req_spaces_before_url:
 628      {
 629        if (ch == ' ') break;
 630
 631        if (ch == '/' || ch == '*') {
 632          MARK(url);
 633          MARK(path);
 634          state = s_req_path;
 635          break;
 636        }
 637
 638        c = LOWER(ch);
 639
 640        if (c >= 'a' && c <= 'z') {
 641          MARK(url);
 642          state = s_req_schema;
 643          break;
 644        }
 645
 646        goto error;
 647      }
 648
 649      case s_req_schema:
 650      {
 651        c = LOWER(ch);
 652
 653        if (c >= 'a' && c <= 'z') break;
 654
 655        if (ch == ':') {
 656          state = s_req_schema_slash;
 657          break;
 658        } else if (ch == '.') {
 659          state = s_req_host;
 660          break;
 661        } else if ('0' <= ch && ch <= '9') {
 662          state = s_req_host;
 663          break;
 664        }
 665
 666        goto error;
 667      }
 668
 669      case s_req_schema_slash:
 670        STRICT_CHECK(ch != '/');
 671        state = s_req_schema_slash_slash;
 672        break;
 673
 674      case s_req_schema_slash_slash:
 675        STRICT_CHECK(ch != '/');
 676        state = s_req_host;
 677        break;
 678
 679      case s_req_host:
 680      {
 681        c = LOWER(ch);
 682        if (c >= 'a' && c <= 'z') break;
 683        if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break;
 684        switch (ch) {
 685          case ':':
 686            state = s_req_port;
 687            break;
 688          case '/':
 689            MARK(path);
 690            state = s_req_path;
 691            break;
 692          case ' ':
 693            /* The request line looks like:
 694             *   "GET http://foo.bar.com HTTP/1.1"
 695             * That is, there is no path.
 696             */
 697            CALLBACK(url);
 698            state = s_req_http_start;
 699            break;
 700          default:
 701            goto error;
 702        }
 703        break;
 704      }
 705
 706      case s_req_port:
 707      {
 708        if (ch >= '0' && ch <= '9') break;
 709        switch (ch) {
 710          case '/':
 711            MARK(path);
 712            state = s_req_path;
 713            break;
 714          case ' ':
 715            /* The request line looks like:
 716             *   "GET http://foo.bar.com:1234 HTTP/1.1"
 717             * That is, there is no path.
 718             */
 719            CALLBACK(url);
 720            state = s_req_http_start;
 721            break;
 722          default:
 723            goto error;
 724        }
 725        break;
 726      }
 727
 728      case s_req_path:
 729      {
 730        if (normal_url_char[(unsigned char)ch]) break;
 731
 732        switch (ch) {
 733          case ' ':
 734            CALLBACK(url);
 735            CALLBACK(path);
 736            state = s_req_http_start;
 737            break;
 738          case CR:
 739            CALLBACK(url);
 740            CALLBACK(path);
 741            parser->http_major = 0;
 742            parser->http_minor = 9;
 743            state = s_req_line_almost_done;
 744            break;
 745          case LF:
 746            CALLBACK(url);
 747            CALLBACK(path);
 748            parser->http_major = 0;
 749            parser->http_minor = 9;
 750            state = s_header_field_start;
 751            break;
 752          case '?':
 753            CALLBACK(path);
 754            state = s_req_query_string_start;
 755            break;
 756          case '#':
 757            CALLBACK(path);
 758            state = s_req_fragment_start;
 759            break;
 760          default:
 761            goto error;
 762        }
 763        break;
 764      }
 765
 766      case s_req_query_string_start:
 767      {
 768        if (normal_url_char[(unsigned char)ch]) {
 769          MARK(query_string);
 770          state = s_req_query_string;
 771          break;
 772        }
 773
 774        switch (ch) {
 775          case '?':
 776            break; /* XXX ignore extra '?' ... is this right? */
 777          case ' ':
 778            CALLBACK(url);
 779            state = s_req_http_start;
 780            break;
 781          case CR:
 782            CALLBACK(url);
 783            parser->http_major = 0;
 784            parser->http_minor = 9;
 785            state = s_req_line_almost_done;
 786            break;
 787          case LF:
 788            CALLBACK(url);
 789            parser->http_major = 0;
 790            parser->http_minor = 9;
 791            state = s_header_field_start;
 792            break;
 793          case '#':
 794            state = s_req_fragment_start;
 795            break;
 796          default:
 797            goto error;
 798        }
 799        break;
 800      }
 801
 802      case s_req_query_string:
 803      {
 804        if (normal_url_char[(unsigned char)ch]) break;
 805
 806        switch (ch) {
 807          case '?':
 808            /* allow extra '?' in query string */
 809            break;
 810          case ' ':
 811            CALLBACK(url);
 812            CALLBACK(query_string);
 813            state = s_req_http_start;
 814            break;
 815          case CR:
 816            CALLBACK(url);
 817            CALLBACK(query_string);
 818            parser->http_major = 0;
 819            parser->http_minor = 9;
 820            state = s_req_line_almost_done;
 821            break;
 822          case LF:
 823            CALLBACK(url);
 824            CALLBACK(query_string);
 825            parser->http_major = 0;
 826            parser->http_minor = 9;
 827            state = s_header_field_start;
 828            break;
 829          case '#':
 830            CALLBACK(query_string);
 831            state = s_req_fragment_start;
 832            break;
 833          default:
 834            goto error;
 835        }
 836        break;
 837      }
 838
 839      case s_req_fragment_start:
 840      {
 841        if (normal_url_char[(unsigned char)ch]) {
 842          MARK(fragment);
 843          state = s_req_fragment;
 844          break;
 845        }
 846
 847        switch (ch) {
 848          case ' ':
 849            CALLBACK(url);
 850            state = s_req_http_start;
 851            break;
 852          case CR:
 853            CALLBACK(url);
 854            parser->http_major = 0;
 855            parser->http_minor = 9;
 856            state = s_req_line_almost_done;
 857            break;
 858          case LF:
 859            CALLBACK(url);
 860            parser->http_major = 0;
 861            parser->http_minor = 9;
 862            state = s_header_field_start;
 863            break;
 864          case '?':
 865            MARK(fragment);
 866            state = s_req_fragment;
 867            break;
 868          case '#':
 869            break;
 870          default:
 871            goto error;
 872        }
 873        break;
 874      }
 875
 876      case s_req_fragment:
 877      {
 878        if (normal_url_char[(unsigned char)ch]) break;
 879
 880        switch (ch) {
 881          case ' ':
 882            CALLBACK(url);
 883            CALLBACK(fragment);
 884            state = s_req_http_start;
 885            break;
 886          case CR:
 887            CALLBACK(url);
 888            CALLBACK(fragment);
 889            parser->http_major = 0;
 890            parser->http_minor = 9;
 891            state = s_req_line_almost_done;
 892            break;
 893          case LF:
 894            CALLBACK(url);
 895            CALLBACK(fragment);
 896            parser->http_major = 0;
 897            parser->http_minor = 9;
 898            state = s_header_field_start;
 899            break;
 900          case '?':
 901          case '#':
 902            break;
 903          default:
 904            goto error;
 905        }
 906        break;
 907      }
 908
 909      case s_req_http_start:
 910        switch (ch) {
 911          case 'H':
 912            state = s_req_http_H;
 913            break;
 914          case ' ':
 915            break;
 916          default:
 917            goto error;
 918        }
 919        break;
 920
 921      case s_req_http_H:
 922        STRICT_CHECK(ch != 'T');
 923        state = s_req_http_HT;
 924        break;
 925
 926      case s_req_http_HT:
 927        STRICT_CHECK(ch != 'T');
 928        state = s_req_http_HTT;
 929        break;
 930
 931      case s_req_http_HTT:
 932        STRICT_CHECK(ch != 'P');
 933        state = s_req_http_HTTP;
 934        break;
 935
 936      case s_req_http_HTTP:
 937        STRICT_CHECK(ch != '/');
 938        state = s_req_first_http_major;
 939        break;
 940
 941      /* first digit of major HTTP version */
 942      case s_req_first_http_major:
 943        if (ch < '1' || ch > '9') goto error;
 944        parser->http_major = ch - '0';
 945        state = s_req_http_major;
 946        break;
 947
 948      /* major HTTP version or dot */
 949      case s_req_http_major:
 950      {
 951        if (ch == '.') {
 952          state = s_req_first_http_minor;
 953          break;
 954        }
 955
 956        if (ch < '0' || ch > '9') goto error;
 957
 958        parser->http_major *= 10;
 959        parser->http_major += ch - '0';
 960
 961        if (parser->http_major > 999) goto error;
 962        break;
 963      }
 964
 965      /* first digit of minor HTTP version */
 966      case s_req_first_http_minor:
 967        if (ch < '0' || ch > '9') goto error;
 968        parser->http_minor = ch - '0';
 969        state = s_req_http_minor;
 970        break;
 971
 972      /* minor HTTP version or end of request line */
 973      case s_req_http_minor:
 974      {
 975        if (ch == CR) {
 976          state = s_req_line_almost_done;
 977          break;
 978        }
 979
 980        if (ch == LF) {
 981          state = s_header_field_start;
 982          break;
 983        }
 984
 985        /* XXX allow spaces after digit? */
 986
 987        if (ch < '0' || ch > '9') goto error;
 988
 989        parser->http_minor *= 10;
 990        parser->http_minor += ch - '0';
 991
 992        if (parser->http_minor > 999) goto error;
 993        break;
 994      }
 995
 996      /* end of request line */
 997      case s_req_line_almost_done:
 998      {
 999        if (ch != LF) goto error;
1000        state = s_header_field_start;
1001        break;
1002      }
1003
1004      case s_header_field_start:
1005      {
1006        if (ch == CR) {
1007          state = s_headers_almost_done;
1008          break;
1009        }
1010
1011        if (ch == LF) {
1012          /* they might be just sending \n instead of \r\n so this would be
1013           * the second \n to denote the end of headers*/
1014          state = s_headers_almost_done;
1015          goto headers_almost_done;
1016        }
1017
1018        c = TOKEN(ch);
1019
1020        if (!c) goto error;
1021
1022        MARK(header_field);
1023
1024        index = 0;
1025        state = s_header_field;
1026
1027        switch (c) {
1028          case 'c':
1029            header_state = h_C;
1030            break;
1031
1032          case 'p':
1033            header_state = h_matching_proxy_connection;
1034            break;
1035
1036          case 't':
1037            header_state = h_matching_transfer_encoding;
1038            break;
1039
1040          case 'u':
1041            header_state = h_matching_upgrade;
1042            break;
1043
1044          default:
1045            header_state = h_general;
1046            break;
1047        }
1048        break;
1049      }
1050
1051      case s_header_field:
1052      {
1053        c = TOKEN(ch);
1054
1055        if (c) {
1056          switch (header_state) {
1057            case h_general:
1058              break;
1059
1060            case h_C:
1061              index++;
1062              header_state = (c == 'o' ? h_CO : h_general);
1063              break;
1064
1065            case h_CO:
1066              index++;
1067              header_state = (c == 'n' ? h_CON : h_general);
1068              break;
1069
1070            case h_CON:
1071              index++;
1072              switch (c) {
1073                case 'n':
1074                  header_state = h_matching_connection;
1075                  break;
1076                case 't':
1077                  header_state = h_matching_content_length;
1078                  break;
1079                default:
1080                  header_state = h_general;
1081                  break;
1082              }
1083              break;
1084
1085            /* connection */
1086
1087            case h_matching_connection:
1088              index++;
1089              if (index > sizeof(CONNECTION)-1
1090                  || c != CONNECTION[index]) {
1091                header_state = h_general;
1092              } else if (index == sizeof(CONNECTION)-2) {
1093                header_state = h_connection;
1094              }
1095              break;
1096
1097            /* proxy-connection */
1098
1099            case h_matching_proxy_connection:
1100              index++;
1101              if (index > sizeof(PROXY_CONNECTION)-1
1102                  || c != PROXY_CONNECTION[index]) {
1103                header_state = h_general;
1104              } else if (index == sizeof(PROXY_CONNECTION)-2) {
1105                header_state = h_connection;
1106              }
1107              break;
1108
1109            /* content-length */
1110
1111            case h_matching_content_length:
1112              index++;
1113              if (index > sizeof(CONTENT_LENGTH)-1
1114                  || c != CONTENT_LENGTH[index]) {
1115                header_state = h_general;
1116              } else if (index == sizeof(CONTENT_LENGTH)-2) {
1117                header_state = h_content_length;
1118              }
1119              break;
1120
1121            /* transfer-encoding */
1122
1123            case h_matching_transfer_encoding:
1124              index++;
1125              if (index > sizeof(TRANSFER_ENCODING)-1
1126                  || c != TRANSFER_ENCODING[index]) {
1127                header_state = h_general;
1128              } else if (index == sizeof(TRANSFER_ENCODING)-2) {
1129                header_state = h_transfer_encoding;
1130              }
1131              break;
1132
1133            /* upgrade */
1134
1135            case h_matching_upgrade:
1136              index++;
1137              if (index > sizeof(UPGRADE)-1
1138                  || c != UPGRADE[index]) {
1139                header_state = h_general;
1140              } else if (index == sizeof(UPGRADE)-2) {
1141                header_state = h_upgrade;
1142              }
1143              break;
1144
1145            case h_connection:
1146            case h_content_length:
1147            case h_transfer_encoding:
1148            case h_upgrade:
1149              if (ch != ' ') header_state = h_general;
1150              break;
1151
1152            default:
1153              assert(0 && "Unknown header_state");
1154              break;
1155          }
1156          break;
1157        }
1158
1159        if (ch == ':') {
1160          CALLBACK(header_field);
1161          state = s_header_value_start;
1162          break;
1163        }
1164
1165        if (ch == CR) {
1166          state = s_header_almost_done;
1167          CALLBACK(header_field);
1168          break;
1169        }
1170
1171        if (ch == LF) {
1172          CALLBACK(header_field);
1173          state = s_header_field_start;
1174          break;
1175        }
1176
1177        goto error;
1178      }
1179
1180      case s_header_value_start:
1181      {
1182        if (ch == ' ') break;
1183
1184        MARK(header_value);
1185
1186        state = s_header_value;
1187        index = 0;
1188
1189        c = LOWER(ch);
1190
1191        if (ch == CR) {
1192          CALLBACK(header_value);
1193          header_state = h_general;
1194          state = s_header_almost_done;
1195          break;
1196        }
1197
1198        if (ch == LF) {
1199          CALLBACK(header_value);
1200          state = s_header_field_start;
1201          break;
1202        }
1203
1204        switch (header_state) {
1205          case h_upgrade:
1206            parser->flags |= F_UPGRADE;
1207            header_state = h_general;
1208            break;
1209
1210          case h_transfer_encoding:
1211            /* looking for 'Transfer-Encoding: chunked' */
1212            if ('c' == c) {
1213              header_state = h_matching_transfer_encoding_chunked;
1214            } else {
1215              header_state = h_general;
1216            }
1217            break;
1218
1219          case h_content_length:
1220            if (ch < '0' || ch > '9') goto error;
1221            parser->content_length = ch - '0';
1222            break;
1223
1224          case h_connection:
1225            /* looking for 'Connection: keep-alive' */
1226            if (c == 'k') {
1227              header_state = h_matching_connection_keep_alive;
1228            /* looking for 'Connection: close' */
1229            } else if (c == 'c') {
1230              header_state = h_matching_connection_close;
1231            } else {
1232              header_state = h_general;
1233            }
1234            break;
1235
1236          default:
1237            header_state = h_general;
1238            break;
1239        }
1240        break;
1241      }
1242
1243      case s_header_value:
1244      {
1245        c = LOWER(ch);
1246
1247        if (ch == CR) {
1248          CALLBACK(header_value);
1249          state = s_header_almost_done;
1250          break;
1251        }
1252
1253        if (ch == LF) {
1254          CALLBACK(header_value);
1255          goto header_almost_done;
1256        }
1257
1258        switch (header_state) {
1259          case h_general:
1260            break;
1261
1262          case h_connection:
1263          case h_transfer_encoding:
1264            assert(0 && "Shouldn't get here.");
1265            break;
1266
1267          case h_content_length:
1268            if (ch == ' ') break;
1269            if (ch < '0' || ch > '9') goto error;
1270            parser->content_length *= 10;
1271            parser->content_length += ch - '0';
1272            break;
1273
1274          /* Transfer-Encoding: chunked */
1275          case h_matching_transfer_encoding_chunked:
1276            index++;
1277            if (index > sizeof(CHUNKED)-1
1278                || c != CHUNKED[index]) {
1279              header_state = h_general;
1280            } else if (index == sizeof(CHUNKED)-2) {
1281              header_state = h_transfer_encoding_chunked;
1282            }
1283            break;
1284
1285          /* looking for 'Connection: keep-alive' */
1286          case h_matching_connection_keep_alive:
1287            index++;
1288            if (index > sizeof(KEEP_ALIVE)-1
1289                || c != KEEP_ALIVE[index]) {
1290              header_state = h_general;
1291            } else if (index == sizeof(KEEP_ALIVE)-2) {
1292              header_state = h_connection_keep_alive;
1293            }
1294            break;
1295
1296          /* looking for 'Connection: close' */
1297          case h_matching_connection_close:
1298            index++;
1299            if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) {
1300              header_state = h_general;
1301            } else if (index == sizeof(CLOSE)-2) {
1302              header_state = h_connection_close;
1303            }
1304            break;
1305
1306          case h_transfer_encoding_chunked:
1307          case h_connection_keep_alive:
1308          case h_connection_close:
1309            if (ch != ' ') header_state = h_general;
1310            break;
1311
1312          default:
1313            state = s_header_value;
1314            header_state = h_general;
1315            break;
1316        }
1317        break;
1318      }
1319
1320      case s_header_almost_done:
1321      header_almost_done:
1322      {
1323        STRICT_CHECK(ch != LF);
1324
1325        state = s_header_field_start;
1326
1327        switch (header_state) {
1328          case h_connection_keep_alive:
1329            parser->flags |= F_CONNECTION_KEEP_ALIVE;
1330            break;
1331          case h_connection_close:
1332            parser->flags |= F_CONNECTION_CLOSE;
1333            break;
1334          case h_transfer_encoding_chunked:
1335            parser->flags |= F_CHUNKED;
1336            break;
1337          default:
1338            break;
1339        }
1340        break;
1341      }
1342
1343      case s_headers_almost_done:
1344      headers_almost_done:
1345      {
1346        STRICT_CHECK(ch != LF);
1347
1348        if (parser->flags & F_TRAILING) {
1349          /* End of a chunked request */
1350          CALLBACK2(message_complete);
1351          state = NEW_MESSAGE();
1352          break;
1353        }
1354
1355        nread = 0;
1356
1357        if (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT) {
1358          parser->upgrade = 1;
1359        }
1360
1361        /* Here we call the headers_complete callback. This is somewhat
1362         * different than other callbacks because if the user returns 1, we
1363         * will interpret that as saying that this message has no body. This
1364         * is needed for the annoying case of recieving a response to a HEAD
1365         * request.
1366         */
1367        if (settings->on_headers_complete) {
1368          switch (settings->on_headers_complete(parser)) {
1369            case 0:
1370              break;
1371
1372            case 1:
1373              parser->flags |= F_SKIPBODY;
1374              break;
1375
1376            default:
1377              return p - data; /* Error */
1378          }
1379        }
1380
1381        /* Exit, the rest of the connect is in a different protocol. */
1382        if (parser->upgrade) {
1383          CALLBACK2(message_complete);
1384          return (p - data);
1385        }
1386
1387        if (parser->flags & F_SKIPBODY) {
1388          CALLBACK2(message_complete);
1389          state = NEW_MESSAGE();
1390        } else if (parser->flags & F_CHUNKED) {
1391          /* chunked encoding - ignore Content-Length header */
1392          state = s_chunk_size_start;
1393        } else {
1394          if (parser->content_length == 0) {
1395            /* Content-Length header given but zero: Content-Length: 0\r\n */
1396            CALLBACK2(message_complete);
1397            state = NEW_MESSAGE();
1398          } else if (parser->content_length > 0) {
1399            /* Content-Length header given and non-zero */
1400            state = s_body_identity;
1401          } else {
1402            if (parser->type == HTTP_REQUEST || http_should_keep_alive(parser)) {
1403              /* Assume content-length 0 - read the next */
1404              CALLBACK2(message_complete);
1405              state = NEW_MESSAGE();
1406            } else {
1407              /* Read body until EOF */
1408              state = s_body_identity_eof;
1409            }
1410          }
1411        }
1412
1413        break;
1414      }
1415
1416      case s_body_identity:
1417        to_read = MIN(pe - p, (int64_t)parser->content_length);
1418        if (to_read > 0) {
1419          if (settings->on_body) settings->on_body(parser, p, to_read);
1420          p += to_read - 1;
1421          parser->content_length -= to_read;
1422          if (parser->content_length == 0) {
1423            CALLBACK2(message_complete);
1424            state = NEW_MESSAGE();
1425          }
1426        }
1427        break;
1428
1429      /* read until EOF */
1430      case s_body_identity_eof:
1431        to_read = pe - p;
1432        if (to_read > 0) {
1433          if (settings->on_body) settings->on_body(parser, p, to_read);
1434          p += to_read - 1;
1435        }
1436        break;
1437
1438      case s_chunk_size_start:
1439      {
1440        assert(parser->flags & F_CHUNKED);
1441
1442        c = unhex[(unsigned char)ch];
1443        if (c == -1) goto error;
1444        parser->content_length = c;
1445        state = s_chunk_size;
1446        break;
1447      }
1448
1449      case s_chunk_size:
1450      {
1451        assert(parser->flags & F_CHUNKED);
1452
1453        if (ch == CR) {
1454          state = s_chunk_size_almost_done;
1455          break;
1456        }
1457
1458        c = unhex[(unsigned char)ch];
1459
1460        if (c == -1) {
1461          if (ch == ';' || ch == ' ') {
1462            state = s_chunk_parameters;
1463            break;
1464          }
1465          goto error;
1466        }
1467
1468        parser->content_length *= 16;
1469        parser->content_length += c;
1470        break;
1471      }
1472
1473      case s_chunk_parameters:
1474      {
1475        assert(parser->flags & F_CHUNKED);
1476        /* just ignore this shit. TODO check for overflow */
1477        if (ch == CR) {
1478          state = s_chunk_size_almost_done;
1479          break;
1480        }
1481        break;
1482      }
1483
1484      case s_chunk_size_almost_done:
1485      {
1486        assert(parser->flags & F_CHUNKED);
1487        STRICT_CHECK(ch != LF);
1488
1489        if (parser->content_length == 0) {
1490          parser->flags |= F_TRAILING;
1491          state = s_header_field_start;
1492        } else {
1493          state = s_chunk_data;
1494        }
1495        break;
1496      }
1497
1498      case s_chunk_data:
1499      {
1500        assert(parser->flags & F_CHUNKED);
1501
1502        to_read = MIN(pe - p, (int64_t)(parser->content_length));
1503
1504        if (to_read > 0) {
1505          if (settings->on_body) settings->on_body(parser, p, to_read);
1506          p += to_read - 1;
1507        }
1508
1509        if (to_read == parser->content_length) {
1510          state = s_chunk_data_almost_done;
1511        }
1512
1513        parser->content_length -= to_read;
1514        break;
1515      }
1516
1517      case s_chunk_data_almost_done:
1518        assert(parser->flags & F_CHUNKED);
1519        STRICT_CHECK(ch != CR);
1520        state = s_chunk_data_done;
1521        break;
1522
1523      case s_chunk_data_done:
1524        assert(parser->flags & F_CHUNKED);
1525        STRICT_CHECK(ch != LF);
1526        state = s_chunk_size_start;
1527        break;
1528
1529      default:
1530        assert(0 && "unhandled state");
1531        goto error;
1532    }
1533  }
1534
1535  CALLBACK_NOCLEAR(header_field);
1536  CALLBACK_NOCLEAR(header_value);
1537  CALLBACK_NOCLEAR(fragment);
1538  CALLBACK_NOCLEAR(query_string);
1539  CALLBACK_NOCLEAR(path);
1540  CALLBACK_NOCLEAR(url);
1541
1542  parser->state = state;
1543  parser->header_state = header_state;
1544  parser->index = index;
1545  parser->nread = nread;
1546
1547  return len;
1548
1549error:
1550  parser->state = s_dead;
1551  return (p - data);
1552}
1553
1554
1555int
1556http_should_keep_alive (http_parser *parser)
1557{
1558  if (parser->http_major > 0 && parser->http_minor > 0) {
1559    /* HTTP/1.1 */
1560    if (parser->flags & F_CONNECTION_CLOSE) {
1561      return 0;
1562    } else {
1563      return 1;
1564    }
1565  } else {
1566    /* HTTP/1.0 or earlier */
1567    if (parser->flags & F_CONNECTION_KEEP_ALIVE) {
1568      return 1;
1569    } else {
1570      return 0;
1571    }
1572  }
1573}
1574
1575
1576const char * http_method_str (enum http_method m)
1577{
1578  return method_strings[m];
1579}
1580
1581
1582void
1583http_parser_init (http_parser *parser, enum http_parser_type t)
1584{
1585  parser->type = t;
1586  parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
1587  parser->nread = 0;
1588  parser->upgrade = 0;
1589  parser->flags = 0;
1590  parser->method = 0;
1591}