Coverage Report

Created: 2025-12-31 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/http-parser/http_parser.c
Line
Count
Source
1
/* Copyright Joyent, Inc. and other Node contributors.
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
#include <ctype.h>
25
#include <string.h>
26
#include <limits.h>
27
28
static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE;
29
30
#ifndef ULLONG_MAX
31
# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
32
#endif
33
34
#ifndef MIN
35
0
# define MIN(a,b) ((a) < (b) ? (a) : (b))
36
#endif
37
38
#ifndef ARRAY_SIZE
39
0
# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
40
#endif
41
42
#ifndef BIT_AT
43
# define BIT_AT(a, i)                                                \
44
1.68M
  (!!((unsigned int) (a)[(unsigned int) (i) >> 3] &                  \
45
1.68M
   (1 << ((unsigned int) (i) & 7))))
46
#endif
47
48
#ifndef ELEM_AT
49
0
# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
50
#endif
51
52
0
#define SET_ERRNO(e)                                                 \
53
0
do {                                                                 \
54
0
  parser->nread = nread;                                             \
55
0
  parser->http_errno = (e);                                          \
56
0
} while(0)
57
58
0
#define CURRENT_STATE() p_state
59
0
#define UPDATE_STATE(V) p_state = (enum state) (V);
60
0
#define RETURN(V)                                                    \
61
0
do {                                                                 \
62
0
  parser->nread = nread;                                             \
63
0
  parser->state = CURRENT_STATE();                                   \
64
0
  return (V);                                                        \
65
0
} while (0);
66
#define REEXECUTE()                                                  \
67
0
  goto reexecute;                                                    \
68
69
70
#ifdef __GNUC__
71
0
# define LIKELY(X) __builtin_expect(!!(X), 1)
72
0
# define UNLIKELY(X) __builtin_expect(!!(X), 0)
73
#else
74
# define LIKELY(X) (X)
75
# define UNLIKELY(X) (X)
76
#endif
77
78
79
/* Run the notify callback FOR, returning ER if it fails */
80
0
#define CALLBACK_NOTIFY_(FOR, ER)                                    \
81
0
do {                                                                 \
82
0
  assert(HTTP_PARSER_ERRNO(parser) == HPE_OK);                       \
83
0
                                                                     \
84
0
  if (LIKELY(settings->on_##FOR)) {                                  \
85
0
    parser->state = CURRENT_STATE();                                 \
86
0
    if (UNLIKELY(0 != settings->on_##FOR(parser))) {                 \
87
0
      SET_ERRNO(HPE_CB_##FOR);                                       \
88
0
    }                                                                \
89
0
    UPDATE_STATE(parser->state);                                     \
90
0
                                                                     \
91
0
    /* We either errored above or got paused; get out */             \
92
0
    if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) {             \
93
0
      return (ER);                                                   \
94
0
    }                                                                \
95
0
  }                                                                  \
96
0
} while (0)
97
98
/* Run the notify callback FOR and consume the current byte */
99
0
#define CALLBACK_NOTIFY(FOR)            CALLBACK_NOTIFY_(FOR, p - data + 1)
100
101
/* Run the notify callback FOR and don't consume the current byte */
102
0
#define CALLBACK_NOTIFY_NOADVANCE(FOR)  CALLBACK_NOTIFY_(FOR, p - data)
103
104
/* Run data callback FOR with LEN bytes, returning ER if it fails */
105
0
#define CALLBACK_DATA_(FOR, LEN, ER)                                 \
106
0
do {                                                                 \
107
0
  assert(HTTP_PARSER_ERRNO(parser) == HPE_OK);                       \
108
0
                                                                     \
109
0
  if (FOR##_mark) {                                                  \
110
0
    if (LIKELY(settings->on_##FOR)) {                                \
111
0
      parser->state = CURRENT_STATE();                               \
112
0
      if (UNLIKELY(0 !=                                              \
113
0
                   settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \
114
0
        SET_ERRNO(HPE_CB_##FOR);                                     \
115
0
      }                                                              \
116
0
      UPDATE_STATE(parser->state);                                   \
117
0
                                                                     \
118
0
      /* We either errored above or got paused; get out */           \
119
0
      if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) {           \
120
0
        return (ER);                                                 \
121
0
      }                                                              \
122
0
    }                                                                \
123
0
    FOR##_mark = NULL;                                               \
124
0
  }                                                                  \
125
0
} while (0)
126
127
/* Run the data callback FOR and consume the current byte */
128
#define CALLBACK_DATA(FOR)                                           \
129
0
    CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
130
131
/* Run the data callback FOR and don't consume the current byte */
132
#define CALLBACK_DATA_NOADVANCE(FOR)                                 \
133
0
    CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
134
135
/* Set the mark FOR; non-destructive if mark is already set */
136
0
#define MARK(FOR)                                                    \
137
0
do {                                                                 \
138
0
  if (!FOR##_mark) {                                                 \
139
0
    FOR##_mark = p;                                                  \
140
0
  }                                                                  \
141
0
} while (0)
142
143
/* Don't allow the total size of the HTTP headers (including the status
144
 * line) to exceed max_header_size.  This check is here to protect
145
 * embedders against denial-of-service attacks where the attacker feeds
146
 * us a never-ending header that the embedder keeps buffering.
147
 *
148
 * This check is arguably the responsibility of embedders but we're doing
149
 * it on the embedder's behalf because most won't bother and this way we
150
 * make the web a little safer.  max_header_size is still far bigger
151
 * than any reasonable request or response so this should never affect
152
 * day-to-day operation.
153
 */
154
0
#define COUNT_HEADER_SIZE(V)                                         \
155
0
do {                                                                 \
156
0
  nread += (uint32_t)(V);                                            \
157
0
  if (UNLIKELY(nread > max_header_size)) {                           \
158
0
    SET_ERRNO(HPE_HEADER_OVERFLOW);                                  \
159
0
    goto error;                                                      \
160
0
  }                                                                  \
161
0
} while (0)
162
163
164
0
#define PROXY_CONNECTION "proxy-connection"
165
0
#define CONNECTION "connection"
166
0
#define CONTENT_LENGTH "content-length"
167
0
#define TRANSFER_ENCODING "transfer-encoding"
168
0
#define UPGRADE "upgrade"
169
0
#define CHUNKED "chunked"
170
0
#define KEEP_ALIVE "keep-alive"
171
0
#define CLOSE "close"
172
173
174
static const char *method_strings[] =
175
  {
176
#define XX(num, name, string) #string,
177
  HTTP_METHOD_MAP(XX)
178
#undef XX
179
  };
180
181
182
/* Tokens as defined by rfc 2616. Also lowercases them.
183
 *        token       = 1*<any CHAR except CTLs or separators>
184
 *     separators     = "(" | ")" | "<" | ">" | "@"
185
 *                    | "," | ";" | ":" | "\" | <">
186
 *                    | "/" | "[" | "]" | "?" | "="
187
 *                    | "{" | "}" | SP | HT
188
 */
189
static const char tokens[256] = {
190
/*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */
191
        0,       0,       0,       0,       0,       0,       0,       0,
192
/*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */
193
        0,       0,       0,       0,       0,       0,       0,       0,
194
/*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */
195
        0,       0,       0,       0,       0,       0,       0,       0,
196
/*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */
197
        0,       0,       0,       0,       0,       0,       0,       0,
198
/*  32 sp    33  !    34  "    35  #    36  $    37  %    38  &    39  '  */
199
       ' ',     '!',      0,      '#',     '$',     '%',     '&',    '\'',
200
/*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */
201
        0,       0,      '*',     '+',      0,      '-',     '.',      0,
202
/*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */
203
       '0',     '1',     '2',     '3',     '4',     '5',     '6',     '7',
204
/*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */
205
       '8',     '9',      0,       0,       0,       0,       0,       0,
206
/*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */
207
        0,      'a',     'b',     'c',     'd',     'e',     'f',     'g',
208
/*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */
209
       'h',     'i',     'j',     'k',     'l',     'm',     'n',     'o',
210
/*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */
211
       'p',     'q',     'r',     's',     't',     'u',     'v',     'w',
212
/*  88  X    89  Y    90  Z    91  [    92  \    93  ]    94  ^    95  _  */
213
       'x',     'y',     'z',      0,       0,       0,      '^',     '_',
214
/*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */
215
       '`',     'a',     'b',     'c',     'd',     'e',     'f',     'g',
216
/* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */
217
       'h',     'i',     'j',     'k',     'l',     'm',     'n',     'o',
218
/* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */
219
       'p',     'q',     'r',     's',     't',     'u',     'v',     'w',
220
/* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */
221
       'x',     'y',     'z',      0,      '|',      0,      '~',       0 };
222
223
224
static const int8_t unhex[256] =
225
  {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
226
  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
227
  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
228
  , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
229
  ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
230
  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
231
  ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
232
  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
233
  };
234
235
236
#if HTTP_PARSER_STRICT
237
# define T(v) 0
238
#else
239
# define T(v) v
240
#endif
241
242
243
static const uint8_t normal_url_char[32] = {
244
/*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */
245
        0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,
246
/*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */
247
        0    | T(2)   |   0    |   0    | T(16)  |   0    |   0    |   0,
248
/*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */
249
        0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,
250
/*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */
251
        0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,
252
/*  32 sp    33  !    34  "    35  #    36  $    37  %    38  &    39  '  */
253
        0    |   2    |   4    |   0    |   16   |   32   |   64   |  128,
254
/*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */
255
        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
256
/*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */
257
        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
258
/*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */
259
        1    |   2    |   4    |   8    |   16   |   32   |   64   |   0,
260
/*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */
261
        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
262
/*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */
263
        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
264
/*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */
265
        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
266
/*  88  X    89  Y    90  Z    91  [    92  \    93  ]    94  ^    95  _  */
267
        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
268
/*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */
269
        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
270
/* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */
271
        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
272
/* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */
273
        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,
274
/* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */
275
        1    |   2    |   4    |   8    |   16   |   32   |   64   |   0, };
276
277
#undef T
278
279
enum state
280
  { s_dead = 1 /* important that this is > 0 */
281
282
  , s_start_req_or_res
283
  , s_res_or_resp_H
284
  , s_start_res
285
  , s_res_H
286
  , s_res_HT
287
  , s_res_HTT
288
  , s_res_HTTP
289
  , s_res_http_major
290
  , s_res_http_dot
291
  , s_res_http_minor
292
  , s_res_http_end
293
  , s_res_first_status_code
294
  , s_res_status_code
295
  , s_res_status_start
296
  , s_res_status
297
  , s_res_line_almost_done
298
299
  , s_start_req
300
301
  , s_req_method
302
  , s_req_spaces_before_url
303
  , s_req_schema
304
  , s_req_schema_slash
305
  , s_req_schema_slash_slash
306
  , s_req_server_start
307
  , s_req_server
308
  , s_req_server_with_at
309
  , s_req_path
310
  , s_req_query_string_start
311
  , s_req_query_string
312
  , s_req_fragment_start
313
  , s_req_fragment
314
  , s_req_http_start
315
  , s_req_http_H
316
  , s_req_http_HT
317
  , s_req_http_HTT
318
  , s_req_http_HTTP
319
  , s_req_http_I
320
  , s_req_http_IC
321
  , s_req_http_major
322
  , s_req_http_dot
323
  , s_req_http_minor
324
  , s_req_http_end
325
  , s_req_line_almost_done
326
327
  , s_header_field_start
328
  , s_header_field
329
  , s_header_value_discard_ws
330
  , s_header_value_discard_ws_almost_done
331
  , s_header_value_discard_lws
332
  , s_header_value_start
333
  , s_header_value
334
  , s_header_value_lws
335
336
  , s_header_almost_done
337
338
  , s_chunk_size_start
339
  , s_chunk_size
340
  , s_chunk_parameters
341
  , s_chunk_size_almost_done
342
343
  , s_headers_almost_done
344
  , s_headers_done
345
346
  /* Important: 's_headers_done' must be the last 'header' state. All
347
   * states beyond this must be 'body' states. It is used for overflow
348
   * checking. See the PARSING_HEADER() macro.
349
   */
350
351
  , s_chunk_data
352
  , s_chunk_data_almost_done
353
  , s_chunk_data_done
354
355
  , s_body_identity
356
  , s_body_identity_eof
357
358
  , s_message_done
359
  };
360
361
362
0
#define PARSING_HEADER(state) (state <= s_headers_done)
363
364
365
enum header_states
366
  { h_general = 0
367
  , h_C
368
  , h_CO
369
  , h_CON
370
371
  , h_matching_connection
372
  , h_matching_proxy_connection
373
  , h_matching_content_length
374
  , h_matching_transfer_encoding
375
  , h_matching_upgrade
376
377
  , h_connection
378
  , h_content_length
379
  , h_content_length_num
380
  , h_content_length_ws
381
  , h_transfer_encoding
382
  , h_upgrade
383
384
  , h_matching_transfer_encoding_token_start
385
  , h_matching_transfer_encoding_chunked
386
  , h_matching_transfer_encoding_token
387
388
  , h_matching_connection_token_start
389
  , h_matching_connection_keep_alive
390
  , h_matching_connection_close
391
  , h_matching_connection_upgrade
392
  , h_matching_connection_token
393
394
  , h_transfer_encoding_chunked
395
  , h_connection_keep_alive
396
  , h_connection_close
397
  , h_connection_upgrade
398
  };
399
400
enum http_host_state
401
  {
402
    s_http_host_dead = 1
403
  , s_http_userinfo_start
404
  , s_http_userinfo
405
  , s_http_host_start
406
  , s_http_host_v6_start
407
  , s_http_host
408
  , s_http_host_v6
409
  , s_http_host_v6_end
410
  , s_http_host_v6_zone_start
411
  , s_http_host_v6_zone
412
  , s_http_host_port_start
413
  , s_http_host_port
414
};
415
416
/* Macros for character classes; depends on strict-mode  */
417
0
#define CR                  '\r'
418
0
#define LF                  '\n'
419
2.98M
#define LOWER(c)            (unsigned char)(c | 0x20)
420
3.11M
#define IS_ALPHA(c)         (LOWER(c) >= 'a' && LOWER(c) <= 'z')
421
486k
#define IS_NUM(c)           ((c) >= '0' && (c) <= '9')
422
2.82M
#define IS_ALPHANUM(c)      (IS_ALPHA(c) || IS_NUM(c))
423
4.26k
#define IS_HEX(c)           (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
424
1.55M
#define IS_MARK(c)          ((c) == '-' || (c) == '_' || (c) == '.' || \
425
362k
  (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
426
1.55M
  (c) == ')')
427
2.09M
#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
428
1.19M
  (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
429
1.19M
  (c) == '$' || (c) == ',')
430
431
0
#define STRICT_TOKEN(c)     ((c == ' ') ? 0 : tokens[(unsigned char)c])
432
433
#if HTTP_PARSER_STRICT
434
#define TOKEN(c)            STRICT_TOKEN(c)
435
#define IS_URL_CHAR(c)      (BIT_AT(normal_url_char, (unsigned char)c))
436
#define IS_HOST_CHAR(c)     (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
437
#else
438
0
#define TOKEN(c)            tokens[(unsigned char)c]
439
#define IS_URL_CHAR(c)                                                         \
440
841k
  (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
441
#define IS_HOST_CHAR(c)                                                        \
442
221k
  (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
443
#endif
444
445
/**
446
 * Verify that a char is a valid visible (printable) US-ASCII
447
 * character or %x80-FF
448
 **/
449
#define IS_HEADER_CHAR(ch)                                                     \
450
0
  (ch == CR || ch == LF || ch == 9 || ((unsigned char)ch > 31 && ch != 127))
451
452
#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
453
454
455
#if HTTP_PARSER_STRICT
456
# define STRICT_CHECK(cond)                                          \
457
do {                                                                 \
458
  if (cond) {                                                        \
459
    SET_ERRNO(HPE_STRICT);                                           \
460
    goto error;                                                      \
461
  }                                                                  \
462
} while (0)
463
# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
464
#else
465
# define STRICT_CHECK(cond)
466
# define NEW_MESSAGE() start_state
467
#endif
468
469
470
/* Map errno values to strings for human-readable output */
471
#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
472
static struct {
473
  const char *name;
474
  const char *description;
475
} http_strerror_tab[] = {
476
  HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
477
};
478
#undef HTTP_STRERROR_GEN
479
480
int http_message_needs_eof(const http_parser *parser);
481
482
/* Our URL parser.
483
 *
484
 * This is designed to be shared by http_parser_execute() for URL validation,
485
 * hence it has a state transition + byte-for-byte interface. In addition, it
486
 * is meant to be embedded in http_parser_parse_url(), which does the dirty
487
 * work of turning state transitions URL components for its API.
488
 *
489
 * This function should only be invoked with non-space characters. It is
490
 * assumed that the caller cares about (and can detect) the transition between
491
 * URL and non-URL states by looking for these.
492
 */
493
static enum state
494
parse_url_char(enum state s, const char ch)
495
2.03M
{
496
2.03M
  if (ch == ' ' || ch == '\r' || ch == '\n') {
497
9
    return s_dead;
498
9
  }
499
500
#if HTTP_PARSER_STRICT
501
  if (ch == '\t' || ch == '\f') {
502
    return s_dead;
503
  }
504
#endif
505
506
2.03M
  switch (s) {
507
963
    case s_req_spaces_before_url:
508
      /* Proxied requests are followed by scheme of an absolute URI (alpha).
509
       * All methods except CONNECT are followed by '/' or '*'.
510
       */
511
512
963
      if (ch == '/' || ch == '*') {
513
143
        return s_req_path;
514
143
      }
515
516
820
      if (IS_ALPHA(ch)) {
517
165
        return s_req_schema;
518
165
      }
519
520
655
      break;
521
522
284k
    case s_req_schema:
523
284k
      if (IS_ALPHA(ch)) {
524
284k
        return s;
525
284k
      }
526
527
144
      if (ch == ':') {
528
81
        return s_req_schema_slash;
529
81
      }
530
531
63
      break;
532
533
80
    case s_req_schema_slash:
534
80
      if (ch == '/') {
535
37
        return s_req_schema_slash_slash;
536
37
      }
537
538
43
      break;
539
540
43
    case s_req_schema_slash_slash:
541
36
      if (ch == '/') {
542
27
        return s_req_server_start;
543
27
      }
544
545
9
      break;
546
547
266
    case s_req_server_with_at:
548
266
      if (ch == '@') {
549
1
        return s_dead;
550
1
      }
551
552
    /* fall through */
553
1.25k
    case s_req_server_start:
554
906k
    case s_req_server:
555
906k
      if (ch == '/') {
556
139
        return s_req_path;
557
139
      }
558
559
906k
      if (ch == '?') {
560
78
        return s_req_query_string_start;
561
78
      }
562
563
906k
      if (ch == '@') {
564
450
        return s_req_server_with_at;
565
450
      }
566
567
905k
      if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
568
905k
        return s_req_server;
569
905k
      }
570
571
88
      break;
572
573
404k
    case s_req_path:
574
404k
      if (IS_URL_CHAR(ch)) {
575
404k
        return s;
576
404k
      }
577
578
186
      switch (ch) {
579
55
        case '?':
580
55
          return s_req_query_string_start;
581
582
113
        case '#':
583
113
          return s_req_fragment_start;
584
186
      }
585
586
18
      break;
587
588
98
    case s_req_query_string_start:
589
436k
    case s_req_query_string:
590
436k
      if (IS_URL_CHAR(ch)) {
591
435k
        return s_req_query_string;
592
435k
      }
593
594
289
      switch (ch) {
595
238
        case '?':
596
          /* allow extra '?' in query string */
597
238
          return s_req_query_string;
598
599
25
        case '#':
600
25
          return s_req_fragment_start;
601
289
      }
602
603
26
      break;
604
605
483
    case s_req_fragment_start:
606
483
      if (IS_URL_CHAR(ch)) {
607
88
        return s_req_fragment;
608
88
      }
609
610
395
      switch (ch) {
611
9
        case '?':
612
9
          return s_req_fragment;
613
614
364
        case '#':
615
364
          return s;
616
395
      }
617
618
22
      break;
619
620
783
    case s_req_fragment:
621
783
      if (IS_URL_CHAR(ch)) {
622
574
        return s;
623
574
      }
624
625
209
      switch (ch) {
626
48
        case '?':
627
191
        case '#':
628
191
          return s;
629
209
      }
630
631
18
      break;
632
633
18
    default:
634
0
      break;
635
2.03M
  }
636
637
  /* We should never fall out of the switch above unless there's an error */
638
942
  return s_dead;
639
2.03M
}
640
641
size_t http_parser_execute (http_parser *parser,
642
                            const http_parser_settings *settings,
643
                            const char *data,
644
                            size_t len)
645
0
{
646
0
  char c, ch;
647
0
  int8_t unhex_val;
648
0
  const char *p = data;
649
0
  const char *header_field_mark = 0;
650
0
  const char *header_value_mark = 0;
651
0
  const char *url_mark = 0;
652
0
  const char *body_mark = 0;
653
0
  const char *status_mark = 0;
654
0
  enum state p_state = (enum state) parser->state;
655
0
  const unsigned int lenient = parser->lenient_http_headers;
656
0
  const unsigned int allow_chunked_length = parser->allow_chunked_length;
657
658
0
  uint32_t nread = parser->nread;
659
660
  /* We're in an error state. Don't bother doing anything. */
661
0
  if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
662
0
    return 0;
663
0
  }
664
665
0
  if (len == 0) {
666
0
    switch (CURRENT_STATE()) {
667
0
      case s_body_identity_eof:
668
        /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
669
         * we got paused.
670
         */
671
0
        CALLBACK_NOTIFY_NOADVANCE(message_complete);
672
0
        return 0;
673
674
0
      case s_dead:
675
0
      case s_start_req_or_res:
676
0
      case s_start_res:
677
0
      case s_start_req:
678
0
        return 0;
679
680
0
      default:
681
0
        SET_ERRNO(HPE_INVALID_EOF_STATE);
682
0
        return 1;
683
0
    }
684
0
  }
685
686
687
0
  if (CURRENT_STATE() == s_header_field)
688
0
    header_field_mark = data;
689
0
  if (CURRENT_STATE() == s_header_value)
690
0
    header_value_mark = data;
691
0
  switch (CURRENT_STATE()) {
692
0
  case s_req_path:
693
0
  case s_req_schema:
694
0
  case s_req_schema_slash:
695
0
  case s_req_schema_slash_slash:
696
0
  case s_req_server_start:
697
0
  case s_req_server:
698
0
  case s_req_server_with_at:
699
0
  case s_req_query_string_start:
700
0
  case s_req_query_string:
701
0
  case s_req_fragment_start:
702
0
  case s_req_fragment:
703
0
    url_mark = data;
704
0
    break;
705
0
  case s_res_status:
706
0
    status_mark = data;
707
0
    break;
708
0
  default:
709
0
    break;
710
0
  }
711
712
0
  for (p=data; p != data + len; p++) {
713
0
    ch = *p;
714
715
0
    if (PARSING_HEADER(CURRENT_STATE()))
716
0
      COUNT_HEADER_SIZE(1);
717
718
0
reexecute:
719
0
    switch (CURRENT_STATE()) {
720
721
0
      case s_dead:
722
        /* this state is used after a 'Connection: close' message
723
         * the parser will error out if it reads another message
724
         */
725
0
        if (LIKELY(ch == CR || ch == LF))
726
0
          break;
727
728
0
        SET_ERRNO(HPE_CLOSED_CONNECTION);
729
0
        goto error;
730
731
0
      case s_start_req_or_res:
732
0
      {
733
0
        if (ch == CR || ch == LF)
734
0
          break;
735
0
        parser->flags = 0;
736
0
        parser->uses_transfer_encoding = 0;
737
0
        parser->content_length = ULLONG_MAX;
738
739
0
        if (ch == 'H') {
740
0
          UPDATE_STATE(s_res_or_resp_H);
741
742
0
          CALLBACK_NOTIFY(message_begin);
743
0
        } else {
744
0
          parser->type = HTTP_REQUEST;
745
0
          UPDATE_STATE(s_start_req);
746
0
          REEXECUTE();
747
0
        }
748
749
0
        break;
750
0
      }
751
752
0
      case s_res_or_resp_H:
753
0
        if (ch == 'T') {
754
0
          parser->type = HTTP_RESPONSE;
755
0
          UPDATE_STATE(s_res_HT);
756
0
        } else {
757
0
          if (UNLIKELY(ch != 'E')) {
758
0
            SET_ERRNO(HPE_INVALID_CONSTANT);
759
0
            goto error;
760
0
          }
761
762
0
          parser->type = HTTP_REQUEST;
763
0
          parser->method = HTTP_HEAD;
764
0
          parser->index = 2;
765
0
          UPDATE_STATE(s_req_method);
766
0
        }
767
0
        break;
768
769
0
      case s_start_res:
770
0
      {
771
0
        if (ch == CR || ch == LF)
772
0
          break;
773
0
        parser->flags = 0;
774
0
        parser->uses_transfer_encoding = 0;
775
0
        parser->content_length = ULLONG_MAX;
776
777
0
        if (ch == 'H') {
778
0
          UPDATE_STATE(s_res_H);
779
0
        } else {
780
0
          SET_ERRNO(HPE_INVALID_CONSTANT);
781
0
          goto error;
782
0
        }
783
784
0
        CALLBACK_NOTIFY(message_begin);
785
0
        break;
786
0
      }
787
788
0
      case s_res_H:
789
0
        STRICT_CHECK(ch != 'T');
790
0
        UPDATE_STATE(s_res_HT);
791
0
        break;
792
793
0
      case s_res_HT:
794
0
        STRICT_CHECK(ch != 'T');
795
0
        UPDATE_STATE(s_res_HTT);
796
0
        break;
797
798
0
      case s_res_HTT:
799
0
        STRICT_CHECK(ch != 'P');
800
0
        UPDATE_STATE(s_res_HTTP);
801
0
        break;
802
803
0
      case s_res_HTTP:
804
0
        STRICT_CHECK(ch != '/');
805
0
        UPDATE_STATE(s_res_http_major);
806
0
        break;
807
808
0
      case s_res_http_major:
809
0
        if (UNLIKELY(!IS_NUM(ch))) {
810
0
          SET_ERRNO(HPE_INVALID_VERSION);
811
0
          goto error;
812
0
        }
813
814
0
        parser->http_major = ch - '0';
815
0
        UPDATE_STATE(s_res_http_dot);
816
0
        break;
817
818
0
      case s_res_http_dot:
819
0
      {
820
0
        if (UNLIKELY(ch != '.')) {
821
0
          SET_ERRNO(HPE_INVALID_VERSION);
822
0
          goto error;
823
0
        }
824
825
0
        UPDATE_STATE(s_res_http_minor);
826
0
        break;
827
0
      }
828
829
0
      case s_res_http_minor:
830
0
        if (UNLIKELY(!IS_NUM(ch))) {
831
0
          SET_ERRNO(HPE_INVALID_VERSION);
832
0
          goto error;
833
0
        }
834
835
0
        parser->http_minor = ch - '0';
836
0
        UPDATE_STATE(s_res_http_end);
837
0
        break;
838
839
0
      case s_res_http_end:
840
0
      {
841
0
        if (UNLIKELY(ch != ' ')) {
842
0
          SET_ERRNO(HPE_INVALID_VERSION);
843
0
          goto error;
844
0
        }
845
846
0
        UPDATE_STATE(s_res_first_status_code);
847
0
        break;
848
0
      }
849
850
0
      case s_res_first_status_code:
851
0
      {
852
0
        if (!IS_NUM(ch)) {
853
0
          if (ch == ' ') {
854
0
            break;
855
0
          }
856
857
0
          SET_ERRNO(HPE_INVALID_STATUS);
858
0
          goto error;
859
0
        }
860
0
        parser->status_code = ch - '0';
861
0
        UPDATE_STATE(s_res_status_code);
862
0
        break;
863
0
      }
864
865
0
      case s_res_status_code:
866
0
      {
867
0
        if (!IS_NUM(ch)) {
868
0
          switch (ch) {
869
0
            case ' ':
870
0
              UPDATE_STATE(s_res_status_start);
871
0
              break;
872
0
            case CR:
873
0
            case LF:
874
0
              UPDATE_STATE(s_res_status_start);
875
0
              REEXECUTE();
876
0
              break;
877
0
            default:
878
0
              SET_ERRNO(HPE_INVALID_STATUS);
879
0
              goto error;
880
0
          }
881
0
          break;
882
0
        }
883
884
0
        parser->status_code *= 10;
885
0
        parser->status_code += ch - '0';
886
887
0
        if (UNLIKELY(parser->status_code > 999)) {
888
0
          SET_ERRNO(HPE_INVALID_STATUS);
889
0
          goto error;
890
0
        }
891
892
0
        break;
893
0
      }
894
895
0
      case s_res_status_start:
896
0
      {
897
0
        MARK(status);
898
0
        UPDATE_STATE(s_res_status);
899
0
        parser->index = 0;
900
901
0
        if (ch == CR || ch == LF)
902
0
          REEXECUTE();
903
904
0
        break;
905
0
      }
906
907
0
      case s_res_status:
908
0
        if (ch == CR) {
909
0
          UPDATE_STATE(s_res_line_almost_done);
910
0
          CALLBACK_DATA(status);
911
0
          break;
912
0
        }
913
914
0
        if (ch == LF) {
915
0
          UPDATE_STATE(s_header_field_start);
916
0
          CALLBACK_DATA(status);
917
0
          break;
918
0
        }
919
920
0
        break;
921
922
0
      case s_res_line_almost_done:
923
0
        STRICT_CHECK(ch != LF);
924
0
        UPDATE_STATE(s_header_field_start);
925
0
        break;
926
927
0
      case s_start_req:
928
0
      {
929
0
        if (ch == CR || ch == LF)
930
0
          break;
931
0
        parser->flags = 0;
932
0
        parser->uses_transfer_encoding = 0;
933
0
        parser->content_length = ULLONG_MAX;
934
935
0
        if (UNLIKELY(!IS_ALPHA(ch))) {
936
0
          SET_ERRNO(HPE_INVALID_METHOD);
937
0
          goto error;
938
0
        }
939
940
0
        parser->method = (enum http_method) 0;
941
0
        parser->index = 1;
942
0
        switch (ch) {
943
0
          case 'A': parser->method = HTTP_ACL; break;
944
0
          case 'B': parser->method = HTTP_BIND; break;
945
0
          case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
946
0
          case 'D': parser->method = HTTP_DELETE; break;
947
0
          case 'G': parser->method = HTTP_GET; break;
948
0
          case 'H': parser->method = HTTP_HEAD; break;
949
0
          case 'L': parser->method = HTTP_LOCK; /* or LINK */ break;
950
0
          case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break;
951
0
          case 'N': parser->method = HTTP_NOTIFY; break;
952
0
          case 'O': parser->method = HTTP_OPTIONS; break;
953
0
          case 'P': parser->method = HTTP_POST;
954
            /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
955
0
            break;
956
0
          case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break;
957
0
          case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH, SOURCE */ break;
958
0
          case 'T': parser->method = HTTP_TRACE; break;
959
0
          case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break;
960
0
          default:
961
0
            SET_ERRNO(HPE_INVALID_METHOD);
962
0
            goto error;
963
0
        }
964
0
        UPDATE_STATE(s_req_method);
965
966
0
        CALLBACK_NOTIFY(message_begin);
967
968
0
        break;
969
0
      }
970
971
0
      case s_req_method:
972
0
      {
973
0
        const char *matcher;
974
0
        if (UNLIKELY(ch == '\0')) {
975
0
          SET_ERRNO(HPE_INVALID_METHOD);
976
0
          goto error;
977
0
        }
978
979
0
        matcher = method_strings[parser->method];
980
0
        if (ch == ' ' && matcher[parser->index] == '\0') {
981
0
          UPDATE_STATE(s_req_spaces_before_url);
982
0
        } else if (ch == matcher[parser->index]) {
983
0
          ; /* nada */
984
0
        } else if ((ch >= 'A' && ch <= 'Z') || ch == '-') {
985
986
0
          switch (parser->method << 16 | parser->index << 8 | ch) {
987
0
#define XX(meth, pos, ch, new_meth) \
988
0
            case (HTTP_##meth << 16 | pos << 8 | ch): \
989
0
              parser->method = HTTP_##new_meth; break;
990
991
0
            XX(POST,      1, 'U', PUT)
992
0
            XX(POST,      1, 'A', PATCH)
993
0
            XX(POST,      1, 'R', PROPFIND)
994
0
            XX(PUT,       2, 'R', PURGE)
995
0
            XX(CONNECT,   1, 'H', CHECKOUT)
996
0
            XX(CONNECT,   2, 'P', COPY)
997
0
            XX(MKCOL,     1, 'O', MOVE)
998
0
            XX(MKCOL,     1, 'E', MERGE)
999
0
            XX(MKCOL,     1, '-', MSEARCH)
1000
0
            XX(MKCOL,     2, 'A', MKACTIVITY)
1001
0
            XX(MKCOL,     3, 'A', MKCALENDAR)
1002
0
            XX(SUBSCRIBE, 1, 'E', SEARCH)
1003
0
            XX(SUBSCRIBE, 1, 'O', SOURCE)
1004
0
            XX(REPORT,    2, 'B', REBIND)
1005
0
            XX(PROPFIND,  4, 'P', PROPPATCH)
1006
0
            XX(LOCK,      1, 'I', LINK)
1007
0
            XX(UNLOCK,    2, 'S', UNSUBSCRIBE)
1008
0
            XX(UNLOCK,    2, 'B', UNBIND)
1009
0
            XX(UNLOCK,    3, 'I', UNLINK)
1010
0
#undef XX
1011
0
            default:
1012
0
              SET_ERRNO(HPE_INVALID_METHOD);
1013
0
              goto error;
1014
0
          }
1015
0
        } else {
1016
0
          SET_ERRNO(HPE_INVALID_METHOD);
1017
0
          goto error;
1018
0
        }
1019
1020
0
        ++parser->index;
1021
0
        break;
1022
0
      }
1023
1024
0
      case s_req_spaces_before_url:
1025
0
      {
1026
0
        if (ch == ' ') break;
1027
1028
0
        MARK(url);
1029
0
        if (parser->method == HTTP_CONNECT) {
1030
0
          UPDATE_STATE(s_req_server_start);
1031
0
        }
1032
1033
0
        UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
1034
0
        if (UNLIKELY(CURRENT_STATE() == s_dead)) {
1035
0
          SET_ERRNO(HPE_INVALID_URL);
1036
0
          goto error;
1037
0
        }
1038
1039
0
        break;
1040
0
      }
1041
1042
0
      case s_req_schema:
1043
0
      case s_req_schema_slash:
1044
0
      case s_req_schema_slash_slash:
1045
0
      case s_req_server_start:
1046
0
      {
1047
0
        switch (ch) {
1048
          /* No whitespace allowed here */
1049
0
          case ' ':
1050
0
          case CR:
1051
0
          case LF:
1052
0
            SET_ERRNO(HPE_INVALID_URL);
1053
0
            goto error;
1054
0
          default:
1055
0
            UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
1056
0
            if (UNLIKELY(CURRENT_STATE() == s_dead)) {
1057
0
              SET_ERRNO(HPE_INVALID_URL);
1058
0
              goto error;
1059
0
            }
1060
0
        }
1061
1062
0
        break;
1063
0
      }
1064
1065
0
      case s_req_server:
1066
0
      case s_req_server_with_at:
1067
0
      case s_req_path:
1068
0
      case s_req_query_string_start:
1069
0
      case s_req_query_string:
1070
0
      case s_req_fragment_start:
1071
0
      case s_req_fragment:
1072
0
      {
1073
0
        switch (ch) {
1074
0
          case ' ':
1075
0
            UPDATE_STATE(s_req_http_start);
1076
0
            CALLBACK_DATA(url);
1077
0
            break;
1078
0
          case CR:
1079
0
          case LF:
1080
0
            parser->http_major = 0;
1081
0
            parser->http_minor = 9;
1082
0
            UPDATE_STATE((ch == CR) ?
1083
0
              s_req_line_almost_done :
1084
0
              s_header_field_start);
1085
0
            CALLBACK_DATA(url);
1086
0
            break;
1087
0
          default:
1088
0
            UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
1089
0
            if (UNLIKELY(CURRENT_STATE() == s_dead)) {
1090
0
              SET_ERRNO(HPE_INVALID_URL);
1091
0
              goto error;
1092
0
            }
1093
0
        }
1094
0
        break;
1095
0
      }
1096
1097
0
      case s_req_http_start:
1098
0
        switch (ch) {
1099
0
          case ' ':
1100
0
            break;
1101
0
          case 'H':
1102
0
            UPDATE_STATE(s_req_http_H);
1103
0
            break;
1104
0
          case 'I':
1105
0
            if (parser->method == HTTP_SOURCE) {
1106
0
              UPDATE_STATE(s_req_http_I);
1107
0
              break;
1108
0
            }
1109
            /* fall through */
1110
0
          default:
1111
0
            SET_ERRNO(HPE_INVALID_CONSTANT);
1112
0
            goto error;
1113
0
        }
1114
0
        break;
1115
1116
0
      case s_req_http_H:
1117
0
        STRICT_CHECK(ch != 'T');
1118
0
        UPDATE_STATE(s_req_http_HT);
1119
0
        break;
1120
1121
0
      case s_req_http_HT:
1122
0
        STRICT_CHECK(ch != 'T');
1123
0
        UPDATE_STATE(s_req_http_HTT);
1124
0
        break;
1125
1126
0
      case s_req_http_HTT:
1127
0
        STRICT_CHECK(ch != 'P');
1128
0
        UPDATE_STATE(s_req_http_HTTP);
1129
0
        break;
1130
1131
0
      case s_req_http_I:
1132
0
        STRICT_CHECK(ch != 'C');
1133
0
        UPDATE_STATE(s_req_http_IC);
1134
0
        break;
1135
1136
0
      case s_req_http_IC:
1137
0
        STRICT_CHECK(ch != 'E');
1138
0
        UPDATE_STATE(s_req_http_HTTP);  /* Treat "ICE" as "HTTP". */
1139
0
        break;
1140
1141
0
      case s_req_http_HTTP:
1142
0
        STRICT_CHECK(ch != '/');
1143
0
        UPDATE_STATE(s_req_http_major);
1144
0
        break;
1145
1146
0
      case s_req_http_major:
1147
0
        if (UNLIKELY(!IS_NUM(ch))) {
1148
0
          SET_ERRNO(HPE_INVALID_VERSION);
1149
0
          goto error;
1150
0
        }
1151
1152
0
        parser->http_major = ch - '0';
1153
0
        UPDATE_STATE(s_req_http_dot);
1154
0
        break;
1155
1156
0
      case s_req_http_dot:
1157
0
      {
1158
0
        if (UNLIKELY(ch != '.')) {
1159
0
          SET_ERRNO(HPE_INVALID_VERSION);
1160
0
          goto error;
1161
0
        }
1162
1163
0
        UPDATE_STATE(s_req_http_minor);
1164
0
        break;
1165
0
      }
1166
1167
0
      case s_req_http_minor:
1168
0
        if (UNLIKELY(!IS_NUM(ch))) {
1169
0
          SET_ERRNO(HPE_INVALID_VERSION);
1170
0
          goto error;
1171
0
        }
1172
1173
0
        parser->http_minor = ch - '0';
1174
0
        UPDATE_STATE(s_req_http_end);
1175
0
        break;
1176
1177
0
      case s_req_http_end:
1178
0
      {
1179
0
        if (ch == CR) {
1180
0
          UPDATE_STATE(s_req_line_almost_done);
1181
0
          break;
1182
0
        }
1183
1184
0
        if (ch == LF) {
1185
0
          UPDATE_STATE(s_header_field_start);
1186
0
          break;
1187
0
        }
1188
1189
0
        SET_ERRNO(HPE_INVALID_VERSION);
1190
0
        goto error;
1191
0
        break;
1192
0
      }
1193
1194
      /* end of request line */
1195
0
      case s_req_line_almost_done:
1196
0
      {
1197
0
        if (UNLIKELY(ch != LF)) {
1198
0
          SET_ERRNO(HPE_LF_EXPECTED);
1199
0
          goto error;
1200
0
        }
1201
1202
0
        UPDATE_STATE(s_header_field_start);
1203
0
        break;
1204
0
      }
1205
1206
0
      case s_header_field_start:
1207
0
      {
1208
0
        if (ch == CR) {
1209
0
          UPDATE_STATE(s_headers_almost_done);
1210
0
          break;
1211
0
        }
1212
1213
0
        if (ch == LF) {
1214
          /* they might be just sending \n instead of \r\n so this would be
1215
           * the second \n to denote the end of headers*/
1216
0
          UPDATE_STATE(s_headers_almost_done);
1217
0
          REEXECUTE();
1218
0
        }
1219
1220
0
        c = TOKEN(ch);
1221
1222
0
        if (UNLIKELY(!c)) {
1223
0
          SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1224
0
          goto error;
1225
0
        }
1226
1227
0
        MARK(header_field);
1228
1229
0
        parser->index = 0;
1230
0
        UPDATE_STATE(s_header_field);
1231
1232
0
        switch (c) {
1233
0
          case 'c':
1234
0
            parser->header_state = h_C;
1235
0
            break;
1236
1237
0
          case 'p':
1238
0
            parser->header_state = h_matching_proxy_connection;
1239
0
            break;
1240
1241
0
          case 't':
1242
0
            parser->header_state = h_matching_transfer_encoding;
1243
0
            break;
1244
1245
0
          case 'u':
1246
0
            parser->header_state = h_matching_upgrade;
1247
0
            break;
1248
1249
0
          default:
1250
0
            parser->header_state = h_general;
1251
0
            break;
1252
0
        }
1253
0
        break;
1254
0
      }
1255
1256
0
      case s_header_field:
1257
0
      {
1258
0
        const char* start = p;
1259
0
        for (; p != data + len; p++) {
1260
0
          ch = *p;
1261
0
          c = TOKEN(ch);
1262
1263
0
          if (!c)
1264
0
            break;
1265
1266
0
          switch (parser->header_state) {
1267
0
            case h_general: {
1268
0
              size_t left = data + len - p;
1269
0
              const char* pe = p + MIN(left, max_header_size);
1270
0
              while (p+1 < pe && TOKEN(p[1])) {
1271
0
                p++;
1272
0
              }
1273
0
              break;
1274
0
            }
1275
1276
0
            case h_C:
1277
0
              parser->index++;
1278
0
              parser->header_state = (c == 'o' ? h_CO : h_general);
1279
0
              break;
1280
1281
0
            case h_CO:
1282
0
              parser->index++;
1283
0
              parser->header_state = (c == 'n' ? h_CON : h_general);
1284
0
              break;
1285
1286
0
            case h_CON:
1287
0
              parser->index++;
1288
0
              switch (c) {
1289
0
                case 'n':
1290
0
                  parser->header_state = h_matching_connection;
1291
0
                  break;
1292
0
                case 't':
1293
0
                  parser->header_state = h_matching_content_length;
1294
0
                  break;
1295
0
                default:
1296
0
                  parser->header_state = h_general;
1297
0
                  break;
1298
0
              }
1299
0
              break;
1300
1301
            /* connection */
1302
1303
0
            case h_matching_connection:
1304
0
              parser->index++;
1305
0
              if (parser->index > sizeof(CONNECTION)-1
1306
0
                  || c != CONNECTION[parser->index]) {
1307
0
                parser->header_state = h_general;
1308
0
              } else if (parser->index == sizeof(CONNECTION)-2) {
1309
0
                parser->header_state = h_connection;
1310
0
              }
1311
0
              break;
1312
1313
            /* proxy-connection */
1314
1315
0
            case h_matching_proxy_connection:
1316
0
              parser->index++;
1317
0
              if (parser->index > sizeof(PROXY_CONNECTION)-1
1318
0
                  || c != PROXY_CONNECTION[parser->index]) {
1319
0
                parser->header_state = h_general;
1320
0
              } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {
1321
0
                parser->header_state = h_connection;
1322
0
              }
1323
0
              break;
1324
1325
            /* content-length */
1326
1327
0
            case h_matching_content_length:
1328
0
              parser->index++;
1329
0
              if (parser->index > sizeof(CONTENT_LENGTH)-1
1330
0
                  || c != CONTENT_LENGTH[parser->index]) {
1331
0
                parser->header_state = h_general;
1332
0
              } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
1333
0
                parser->header_state = h_content_length;
1334
0
              }
1335
0
              break;
1336
1337
            /* transfer-encoding */
1338
1339
0
            case h_matching_transfer_encoding:
1340
0
              parser->index++;
1341
0
              if (parser->index > sizeof(TRANSFER_ENCODING)-1
1342
0
                  || c != TRANSFER_ENCODING[parser->index]) {
1343
0
                parser->header_state = h_general;
1344
0
              } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
1345
0
                parser->header_state = h_transfer_encoding;
1346
0
                parser->uses_transfer_encoding = 1;
1347
0
              }
1348
0
              break;
1349
1350
            /* upgrade */
1351
1352
0
            case h_matching_upgrade:
1353
0
              parser->index++;
1354
0
              if (parser->index > sizeof(UPGRADE)-1
1355
0
                  || c != UPGRADE[parser->index]) {
1356
0
                parser->header_state = h_general;
1357
0
              } else if (parser->index == sizeof(UPGRADE)-2) {
1358
0
                parser->header_state = h_upgrade;
1359
0
              }
1360
0
              break;
1361
1362
0
            case h_connection:
1363
0
            case h_content_length:
1364
0
            case h_transfer_encoding:
1365
0
            case h_upgrade:
1366
0
              if (ch != ' ') parser->header_state = h_general;
1367
0
              break;
1368
1369
0
            default:
1370
0
              assert(0 && "Unknown header_state");
1371
0
              break;
1372
0
          }
1373
0
        }
1374
1375
0
        if (p == data + len) {
1376
0
          --p;
1377
0
          COUNT_HEADER_SIZE(p - start);
1378
0
          break;
1379
0
        }
1380
1381
0
        COUNT_HEADER_SIZE(p - start);
1382
1383
0
        if (ch == ':') {
1384
0
          UPDATE_STATE(s_header_value_discard_ws);
1385
0
          CALLBACK_DATA(header_field);
1386
0
          break;
1387
0
        }
1388
1389
0
        SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1390
0
        goto error;
1391
0
      }
1392
1393
0
      case s_header_value_discard_ws:
1394
0
        if (ch == ' ' || ch == '\t') break;
1395
1396
0
        if (ch == CR) {
1397
0
          UPDATE_STATE(s_header_value_discard_ws_almost_done);
1398
0
          break;
1399
0
        }
1400
1401
0
        if (ch == LF) {
1402
0
          UPDATE_STATE(s_header_value_discard_lws);
1403
0
          break;
1404
0
        }
1405
1406
        /* fall through */
1407
1408
0
      case s_header_value_start:
1409
0
      {
1410
0
        MARK(header_value);
1411
1412
0
        UPDATE_STATE(s_header_value);
1413
0
        parser->index = 0;
1414
1415
0
        c = LOWER(ch);
1416
1417
0
        switch (parser->header_state) {
1418
0
          case h_upgrade:
1419
0
            parser->flags |= F_UPGRADE;
1420
0
            parser->header_state = h_general;
1421
0
            break;
1422
1423
0
          case h_transfer_encoding:
1424
            /* looking for 'Transfer-Encoding: chunked' */
1425
0
            if ('c' == c) {
1426
0
              parser->header_state = h_matching_transfer_encoding_chunked;
1427
0
            } else {
1428
0
              parser->header_state = h_matching_transfer_encoding_token;
1429
0
            }
1430
0
            break;
1431
1432
          /* Multi-value `Transfer-Encoding` header */
1433
0
          case h_matching_transfer_encoding_token_start:
1434
0
            break;
1435
1436
0
          case h_content_length:
1437
0
            if (UNLIKELY(!IS_NUM(ch))) {
1438
0
              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1439
0
              goto error;
1440
0
            }
1441
1442
0
            if (parser->flags & F_CONTENTLENGTH) {
1443
0
              SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
1444
0
              goto error;
1445
0
            }
1446
1447
0
            parser->flags |= F_CONTENTLENGTH;
1448
0
            parser->content_length = ch - '0';
1449
0
            parser->header_state = h_content_length_num;
1450
0
            break;
1451
1452
          /* when obsolete line folding is encountered for content length
1453
           * continue to the s_header_value state */
1454
0
          case h_content_length_ws:
1455
0
            break;
1456
1457
0
          case h_connection:
1458
            /* looking for 'Connection: keep-alive' */
1459
0
            if (c == 'k') {
1460
0
              parser->header_state = h_matching_connection_keep_alive;
1461
            /* looking for 'Connection: close' */
1462
0
            } else if (c == 'c') {
1463
0
              parser->header_state = h_matching_connection_close;
1464
0
            } else if (c == 'u') {
1465
0
              parser->header_state = h_matching_connection_upgrade;
1466
0
            } else {
1467
0
              parser->header_state = h_matching_connection_token;
1468
0
            }
1469
0
            break;
1470
1471
          /* Multi-value `Connection` header */
1472
0
          case h_matching_connection_token_start:
1473
0
            break;
1474
1475
0
          default:
1476
0
            parser->header_state = h_general;
1477
0
            break;
1478
0
        }
1479
0
        break;
1480
0
      }
1481
1482
0
      case s_header_value:
1483
0
      {
1484
0
        const char* start = p;
1485
0
        enum header_states h_state = (enum header_states) parser->header_state;
1486
0
        for (; p != data + len; p++) {
1487
0
          ch = *p;
1488
0
          if (ch == CR) {
1489
0
            UPDATE_STATE(s_header_almost_done);
1490
0
            parser->header_state = h_state;
1491
0
            CALLBACK_DATA(header_value);
1492
0
            break;
1493
0
          }
1494
1495
0
          if (ch == LF) {
1496
0
            UPDATE_STATE(s_header_almost_done);
1497
0
            COUNT_HEADER_SIZE(p - start);
1498
0
            parser->header_state = h_state;
1499
0
            CALLBACK_DATA_NOADVANCE(header_value);
1500
0
            REEXECUTE();
1501
0
          }
1502
1503
0
          if (!lenient && !IS_HEADER_CHAR(ch)) {
1504
0
            SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1505
0
            goto error;
1506
0
          }
1507
1508
0
          c = LOWER(ch);
1509
1510
0
          switch (h_state) {
1511
0
            case h_general:
1512
0
              {
1513
0
                size_t left = data + len - p;
1514
0
                const char* pe = p + MIN(left, max_header_size);
1515
1516
0
                for (; p != pe; p++) {
1517
0
                  ch = *p;
1518
0
                  if (ch == CR || ch == LF) {
1519
0
                    --p;
1520
0
                    break;
1521
0
                  }
1522
0
                  if (!lenient && !IS_HEADER_CHAR(ch)) {
1523
0
                    SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1524
0
                    goto error;
1525
0
                  }
1526
0
                }
1527
0
                if (p == data + len)
1528
0
                  --p;
1529
0
                break;
1530
0
              }
1531
1532
0
            case h_connection:
1533
0
            case h_transfer_encoding:
1534
0
              assert(0 && "Shouldn't get here.");
1535
0
              break;
1536
1537
0
            case h_content_length:
1538
0
              if (ch == ' ') break;
1539
0
              h_state = h_content_length_num;
1540
              /* fall through */
1541
1542
0
            case h_content_length_num:
1543
0
            {
1544
0
              uint64_t t;
1545
1546
0
              if (ch == ' ') {
1547
0
                h_state = h_content_length_ws;
1548
0
                break;
1549
0
              }
1550
1551
0
              if (UNLIKELY(!IS_NUM(ch))) {
1552
0
                SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1553
0
                parser->header_state = h_state;
1554
0
                goto error;
1555
0
              }
1556
1557
0
              t = parser->content_length;
1558
0
              t *= 10;
1559
0
              t += ch - '0';
1560
1561
              /* Overflow? Test against a conservative limit for simplicity. */
1562
0
              if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) {
1563
0
                SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1564
0
                parser->header_state = h_state;
1565
0
                goto error;
1566
0
              }
1567
1568
0
              parser->content_length = t;
1569
0
              break;
1570
0
            }
1571
1572
0
            case h_content_length_ws:
1573
0
              if (ch == ' ') break;
1574
0
              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1575
0
              parser->header_state = h_state;
1576
0
              goto error;
1577
1578
            /* Transfer-Encoding: chunked */
1579
0
            case h_matching_transfer_encoding_token_start:
1580
              /* looking for 'Transfer-Encoding: chunked' */
1581
0
              if ('c' == c) {
1582
0
                h_state = h_matching_transfer_encoding_chunked;
1583
0
              } else if (STRICT_TOKEN(c)) {
1584
                /* TODO(indutny): similar code below does this, but why?
1585
                 * At the very least it seems to be inconsistent given that
1586
                 * h_matching_transfer_encoding_token does not check for
1587
                 * `STRICT_TOKEN`
1588
                 */
1589
0
                h_state = h_matching_transfer_encoding_token;
1590
0
              } else if (c == ' ' || c == '\t') {
1591
                /* Skip lws */
1592
0
              } else {
1593
0
                h_state = h_general;
1594
0
              }
1595
0
              break;
1596
1597
0
            case h_matching_transfer_encoding_chunked:
1598
0
              parser->index++;
1599
0
              if (parser->index > sizeof(CHUNKED)-1
1600
0
                  || c != CHUNKED[parser->index]) {
1601
0
                h_state = h_matching_transfer_encoding_token;
1602
0
              } else if (parser->index == sizeof(CHUNKED)-2) {
1603
0
                h_state = h_transfer_encoding_chunked;
1604
0
              }
1605
0
              break;
1606
1607
0
            case h_matching_transfer_encoding_token:
1608
0
              if (ch == ',') {
1609
0
                h_state = h_matching_transfer_encoding_token_start;
1610
0
                parser->index = 0;
1611
0
              }
1612
0
              break;
1613
1614
0
            case h_matching_connection_token_start:
1615
              /* looking for 'Connection: keep-alive' */
1616
0
              if (c == 'k') {
1617
0
                h_state = h_matching_connection_keep_alive;
1618
              /* looking for 'Connection: close' */
1619
0
              } else if (c == 'c') {
1620
0
                h_state = h_matching_connection_close;
1621
0
              } else if (c == 'u') {
1622
0
                h_state = h_matching_connection_upgrade;
1623
0
              } else if (STRICT_TOKEN(c)) {
1624
0
                h_state = h_matching_connection_token;
1625
0
              } else if (c == ' ' || c == '\t') {
1626
                /* Skip lws */
1627
0
              } else {
1628
0
                h_state = h_general;
1629
0
              }
1630
0
              break;
1631
1632
            /* looking for 'Connection: keep-alive' */
1633
0
            case h_matching_connection_keep_alive:
1634
0
              parser->index++;
1635
0
              if (parser->index > sizeof(KEEP_ALIVE)-1
1636
0
                  || c != KEEP_ALIVE[parser->index]) {
1637
0
                h_state = h_matching_connection_token;
1638
0
              } else if (parser->index == sizeof(KEEP_ALIVE)-2) {
1639
0
                h_state = h_connection_keep_alive;
1640
0
              }
1641
0
              break;
1642
1643
            /* looking for 'Connection: close' */
1644
0
            case h_matching_connection_close:
1645
0
              parser->index++;
1646
0
              if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
1647
0
                h_state = h_matching_connection_token;
1648
0
              } else if (parser->index == sizeof(CLOSE)-2) {
1649
0
                h_state = h_connection_close;
1650
0
              }
1651
0
              break;
1652
1653
            /* looking for 'Connection: upgrade' */
1654
0
            case h_matching_connection_upgrade:
1655
0
              parser->index++;
1656
0
              if (parser->index > sizeof(UPGRADE) - 1 ||
1657
0
                  c != UPGRADE[parser->index]) {
1658
0
                h_state = h_matching_connection_token;
1659
0
              } else if (parser->index == sizeof(UPGRADE)-2) {
1660
0
                h_state = h_connection_upgrade;
1661
0
              }
1662
0
              break;
1663
1664
0
            case h_matching_connection_token:
1665
0
              if (ch == ',') {
1666
0
                h_state = h_matching_connection_token_start;
1667
0
                parser->index = 0;
1668
0
              }
1669
0
              break;
1670
1671
0
            case h_transfer_encoding_chunked:
1672
0
              if (ch != ' ') h_state = h_matching_transfer_encoding_token;
1673
0
              break;
1674
1675
0
            case h_connection_keep_alive:
1676
0
            case h_connection_close:
1677
0
            case h_connection_upgrade:
1678
0
              if (ch == ',') {
1679
0
                if (h_state == h_connection_keep_alive) {
1680
0
                  parser->flags |= F_CONNECTION_KEEP_ALIVE;
1681
0
                } else if (h_state == h_connection_close) {
1682
0
                  parser->flags |= F_CONNECTION_CLOSE;
1683
0
                } else if (h_state == h_connection_upgrade) {
1684
0
                  parser->flags |= F_CONNECTION_UPGRADE;
1685
0
                }
1686
0
                h_state = h_matching_connection_token_start;
1687
0
                parser->index = 0;
1688
0
              } else if (ch != ' ') {
1689
0
                h_state = h_matching_connection_token;
1690
0
              }
1691
0
              break;
1692
1693
0
            default:
1694
0
              UPDATE_STATE(s_header_value);
1695
0
              h_state = h_general;
1696
0
              break;
1697
0
          }
1698
0
        }
1699
0
        parser->header_state = h_state;
1700
1701
0
        if (p == data + len)
1702
0
          --p;
1703
1704
0
        COUNT_HEADER_SIZE(p - start);
1705
0
        break;
1706
0
      }
1707
1708
0
      case s_header_almost_done:
1709
0
      {
1710
0
        if (UNLIKELY(ch != LF)) {
1711
0
          SET_ERRNO(HPE_LF_EXPECTED);
1712
0
          goto error;
1713
0
        }
1714
1715
0
        UPDATE_STATE(s_header_value_lws);
1716
0
        break;
1717
0
      }
1718
1719
0
      case s_header_value_lws:
1720
0
      {
1721
0
        if (ch == ' ' || ch == '\t') {
1722
0
          if (parser->header_state == h_content_length_num) {
1723
              /* treat obsolete line folding as space */
1724
0
              parser->header_state = h_content_length_ws;
1725
0
          }
1726
0
          UPDATE_STATE(s_header_value_start);
1727
0
          REEXECUTE();
1728
0
        }
1729
1730
        /* finished the header */
1731
0
        switch (parser->header_state) {
1732
0
          case h_connection_keep_alive:
1733
0
            parser->flags |= F_CONNECTION_KEEP_ALIVE;
1734
0
            break;
1735
0
          case h_connection_close:
1736
0
            parser->flags |= F_CONNECTION_CLOSE;
1737
0
            break;
1738
0
          case h_transfer_encoding_chunked:
1739
0
            parser->flags |= F_CHUNKED;
1740
0
            break;
1741
0
          case h_connection_upgrade:
1742
0
            parser->flags |= F_CONNECTION_UPGRADE;
1743
0
            break;
1744
0
          default:
1745
0
            break;
1746
0
        }
1747
1748
0
        UPDATE_STATE(s_header_field_start);
1749
0
        REEXECUTE();
1750
0
      }
1751
1752
0
      case s_header_value_discard_ws_almost_done:
1753
0
      {
1754
0
        STRICT_CHECK(ch != LF);
1755
0
        UPDATE_STATE(s_header_value_discard_lws);
1756
0
        break;
1757
0
      }
1758
1759
0
      case s_header_value_discard_lws:
1760
0
      {
1761
0
        if (ch == ' ' || ch == '\t') {
1762
0
          UPDATE_STATE(s_header_value_discard_ws);
1763
0
          break;
1764
0
        } else {
1765
0
          switch (parser->header_state) {
1766
0
            case h_connection_keep_alive:
1767
0
              parser->flags |= F_CONNECTION_KEEP_ALIVE;
1768
0
              break;
1769
0
            case h_connection_close:
1770
0
              parser->flags |= F_CONNECTION_CLOSE;
1771
0
              break;
1772
0
            case h_connection_upgrade:
1773
0
              parser->flags |= F_CONNECTION_UPGRADE;
1774
0
              break;
1775
0
            case h_transfer_encoding_chunked:
1776
0
              parser->flags |= F_CHUNKED;
1777
0
              break;
1778
0
            case h_content_length:
1779
              /* do not allow empty content length */
1780
0
              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1781
0
              goto error;
1782
0
              break;
1783
0
            default:
1784
0
              break;
1785
0
          }
1786
1787
          /* header value was empty */
1788
0
          MARK(header_value);
1789
0
          UPDATE_STATE(s_header_field_start);
1790
0
          CALLBACK_DATA_NOADVANCE(header_value);
1791
0
          REEXECUTE();
1792
0
        }
1793
0
      }
1794
1795
0
      case s_headers_almost_done:
1796
0
      {
1797
0
        STRICT_CHECK(ch != LF);
1798
1799
0
        if (parser->flags & F_TRAILING) {
1800
          /* End of a chunked request */
1801
0
          UPDATE_STATE(s_message_done);
1802
0
          CALLBACK_NOTIFY_NOADVANCE(chunk_complete);
1803
0
          REEXECUTE();
1804
0
        }
1805
1806
        /* Cannot use transfer-encoding and a content-length header together
1807
           per the HTTP specification. (RFC 7230 Section 3.3.3) */
1808
0
        if ((parser->uses_transfer_encoding == 1) &&
1809
0
            (parser->flags & F_CONTENTLENGTH)) {
1810
          /* Allow it for lenient parsing as long as `Transfer-Encoding` is
1811
           * not `chunked` or allow_length_with_encoding is set
1812
           */
1813
0
          if (parser->flags & F_CHUNKED) {
1814
0
            if (!allow_chunked_length) {
1815
0
              SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
1816
0
              goto error;
1817
0
            }
1818
0
          } else if (!lenient) {
1819
0
            SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
1820
0
            goto error;
1821
0
          }
1822
0
        }
1823
1824
0
        UPDATE_STATE(s_headers_done);
1825
1826
        /* Set this here so that on_headers_complete() callbacks can see it */
1827
0
        if ((parser->flags & F_UPGRADE) &&
1828
0
            (parser->flags & F_CONNECTION_UPGRADE)) {
1829
          /* For responses, "Upgrade: foo" and "Connection: upgrade" are
1830
           * mandatory only when it is a 101 Switching Protocols response,
1831
           * otherwise it is purely informational, to announce support.
1832
           */
1833
0
          parser->upgrade =
1834
0
              (parser->type == HTTP_REQUEST || parser->status_code == 101);
1835
0
        } else {
1836
0
          parser->upgrade = (parser->method == HTTP_CONNECT);
1837
0
        }
1838
1839
        /* Here we call the headers_complete callback. This is somewhat
1840
         * different than other callbacks because if the user returns 1, we
1841
         * will interpret that as saying that this message has no body. This
1842
         * is needed for the annoying case of recieving a response to a HEAD
1843
         * request.
1844
         *
1845
         * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
1846
         * we have to simulate it by handling a change in errno below.
1847
         */
1848
0
        if (settings->on_headers_complete) {
1849
0
          switch (settings->on_headers_complete(parser)) {
1850
0
            case 0:
1851
0
              break;
1852
1853
0
            case 2:
1854
0
              parser->upgrade = 1;
1855
1856
              /* fall through */
1857
0
            case 1:
1858
0
              parser->flags |= F_SKIPBODY;
1859
0
              break;
1860
1861
0
            default:
1862
0
              SET_ERRNO(HPE_CB_headers_complete);
1863
0
              RETURN(p - data); /* Error */
1864
0
          }
1865
0
        }
1866
1867
0
        if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
1868
0
          RETURN(p - data);
1869
0
        }
1870
1871
0
        REEXECUTE();
1872
0
      }
1873
1874
0
      case s_headers_done:
1875
0
      {
1876
0
        int hasBody;
1877
0
        STRICT_CHECK(ch != LF);
1878
1879
0
        parser->nread = 0;
1880
0
        nread = 0;
1881
1882
0
        hasBody = parser->flags & F_CHUNKED ||
1883
0
          (parser->content_length > 0 && parser->content_length != ULLONG_MAX);
1884
0
        if (parser->upgrade && (parser->method == HTTP_CONNECT ||
1885
0
                                (parser->flags & F_SKIPBODY) || !hasBody)) {
1886
          /* Exit, the rest of the message is in a different protocol. */
1887
0
          UPDATE_STATE(NEW_MESSAGE());
1888
0
          CALLBACK_NOTIFY(message_complete);
1889
0
          RETURN((p - data) + 1);
1890
0
        }
1891
1892
0
        if (parser->flags & F_SKIPBODY) {
1893
0
          UPDATE_STATE(NEW_MESSAGE());
1894
0
          CALLBACK_NOTIFY(message_complete);
1895
0
        } else if (parser->flags & F_CHUNKED) {
1896
          /* chunked encoding - ignore Content-Length header,
1897
           * prepare for a chunk */
1898
0
          UPDATE_STATE(s_chunk_size_start);
1899
0
        } else if (parser->uses_transfer_encoding == 1) {
1900
0
          if (parser->type == HTTP_REQUEST && !lenient) {
1901
            /* RFC 7230 3.3.3 */
1902
1903
            /* If a Transfer-Encoding header field
1904
             * is present in a request and the chunked transfer coding is not
1905
             * the final encoding, the message body length cannot be determined
1906
             * reliably; the server MUST respond with the 400 (Bad Request)
1907
             * status code and then close the connection.
1908
             */
1909
0
            SET_ERRNO(HPE_INVALID_TRANSFER_ENCODING);
1910
0
            RETURN(p - data); /* Error */
1911
0
          } else {
1912
            /* RFC 7230 3.3.3 */
1913
1914
            /* If a Transfer-Encoding header field is present in a response and
1915
             * the chunked transfer coding is not the final encoding, the
1916
             * message body length is determined by reading the connection until
1917
             * it is closed by the server.
1918
             */
1919
0
            UPDATE_STATE(s_body_identity_eof);
1920
0
          }
1921
0
        } else {
1922
0
          if (parser->content_length == 0) {
1923
            /* Content-Length header given but zero: Content-Length: 0\r\n */
1924
0
            UPDATE_STATE(NEW_MESSAGE());
1925
0
            CALLBACK_NOTIFY(message_complete);
1926
0
          } else if (parser->content_length != ULLONG_MAX) {
1927
            /* Content-Length header given and non-zero */
1928
0
            UPDATE_STATE(s_body_identity);
1929
0
          } else {
1930
0
            if (!http_message_needs_eof(parser)) {
1931
              /* Assume content-length 0 - read the next */
1932
0
              UPDATE_STATE(NEW_MESSAGE());
1933
0
              CALLBACK_NOTIFY(message_complete);
1934
0
            } else {
1935
              /* Read body until EOF */
1936
0
              UPDATE_STATE(s_body_identity_eof);
1937
0
            }
1938
0
          }
1939
0
        }
1940
1941
0
        break;
1942
0
      }
1943
1944
0
      case s_body_identity:
1945
0
      {
1946
0
        uint64_t to_read = MIN(parser->content_length,
1947
0
                               (uint64_t) ((data + len) - p));
1948
1949
0
        assert(parser->content_length != 0
1950
0
            && parser->content_length != ULLONG_MAX);
1951
1952
        /* The difference between advancing content_length and p is because
1953
         * the latter will automaticaly advance on the next loop iteration.
1954
         * Further, if content_length ends up at 0, we want to see the last
1955
         * byte again for our message complete callback.
1956
         */
1957
0
        MARK(body);
1958
0
        parser->content_length -= to_read;
1959
0
        p += to_read - 1;
1960
1961
0
        if (parser->content_length == 0) {
1962
0
          UPDATE_STATE(s_message_done);
1963
1964
          /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
1965
           *
1966
           * The alternative to doing this is to wait for the next byte to
1967
           * trigger the data callback, just as in every other case. The
1968
           * problem with this is that this makes it difficult for the test
1969
           * harness to distinguish between complete-on-EOF and
1970
           * complete-on-length. It's not clear that this distinction is
1971
           * important for applications, but let's keep it for now.
1972
           */
1973
0
          CALLBACK_DATA_(body, p - body_mark + 1, p - data);
1974
0
          REEXECUTE();
1975
0
        }
1976
1977
0
        break;
1978
0
      }
1979
1980
      /* read until EOF */
1981
0
      case s_body_identity_eof:
1982
0
        MARK(body);
1983
0
        p = data + len - 1;
1984
1985
0
        break;
1986
1987
0
      case s_message_done:
1988
0
        UPDATE_STATE(NEW_MESSAGE());
1989
0
        CALLBACK_NOTIFY(message_complete);
1990
0
        if (parser->upgrade) {
1991
          /* Exit, the rest of the message is in a different protocol. */
1992
0
          RETURN((p - data) + 1);
1993
0
        }
1994
0
        break;
1995
1996
0
      case s_chunk_size_start:
1997
0
      {
1998
0
        assert(nread == 1);
1999
0
        assert(parser->flags & F_CHUNKED);
2000
2001
0
        unhex_val = unhex[(unsigned char)ch];
2002
0
        if (UNLIKELY(unhex_val == -1)) {
2003
0
          SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
2004
0
          goto error;
2005
0
        }
2006
2007
0
        parser->content_length = unhex_val;
2008
0
        UPDATE_STATE(s_chunk_size);
2009
0
        break;
2010
0
      }
2011
2012
0
      case s_chunk_size:
2013
0
      {
2014
0
        uint64_t t;
2015
2016
0
        assert(parser->flags & F_CHUNKED);
2017
2018
0
        if (ch == CR) {
2019
0
          UPDATE_STATE(s_chunk_size_almost_done);
2020
0
          break;
2021
0
        }
2022
2023
0
        unhex_val = unhex[(unsigned char)ch];
2024
2025
0
        if (unhex_val == -1) {
2026
0
          if (ch == ';' || ch == ' ') {
2027
0
            UPDATE_STATE(s_chunk_parameters);
2028
0
            break;
2029
0
          }
2030
2031
0
          SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
2032
0
          goto error;
2033
0
        }
2034
2035
0
        t = parser->content_length;
2036
0
        t *= 16;
2037
0
        t += unhex_val;
2038
2039
        /* Overflow? Test against a conservative limit for simplicity. */
2040
0
        if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) {
2041
0
          SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
2042
0
          goto error;
2043
0
        }
2044
2045
0
        parser->content_length = t;
2046
0
        break;
2047
0
      }
2048
2049
0
      case s_chunk_parameters:
2050
0
      {
2051
0
        assert(parser->flags & F_CHUNKED);
2052
        /* just ignore this shit. TODO check for overflow */
2053
0
        if (ch == CR) {
2054
0
          UPDATE_STATE(s_chunk_size_almost_done);
2055
0
          break;
2056
0
        }
2057
0
        break;
2058
0
      }
2059
2060
0
      case s_chunk_size_almost_done:
2061
0
      {
2062
0
        assert(parser->flags & F_CHUNKED);
2063
0
        STRICT_CHECK(ch != LF);
2064
2065
0
        parser->nread = 0;
2066
0
        nread = 0;
2067
2068
0
        if (parser->content_length == 0) {
2069
0
          parser->flags |= F_TRAILING;
2070
0
          UPDATE_STATE(s_header_field_start);
2071
0
        } else {
2072
0
          UPDATE_STATE(s_chunk_data);
2073
0
        }
2074
0
        CALLBACK_NOTIFY(chunk_header);
2075
0
        break;
2076
0
      }
2077
2078
0
      case s_chunk_data:
2079
0
      {
2080
0
        uint64_t to_read = MIN(parser->content_length,
2081
0
                               (uint64_t) ((data + len) - p));
2082
2083
0
        assert(parser->flags & F_CHUNKED);
2084
0
        assert(parser->content_length != 0
2085
0
            && parser->content_length != ULLONG_MAX);
2086
2087
        /* See the explanation in s_body_identity for why the content
2088
         * length and data pointers are managed this way.
2089
         */
2090
0
        MARK(body);
2091
0
        parser->content_length -= to_read;
2092
0
        p += to_read - 1;
2093
2094
0
        if (parser->content_length == 0) {
2095
0
          UPDATE_STATE(s_chunk_data_almost_done);
2096
0
        }
2097
2098
0
        break;
2099
0
      }
2100
2101
0
      case s_chunk_data_almost_done:
2102
0
        assert(parser->flags & F_CHUNKED);
2103
0
        assert(parser->content_length == 0);
2104
0
        STRICT_CHECK(ch != CR);
2105
0
        UPDATE_STATE(s_chunk_data_done);
2106
0
        CALLBACK_DATA(body);
2107
0
        break;
2108
2109
0
      case s_chunk_data_done:
2110
0
        assert(parser->flags & F_CHUNKED);
2111
0
        STRICT_CHECK(ch != LF);
2112
0
        parser->nread = 0;
2113
0
        nread = 0;
2114
0
        UPDATE_STATE(s_chunk_size_start);
2115
0
        CALLBACK_NOTIFY(chunk_complete);
2116
0
        break;
2117
2118
0
      default:
2119
0
        assert(0 && "unhandled state");
2120
0
        SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
2121
0
        goto error;
2122
0
    }
2123
0
  }
