Coverage Report

Created: 2026-08-31 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/src/h1.c
Line
Count
Source
1
/*
2
 * HTTP/1 protocol analyzer
3
 *
4
 * Copyright 2000-2017 Willy Tarreau <w@1wt.eu>
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version
9
 * 2 of the License, or (at your option) any later version.
10
 *
11
 */
12
13
#include <ctype.h>
14
15
#include <import/sha1.h>
16
17
#include <haproxy/api.h>
18
#include <haproxy/base64.h>
19
#include <haproxy/cfgparse.h>
20
#include <haproxy/h1.h>
21
#include <haproxy/http-hdr.h>
22
#include <haproxy/tools.h>
23
24
/* by default, RFC9112#6.1 applies, t-e combined with c-l represents a risk of
25
 * smuggling if it crosses another 1.0 agent so we must close at the end of the
26
 * transaction. But it may cause difficulties to some very old broken devices.
27
 */
28
int h1_do_not_close_on_insecure_t_e = 0;
29
30
/* Parse the Transfer-Encoding: header field of an HTTP/1 request, looking for
31
 * "chunked" encoding to perform some checks (it must be the last encoding for
32
 * the request and must not be performed twice for any message). The
33
 * H1_MF_TE_CHUNKED is set if a valid "chunked" encoding is found. The
34
 * H1_MF_TE_OTHER flag is set if any other encoding is found. The H1_MF_XFER_ENC
35
 * flag is always set. The H1_MF_CHNK is set when "chunked" encoding is the last
36
 * one. Note that transfer codings are case-insensitive (cf RFC7230#4). This
37
 * function returns -2 for a fatal error, -1 for an error that may be hiidden by
38
 * config, 0 if the whole header can be dropped (not used yet), or >0 if the
39
 * value can be indexed.
40
 */
41
int h1_parse_xfer_enc_header(struct h1m *h1m, struct ist value)
42
0
{
43
0
  char *e, *n;
44
0
  struct ist word;
45
0
  int ret = 1;
46
47
  /* Reject empty header */
48
0
  if (istptr(value) == istend(value)) {
49
0
    ret = -1;
50
0
    goto end;
51
0
  }
52
53
0
  h1m->flags |= H1_MF_XFER_ENC;
54
55
0
  word.ptr = value.ptr - 1; // -1 for next loop's pre-increment
56
0
  e = istend(value);
57
58
0
  while (++word.ptr < e) {
59
    /* skip leading delimiter and blanks */
60
0
    if (HTTP_IS_LWS(*word.ptr))
61
0
      continue;
62
63
0
    n = http_find_hdr_value_end(word.ptr, e); // next comma or end of line
64
65
    /* a comma at the end means the last value is empty */
66
0
    if (n+1 == e)
67
0
      ret = -1;
68
0
    word.len = n - word.ptr;
69
70
    /* trim trailing blanks */
71
0
    while (word.len && HTTP_IS_LWS(word.ptr[word.len-1]))
72
0
      word.len--;
73
74
0
    h1m->flags &= ~H1_MF_CHNK;
75
76
    /* empty values are forbidden */
77
0
    if (!word.len)
78
0
      ret = -1;
79
0
    else if (isteqi(word, ist("chunked"))) {
80
0
      if (h1m->flags & H1_MF_TE_CHUNKED) {
81
        /* cf RFC7230#3.3.1 : A sender MUST NOT apply
82
         * chunked more than once to a message body
83
         * (i.e., chunking an already chunked message is
84
         * not allowed)
85
         */
86
0
        ret = -1;
87
0
      }
88
0
      h1m->flags |= (H1_MF_TE_CHUNKED|H1_MF_CHNK);
89
0
    }
90
0
    else {
91
0
      if ((h1m->flags & (H1_MF_RESP|H1_MF_TE_CHUNKED)) == H1_MF_TE_CHUNKED) {
92
        /* cf RFC7230#3.3.1 : If any transfer coding
93
         * other than chunked is applied to a request
94
         * payload body, the sender MUST apply chunked
95
         * as the final transfer coding to ensure that
96
         * the message is properly framed.
97
         */
98
0
        ret = -2;
99
0
        goto end;
100
0
      }
101
0
      h1m->flags |= H1_MF_TE_OTHER;
102
0
    }
103
104
0
    word.ptr = n;
105
0
  }
106
107
0
  end:
108
0
  return ret;
109
0
}
110
111
/* Validate the authority and the host header value for CONNECT method. If there
112
 * is hast header, its value is normalized. 0 is returned on success, -1 if the
113
 * authority is invalid and -2 if the host is invalid.
114
 */
115
static int h1_validate_connect_authority(struct ist scheme, struct ist authority, struct ist *host_hdr)
116
0
{
117
0
  struct ist uri_host, uri_port, host, host_port;
118
119
0
  if (isttest(scheme) || !isttest(authority))
120
0
    goto invalid_authority;
121
0
  uri_host = authority;
122
0
  uri_port = http_get_host_port(authority);
123
0
  if (!istlen(uri_port))
124
0
    goto invalid_authority;
125
0
  uri_host.len -= (istlen(uri_port) + 1);
126
127
0
  if (!host_hdr || !isttest(*host_hdr))
128
0
    goto end;
129
130
  /* Get the port of the host header value, if any */
131
0
  host = *host_hdr;
132
0
  host_port = http_get_host_port(*host_hdr);
133
0
  if (isttest(host_port))
134
0
    host.len -= (istlen(host_port) + 1);
135
136
0
  if (istlen(host_port)) {
137
0
    if (!isteqi(host, uri_host) || !isteq(host_port, uri_port))
138
0
      goto invalid_host;
139
0
    if (http_is_default_port(IST_NULL, uri_port))
140
0
      *host_hdr = host; /* normalize */
141
0
  }
142
0
  else {
143
0
    if (!http_is_default_port(IST_NULL, uri_port) || !isteqi(host, uri_host))
144
0
      goto invalid_host;
145
0
  }
146
147
0
  end:
148
0
  return 0;
149
150
0
  invalid_authority:
151
0
  return -1;
152
153
0
  invalid_host:
154
0
  return -2;
155
0
}
156
157
158
/* Validate the authority and the host header value for non-CONNECT method, when
159
 * an absolute-URI is detected but when it does not exactly match the host
160
 * value. The idea is to detect default port (http or https). authority and host
161
 * are defined here. 0 is returned on success, -1 if the host is does not match
162
 * the authority.
163
 */
