Coverage Report

Created: 2026-07-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-http/http-request-parser.c
Line
Count
Source
1
/* Copyright (c) Dovecot authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "istream.h"
5
#include "http-url.h"
6
#include "http-parser.h"
7
#include "http-message-parser.h"
8
#include "http-request-parser.h"
9
10
82.9k
#define HTTP_REQUEST_PARSER_MAX_METHOD_LENGTH 32
11
12
enum http_request_parser_state {
13
  HTTP_REQUEST_PARSE_STATE_INIT = 0,
14
  HTTP_REQUEST_PARSE_STATE_SKIP_LINE,
15
  HTTP_REQUEST_PARSE_STATE_METHOD,
16
  HTTP_REQUEST_PARSE_STATE_SP1,
17
  HTTP_REQUEST_PARSE_STATE_TARGET,
18
  HTTP_REQUEST_PARSE_STATE_SP2,
19
  HTTP_REQUEST_PARSE_STATE_VERSION,
20
  HTTP_REQUEST_PARSE_STATE_CR,
21
  HTTP_REQUEST_PARSE_STATE_LF,
22
  HTTP_REQUEST_PARSE_STATE_HEADER
23
};
24
25
struct http_request_parser {
26
  struct http_message_parser parser;
27
  pool_t pool;
28
29
  enum http_request_parser_state state;
30
31
  struct http_url *default_base_url;
32
33
  uoff_t max_target_length;
34
35
  enum http_request_parse_error error_code;
36
37
  const char *request_method;
38
  const char *request_target;
39
40
  bool skipping_line:1;
41
};
42
43
struct http_request_parser *
44
http_request_parser_init(struct istream *input,
45
       const struct http_url *default_base_url,
46
       const struct http_request_limits *limits,
47
       enum http_request_parse_flags flags)
48
7.00k
{
49
7.00k
  struct http_request_parser *parser;
50
7.00k
  pool_t pool;
51
7.00k
  struct http_header_limits hdr_limits;
52
7.00k
  uoff_t max_payload_size;
53
7.00k
  enum http_message_parse_flags msg_flags = 0;
54
55
7.00k
  pool = pool_alloconly_create("http request parser", 1024);
56
7.00k
  parser = p_new(pool, struct http_request_parser, 1);
57
7.00k
  parser->pool = pool;
58
59
7.00k
  if (default_base_url != NULL) {
60
0
    parser->default_base_url =
61
0
      http_url_clone_authority(pool, default_base_url);
62
0
  }
63
64
7.00k
  if (limits != NULL) {
65
0
    hdr_limits = limits->header;
66
0
    max_payload_size = limits->max_payload_size;
67
0
    parser->max_target_length = limits->max_target_length;
68
7.00k
  } else {
69
7.00k
    i_zero(&hdr_limits);
70
7.00k
    max_payload_size = 0;
71
7.00k
    parser->max_target_length = 0;
72
7.00k
  }
73
74
  /* substitute default limits */
75
7.00k
  if (parser->max_target_length == 0)
76
7.00k
    parser->max_target_length = HTTP_REQUEST_DEFAULT_MAX_TARGET_LENGTH;
77
7.00k
  if (hdr_limits.max_size == 0)
78
7.00k
    hdr_limits.max_size = HTTP_REQUEST_DEFAULT_MAX_HEADER_SIZE;
79
7.00k
  if (hdr_limits.max_field_size == 0)
80
7.00k
    hdr_limits.max_field_size = HTTP_REQUEST_DEFAULT_MAX_HEADER_FIELD_SIZE;
81
7.00k
  if (hdr_limits.max_fields == 0)
82
7.00k
    hdr_limits.max_fields = HTTP_REQUEST_DEFAULT_MAX_HEADER_FIELDS;
83
7.00k
  if (max_payload_size == 0)
84
7.00k
    max_payload_size = HTTP_REQUEST_DEFAULT_MAX_PAYLOAD_SIZE;