2124
2125
  /* Run callbacks for any marks that we have leftover after we ran out of
2126
   * bytes. There should be at most one of these set, so it's OK to invoke
2127
   * them in series (unset marks will not result in callbacks).
2128
   *
2129
   * We use the NOADVANCE() variety of callbacks here because 'p' has already
2130
   * overflowed 'data' and this allows us to correct for the off-by-one that
2131
   * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'
2132
   * value that's in-bounds).
2133
   */
2134
2135
0
  assert(((header_field_mark ? 1 : 0) +
2136
0
          (header_value_mark ? 1 : 0) +
2137
0
          (url_mark ? 1 : 0)  +
2138
0
          (body_mark ? 1 : 0) +
2139
0
          (status_mark ? 1 : 0)) <= 1);
2140
2141
0
  CALLBACK_DATA_NOADVANCE(header_field);
2142
0
  CALLBACK_DATA_NOADVANCE(header_value);
2143
0
  CALLBACK_DATA_NOADVANCE(url);
2144
0
  CALLBACK_DATA_NOADVANCE(body);
2145
0
  CALLBACK_DATA_NOADVANCE(status);
2146
2147
0
  RETURN(len);
2148
2149
0
error:
2150
0
  if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
2151
0
    SET_ERRNO(HPE_UNKNOWN);