164
static int h1_validate_mismatch_authority(struct ist scheme, struct ist authority, struct ist host_hdr)
165
0
{
166
0
  struct ist uri_host, uri_port, host, host_port;
167
168
0
  if (!isttest(scheme))
169
0
    goto mismatch;
170
171
0
  uri_host = authority;
172
0
  uri_port = http_get_host_port(authority);
173
0
  if (isttest(uri_port))
174
0
    uri_host.len -= (istlen(uri_port) + 1);
175
176
0
  host = host_hdr;
177
0
  host_port = http_get_host_port(host_hdr);
178
0
  if (isttest(host_port))
179
0
      host.len -= (istlen(host_port) + 1);
180
181
0
  if (!isttest(uri_port) && !isttest(host_port)) {
182
    /* No port on both: we already know the authority does not match
183
     * the host value
184
     */
185
0
    goto mismatch;
186
0
  }
187
0
  else if (isttest(uri_port) && !http_is_default_port(scheme, uri_port)) {
188
    /* here there is no port for the host value and the port for the
189
     * authority is not the default one
190
     */
191
0
    goto mismatch;
192
0
  }
193
0
  else if (isttest(host_port) && !http_is_default_port(scheme, host_port)) {
194
    /* here there is no port for the authority and the port for the
195
     * host value is not the default one
196
     */
197
0
    goto mismatch;
198
0
  }
199
0
  else {
200
    /* the authority or the host value contain a default port and
201
     * there is no port on the other value
202
     */
203
0
    if (!isteqi(uri_host, host))
204
0
      goto mismatch;
205
0
  }
206
207
0
  return 0;
208
209
0
  mismatch:
210
0
  return -1;
211
0
}
212
213
214
/* Parse the Connection: header of an HTTP/1 request, looking for "close",
215
 * "keep-alive", and "upgrade" values, and updating h1m->flags according to
216
 * what was found there. Note that flags are only added, not removed, so the
217
 * function is safe for being called multiple times if multiple occurrences
218
 * are found. If the flag H1_MF_CLEAN_CONN_HDR, the header value is cleaned
219
 * up from "keep-alive" and "close" values. To do so, the header value is
220
 * rewritten in place and its length is updated.
221
 */
222
void h1_parse_connection_header(struct h1m *h1m, struct ist *value)
223
0
{
224
0
  char *e, *n, *p;
225
0
  struct ist word;
226
227
0
  word.ptr = value->ptr - 1; // -1 for next loop's pre-increment
228
0
  p = value->ptr;
229
0
  e = value->ptr + value->len;
230
0
  if (h1m->flags & H1_MF_CLEAN_CONN_HDR)
231
0
    value->len = 0;
232
233
0
  while (++word.ptr < e) {
234
    /* skip leading delimiter and blanks */
235
0
    if (HTTP_IS_LWS(*word.ptr))
236
0
      continue;
237
238
0
    n = http_find_hdr_value_end(word.ptr, e); // next comma or end of line
239
0
    word.len = n - word.ptr;
240
241
    /* trim trailing blanks */
242
0
    while (word.len && HTTP_IS_LWS(word.ptr[word.len-1]))
243
0
      word.len--;
244
245
0
    if (isteqi(word, ist("keep-alive"))) {
246
0
      h1m->flags |= H1_MF_CONN_KAL;
247
0
      if (h1m->flags & H1_MF_CLEAN_CONN_HDR)
248
0
        goto skip_val;
249
0
    }
250
0
    else if (isteqi(word, ist("close"))) {
251
0
      h1m->flags |= H1_MF_CONN_CLO;
252
0
      if (h1m->flags & H1_MF_CLEAN_CONN_HDR)
253
0
        goto skip_val;
254
0
    }
255
0
    else if (isteqi(word, ist("upgrade")))
256
0
      h1m->flags |= H1_MF_CONN_UPG;
257
258
0
    if (h1m->flags & H1_MF_CLEAN_CONN_HDR) {
259
0
      if (value->ptr + value->len == p) {
260
        /* no rewrite done till now */
261
0
        value->len = n - value->ptr;
262
0
      }
263
0
      else {
264
0
        if (value->len)
265
0
          value->ptr[value->len++] = ',';
266
0
        istcat(value, word, e - value->ptr);
267
0
      }
268
0
    }
269
270
0
    skip_val:
271
0
    word.ptr = p = n;
272
0
  }
273
0
}
274
275
/* Parse the Upgrade: header of an HTTP/1 request.
276
 * If "websocket" is found, set H1_MF_UPG_WEBSOCKET flag
277
 * If "h2c" or "h2" found, the value is skipped.
278
 */
279
void h1_parse_upgrade_header(struct h1m *h1m, struct ist *value)
280
0
{
281
0
  char *e, *n, *p;
282
0
  struct ist word;
283
284
0
  word.ptr = value->ptr - 1; // -1 for next loop's pre-increment
285
0
  p = value->ptr;
286
0
  e = value->ptr + value->len;
287
0
  value->len = 0;
288
289
0
  while (++word.ptr < e) {
290
    /* skip leading delimiter and blanks */
291
0
    if (HTTP_IS_LWS(*word.ptr))
292
0
      continue;
293
294
0
    n = http_find_hdr_value_end(word.ptr, e); // next comma or end of line
295
0
    word.len = n - word.ptr;
296
297
    /* trim trailing blanks */
298
0
    while (word.len && HTTP_IS_LWS(word.ptr[word.len-1]))
299
0
      word.len--;
300
301
0
    if (isteqi(word, ist("websocket")))
302
0
      h1m->flags |= H1_MF_UPG_WEBSOCKET;
303
0
    else if (isteqi(word, ist("h2c")) || isteqi(word, ist("h2")))
304
0
      goto skip_val;
305
306
0
    if (value->ptr + value->len == p) {
307
      /* no rewrite done till now */
308
0
      value->len = n - value->ptr;
309
0
    }
310
0
    else {
311
0
      if (value->len)
312
0
        value->ptr[value->len++] = ',';
313
0
      istcat(value, word, e - value->ptr);
314
0
    }
315
316
0
    skip_val:
317
0
    word.ptr = p = n;
318
0
  }
319
320
0
  if (istlen(*value))
321
0
    h1m->flags |= H1_MF_UPG_HDR;
322
0
}
323
324
/* Macros used in the HTTP/1 parser, to check for the expected presence of
325
 * certain bytes (ef: LF) or to skip to next byte and yield in case of failure.
326
 */
327
328
/* Expects to find an LF at <ptr>. If not, set <state> to <where> and jump to
329
 * <bad>.
330
 */
331
#define EXPECT_LF_HERE(ptr, bad, state, where)                  \
332
0
  do {                                                    \
333
0
    if (unlikely(*(ptr) != '\n')) {                 \
334
0
      state = (where);                        \
335
0
      goto bad;                               \
336
0
    }                                               \
337
0
  } while (0)
338
339
/* Increments pointer <ptr>, continues to label <more> if it's still below
340
 * pointer <end>, or goes to <stop> and sets <state> to <where> if the end
341
 * of buffer was reached.
342
 */
343
#define EAT_AND_JUMP_OR_RETURN(ptr, end, more, stop, state, where)        \
344
0
  do {                                                              \
345
0
    if (likely(++(ptr) < (end)))                              \
346
0
      goto more;                                        \
347
0
    else {                                                    \
348
0
      state = (where);                                  \
349
0
      goto stop;                                        \
350
0
    }                                                         \
351
0
  } while (0)