85
86
7.00k
  if ((flags & HTTP_REQUEST_PARSE_FLAG_STRICT) != 0)
87
0
    msg_flags |= HTTP_MESSAGE_PARSE_FLAG_STRICT;
88
7.00k
  http_message_parser_init(&parser->parser, input,
89
7.00k
    &hdr_limits, max_payload_size, msg_flags);
90
7.00k
  return parser;
91
7.00k
}
92
93
void http_request_parser_deinit(struct http_request_parser **_parser)
94
7.00k
{
95
7.00k
  struct http_request_parser *parser = *_parser;
96
97
7.00k
  *_parser = NULL;
98
99
7.00k
  http_message_parser_deinit(&parser->parser);
100
7.00k
  pool_unref(&parser->pool);
101
7.00k
}
102
103
static void
104
http_request_parser_restart(struct http_request_parser *parser,
105
  pool_t pool)
106
86.9k
{
107
86.9k
  http_message_parser_restart(&parser->parser, pool);
108
86.9k
  parser->request_method = NULL;
109
86.9k
  parser->request_target = NULL;
110
86.9k
}
111
112
static int http_request_parse_method(struct http_request_parser *parser)
113
82.9k
{
114
82.9k
  const unsigned char *p = parser->parser.cur;
115
82.9k
  pool_t pool;
116
117
  /* method         = token
118
   */
119
142k
  while (p < parser->parser.end && http_char_is_token(*p))
120
59.4k
    p++;
121
122
82.9k
  if ((p - parser->parser.cur) > HTTP_REQUEST_PARSER_MAX_METHOD_LENGTH) {
123
4
    parser->error_code = HTTP_REQUEST_PARSE_ERROR_METHOD_TOO_LONG;
124
4
    parser->parser.error = "HTTP request method is too long";
125
4
    return -1;
126
4
  }
127
82.9k
  if (p == parser->parser.end)
128
135
    return 0;
129
82.8k
  pool = http_message_parser_get_pool(&parser->parser);
130
82.8k
  parser->request_method =
131
82.8k
    p_strdup_until(pool, parser->parser.cur, p);
132
82.8k
  parser->parser.cur = p;
133
82.8k
  return 1;
134
82.9k
}
135
136
static int http_request_parse_target(struct http_request_parser *parser)
137
82.5k
{
138
82.5k
  struct http_message_parser *_parser = &parser->parser;
139
82.5k
  const unsigned char *p = parser->parser.cur;
140
82.5k
  pool_t pool;
141
142
  /* We'll just parse anything up to the first SP or a control char.
143
     We could also implement workarounds for buggy HTTP clients and
144
     parse anything up to the HTTP-version and return 301 with the
145
     target properly encoded (FIXME). */
146
20.0M
  while (p < _parser->end && *p > ' ')
147
19.9M
    p++;
148
149
  /* target is too long when explicit limit is exceeded or when input buffer
150
     runs out of space */
151
  /* FIXME: put limit on full request line rather than target and method
152
     separately */
153
  /* FIXME: is it wise to keep target in stream buffer? It can become very
154
     large for some applications, increasing the stream buffer size */
155
82.5k
  if ((uoff_t)(p - _parser->cur) > parser->max_target_length ||
156
82.5k
    (p == _parser->end && ((uoff_t)(p - _parser->cur) >=
157
131
      i_stream_get_max_buffer_size(_parser->input)))) {
158
27
    parser->error_code = HTTP_REQUEST_PARSE_ERROR_TARGET_TOO_LONG;
159
27
    parser->parser.error = "HTTP request target is too long";
160
27
    return -1;
161
27
  }
162
82.5k
  if (p == _parser->end)
163
131
    return 0;
164
82.4k
  pool = http_message_parser_get_pool(_parser);
165
82.4k
  parser->request_target = p_strdup_until(pool, _parser->cur, p);
166
82.4k
  parser->parser.cur = p;
167
82.4k
  return 1;
168
82.5k
}
169
170
static inline const char *_chr_sanitize(unsigned char c)
171
433
{
172
433
  if (c >= 0x20 && c < 0x7F)
173
99
    return t_strdup_printf("`%c'", c);
174
334
  if (c == 0x0a)
175
108
    return "<LF>";
176
226
  if (c == 0x0d)
177
3
    return "<CR>";
178
223
  return t_strdup_printf("<0x%02x>", c);
179
226
}
180
181
static int http_request_parse(struct http_request_parser *parser,
182
            pool_t pool)