2152
0
  }
2153
2154
0
  RETURN(p - data);
2155
0
}
2156
2157
2158
/* Does the parser need to see an EOF to find the end of the message? */
2159
int
2160
http_message_needs_eof (const http_parser *parser)
2161
0
{
2162
0
  if (parser->type == HTTP_REQUEST) {
2163
0
    return 0;
2164
0
  }
2165
2166
  /* See RFC 2616 section 4.4 */
2167
0
  if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
2168
0
      parser->status_code == 204 ||     /* No Content */
2169
0
      parser->status_code == 304 ||     /* Not Modified */
2170
0
      parser->flags & F_SKIPBODY) {     /* response to a HEAD request */
2171
0
    return 0;
2172
0
  }
2173
2174
  /* RFC 7230 3.3.3, see `s_headers_almost_done` */
2175
0
  if ((parser->uses_transfer_encoding == 1) &&
2176
0
      (parser->flags & F_CHUNKED) == 0) {
2177
0
    return 1;
2178
0
  }
2179
2180
0
  if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
2181
0
    return 0;
2182
0
  }
2183
2184
0
  return 1;
2185
0
}
2186
2187
2188
int
2189
http_should_keep_alive (const http_parser *parser)
2190
0
{
2191
0
  if (parser->http_major > 0 && parser->http_minor > 0) {
2192
    /* HTTP/1.1 */
2193
0
    if (parser->flags & F_CONNECTION_CLOSE) {
2194
0
      return 0;
2195
0
    }
2196
0
  } else {
2197
    /* HTTP/1.0 or earlier */
2198
0
    if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
2199
0
      return 0;
2200
0
    }
2201
0
  }