352
353
/* This function parses a contiguous HTTP/1 headers block starting at <start>
354
 * and ending before <stop>, at once, and converts it a list of (name,value)
355
 * pairs representing header fields into the array <hdr> of size <hdr_num>,
356
 * whose last entry will have an empty name and an empty value. If <hdr_num> is
357
 * too small to represent the whole message, an error is returned. Some
358
 * protocol elements such as content-length and transfer-encoding will be
359
 * parsed and stored into h1m as well. <hdr> may be null, in which case only
360
 * the parsing state will be updated. This may be used to restart the parsing
361
 * where it stopped for example.
362
 *
363
 * For now it's limited to the response. If the header block is incomplete,
364
 * 0 is returned, waiting to be called again with more data to try it again.
365
 * The caller is responsible for initializing h1m->state to H1_MSG_RPBEFORE,
366
 * and h1m->next to zero on the first call, the parser will do the rest. If
367
 * an incomplete message is seen, the caller only needs to present h1m->state
368
 * and h1m->next again, with an empty header list so that the parser can start
369
 * again. In this case, it will detect that it interrupted a previous session
370
 * and will first look for the end of the message before reparsing it again and
371
 * indexing it at the same time. This ensures that incomplete messages fed 1
372
 * character at a time are never processed entirely more than exactly twice,
373
 * and that there is no need to store all the internal state and pre-parsed
374
 * headers or start line between calls.
375
 *
376
 * A pointer to a start line descriptor may be passed in <slp>, in which case
377
 * the parser will fill it with whatever it found.
378
 *
379
 * The code derived from the main HTTP/1 parser above but was simplified and
380
 * optimized to process responses produced or forwarded by haproxy. The caller
381
 * is responsible for ensuring that the message doesn't wrap, and should ensure
382
 * it is complete to avoid having to retry the operation after a failed
383
 * attempt. The message is not supposed to be invalid, which is why a few
384
 * properties such as the character set used in the header field names are not
385
 * checked. In case of an unparsable response message, a negative value will be
386
 * returned with h1m->err_pos and h1m->err_state matching the location and
387
 * state where the error was met. Leading blank likes are tolerated but not
388
 * recommended. If flag H1_MF_HDRS_ONLY is set in h1m->flags, only headers are
389
 * parsed and the start line is skipped. It is not required to set h1m->state
390
 * nor h1m->next in this case.
391
 *
392
 * This function returns :
393
 *    -1 in case of error. In this case, h1m->err_state is filled (if h1m is
394
 *       set) with the state the error occurred in and h1m->err_pos with the
395
 *       the position relative to <start>
396
 *    -2 if the output is full (hdr_num reached). err_state and err_pos also
397
 *       indicate where it failed.
398
 *     0 in case of missing data.
399
 *   > 0 on success, it then corresponds to the number of bytes read since
400
 *       <start> so that the caller can go on with the payload.
401
 */
402
int h1_headers_to_hdr_list(char *start, const char *stop,
403
                           struct http_hdr *hdr, unsigned int hdr_num,
404
                           struct h1m *h1m, union h1_sl *slp)
405
0
{
406
0
  enum h1m_state state;
407
0
  register char *ptr;
408
0
  register const char *end;
409
0
  unsigned int hdr_count;
410
0
  unsigned int skip; /* number of bytes skipped at the beginning */
411
0
  unsigned int sol;  /* start of line */
412
0
  unsigned int col;  /* position of the colon */
413
0
  unsigned int eol;  /* end of line */
414
0
  unsigned int sov;  /* start of value */
415
0
  union h1_sl sl;
416
0
  int skip_update;
417
0
  int restarting;
418
0
  int host_idx;
419
0
  struct ist n, v;       /* header name and value during parsing */
420
421
0
  skip = 0; // do it only once to keep track of the leading CRLF.
422
423
0
 try_again:
424
0
  hdr_count = sol = col = eol = sov = 0;
425
0
  sl.st.status = 0;
426
0
  skip_update = restarting = 0;
427
0
  host_idx = -1;
428
429
0
  if (h1m->flags & H1_MF_HDRS_ONLY) {
430
0
    state = H1_MSG_HDR_FIRST;
431
0
    h1m->next = 0;
432
0
  }
433
0
  else {
434
0
    state = h1m->state;
435
0
    if (h1m->state != H1_MSG_RQBEFORE && h1m->state != H1_MSG_RPBEFORE)
436
0
      restarting = 1;
437
0
  }
438
439
0
  ptr   = start + h1m->next;
440
0
  end   = stop;
441
442
0
  if (unlikely(ptr >= end))
443
0
    goto http_msg_ood;
444
445
  /* don't update output if hdr is NULL or if we're restarting */
446
0
  if (!hdr || restarting)
447
0
    skip_update = 1;
448
449
0
  switch (state)  {
450
0
  case H1_MSG_RQBEFORE:
451
0
  http_msg_rqbefore:
452
0
    if (likely(HTTP_IS_TOKEN(*ptr))) {
453
      /* we have a start of message, we may have skipped some
454
       * heading CRLF. Skip them now.
455
       */
456
0
      skip += ptr - start;
457
0
      start = ptr;
458
459
0
      sol = 0;
460
0
      sl.rq.m.ptr = ptr;
461
0
      hdr_count = 0;
462
0
      state = H1_MSG_RQMETH;
463
0
      goto http_msg_rqmeth;
464
0
    }
465
466
0
    if (unlikely(!HTTP_IS_CRLF(*ptr))) {
467
0
      state = H1_MSG_RQBEFORE;
468
0
      goto http_msg_invalid;
469
0
    }
470
471
0
    if (unlikely(*ptr == '\n'))
472
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqbefore, http_msg_ood, state, H1_MSG_RQBEFORE);
473
0
    EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqbefore_cr, http_msg_ood, state, H1_MSG_RQBEFORE_CR);
474
    /* stop here */
475
476
0
  case H1_MSG_RQBEFORE_CR:
477
0
  http_msg_rqbefore_cr:
478
0
    EXPECT_LF_HERE(ptr, http_msg_invalid, state, H1_MSG_RQBEFORE_CR);
479
0
    EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqbefore, http_msg_ood, state, H1_MSG_RQBEFORE);
480
    /* stop here */
481
482
0
  case H1_MSG_RQMETH:
483
0
  http_msg_rqmeth:
484
0
    if (likely(HTTP_IS_TOKEN(*ptr)))
485
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqmeth, http_msg_ood, state, H1_MSG_RQMETH);
486
487
0
    if (likely(HTTP_IS_SPHT(*ptr))) {
488
0
      sl.rq.m.len = ptr - sl.rq.m.ptr;
489
0
      sl.rq.meth = find_http_meth(start, sl.rq.m.len);
490
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqmeth_sp, http_msg_ood, state, H1_MSG_RQMETH_SP);
491
0
    }
492
493
0
    if (likely(HTTP_IS_CRLF(*ptr))) {
494
      /* HTTP 0.9 request */
495
0
      sl.rq.m.len = ptr - sl.rq.m.ptr;
496
0
      sl.rq.meth = find_http_meth(sl.rq.m.ptr, sl.rq.m.len);
497
0
    http_msg_req09_uri:
498
0
      sl.rq.u.ptr = ptr;
499
0
    http_msg_req09_uri_e:
500
0
      sl.rq.u.len = ptr - sl.rq.u.ptr;
501
0
    http_msg_req09_ver:
502
0
      sl.rq.v = ist2(ptr, 0);
503
0
      goto http_msg_rqline_eol;
504
0
    }
505
0
    state = H1_MSG_RQMETH;
506
0
    goto http_msg_invalid;
507
508
0
  case H1_MSG_RQMETH_SP:
509
0
  http_msg_rqmeth_sp:
510
0
    if (likely(!HTTP_IS_LWS(*ptr))) {
511
0
      sl.rq.u.ptr = ptr;
512
0
      goto http_msg_rquri;
513
0
    }
514
0
    if (likely(HTTP_IS_SPHT(*ptr)))
515
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqmeth_sp, http_msg_ood, state, H1_MSG_RQMETH_SP);
516
    /* so it's a CR/LF, meaning an HTTP 0.9 request */
517
0
    goto http_msg_req09_uri;
518
519
0
  case H1_MSG_RQURI:
520
0
  http_msg_rquri:
521
0
#ifdef HA_UNALIGNED_LE
522
    /* speedup: skip bytes not between 0x24 and 0x7e inclusive */