183
83.0k
{
184
83.0k
  struct http_message_parser *_parser = &parser->parser;
185
83.0k
  int ret;
186
187
  /* RFC 7230, Section 3.1.1: Request Line
188
189
     request-line  = method SP request-target SP HTTP-version CRLF
190
     method        = token
191
   */
192
90.9k
  for (;;) {
193
90.9k
    switch (parser->state) {
194
86.9k
    case HTTP_REQUEST_PARSE_STATE_INIT:
195
86.9k
      http_request_parser_restart(parser, pool);
196
86.9k
      parser->state = HTTP_REQUEST_PARSE_STATE_SKIP_LINE;
197
86.9k
      if (_parser->cur == _parser->end)
198
9
        return 0;
199
      /* fall through */
200
86.9k
    case HTTP_REQUEST_PARSE_STATE_SKIP_LINE:
201
86.9k
      if (*_parser->cur == '\r' || *_parser->cur == '\n') {
202
3.98k
        if (parser->skipping_line) {
203
          /* second extra CRLF; not allowed */
204
10
          parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
205
10
          _parser->error = "Empty request line";
206
10
          return -1;
207
10
        }
208
        /* HTTP/1.0 client sent one extra CRLF after body.
209
           ignore it. */
210
3.97k
        parser->skipping_line = TRUE;
211
3.97k
        parser->state = HTTP_REQUEST_PARSE_STATE_CR;
212
3.97k
        break;
213
3.98k
      }
214
82.9k
      parser->state = HTTP_REQUEST_PARSE_STATE_METHOD;
215
82.9k
      parser->skipping_line = FALSE;
216
      /* fall through */
217
82.9k
    case HTTP_REQUEST_PARSE_STATE_METHOD:
218
82.9k
      if ((ret=http_request_parse_method(parser)) <= 0)
219
139
        return ret;
220
82.8k
      parser->state = HTTP_REQUEST_PARSE_STATE_SP1;
221
82.8k
      if (_parser->cur == _parser->end)
222
0
        return 0;
223
      /* fall through */
224
82.8k
    case HTTP_REQUEST_PARSE_STATE_SP1:
225
82.8k
      if (*_parser->cur != ' ') {
226
226
        parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
227
226
        _parser->error = t_strdup_printf
228
226
          ("Unexpected character %s in request method",
229
226
            _chr_sanitize(*_parser->cur));
230
226
        return -1;
231
226
      }
232
82.6k
      _parser->cur++;
233
82.6k
      parser->state = HTTP_REQUEST_PARSE_STATE_TARGET;
234
82.6k
      if (_parser->cur >= _parser->end)
235
32
        return 0;
236
      /* fall through */
237
82.5k
    case HTTP_REQUEST_PARSE_STATE_TARGET:
238
82.5k
      if ((ret=http_request_parse_target(parser)) <= 0)
239
158
        return ret;
240
82.4k
      parser->state = HTTP_REQUEST_PARSE_STATE_SP2;
241
82.4k
      if (_parser->cur == _parser->end)
242
0
        return 0;
243
      /* fall through */
244
82.4k
    case HTTP_REQUEST_PARSE_STATE_SP2:
245
82.4k
      if (*_parser->cur != ' ') {
246
163
        parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
247
163
        _parser->error = t_strdup_printf
248
163
          ("Unexpected character %s in request target",
249
163
            _chr_sanitize(*_parser->cur));
250
163
        return -1;
251
163
      }
252
82.2k
      _parser->cur++;
253
82.2k
      parser->state = HTTP_REQUEST_PARSE_STATE_VERSION;
254
82.2k
      if (_parser->cur >= _parser->end)
255
19
        return 0;
256
      /* fall through */
257
82.2k
    case HTTP_REQUEST_PARSE_STATE_VERSION:
258
82.2k
      if ((ret=http_message_parse_version(&parser->parser)) <= 0) {
259
158
        if (ret < 0) {
260
107
          parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
261
107
          _parser->error = "Invalid HTTP version in request";
262
107
        }
263
158
        return ret;
264
158
      }
265
82.0k
      parser->state = HTTP_REQUEST_PARSE_STATE_CR;
266
82.0k
      if (_parser->cur == _parser->end)
267
2
        return 0;
268
      /* fall through */
269
86.0k
    case HTTP_REQUEST_PARSE_STATE_CR:
270
86.0k
      if (*_parser->cur == '\r')
271
3.59k
        _parser->cur++;
272
86.0k
      parser->state = HTTP_REQUEST_PARSE_STATE_LF;
273
86.0k
      if (_parser->cur == _parser->end)
274
5
        return 0;
275
      /* fall through */
276
86.0k
    case HTTP_REQUEST_PARSE_STATE_LF:
277
86.0k
      if (*_parser->cur != '\n') {
278
44
        parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
279
44
        _parser->error = t_strdup_printf
280
44
          ("Unexpected character %s at end of request line",
281
44
            _chr_sanitize(*_parser->cur));
282
44
        return -1;
283
44
      }
284
86.0k
      _parser->cur++;
285
86.0k
      if (!parser->skipping_line) {
286
82.0k
        parser->state = HTTP_REQUEST_PARSE_STATE_HEADER;
287
82.0k
        return 1;
288
82.0k
      }
289
3.94k
      parser->state = HTTP_REQUEST_PARSE_STATE_INIT;
290
3.94k
      break;
291
0
    case HTTP_REQUEST_PARSE_STATE_HEADER:
292
0
    default:
293
0
      i_unreached();
294
90.9k
    }
295
90.9k
  }
296
297
83.0k
  i_unreached();
298
83.0k
}
299
300
static int http_request_parse_request_line(struct http_request_parser *parser,
301
             pool_t pool)