2202
2203
0
  return !http_message_needs_eof(parser);
2204
0
}
2205
2206
2207
const char *
2208
http_method_str (enum http_method m)
2209
0
{
2210
0
  return ELEM_AT(method_strings, m, "<unknown>");
2211
0
}
2212
2213
const char *
2214
http_status_str (enum http_status s)
2215
0
{
2216
0
  switch (s) {
2217
0
#define XX(num, name, string) case HTTP_STATUS_##name: return #string;
2218
0
    HTTP_STATUS_MAP(XX)
2219
0
#undef XX
2220
0
    default: return "<unknown>";
2221
0
  }
2222
0
}
2223
2224
void
2225
http_parser_init (http_parser *parser, enum http_parser_type t)
2226
0
{
2227
0
  void *data = parser->data; /* preserve application data */
2228
0
  memset(parser, 0, sizeof(*parser));
2229
0
  parser->data = data;
2230
0
  parser->type = t;
2231
0
  parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
2232
0
  parser->http_errno = HPE_OK;
2233
0
}
2234
2235
void
2236
http_parser_settings_init(http_parser_settings *settings)
2237
0
{
2238
0
  memset(settings, 0, sizeof(*settings));
2239
0
}
2240
2241
const char *
2242
0
http_errno_name(enum http_errno err) {
2243
0
  assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab));