523
0
    while (ptr <= end - sizeof(int)) {
524
0
      if (is_char4_outside(*(uint *)ptr, 0x24, 0x7e))
525
0
        break;
526
527
0
      ptr += sizeof(int);
528
0
    }
529
0
#endif
530
0
    if (ptr >= end) {
531
0
      state = H1_MSG_RQURI;
532
0
      goto http_msg_ood;
533
0
    }
534
0
  http_msg_rquri2:
535
0
    if (likely((unsigned char)(*ptr - 33) <= 93)) { /* 33 to 126 included */
536
0
      if (*ptr == '#') {
537
0
        if (h1m->err_pos < -1) /* PR_O2_REQBUG_OK not set */
538
0
          goto invalid_char;
539
0
        if (h1m->err_pos == -1) /* PR_O2_REQBUG_OK set: just log */
540
0
          h1m->err_pos = ptr - start + skip;
541
0
      }
542
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rquri2, http_msg_ood, state, H1_MSG_RQURI);
543
0
    }
544
545
0
    if (likely(HTTP_IS_SPHT(*ptr))) {
546
0
      sl.rq.u.len = ptr - sl.rq.u.ptr;
547
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rquri_sp, http_msg_ood, state, H1_MSG_RQURI_SP);
548
0
    }
549
0
    if (likely((unsigned char)*ptr >= 128)) {
550
      /* non-ASCII chars are forbidden unless option
551
       * accept-unsafe-violations-in-http-request is enabled in the frontend.
552
       * In any case, we capture the faulty char.
553
       */
554
0
      if (h1m->err_pos < -1)
555
0
        goto invalid_char;
556
0
      if (h1m->err_pos == -1)
557
0
        h1m->err_pos = ptr - start + skip;
558
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rquri, http_msg_ood, state, H1_MSG_RQURI);
559
0
    }
560
561
0
    if (likely(HTTP_IS_CRLF(*ptr))) {
562
      /* so it's a CR/LF, meaning an HTTP 0.9 request */
563
0
      goto http_msg_req09_uri_e;
564
0
    }
565
566
    /* OK forbidden chars, 0..31 or 127 */
567
0
  invalid_char:
568
0
    state = H1_MSG_RQURI;
569
0
    goto http_msg_invalid;
570
571
0
  case H1_MSG_RQURI_SP:
572
0
  http_msg_rquri_sp:
573
0
    if (likely(!HTTP_IS_LWS(*ptr))) {
574
0
      sl.rq.v.ptr = ptr;
575
0
      goto http_msg_rqver;
576
0
    }
577
0
    if (likely(HTTP_IS_SPHT(*ptr)))
578
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rquri_sp, http_msg_ood, state, H1_MSG_RQURI_SP);
579
    /* so it's a CR/LF, meaning an HTTP 0.9 request */
580
0
    goto http_msg_req09_ver;
581
582
583
0
  case H1_MSG_RQVER:
584
0
  http_msg_rqver:
585
0
    if (likely(HTTP_IS_VER_TOKEN(*ptr)))
586
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqver, http_msg_ood, state, H1_MSG_RQVER);
587
588
0
    if (likely(HTTP_IS_CRLF(*ptr))) {
589
0
      sl.rq.v.len = ptr - sl.rq.v.ptr;
590
0
    http_msg_rqline_eol:
591
      /* We have seen the end of line. Note that we do not
592
       * necessarily have the \n yet, but at least we know that we
593
       * have EITHER \r OR \n, otherwise the request would not be
594
       * complete. We can then record the request length and return
595
       * to the caller which will be able to register it.
596
       */
597
598
0
      if (likely(!skip_update)) {
599
0
        if ((sl.rq.v.len == 8) &&
600
0
            (*(sl.rq.v.ptr + 5) > '1' ||
601
0
             (*(sl.rq.v.ptr + 5) == '1' && *(sl.rq.v.ptr + 7) >= '1')))
602
0
          h1m->flags |= H1_MF_VER_11;
603
604
0
        if (unlikely(hdr_count >= hdr_num)) {
605
0
          state = H1_MSG_RQVER;
606
0
          goto http_output_full;
607
0
        }
608
0
        if (!(h1m->flags & H1_MF_NO_PHDR))
609
0
          http_set_hdr(&hdr[hdr_count++], ist(":method"), sl.rq.m);
610
611
0
        if (unlikely(hdr_count >= hdr_num)) {
612
0
          state = H1_MSG_RQVER;
613
0
          goto http_output_full;
614
0
        }
615
0
        if (!(h1m->flags & H1_MF_NO_PHDR))
616
0
          http_set_hdr(&hdr[hdr_count++], ist(":path"), sl.rq.u);
617
0
      }
618
619
0
      sol = ptr - start;
620
0
      if (likely(*ptr == '\r'))
621
0
        EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqline_end, http_msg_ood, state, H1_MSG_RQLINE_END);
622
0
      goto http_msg_rqline_end;
623
0
    }
624
625
    /* neither an HTTP_VER token nor a CRLF */
626
0
    state = H1_MSG_RQVER;
627
0
    goto http_msg_invalid;
628
629
0
  case H1_MSG_RQLINE_END:
630
0
  http_msg_rqline_end:
631
    /* check for HTTP/0.9 request : no version information
632
     * available. sol must point to the first of CR or LF. However
633
     * since we don't save these elements between calls, if we come
634
     * here from a restart, we don't necessarily know. Thus in this
635
     * case we simply start over.
636
     */
637
0
    if (restarting)
638
0
      goto restart;
639
640
0
    if (unlikely(sl.rq.v.len == 0))
641
0
      goto http_msg_last_lf;
642
643
0
    EXPECT_LF_HERE(ptr, http_msg_invalid, state, H1_MSG_RQLINE_END);
644
0
    EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_first, http_msg_ood, state, H1_MSG_HDR_FIRST);
645
    /* stop here */
646
647
  /*
648
   * Common states below
649
   */
650
0
  case H1_MSG_RPBEFORE:
651
0
  http_msg_rpbefore:
652
0
    if (likely(HTTP_IS_TOKEN(*ptr))) {
653
      /* we have a start of message, we may have skipped some
654
       * heading CRLF. Skip them now.
655
       */
656
0
      skip += ptr - start;
657
0
      start = ptr;
658
659
0
      sol = 0;
660
0
      sl.st.v.ptr = ptr;
661
0
      hdr_count = 0;
662
0
      state = H1_MSG_RPVER;
663
0
      goto http_msg_rpver;
664
0
    }
665
666
0
    if (unlikely(!HTTP_IS_CRLF(*ptr))) {
667
0
      state = H1_MSG_RPBEFORE;
668
0
      goto http_msg_invalid;
669
0
    }
670
671
0
    if (unlikely(*ptr == '\n'))
672
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpbefore, http_msg_ood, state, H1_MSG_RPBEFORE);
673
0
    EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpbefore_cr, http_msg_ood, state, H1_MSG_RPBEFORE_CR);
674
    /* stop here */
675
676
0
  case H1_MSG_RPBEFORE_CR:
677
0
  http_msg_rpbefore_cr:
678
0
    EXPECT_LF_HERE(ptr, http_msg_invalid, state, H1_MSG_RPBEFORE_CR);
679
0
    EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpbefore, http_msg_ood, state, H1_MSG_RPBEFORE);
680
    /* stop here */
681
682
0
  case H1_MSG_RPVER:
683
0
  http_msg_rpver:
684
0
    if (likely(HTTP_IS_VER_TOKEN(*ptr)))