302
83.7k
{
303
83.7k
  struct http_message_parser *_parser = &parser->parser;
304
83.7k
  const unsigned char *begin;
305
83.7k
  size_t size, old_bytes = 0;
306
83.7k
  int ret;
307
308
84.1k
  while ((ret = i_stream_read_bytes(_parser->input, &begin, &size,
309
84.1k
            old_bytes + 1)) > 0) {
310
83.0k
    _parser->begin = _parser->cur = begin;
311
83.0k
    _parser->end = _parser->begin + size;
312
313
83.0k
    if ((ret = http_request_parse(parser, pool)) < 0)
314
581
      return -1;
315
316
82.4k
    i_stream_skip(_parser->input, _parser->cur - begin);
317
82.4k
    if (ret > 0)
318
82.0k
      return 1;
319
384
    old_bytes = i_stream_get_data_size(_parser->input);
320
384
  }
321
322
1.12k
  if (ret == -2) {
323
0
    parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
324
0
    _parser->error = "HTTP request line is too long";
325
0
    return -1;
326
0
  }
327
1.12k
  if (ret < 0) {
328
1.12k
    if (_parser->input->eof &&
329
1.12k
      parser->state == HTTP_REQUEST_PARSE_STATE_INIT)
330
738
      return 0;
331
384
    parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_STREAM;
332
384
    _parser->error = "Broken stream";
333
384
    return -1;
334
1.12k
  }
335
0
  return 0;
336
1.12k
}
337
338
static inline enum http_request_parse_error
339
http_request_parser_message_error(struct http_request_parser *parser)
340
3.43k
{
341
3.43k
  switch (parser->parser.error_code) {
342
1.33k
  case HTTP_MESSAGE_PARSE_ERROR_BROKEN_STREAM:
343
1.33k
    return HTTP_REQUEST_PARSE_ERROR_BROKEN_STREAM;
344
6
  case HTTP_MESSAGE_PARSE_ERROR_BAD_MESSAGE:
345
6
    return HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
346
7
  case HTTP_MESSAGE_PARSE_ERROR_NOT_IMPLEMENTED:
347
7
    return HTTP_REQUEST_PARSE_ERROR_NOT_IMPLEMENTED;
348
335
  case HTTP_MESSAGE_PARSE_ERROR_PAYLOAD_TOO_LARGE:
349
335
    return HTTP_REQUEST_PARSE_ERROR_PAYLOAD_TOO_LARGE;
350
1.74k
  case HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE:
351
1.74k
    return HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
352
0
  default:
353
0
    break;
354
3.43k
  }
355
3.43k
  i_unreached();
356
3.43k
}
357
358
bool http_request_parser_pending_payload(
359
  struct http_request_parser *parser)