2244
0
  return http_strerror_tab[err].name;
2245
0
}
2246
2247
const char *
2248
0
http_errno_description(enum http_errno err) {
2249
0
  assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab));
2250
0
  return http_strerror_tab[err].description;
2251
0
}
2252
2253
static enum http_host_state
2254
528k
http_parse_host_char(enum http_host_state s, const char ch) {
2255
528k
  switch(s) {
2256
284k
    case s_http_userinfo:
2257
284k
    case s_http_userinfo_start:
2258
284k
      if (ch == '@') {
2259
206
        return s_http_host_start;
2260
206
      }
2261
2262
284k
      if (IS_USERINFO_CHAR(ch)) {
2263
284k
        return s_http_userinfo;
2264
284k
      }
2265
4
      break;
2266
2267
566
    case s_http_host_start:
2268
566
      if (ch == '[') {
2269
182
        return s_http_host_v6_start;
2270
182
      }
2271
2272
384
      if (IS_HOST_CHAR(ch)) {
2273
244
        return s_http_host;
2274
244
      }
2275
2276
140
      break;
2277
2278
221k
    case s_http_host:
2279
221k
      if (IS_HOST_CHAR(ch)) {
2280
221k
        return s_http_host;
2281
221k
      }
2282
2283
    /* fall through */
2284
150
    case s_http_host_v6_end:
2285
150
      if (ch == ':') {
2286
114
        return s_http_host_port_start;
2287
114
      }
2288
2289
36
      break;
2290
2291
1.96k
    case s_http_host_v6:
2292
1.96k
      if (ch == ']') {
2293
9
        return s_http_host_v6_end;
2294
9
      }
2295
2296
    /* fall through */
2297
2.13k
    case s_http_host_v6_start:
2298
2.13k
      if (IS_HEX(ch) || ch == ':' || ch == '.') {
2299
2.00k
        return s_http_host_v6;
2300
2.00k
      }
2301
2302
128
      if (s == s_http_host_v6 && ch == '%') {
2303
92
        return s_http_host_v6_zone_start;
2304
92
      }
2305
36
      break;
2306
2307
2.48k
    case s_http_host_v6_zone:
2308
2.48k
      if (ch == ']') {
2309
1
        return s_http_host_v6_end;
2310
1
      }
2311
2312
    /* fall through */
2313
2.57k
    case s_http_host_v6_zone_start:
2314
      /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
2315
2.57k
      if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' ||
2316
2.55k
          ch == '~') {
2317
2.55k
        return s_http_host_v6_zone;
2318
2.55k
      }
2319
18
      break;
2320
2321
16.4k
    case s_http_host_port:
2322
16.5k
    case s_http_host_port_start:
2323
16.5k
      if (IS_NUM(ch)) {
2324
16.4k
        return s_http_host_port;
2325
16.4k
      }
2326
2327
11
      break;
2328
2329
11
    default:
2330
0
      break;
2331
528k
  }