685
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpver, http_msg_ood, state, H1_MSG_RPVER);
686
687
0
    if (likely(HTTP_IS_SPHT(*ptr))) {
688
0
      sl.st.v.len = ptr - sl.st.v.ptr;
689
690
0
      if ((sl.st.v.len == 8) &&
691
0
          (*(sl.st.v.ptr + 5) > '1' ||
692
0
           (*(sl.st.v.ptr + 5) == '1' && *(sl.st.v.ptr + 7) >= '1')))
693
0
        h1m->flags |= H1_MF_VER_11;
694
695
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpver_sp, http_msg_ood, state, H1_MSG_RPVER_SP);
696
0
    }
697
0
    state = H1_MSG_RPVER;
698
0
    goto http_msg_invalid;
699
700
0
  case H1_MSG_RPVER_SP:
701
0
  http_msg_rpver_sp:
702
0
    if (likely(!HTTP_IS_LWS(*ptr))) {
703
0
      sl.st.status = 0;
704
0
      sl.st.c.ptr = ptr;
705
0
      goto http_msg_rpcode;
706
0
    }
707
0
    if (likely(HTTP_IS_SPHT(*ptr)))
708
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpver_sp, http_msg_ood, state, H1_MSG_RPVER_SP);
709
    /* so it's a CR/LF, this is invalid */
710
0
    state = H1_MSG_RPVER_SP;
711
0
    goto http_msg_invalid;
712
713
0
  case H1_MSG_RPCODE:
714
0
  http_msg_rpcode:
715
0
    if (likely(HTTP_IS_DIGIT(*ptr))) {
716
0
      if (ptr - sl.st.c.ptr >= 3) {
717
        /* more than 3 digits */
718
0
        if (h1m->err_pos == -1) /* only capture the error pointer */
719
0
          h1m->err_pos = ptr - start + skip;
720
0
        else if (h1m->err_pos < -1 || sl.st.status >= ((uint16_t)~0 - 9) / 10) {
721
          /* strict checks or risk of overflow */
722
0
          state = H1_MSG_RPCODE;
723
0
          goto http_msg_invalid;
724
0
        }
725
0
      }
726
0
      sl.st.status = sl.st.status * 10 + *ptr - '0';
727
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode, http_msg_ood, state, H1_MSG_RPCODE);
728
0
    }
729
730
0
    if (unlikely(!HTTP_IS_LWS(*ptr))) {
731
0
      state = H1_MSG_RPCODE;
732
0
      goto http_msg_invalid;
733
0
    }
734
735
0
    if (likely(HTTP_IS_SPHT(*ptr))) {
736
0
      sl.st.c.len = ptr - sl.st.c.ptr;
737
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode_sp, http_msg_ood, state, H1_MSG_RPCODE_SP);
738
0
    }
739
740
    /* so it's a CR/LF, so there is no reason phrase */
741
0
    sl.st.c.len = ptr - sl.st.c.ptr;
742
743
0
  http_msg_rsp_reason:
744
0
    sl.st.r = ist2(ptr, 0);
745
0
    goto http_msg_rpline_eol;
746
747
0
  case H1_MSG_RPCODE_SP:
748
0
  http_msg_rpcode_sp:
749
0
    if (likely(!HTTP_IS_LWS(*ptr))) {
750
0
      sl.st.r.ptr = ptr;
751
0
      goto http_msg_rpreason;
752
0
    }
753
0
    if (likely(HTTP_IS_SPHT(*ptr)))
754
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode_sp, http_msg_ood, state, H1_MSG_RPCODE_SP);
755
    /* so it's a CR/LF, so there is no reason phrase */
756
0
    goto http_msg_rsp_reason;
757
758
0
  case H1_MSG_RPREASON:
759
0
  http_msg_rpreason:
760
0
    if (likely(!HTTP_IS_CRLF(*ptr)))
761
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpreason, http_msg_ood, state, H1_MSG_RPREASON);
762
0
    sl.st.r.len = ptr - sl.st.r.ptr;
763
0
  http_msg_rpline_eol:
764
    /* We have seen the end of line. Note that we do not
765
     * necessarily have the \n yet, but at least we know that we
766
     * have EITHER \r OR \n, otherwise the response would not be
767
     * complete. We can then record the response length and return
768
     * to the caller which will be able to register it.
769
     */
770
771
0
    if (likely(!skip_update)) {
772
0
      if (unlikely(hdr_count >= hdr_num)) {
773
0
        state = H1_MSG_RPREASON;
774
0
        goto http_output_full;
775
0
      }
776
0
      if (!(h1m->flags & H1_MF_NO_PHDR))
777
0
        http_set_hdr(&hdr[hdr_count++], ist(":status"), sl.st.c);
778
0
    }
779
780
0
    sol = ptr - start;
781
0
    if (likely(*ptr == '\r'))
782
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpline_end, http_msg_ood, state, H1_MSG_RPLINE_END);
783
0
    goto http_msg_rpline_end;
784
785
0
  case H1_MSG_RPLINE_END:
786
0
  http_msg_rpline_end:
787
    /* sol must point to the first of CR or LF. */
788
0
    EXPECT_LF_HERE(ptr, http_msg_invalid, state, H1_MSG_RPLINE_END);
789
0
    EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_first, http_msg_ood, state, H1_MSG_HDR_FIRST);
790
    /* stop here */
791
792
0
  case H1_MSG_HDR_FIRST:
793
0
  http_msg_hdr_first:
794
0
    sol = ptr - start;
795
0
    if (likely(!HTTP_IS_CRLF(*ptr))) {
796
0
      goto http_msg_hdr_name;
797
0
    }
798
799
0
    if (likely(*ptr == '\r'))
800
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_last_lf, http_msg_ood, state, H1_MSG_LAST_LF);
801
0
    goto http_msg_last_lf;
802
803
0
  case H1_MSG_HDR_NAME:
804
0
  http_msg_hdr_name:
805
    /* assumes sol points to the first char */
806
0
    if (likely(HTTP_IS_TOKEN(*ptr))) {
807
0
      if (!skip_update) {
808
        /* turn it to lower case if needed */
809
0
        if (isupper((unsigned char)*ptr) && h1m->flags & H1_MF_TOLOWER)
810
0
          *ptr = tolower((unsigned char)*ptr);
811
0
      }
812
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_name, http_msg_ood, state, H1_MSG_HDR_NAME);
813
0
    }
814
815
0
    if (likely(*ptr == ':')) {
816
0
      col = ptr - start;
817
0
      if (col <= sol) {
818
0
        state = H1_MSG_HDR_NAME;
819
0
        goto http_msg_invalid;
820
0
      }
821
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, H1_MSG_HDR_L1_SP);
822
0
    }
823
824
0
    if (likely(h1m->err_pos < -1) || *ptr == '\n') {
825
0
      state = H1_MSG_HDR_NAME;
826
0
      goto http_msg_invalid;
827
0
    }
828
829
0
    if (h1m->err_pos == -1) /* capture the error pointer */
830
0
      h1m->err_pos = ptr - start + skip; /* >= 0 now */
831
832
    /* and we still accept this non-token character */
833
0
    EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_name, http_msg_ood, state, H1_MSG_HDR_NAME);
834
835
0
  case H1_MSG_HDR_L1_SP:
836
0
  http_msg_hdr_l1_sp:
837
    /* assumes sol points to the first char */
838
0
    if (likely(HTTP_IS_SPHT(*ptr)))
839
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, H1_MSG_HDR_L1_SP);
840
841
    /* header value can be basically anything except CR/LF */
842
0
    sov = ptr - start;