360
0
{
361
0
  if (parser->parser.payload == NULL)
362
0
    return FALSE;
363
0
  return i_stream_have_bytes_left(parser->parser.payload);
364
0
}
365
366
static int
367
http_request_parse_expect_header(struct http_request_parser *parser,
368
  struct http_request *request, const struct http_header_field *hdr)
369
630
{
370
630
  struct http_message_parser *_parser = &parser->parser;
371
630
  struct http_parser hparser;
372
630
  bool parse_error = FALSE;
373
630
  unsigned int num_expectations = 0;
374
375
  /* RFC 7231, Section 5.1.1:
376
377
     Expect  = "100-continue"
378
   */
379
  // FIXME: simplify; RFC 7231 discarded Expect extension mechanism
380
630
  http_parser_init(&hparser, (const unsigned char *)hdr->value, hdr->size);
381
4.28k
  while (!parse_error) {
382
4.28k
    const char *expect_name, *expect_value;
383
384
    /* expect-name */
385
4.28k
    if (http_parse_token(&hparser, &expect_name) > 0) {
386
2.54k
      num_expectations++;
387
2.54k
      if (strcasecmp(expect_name, "100-continue") == 0) {
388
1.53k
        request->expect_100_continue = TRUE;
389
1.53k
      } else {
390
1.01k
        if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) {
391
198
          parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED;
392
198
          _parser->error = t_strdup_printf
393
198
            ("Unknown Expectation `%s'", expect_name);
394
198
        }
395
1.01k
      }
396
397
      /* BWS "=" BWS */
398
2.54k
      http_parse_ows(&hparser);
399
2.54k
      if (hparser.cur >= hparser.end)
400
180
        break;
401
402
2.36k
      if (*hparser.cur == '=') {
403
433
        hparser.cur++;
404
433
        http_parse_ows(&hparser);
405
406
        /* value */
407
433
        if (http_parse_token_or_qstring(&hparser, &expect_value) <= 0) {
408
21
          parse_error = TRUE;
409
21
          break;
410
21
        }
411
412
412
        if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) {
413
1
          parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED;
414
1
          _parser->error = t_strdup_printf
415
1
            ("Expectation `%s' has unexpected value", expect_name);
416
1
        }
417
412
      }
418
419
      /* *( OWS ";" [ OWS expect-param ] ) */
420
2.67k
      while (!parse_error) {
421
2.67k
        const char *attribute, *value;
422
423
        /* OWS ";" */
424
2.67k
        http_parse_ows(&hparser);
425
2.67k
        if (hparser.cur >= hparser.end || *hparser.cur != ';')
426
2.33k
          break;
427
340
        hparser.cur++;
428
340
        http_parse_ows(&hparser);
429
430
        /* expect-param */
431
340
        if (http_parse_token(&hparser, &attribute) <= 0) {
432
3
          parse_error = TRUE;
433
3
          break;
434
3
        }
435
436
        /* BWS "=" BWS */
437
337
        http_parse_ows(&hparser);
438
337
        if (hparser.cur >= hparser.end || *hparser.cur != '=') {
439
7
          parse_error = TRUE;
440
7
          break;
441
7
        }
442
330
        hparser.cur++;
443
330
        http_parse_ows(&hparser);
444
445
        /* value */
446
330
        if (http_parse_token_or_qstring(&hparser, &value) <= 0) {
447
4
          parse_error = TRUE;
448
4
          break;
449
4
        }
450
451
326
        if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) {
452
1
          parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED;
453
1
          _parser->error = t_strdup_printf
454
1
            ("Expectation `%s' has unknown parameter `'%s'",
455
1
              expect_name, attribute);
456
1
        }
457
326
      }