2332
245
  return s_http_host_dead;
2333
528k
}
2334
2335
static int
2336
747
http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
2337
747
  enum http_host_state s;
2338
2339
747
  const char *p;
2340
747
  size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;
2341
2342
747
  assert(u->field_set & (1 << UF_HOST));
2343
2344
747
  u->field_data[UF_HOST].len = 0;
2345
2346
747
  s = found_at ? s_http_userinfo_start : s_http_host_start;
2347
2348
528k
  for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {
2349
528k
    enum http_host_state new_s = http_parse_host_char(s, *p);
2350
2351
528k
    if (new_s == s_http_host_dead) {
2352
245
      return 1;
2353
245
    }
2354
2355
527k
    switch(new_s) {
2356
221k
      case s_http_host:
2357
221k
        if (s != s_http_host) {
2358
244
          u->field_data[UF_HOST].off = (uint16_t)(p - buf);
2359
244
        }
2360
221k
        u->field_data[UF_HOST].len++;
2361
221k
        break;
2362
2363
2.00k
      case s_http_host_v6:
2364
2.00k
        if (s != s_http_host_v6) {
2365
159
          u->field_data[UF_HOST].off = (uint16_t)(p - buf);
2366
159
        }
2367
2.00k
        u->field_data[UF_HOST].len++;
2368
2.00k
        break;
2369
2370
92
      case s_http_host_v6_zone_start:
2371
2.64k
      case s_http_host_v6_zone:
2372
2.64k
        u->field_data[UF_HOST].len++;
2373
2.64k
        break;
2374
2375
16.4k
      case s_http_host_port:
2376
16.4k
        if (s != s_http_host_port) {
2377
69
          u->field_data[UF_PORT].off = (uint16_t)(p - buf);
2378
69
          u->field_data[UF_PORT].len = 0;
2379
69
          u->field_set |= (1 << UF_PORT);
2380
69
        }
2381
16.4k
        u->field_data[UF_PORT].len++;
2382
16.4k
        break;
2383
2384
284k
      case s_http_userinfo:
2385
284k
        if (s != s_http_userinfo) {
2386
191
          u->field_data[UF_USERINFO].off = (uint16_t)(p - buf);
2387
191
          u->field_data[UF_USERINFO].len = 0;
2388
191
          u->field_set |= (1 << UF_USERINFO);
2389
191
        }
2390
284k
        u->field_data[UF_USERINFO].len++;
2391
284k
        break;
2392
2393
512
      default:
2394
512
        break;
2395
527k
    }
2396
527k
    s = new_s;
2397
527k
  }