843
844
0
    if (likely(!HTTP_IS_CRLF(*ptr))) {
845
0
      goto http_msg_hdr_val;
846
0
    }
847
848
0
    if (likely(*ptr == '\r'))
849
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_lf, http_msg_ood, state, H1_MSG_HDR_L1_LF);
850
0
    goto http_msg_hdr_l1_lf;
851
852
0
  case H1_MSG_HDR_L1_LF:
853
0
  http_msg_hdr_l1_lf:
854
0
    EXPECT_LF_HERE(ptr, http_msg_invalid, state, H1_MSG_HDR_L1_LF);
855
0
    EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_lws, http_msg_ood, state, H1_MSG_HDR_L1_LWS);
856
857
0
  case H1_MSG_HDR_L1_LWS:
858
0
  http_msg_hdr_l1_lws:
859
0
    if (likely(HTTP_IS_SPHT(*ptr))) {
860
0
      if (!skip_update) {
861
        /* replace HT,CR,LF with spaces */
862
0
        for (; start + sov < ptr; sov++)
863
0
          start[sov] = ' ';
864
0
      }
865
0
      goto http_msg_hdr_l1_sp;
866
0
    }
867
    /* we had a header consisting only in spaces ! */
868
0
    eol = sov;
869
0
    goto http_msg_complete_header;
870
871
0
  case H1_MSG_HDR_VAL:
872
0
  http_msg_hdr_val:
873
    /* assumes sol points to the first char, and sov
874
     * points to the first character of the value.
875
     */
876
877
    /* speedup: we'll skip packs of 4 or 8 bytes not containing bytes 0x0D
878
     * and lower. In fact since most of the time is spent in the loop, we
879
     * also remove the sign bit test so that bytes 0x8e..0x0d break the
880
     * loop, but we don't care since they're very rare in header values.
881
     */
882
0
#ifdef HA_UNALIGNED_LE64
883
0
    while (ptr <= end - sizeof(long)) {
884
0
      if (is_char8_below_opt(*(ulong *)ptr, 0x0e))
885
0
        goto http_msg_hdr_val2;
886
0
      ptr += sizeof(long);
887
0
    }
888
0
#endif
889
0
#ifdef HA_UNALIGNED_LE
890
0
    while (ptr <= end - sizeof(int)) {
891
0
      if (is_char4_below_opt(*(uint *)ptr, 0x0e))
892
0
        goto http_msg_hdr_val2;
893
0
      ptr += sizeof(int);
894
0
    }
895
0
#endif
896
0
    if (ptr >= end) {
897
0
      state = H1_MSG_HDR_VAL;
898
0
      goto http_msg_ood;
899
0
    }
900
0
  http_msg_hdr_val2:
901
0
    if (likely(!*ptr)) {
902
      /* RFC9110 clarified that NUL is explicitly forbidden in header values
903
       * (like CR and LF).
904
       */
905
0
      if (h1m->err_pos < -1) { /* PR_O2_REQBUG_OK not set */
906
0
        state = H1_MSG_HDR_VAL;
907
0
        goto http_msg_invalid;
908
0
      }
909
0
      if (h1m->err_pos == -1) /* PR_O2_REQBUG_OK set: just log */
910
0
        h1m->err_pos = ptr - start + skip;
911
0
    }
912
0
    if (likely(!HTTP_IS_CRLF(*ptr)))
913
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_val2, http_msg_ood, state, H1_MSG_HDR_VAL);
914
915
0
    eol = ptr - start;
916
    /* Note: we could also copy eol into ->eoh so that we have the
917
     * real header end in case it ends with lots of LWS, but is this
918
     * really needed ?
919
     */
920
0
    if (likely(*ptr == '\r'))
921
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l2_lf, http_msg_ood, state, H1_MSG_HDR_L2_LF);
922
0
    goto http_msg_hdr_l2_lf;
923
924
0
  case H1_MSG_HDR_L2_LF:
925
0
  http_msg_hdr_l2_lf:
926
0
    EXPECT_LF_HERE(ptr, http_msg_invalid, state, H1_MSG_HDR_L2_LF);
927
0
    EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l2_lws, http_msg_ood, state, H1_MSG_HDR_L2_LWS);
928
929
0
  case H1_MSG_HDR_L2_LWS:
930
0
  http_msg_hdr_l2_lws:
931
0
    if (unlikely(HTTP_IS_SPHT(*ptr))) {
932
0
      if (!skip_update) {
933
        /* LWS: replace HT,CR,LF with spaces */
934
0
        for (; start + eol < ptr; eol++)
935
0
          start[eol] = ' ';
936
0
      }
937
0
      goto http_msg_hdr_val;
938
0
    }
939
0
  http_msg_complete_header:
940
    /*
941
     * It was a new header, so the last one is finished. Assumes
942
     * <sol> points to the first char of the name, <col> to the
943
     * colon, <sov> points to the first character of the value and
944
     * <eol> to the first CR or LF so we know how the line ends. We
945
     * will trim spaces around the value. It's possible to do it by
946
     * adjusting <eol> and <sov> which are no more used after this.
947
     * We can add the header field to the list.
948
     */
949
0
    if (likely(!skip_update)) {
950
0
      while (sov < eol && HTTP_IS_LWS(start[sov]))
951
0
        sov++;
952
953
0
      while (eol - 1 > sov && HTTP_IS_LWS(start[eol - 1]))
954
0
        eol--;
955
956
957
0
      n = ist2(start + sol, col - sol);
958
0
      v = ist2(start + sov, eol - sov);
959
960
0
      do {
961
0
        int ret;
962
963
0
        if (unlikely(hdr_count >= hdr_num)) {
964
0
          state = H1_MSG_HDR_L2_LWS;
965
0
          goto http_output_full;
966
0
        }
967
968
        /* Skip headers whose names contain forbidden
969
         * chars. When any is detected, h1m->err_pos >= 0,
970
         * so we recheck the name only when an error was
971
         * detected.
972
         */
973
0
        if (unlikely(h1m->err_pos >= 0)) {
974
0
          size_t i = 0;
975
0
          while (i < n.len && HTTP_IS_TOKEN(n.ptr[i]))
976
0
            i++;
977
978
0
          if (i < n.len)
979
0
            break;
980
0
        }
981
982
0
        if (isteqi(n, ist("transfer-encoding"))) {
983
0
          ret = h1_parse_xfer_enc_header(h1m, v);
984
0
          if (ret < 0) {
985
            /* For the response only, don't report error if PR_O2_RSPBUG_OK is set
986
             * and the error can be hidden */
987
0
            if (ret == -2 || !(h1m->flags & H1_MF_RESP) || (h1m->err_pos < -1)) {
988
0
              state = H1_MSG_HDR_L2_LWS;
989
0
              ptr = v.ptr; /* Set ptr on the error */
990
0
              goto http_msg_invalid;
991
0
            }
992
0
            if (h1m->err_pos == -1)
993
0
              h1m->err_pos = ptr - start + skip;
994
0
          }
995
0
          else if (ret == 0) {
996
            /* skip it */
997
0
            break;
998
0
          }
999
0
        }
1000
0
        else if (isteqi(n, ist("content-length"))) {
1001
0
          unsigned long long body_len = h1m->body_len;
1002
1003
0
          ret = http_parse_cont_len_header(&v, &body_len, (h1m->flags & H1_MF_CLEN));
1004
0
          if (ret < 0) {
1005
0
            state = H1_MSG_HDR_L2_LWS;
1006
0
            ptr = v.ptr; /* Set ptr on the error */
1007
0
            goto http_msg_invalid;
1008
0
          }
1009
0
          else if (ret == 0) {
1010
            /* skip it */
1011
0
            break;
1012
0
          }
1013
0
          h1m->flags |= H1_MF_CLEN;
1014
0
          h1m->curr_len = h1m->body_len = body_len;
1015
0
        }
1016
0
        else if (isteqi(n, ist("connection"))) {
1017
0
          h1_parse_connection_header(h1m, &v);
1018
0
          if (!v.len) {
1019
            /* skip it */
1020
0
            break;
1021
0
          }
1022
0
        }
1023
0
        else if (isteqi(n, ist("upgrade"))) {
1024
0
          h1_parse_upgrade_header(h1m, &v);
1025
0
          if (!v.len) {
1026
            /* skip it */
1027
0
            break;
1028
0
          }
1029
0
        }
1030
0
        else if (!(h1m->flags & H1_MF_RESP) && isteqi(n, ist("host"))) {
1031
0
          if (host_idx == -1) {
1032
0
            host_idx = hdr_count;
1033
0
            if (http_authority_has_forbidden_char(v)) {
1034
0
              state = H1_MSG_HDR_L2_LWS;
1035
0
              ptr = v.ptr; /* Set ptr on the error */
1036
0
              goto http_msg_invalid;
1037
0
            }
1038
0
          }
1039
0
          else {
1040
0
            if (!isteqi(v, hdr[host_idx].v)) {
1041
0
              state = H1_MSG_HDR_L2_LWS;
1042
0
              ptr = v.ptr; /* Set ptr on the error */
1043
0
              goto http_msg_invalid;
1044
0
            }
1045
            /* if the same host, skip it */
1046
0
            break;
1047
0
          }
1048
0
        }
1049
1050
0
        http_set_hdr(&hdr[hdr_count++], n, v);
1051
0
      } while (0);
1052
0
    }