458
2.34k
      if (parse_error)
459
14
        break;
460
2.34k
    }
461
4.06k
    http_parse_ows(&hparser);
462
4.06k
    if (hparser.cur >= hparser.end || *hparser.cur != ',')
463
415
      break;
464
3.65k
    hparser.cur++;
465
3.65k
    http_parse_ows(&hparser);
466
3.65k
  }
467
468
630
  if (parse_error || hparser.cur < hparser.end) {
469
83
    parser->error_code = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
470
83
    _parser->error = "Invalid Expect header";
471
83
    return -1;
472
83
  }
473
474
547
  if (parser->error_code != HTTP_REQUEST_PARSE_ERROR_NONE)
475
132
    return -1;
476
477
415
  if (num_expectations == 0) {
478
14
    parser->error_code = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
479
14
    _parser->error = "Empty Expect header";
480
14
    return -1;
481
14
  }
482
401
  return 0;
483
415
}
484
485
static int
486
http_request_parse_headers(struct http_request_parser *parser,
487
  struct http_request *request)
488
77.7k
{
489
77.7k
  const ARRAY_TYPE(http_header_field) *hdrs;
490
77.7k
  const struct http_header_field *hdr;
491
492
77.7k
  hdrs = http_header_get_fields(parser->parser.msg.header);
493
232k
  array_foreach(hdrs, hdr) {
494
232k
    int ret = 0;
495
496
    /* Expect: */
497
232k
    if (http_header_field_is(hdr, "Expect"))
498
630
      ret = http_request_parse_expect_header(parser, request, hdr);
499
500
232k
    if (ret < 0)
501
229
      return -1;
502
232k
  }
503
77.5k
  return 0;
504
77.7k
}
505
506
int http_request_parse_finish_payload(
507
  struct http_request_parser *parser,
508
  enum http_request_parse_error *error_code_r,
509
  const char **error_r)
510
84.5k
{
511
84.5k
  int ret;
512
513
84.5k
  *error_code_r = parser->error_code = HTTP_REQUEST_PARSE_ERROR_NONE;
514
84.5k
  *error_r = parser->parser.error = NULL;
515
516
  /* make sure we finished streaming payload from previous request
517
     before we continue. */
518
84.5k
  if ((ret = http_message_parse_finish_payload(&parser->parser)) <= 0) {
519
797
    if (ret < 0) {
520
797
      *error_code_r = http_request_parser_message_error(parser);
521
797
      *error_r = parser->parser.error;
522
797
    }
523
797
  }
524
84.5k
  return ret;
525
84.5k
}
526
527
int http_request_parse_next(struct http_request_parser *parser,
528
          pool_t pool, struct http_request *request,
529
          enum http_request_parse_error *error_code_r, const char **error_r)