2398
2399
  /* Make sure we don't end somewhere unexpected */
2400
502
  switch (s) {
2401
175
    case s_http_host_start:
2402
176
    case s_http_host_v6_start:
2403
220
    case s_http_host_v6:
2404
221
    case s_http_host_v6_zone_start:
2405
293
    case s_http_host_v6_zone:
2406
327
    case s_http_host_port_start:
2407
327
    case s_http_userinfo:
2408
329
    case s_http_userinfo_start:
2409
329
      return 1;
2410
173
    default:
2411
173
      break;
2412
502
  }
2413
2414
173
  return 0;
2415
502
}
2416
2417
void
2418
966
http_parser_url_init(struct http_parser_url *u) {
2419
966
  memset(u, 0, sizeof(*u));
2420
966
}
2421
2422
int
2423
http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
2424
                      struct http_parser_url *u)
2425
1.93k
{
2426
1.93k
  enum state s;
2427
1.93k
  const char *p;
2428
1.93k
  enum http_parser_url_fields uf, old_uf;
2429
1.93k
  int found_at = 0;
2430
2431
1.93k
  if (buflen == 0) {
2432
0
    return 1;
2433
0
  }
2434
2435
1.93k
  u->port = u->field_set = 0;
2436
1.93k
  s = is_connect ? s_req_server_start : s_req_spaces_before_url;
2437
1.93k
  old_uf = UF_MAX;
2438
2439
2.03M
  for (p = buf; p < buf + buflen; p++) {
2440
2.03M
    s = parse_url_char(s, *p);
2441
2442
    /* Figure out the next field that we're operating on */
2443
2.03M
    switch (s) {
2444
952
      case s_dead:
2445
952
        return 1;
2446
2447
      /* Skip delimeters */
2448
81
      case s_req_schema_slash:
2449
118
      case s_req_schema_slash_slash:
2450
145
      case s_req_server_start:
2451
278
      case s_req_query_string_start:
2452
780
      case s_req_fragment_start:
2453
780
        continue;
2454
2455
284k
      case s_req_schema:
2456
284k
        uf = UF_SCHEMA;
2457
284k
        break;
2458
2459
450
      case s_req_server_with_at:
2460
450
        found_at = 1;
2461
2462
      /* fall through */
2463
905k
      case s_req_server:
2464
905k
        uf = UF_HOST;
2465
905k
        break;
2466
2467
404k
      case s_req_path:
2468
404k
        uf = UF_PATH;
2469
404k
        break;
2470
2471
435k
      case s_req_query_string:
2472
435k
        uf = UF_QUERY;
2473
435k
        break;
2474
2475
862
      case s_req_fragment:
2476
862
        uf = UF_FRAGMENT;
2477
862
        break;
2478
2479
0
      default:
2480
0
        assert(!"Unexpected state");
2481
0
        return 1;
2482
2.03M
    }
2483
2484
    /* Nothing's changed; soldier on */
2485
2.03M
    if (uf == old_uf) {
2486
2.03M
      u->field_data[uf].len++;
2487
2.03M
      continue;
2488
2.03M
    }
2489
2490
1.40k
    u->field_data[uf].off = (uint16_t)(p - buf);
2491
1.40k
    u->field_data[uf].len = 1;
2492
2493
1.40k
    u->field_set |= (1 << uf);
2494
1.40k
    old_uf = uf;
2495
1.40k
  }
2496
2497
  /* host must be present if there is a schema */
2498
  /* parsing http:///toto will fail */
2499
980
  if ((u->field_set & (1 << UF_SCHEMA)) &&
2500
50
      (u->field_set & (1 << UF_HOST)) == 0) {
2501
25
    return 1;
2502
25
  }
2503
2504
955
  if (u->field_set & (1 << UF_HOST)) {
2505
747
    if (http_parse_host(buf, u, found_at) != 0) {
2506
574
      return 1;
2507
574
    }
2508
747
  }
2509
2510
  /* CONNECT requests can only contain "hostname:port" */
2511
381
  if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
2512
200
    return 1;
2513
200
  }