1053
1054
0
    sol = ptr - start;
1055
1056
0
    if (likely(!HTTP_IS_CRLF(*ptr)))
1057
0
      goto http_msg_hdr_name;
1058
1059
0
    if (likely(*ptr == '\r'))
1060
0
      EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_last_lf, http_msg_ood, state, H1_MSG_LAST_LF);
1061
0
    goto http_msg_last_lf;
1062
1063
0
  case H1_MSG_LAST_LF:
1064
0
  http_msg_last_lf:
1065
0
    EXPECT_LF_HERE(ptr, http_msg_invalid, state, H1_MSG_LAST_LF);
1066
0
    ptr++;
1067
    /* <ptr> now points to the first byte of payload. If needed sol
1068
     * still points to the first of either CR or LF of the empty
1069
     * line ending the headers block.
1070
     */
1071
0
    if (likely(!skip_update)) {
1072
0
      if (unlikely(hdr_count >= hdr_num)) {
1073
0
        state = H1_MSG_LAST_LF;
1074
0
        goto http_output_full;
1075
0
      }
1076
0
      http_set_hdr(&hdr[hdr_count++], ist2(start+sol, 0), ist(""));
1077
0
    }
1078
1079
    /* reaching here we've parsed the whole message. We may detect
1080
     * that we were already continuing an interrupted parsing pass
1081
     * so we were silently looking for the end of message not
1082
     * updating anything before deciding to parse it fully at once.
1083
     * It's guaranteed that we won't match this test twice in a row
1084
     * since restarting will turn zero.
1085
     */
1086
0
    if (restarting)
1087
0
      goto restart;
1088
1089
1090
0
    if (!(h1m->flags & (H1_MF_HDRS_ONLY|H1_MF_RESP))) {
1091
0
      struct http_uri_parser parser = http_uri_parser_init(sl.rq.u);
1092
0
      struct ist scheme, authority = IST_NULL;
1093
0
      int ret;
1094
1095
      /* WT: gcc seems to see a path where sl.rq.u.ptr was used
1096
       * uninitialized, but it doesn't know that the function is
1097
       * called with initial states making this impossible.
1098
       */
1099
0
      ALREADY_CHECKED(sl.rq.u.ptr);
1100
0
      switch (parser.format) {
1101
0
      case URI_PARSER_FORMAT_ASTERISK:
1102
        /* We must take care "PRI * HTTP/2.0" is supported here. check for OTHER methods here is enough */
1103
0
        if ((sl.rq.meth != HTTP_METH_OTHER && sl.rq.meth != HTTP_METH_OPTIONS) || istlen(sl.rq.u) != 1) {
1104
0
          ptr = sl.rq.u.ptr; /* Set ptr on the error */
1105
0
          goto http_msg_invalid;
1106
0
        }
1107
0
        break;
1108
1109
0
      case URI_PARSER_FORMAT_ABSPATH:
1110
0
        if (sl.rq.meth == HTTP_METH_CONNECT) {
1111
0
          ptr = sl.rq.u.ptr; /* Set ptr on the error */
1112
0
          goto http_msg_invalid;
1113
0
        }
1114
0
        break;
1115
1116
0
      case URI_PARSER_FORMAT_ABSURI_OR_AUTHORITY:
1117
0
        scheme = http_parse_scheme(&parser);
1118
0
        authority = http_parse_authority(&parser, 1);
1119
0
        if (http_authority_has_forbidden_char(authority)) {
1120
0
          if (h1m->err_pos < -1) {
1121
0
            state = H1_MSG_LAST_LF;
1122
            /* WT: gcc seems to see a path where sl.rq.u.ptr was used
1123
             * uninitialized, but it doesn't know that the function is
1124
             * called with initial states making this impossible.
1125
             */
1126
0
            ALREADY_CHECKED(sl.rq.u.ptr);
1127
0
            ptr = sl.rq.u.ptr; /* Set ptr on the error */
1128
0
            goto http_msg_invalid;
1129
0
          }
1130
0
          if (h1m->err_pos == -1) /* capture the error pointer */
1131
0
            h1m->err_pos = sl.rq.u.ptr - start + skip; /* >= 0 now */
1132
0
        }
1133
1134
0
        if (!isttest(scheme)) { /* scheme not found: MUST be an authority */
1135
0
          struct ist *host = NULL;
1136
1137
0
          if (sl.rq.meth != HTTP_METH_CONNECT) {
1138
0
            ptr = sl.rq.u.ptr; /* Set ptr on the error */
1139
0
            goto http_msg_invalid;
1140
0
          }
1141
0
          if (host_idx != -1)
1142
0
            host = &hdr[host_idx].v;
1143
0
          ret = h1_validate_connect_authority(scheme, authority, host);
1144
0
          if (ret < 0) {
1145
0
            if (h1m->err_pos < -1) {
1146
0
              state = H1_MSG_LAST_LF;
1147
              /* WT: gcc seems to see a path where sl.rq.u.ptr was used
1148
               * uninitialized, but it doesn't know that the function is
1149
               * called with initial states making this impossible.
1150
               */
1151
0
              ALREADY_CHECKED(sl.rq.u.ptr);
1152
0
              ptr = ((ret == -1) ? sl.rq.u.ptr : host->ptr); /* Set ptr on the error */
1153
0
              goto http_msg_invalid;
1154
0
            }
1155
0
            if (h1m->err_pos == -1) /* capture the error pointer */
1156
0
              h1m->err_pos = ((ret == -1) ? sl.rq.u.ptr : host->ptr) - start + skip; /* >= 0 now */
1157
0
          }
1158
0
        }
1159
0
        else { /* Scheme found:  MUST be an absolute-URI */
1160
0
          struct ist host = IST_NULL;
1161
1162
0
          if (sl.rq.meth == HTTP_METH_CONNECT) {
1163
0
            ptr = sl.rq.u.ptr; /* Set ptr on the error */
1164
0
            goto http_msg_invalid;
1165
0
          }
1166
1167
0
          if (host_idx != -1)
1168
0
            host = hdr[host_idx].v;
1169
          /* For non-CONNECT method, the authority must match the host header value */
1170
0
          if (isttest(host) && !isteqi(authority, host)) {
1171
0
            ret = h1_validate_mismatch_authority(scheme, authority, host);
1172
0
            if (ret < 0) {
1173
0
              if (h1m->err_pos < -1) {
1174
0
                state = H1_MSG_LAST_LF;
1175
0
                ptr = host.ptr; /* Set ptr on the error */
1176
0
                goto http_msg_invalid;
1177
0
              }
1178
0
              if (h1m->err_pos == -1) /* capture the error pointer */
1179
0
                h1m->err_pos = host.ptr - start + skip; /* >= 0 now */
1180
0
            }
1181
0
          }
1182
0
        }
1183
0
        break;
1184
1185
0
      default:
1186
0
        ptr = sl.rq.u.ptr; /* Set ptr on the error */
1187
0
        goto http_msg_invalid;
1188
0
      }
1189
0
    }