530
84.5k
{
531
84.5k
  const struct http_header_field *hdr;
532
84.5k
  const char *host_hdr, *error;
533
84.5k
  int ret;
534
535
  /* initialize and get rid of any payload of previous request */
536
84.5k
  if ((ret=http_request_parse_finish_payload
537
84.5k
    (parser, error_code_r, error_r)) <= 0)
538
797
    return ret;
539
540
  /* RFC 7230, Section 3:
541
542
     HTTP-message   = start-line
543
                     *( header-field CRLF )
544
                      CRLF
545
                      [ message-body ]
546
   */
547
83.7k
  if (parser->state != HTTP_REQUEST_PARSE_STATE_HEADER) {
548
83.7k
    ret = http_request_parse_request_line(parser, pool);
549
550
    /* assign early for error reporting */
551
83.7k
    request->method = parser->request_method;
552
83.7k
    request->target_raw = parser->request_target;
553
83.7k
    request->version_major = parser->parser.msg.version_major;
554
83.7k
    request->version_minor = parser->parser.msg.version_minor;
555
556
83.7k
    if (ret <= 0) {
557
1.70k
      if (ret < 0) {
558
965
        *error_code_r = parser->error_code;
559
965
        *error_r = parser->parser.error;
560
965
      }
561
1.70k
      return ret;
562
1.70k
    }
563
83.7k
  }
564
565
82.0k
  if ((ret = http_message_parse_headers(&parser->parser)) <= 0) {
566
2.34k
    if (ret < 0) {
567
2.34k
      *error_code_r = http_request_parser_message_error(parser);
568
2.34k
      *error_r = parser->parser.error;
569
2.34k
    }
570
2.34k
    return ret;
571
2.34k
  }
572
573
79.7k
  if (http_message_parse_body(&parser->parser, TRUE) < 0) {
574
292
    *error_code_r = http_request_parser_message_error(parser);
575
292
    *error_r = parser->parser.error;
576
292
    return -1;
577
292
  }
578
79.4k
  parser->state = HTTP_REQUEST_PARSE_STATE_INIT;
579
580
  /* RFC 7230, Section 5.4: Host
581
582
     A server MUST respond with a 400 (Bad Request) status code to any
583
     HTTP/1.1 request message that lacks a Host header field and to any
584
     request message that contains more than one Host header field or a
585
     Host header field with an invalid field-value.
586
   */
587
79.4k
  host_hdr = NULL;
588
79.4k
  if (parser->parser.msg.version_major == 1 &&
589
79.3k
      parser->parser.msg.version_minor > 0) {
590
79.2k
    if ((ret=http_header_field_find_unique(
591
79.2k
      parser->parser.msg.header, "Host", &hdr)) <= 0) {
592
139
      *error_code_r = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
593
139
      if (ret == 0)
594
128
        *error_r = "Missing Host header";
595
11
      else
596
11
        *error_r = "Duplicate Host header";
597
139
      return -1;
598
139
    }
599
600
79.0k
    host_hdr = hdr->value;
601
79.0k
  }
602
603
79.2k
  i_zero(request);
604
605
79.2k
  pool = http_message_parser_get_pool(&parser->parser);
606
79.2k
  if (http_url_request_target_parse(parser->request_target, host_hdr,
607
79.2k
    parser->default_base_url, pool, &request->target, &error) < 0) {
608
1.50k
    *error_code_r = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
609
1.50k
    *error_r = t_strdup_printf("Bad request target `%s': %s",
610
1.50k
      parser->request_target, error);
611
1.50k
    return -1;
612
1.50k
  }
613
614
  /* parse request-specific headers */
615
77.7k
  if (http_request_parse_headers(parser, request) < 0) {
616
229
    *error_code_r = parser->error_code;
617
229
    *error_r = parser->parser.error;
618
229
    return -1;
619
229
  }
620
621
77.5k
  request->method = parser->request_method;
622
77.5k
  request->target_raw = parser->request_target;
623
77.5k
  request->version_major = parser->parser.msg.version_major;
624
77.5k
  request->version_minor = parser->parser.msg.version_minor;
625
77.5k
  request->date = parser->parser.msg.date;
626
77.5k
  request->payload = parser->parser.payload;
627
77.5k
  request->header = parser->parser.msg.header;
628
77.5k
  request->connection_options = parser->parser.msg.connection_options;
629
77.5k
  request->connection_close = parser->parser.msg.connection_close;
630
631
  /* reset this state early */
632
77.5k
  parser->request_method = NULL;
633
77.5k
  parser->request_target = NULL;
634
77.5k
  return 1;
635
77.7k
}