2514
2515
181
  if (u->field_set & (1 << UF_PORT)) {
2516
69
    uint16_t off;
2517
69
    uint16_t len;
2518
69
    const char* p;
2519
69
    const char* end;
2520
69
    unsigned long v;
2521
2522
69
    off = u->field_data[UF_PORT].off;
2523
69
    len = u->field_data[UF_PORT].len;
2524
69
    end = buf + off + len;
2525
2526
    /* NOTE: The characters are already validated and are in the [0-9] range */
2527
69
    assert((size_t) (off + len) <= buflen && "Port number overflow");
2528
69
    v = 0;
2529
578
    for (p = buf + off; p < end; p++) {
2530
522
      v *= 10;
2531
522
      v += *p - '0';
2532
2533
      /* Ports have a max value of 2^16 */
2534
522
      if (v > 0xffff) {
2535
13
        return 1;
2536
13
      }
2537
522
    }
2538
2539
56
    u->port = (uint16_t) v;
2540
56
  }
2541
2542
168
  return 0;
2543
181
}
2544
2545
void
2546
0
http_parser_pause(http_parser *parser, int paused) {
2547
  /* Users should only be pausing/unpausing a parser that is not in an error
2548
   * state. In non-debug builds, there's not much that we can do about this
2549
   * other than ignore it.
2550
   */
2551
0
  if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
2552
0
      HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
2553
0
    uint32_t nread = parser->nread; /* used by the SET_ERRNO macro */
2554
0
    SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
2555
0
  } else {
2556
0
    assert(0 && "Attempting to pause parser in error state");
2557
0
  }
2558
0
}
2559
2560
int
2561
0
http_body_is_final(const struct http_parser *parser) {
2562
0
    return parser->state == s_message_done;
2563
0
}
2564
2565
unsigned long
2566
0
http_parser_version(void) {
2567
0
  return HTTP_PARSER_VERSION_MAJOR * 0x10000 |
2568
0
         HTTP_PARSER_VERSION_MINOR * 0x00100 |
2569
0
         HTTP_PARSER_VERSION_PATCH * 0x00001;
2570
0
}
2571
2572
void
2573
0
http_parser_set_max_header_size(uint32_t size) {
2574
0
  max_header_size = size;
2575
0
}