1190
1191
0
    state = H1_MSG_DATA;
1192
0
    if (h1m->flags & H1_MF_XFER_ENC) {
1193
0
      if (h1m->flags & H1_MF_CLEN) {
1194
        /* T-E + C-L: force close and remove C-L */
1195
0
        if (!h1_do_not_close_on_insecure_t_e)
1196
0
          h1m->flags |= H1_MF_CONN_CLO;
1197
1198
0
        h1m->flags &= ~H1_MF_CLEN;
1199
0
        h1m->curr_len = h1m->body_len = 0;
1200
0
        hdr_count = http_del_hdr(hdr, ist("content-length"));
1201
0
      }
1202
0
      else if (!(h1m->flags & H1_MF_VER_11)) {
1203
        /* T-E + HTTP/1.0: force close */
1204
0
        h1m->flags |= H1_MF_CONN_CLO;
1205
0
      }
1206
1207
0
      if (h1m->flags & H1_MF_CHNK)
1208
0
        state = H1_MSG_CHUNK_SIZE;
1209
0
      else if (!(h1m->flags & H1_MF_RESP)) {
1210
        /* cf RFC7230#3.3.3 : transfer-encoding in
1211
         * request without chunked encoding is invalid.
1212
         */
1213
0
        goto http_msg_invalid;
1214
0
      }
1215
0
    }
1216
0
    break;
1217
1218
0
  default:
1219
    /* impossible states */
1220
0
    goto http_msg_invalid;
1221
0
  }
1222
1223
  /* Now we've left the headers state and are either in H1_MSG_DATA or
1224
   * H1_MSG_CHUNK_SIZE.
1225
   */
1226
1227
0
  if (slp && !skip_update)
1228
0
    *slp = sl;
1229
1230
0
  h1m->state = state;
1231
0
  h1m->next  = ptr - start + skip;
1232
0
  return h1m->next;
1233
1234
0
 http_msg_ood:
1235
  /* out of data at <ptr> during state <state> */
1236
0
  if (slp && !skip_update)
1237
0
    *slp = sl;
1238
1239
0
  h1m->state = state;
1240
0
  h1m->next  = ptr - start + skip;
1241
0
  return 0;
1242
1243
0
 http_msg_invalid:
1244
  /* invalid message, error at <ptr> */
1245
0
  if (slp && !skip_update)
1246
0
    *slp = sl;
1247
1248
0
  h1m->err_state = h1m->state = state;
1249
0
  h1m->err_pos   = h1m->next  = ptr - start + skip;
1250
0
  return -1;
1251
1252
0
 http_output_full:
1253
  /* no more room to store the current header, error at <ptr> */
1254
0
  if (slp && !skip_update)
1255
0
    *slp = sl;
1256
1257
0
  h1m->err_state = h1m->state = state;
1258
0
  h1m->err_pos   = h1m->next  = ptr - start + skip;
1259
0
  return -2;
1260
1261
0
 restart:
1262
0
  h1m->flags &= H1_MF_RESTART_MASK;
1263
0
  h1m->curr_len = h1m->body_len = h1m->next  = 0;
1264
0
  if (h1m->flags & H1_MF_RESP)
1265
0
    h1m->state = H1_MSG_RPBEFORE;
1266
0
  else
1267
0
    h1m->state = H1_MSG_RQBEFORE;
1268
0
  goto try_again;
1269
0
}
1270
1271
/* Generate a random key for a WebSocket Handshake in respect with rfc6455
1272
 * The key is 128-bits long encoded as a base64 string in <key_out> parameter
1273
 * (25 bytes long).
1274
 */
1275
void h1_generate_random_ws_input_key(char key_out[25])
1276
0
{
1277
  /* generate a random websocket key */
1278
0
  uint64_t rand1, rand2;
1279
0
  char key[16];
1280
1281
0
  ha_random64_pair_hashed(&rand1, &rand2);
1282
0
  memcpy(key, &rand1, 8);
1283
0
  memcpy(&key[8], &rand2, 8);
1284
0
  a2base64(key, 16, key_out, 25);
1285
0
}
1286
1287
0
#define H1_WS_KEY_SUFFIX_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
1288
1289
/*
1290
 * Calculate the WebSocket handshake response key from <key_in>. Following the
1291
 * rfc6455, <key_in> must be 24 bytes longs. The result is  stored in <key_out>
1292
 * as a 29 bytes long string.
1293
 */
1294
void h1_calculate_ws_output_key(const char *key, char *result)
1295
0
{
1296
0
  blk_SHA_CTX sha1_ctx;
1297
0
  char hash_in[60], hash_out[20];
1298
1299
  /* concatenate the key with a fixed suffix */
1300
0
  memcpy(hash_in, key, 24);
1301
0
  memcpy(&hash_in[24], H1_WS_KEY_SUFFIX_GUID, 36);
1302
1303
  /* sha1 the result */
1304
0
  blk_SHA1_Init(&sha1_ctx);
1305
0
  blk_SHA1_Update(&sha1_ctx, hash_in, 60);
1306
0
  blk_SHA1_Final((unsigned char *)hash_out, &sha1_ctx);
1307
1308
  /* encode in base64 the hash */
1309
0
  a2base64(hash_out, 20, result, 29);
1310
0
}
1311
1312
/* config parser for global "h1-do-not-close-on-insecure-transfer-encoding" */
1313
static int cfg_parse_h1_do_not_close_insecure_t_e(char **args, int section_type, struct proxy *curpx,
1314
                                                const struct proxy *defpx, const char *file, int line,
1315
                                                char **err)
1316
0
{
1317
0
  if (too_many_args(0, args, err, NULL))
1318
0
    return -1;
1319
1320
0
  h1_do_not_close_on_insecure_t_e = 1;
1321
0
  return 0;
1322
0
}
1323
1324
/* config keyword parsers */
1325
static struct cfg_kw_list cfg_kws = {{ }, {
1326
  { CFG_GLOBAL, "h1-do-not-close-on-insecure-transfer-encoding", cfg_parse_h1_do_not_close_insecure_t_e },
1327
  { 0, NULL, NULL },
1328
}};
1329
1330
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);