blob: 067a7f863db627cdb304e03b8bf287c335e7d79a [file] [log] [blame]
Willy Tarreauc5a4fd52018-12-11 11:42:27 +01001/*
2 * Legacy HTTP protocol manipulation
3 * If you think you need something from this file, you're mistaken as it will
4 * soon be removed. Please check http_htx.c instead!
5 *
6 * Copyright 2000-2011 Willy Tarreau <w@1wt.eu>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 */
14#include <proto/channel.h>
15#include <proto/hdr_idx.h>
16#include <proto/proto_http.h>
17
18/*
19 * Adds a header and its CRLF at the tail of the message's buffer, just before
20 * the last CRLF. <len> bytes are copied, not counting the CRLF.
21 * The header is also automatically added to the index <hdr_idx>, and the end
22 * of headers is automatically adjusted. The number of bytes added is returned
23 * on success, otherwise <0 is returned indicating an error.
24 */
25int http_header_add_tail2(struct http_msg *msg,
26 struct hdr_idx *hdr_idx, const char *text, int len)
27{
28 int bytes;
29
30 bytes = ci_insert_line2(msg->chn, msg->eoh, text, len);
31 if (!bytes)
32 return -1;
33 http_msg_move_end(msg, bytes);
34 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
35}
36
37/* Find the first or next occurrence of header <name> in message buffer <sol>
38 * using headers index <idx>, and return it in the <ctx> structure. This
39 * structure holds everything necessary to use the header and find next
40 * occurrence. If its <idx> member is 0, the header is searched from the
41 * beginning. Otherwise, the next occurrence is returned. The function returns
42 * 1 when it finds a value, and 0 when there is no more. It is very similar to
43 * http_find_header2() except that it is designed to work with full-line headers
44 * whose comma is not a delimiter but is part of the syntax. As a special case,
45 * if ctx->val is NULL when searching for a new values of a header, the current
46 * header is rescanned. This allows rescanning after a header deletion.
47 */
48int http_find_full_header2(const char *name, int len,
49 char *sol, struct hdr_idx *idx,
50 struct hdr_ctx *ctx)
51{
52 char *eol, *sov;
53 int cur_idx, old_idx;
54
55 cur_idx = ctx->idx;
56 if (cur_idx) {
57 /* We have previously returned a header, let's search another one */
58 sol = ctx->line;
59 eol = sol + idx->v[cur_idx].len;
60 goto next_hdr;
61 }
62
63 /* first request for this header */
64 sol += hdr_idx_first_pos(idx);
65 old_idx = 0;
66 cur_idx = hdr_idx_first_idx(idx);
67 while (cur_idx) {
68 eol = sol + idx->v[cur_idx].len;
69
70 if (len == 0) {
71 /* No argument was passed, we want any header.
72 * To achieve this, we simply build a fake request. */
73 while (sol + len < eol && sol[len] != ':')
74 len++;
75 name = sol;
76 }
77
78 if ((len < eol - sol) &&
79 (sol[len] == ':') &&
80 (strncasecmp(sol, name, len) == 0)) {
81 ctx->del = len;
82 sov = sol + len + 1;
83 while (sov < eol && HTTP_IS_LWS(*sov))
84 sov++;
85
86 ctx->line = sol;
87 ctx->prev = old_idx;
88 ctx->idx = cur_idx;
89 ctx->val = sov - sol;
90 ctx->tws = 0;
91 while (eol > sov && HTTP_IS_LWS(*(eol - 1))) {
92 eol--;
93 ctx->tws++;
94 }
95 ctx->vlen = eol - sov;
96 return 1;
97 }
98 next_hdr:
99 sol = eol + idx->v[cur_idx].cr + 1;
100 old_idx = cur_idx;
101 cur_idx = idx->v[cur_idx].next;
102 }
103 return 0;
104}
105
106/* Find the first or next header field in message buffer <sol> using headers
107 * index <idx>, and return it in the <ctx> structure. This structure holds
108 * everything necessary to use the header and find next occurrence. If its
109 * <idx> member is 0, the first header is retrieved. Otherwise, the next
110 * occurrence is returned. The function returns 1 when it finds a value, and
111 * 0 when there is no more. It is equivalent to http_find_full_header2() with
112 * no header name.
113 */
114int http_find_next_header(char *sol, struct hdr_idx *idx, struct hdr_ctx *ctx)
115{
116 char *eol, *sov;
117 int cur_idx, old_idx;
118 int len;
119
120 cur_idx = ctx->idx;
121 if (cur_idx) {
122 /* We have previously returned a header, let's search another one */
123 sol = ctx->line;
124 eol = sol + idx->v[cur_idx].len;
125 goto next_hdr;
126 }
127
128 /* first request for this header */
129 sol += hdr_idx_first_pos(idx);
130 old_idx = 0;
131 cur_idx = hdr_idx_first_idx(idx);
132 while (cur_idx) {
133 eol = sol + idx->v[cur_idx].len;
134
135 len = 0;
136 while (1) {
137 if (len >= eol - sol)
138 goto next_hdr;
139 if (sol[len] == ':')
140 break;
141 len++;
142 }
143
144 ctx->del = len;
145 sov = sol + len + 1;
146 while (sov < eol && HTTP_IS_LWS(*sov))
147 sov++;
148
149 ctx->line = sol;
150 ctx->prev = old_idx;
151 ctx->idx = cur_idx;
152 ctx->val = sov - sol;
153 ctx->tws = 0;
154
155 while (eol > sov && HTTP_IS_LWS(*(eol - 1))) {
156 eol--;
157 ctx->tws++;
158 }
159 ctx->vlen = eol - sov;
160 return 1;
161
162 next_hdr:
163 sol = eol + idx->v[cur_idx].cr + 1;
164 old_idx = cur_idx;
165 cur_idx = idx->v[cur_idx].next;
166 }
167 return 0;
168}
169
170/* Find the first or next occurrence of header <name> in message buffer <sol>
171 * using headers index <idx>, and return it in the <ctx> structure. This
172 * structure holds everything necessary to use the header and find next
173 * occurrence. If its <idx> member is 0, the header is searched from the
174 * beginning. Otherwise, the next occurrence is returned. The function returns
175 * 1 when it finds a value, and 0 when there is no more. It is designed to work
176 * with headers defined as comma-separated lists. As a special case, if ctx->val
177 * is NULL when searching for a new values of a header, the current header is
178 * rescanned. This allows rescanning after a header deletion.
179 */
180int http_find_header2(const char *name, int len,
181 char *sol, struct hdr_idx *idx,
182 struct hdr_ctx *ctx)
183{
184 char *eol, *sov;
185 int cur_idx, old_idx;
186
187 cur_idx = ctx->idx;
188 if (cur_idx) {
189 /* We have previously returned a value, let's search
190 * another one on the same line.
191 */
192 sol = ctx->line;
193 ctx->del = ctx->val + ctx->vlen + ctx->tws;
194 sov = sol + ctx->del;
195 eol = sol + idx->v[cur_idx].len;
196
197 if (sov >= eol)
198 /* no more values in this header */
199 goto next_hdr;
200
201 /* values remaining for this header, skip the comma but save it
202 * for later use (eg: for header deletion).
203 */
204 sov++;
205 while (sov < eol && HTTP_IS_LWS((*sov)))
206 sov++;
207
208 goto return_hdr;
209 }
210
211 /* first request for this header */
212 sol += hdr_idx_first_pos(idx);
213 old_idx = 0;
214 cur_idx = hdr_idx_first_idx(idx);
215 while (cur_idx) {
216 eol = sol + idx->v[cur_idx].len;
217
218 if (len == 0) {
219 /* No argument was passed, we want any header.
220 * To achieve this, we simply build a fake request. */
221 while (sol + len < eol && sol[len] != ':')
222 len++;
223 name = sol;
224 }
225
226 if ((len < eol - sol) &&
227 (sol[len] == ':') &&
228 (strncasecmp(sol, name, len) == 0)) {
229 ctx->del = len;
230 sov = sol + len + 1;
231 while (sov < eol && HTTP_IS_LWS(*sov))
232 sov++;
233
234 ctx->line = sol;
235 ctx->prev = old_idx;
236 return_hdr:
237 ctx->idx = cur_idx;
238 ctx->val = sov - sol;
239
240 eol = http_find_hdr_value_end(sov, eol);
241 ctx->tws = 0;
242 while (eol > sov && HTTP_IS_LWS(*(eol - 1))) {
243 eol--;
244 ctx->tws++;
245 }
246 ctx->vlen = eol - sov;
247 return 1;
248 }
249 next_hdr:
250 sol = eol + idx->v[cur_idx].cr + 1;
251 old_idx = cur_idx;
252 cur_idx = idx->v[cur_idx].next;
253 }
254 return 0;
255}
256
257/* Remove one value of a header. This only works on a <ctx> returned by one of
258 * the http_find_header functions. The value is removed, as well as surrounding
259 * commas if any. If the removed value was alone, the whole header is removed.
260 * The ctx is always updated accordingly, as well as the buffer and HTTP
261 * message <msg>. The new index is returned. If it is zero, it means there is
262 * no more header, so any processing may stop. The ctx is always left in a form
263 * that can be handled by http_find_header2() to find next occurrence.
264 */
265int http_remove_header2(struct http_msg *msg, struct hdr_idx *idx, struct hdr_ctx *ctx)
266{
267 int cur_idx = ctx->idx;
268 char *sol = ctx->line;
269 struct hdr_idx_elem *hdr;
270 int delta, skip_comma;
271
272 if (!cur_idx)
273 return 0;
274
275 hdr = &idx->v[cur_idx];
276 if (sol[ctx->del] == ':' && ctx->val + ctx->vlen + ctx->tws == hdr->len) {
277 /* This was the only value of the header, we must now remove it entirely. */
278 delta = b_rep_blk(&msg->chn->buf, sol, sol + hdr->len + hdr->cr + 1, NULL, 0);
279 http_msg_move_end(msg, delta);
280 idx->used--;
281 hdr->len = 0; /* unused entry */
282 idx->v[ctx->prev].next = idx->v[ctx->idx].next;
283 if (idx->tail == ctx->idx)
284 idx->tail = ctx->prev;
285 ctx->idx = ctx->prev; /* walk back to the end of previous header */
286 ctx->line -= idx->v[ctx->idx].len + idx->v[ctx->idx].cr + 1;
287 ctx->val = idx->v[ctx->idx].len; /* point to end of previous header */
288 ctx->tws = ctx->vlen = 0;
289 return ctx->idx;
290 }
291
292 /* This was not the only value of this header. We have to remove between
293 * ctx->del+1 and ctx->val+ctx->vlen+ctx->tws+1 included. If it is the
294 * last entry of the list, we remove the last separator.
295 */
296
297 skip_comma = (ctx->val + ctx->vlen + ctx->tws == hdr->len) ? 0 : 1;
298 delta = b_rep_blk(&msg->chn->buf, sol + ctx->del + skip_comma,
299 sol + ctx->val + ctx->vlen + ctx->tws + skip_comma,
300 NULL, 0);
301 hdr->len += delta;
302 http_msg_move_end(msg, delta);
303 ctx->val = ctx->del;
304 ctx->tws = ctx->vlen = 0;
305 return ctx->idx;
306}
307
308int http_legacy_replace_header(struct hdr_idx *idx, struct http_msg *msg,
309 const char *name, unsigned int name_len,
310 const char *str, struct my_regex *re,
311 struct buffer *output)
312{
313 struct hdr_ctx ctx;
314 char *buf = ci_head(msg->chn);
315
316 ctx.idx = 0;
317 while (http_find_header2(name, name_len, buf, idx, &ctx)) {
318 struct hdr_idx_elem *hdr = idx->v + ctx.idx;
319 int delta, len;
320 char *val = ctx.line + ctx.val;
321 char* val_end = val + ctx.vlen;
322
323 if (!regex_exec_match2(re, val, val_end-val, MAX_MATCH, pmatch, 0))
324 continue;
325
326 len = exp_replace(output->area, output->size, val, str, pmatch);
327 if (len == -1)
328 return -1;
329
330 delta = b_rep_blk(&msg->chn->buf, val, val_end, output->area, len);
331
332 hdr->len += delta;
333 http_msg_move_end(msg, delta);
334
335 /* Adjust the length of the current value of the index. */
336 ctx.vlen += delta;
337 }
338 return 0;
339}
340
341int http_legacy_replace_full_header(struct hdr_idx *idx, struct http_msg *msg,
342 const char *name, unsigned int name_len,
343 const char *str, struct my_regex *re,
344 struct buffer *output)
345{
346 struct hdr_ctx ctx;
347 char *buf = ci_head(msg->chn);
348
349 ctx.idx = 0;
350 while (http_find_full_header2(name, name_len, buf, idx, &ctx)) {
351 struct hdr_idx_elem *hdr = idx->v + ctx.idx;
352 int delta, len;
353 char *val = ctx.line + ctx.val;
354 char* val_end = val + ctx.vlen;
355
356 if (!regex_exec_match2(re, val, val_end-val, MAX_MATCH, pmatch, 0))
357 continue;
358
359 len = exp_replace(output->area, output->size, val, str, pmatch);
360 if (len == -1)
361 return -1;
362
363 delta = b_rep_blk(&msg->chn->buf, val, val_end, output->area, len);
364
365 hdr->len += delta;
366 http_msg_move_end(msg, delta);
367
368 /* Adjust the length of the current value of the index. */
369 ctx.vlen += delta;
370 }
371 return 0;
372}
373
374/* Return in <vptr> and <vlen> the pointer and length of occurrence <occ> of
375 * header whose name is <hname> of length <hlen>. If <ctx> is null, lookup is
376 * performed over the whole headers. Otherwise it must contain a valid header
377 * context, initialised with ctx->idx=0 for the first lookup in a series. If
378 * <occ> is positive or null, occurrence #occ from the beginning (or last ctx)
379 * is returned. Occ #0 and #1 are equivalent. If <occ> is negative (and no less
380 * than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is
381 * -1. The value fetch stops at commas, so this function is suited for use with
382 * list headers.
383 * The return value is 0 if nothing was found, or non-zero otherwise.
384 */
385unsigned int http_get_hdr(const struct http_msg *msg, const char *hname, int hlen,
386 struct hdr_idx *idx, int occ,
387 struct hdr_ctx *ctx, char **vptr, size_t *vlen)
388{
389 struct hdr_ctx local_ctx;
390 char *ptr_hist[MAX_HDR_HISTORY];
391 unsigned int len_hist[MAX_HDR_HISTORY];
392 unsigned int hist_ptr;
393 int found;
394
395 if (!ctx) {
396 local_ctx.idx = 0;
397 ctx = &local_ctx;
398 }
399
400 if (occ >= 0) {
401 /* search from the beginning */
402 while (http_find_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
403 occ--;
404 if (occ <= 0) {
405 *vptr = ctx->line + ctx->val;
406 *vlen = ctx->vlen;
407 return 1;
408 }
409 }
410 return 0;
411 }
412
413 /* negative occurrence, we scan all the list then walk back */
414 if (-occ > MAX_HDR_HISTORY)
415 return 0;
416
417 found = hist_ptr = 0;
418 while (http_find_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
419 ptr_hist[hist_ptr] = ctx->line + ctx->val;
420 len_hist[hist_ptr] = ctx->vlen;
421 if (++hist_ptr >= MAX_HDR_HISTORY)
422 hist_ptr = 0;
423 found++;
424 }
425 if (-occ > found)
426 return 0;
427 /* OK now we have the last occurrence in [hist_ptr-1], and we need to
428 * find occurrence -occ. 0 <= hist_ptr < MAX_HDR_HISTORY, and we have
429 * -10 <= occ <= -1. So we have to check [hist_ptr%MAX_HDR_HISTORY+occ]
430 * to remain in the 0..9 range.
431 */
432 hist_ptr += occ + MAX_HDR_HISTORY;
433 if (hist_ptr >= MAX_HDR_HISTORY)
434 hist_ptr -= MAX_HDR_HISTORY;
435 *vptr = ptr_hist[hist_ptr];
436 *vlen = len_hist[hist_ptr];
437 return 1;
438}
439
440/* Return in <vptr> and <vlen> the pointer and length of occurrence <occ> of
441 * header whose name is <hname> of length <hlen>. If <ctx> is null, lookup is
442 * performed over the whole headers. Otherwise it must contain a valid header
443 * context, initialised with ctx->idx=0 for the first lookup in a series. If
444 * <occ> is positive or null, occurrence #occ from the beginning (or last ctx)
445 * is returned. Occ #0 and #1 are equivalent. If <occ> is negative (and no less
446 * than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is
447 * -1. This function differs from http_get_hdr() in that it only returns full
448 * line header values and does not stop at commas.
449 * The return value is 0 if nothing was found, or non-zero otherwise.
450 */
451unsigned int http_get_fhdr(const struct http_msg *msg, const char *hname, int hlen,
452 struct hdr_idx *idx, int occ,
453 struct hdr_ctx *ctx, char **vptr, size_t *vlen)
454{
455 struct hdr_ctx local_ctx;
456 char *ptr_hist[MAX_HDR_HISTORY];
457 unsigned int len_hist[MAX_HDR_HISTORY];
458 unsigned int hist_ptr;
459 int found;
460
461 if (!ctx) {
462 local_ctx.idx = 0;
463 ctx = &local_ctx;
464 }
465
466 if (occ >= 0) {
467 /* search from the beginning */
468 while (http_find_full_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
469 occ--;
470 if (occ <= 0) {
471 *vptr = ctx->line + ctx->val;
472 *vlen = ctx->vlen;
473 return 1;
474 }
475 }
476 return 0;
477 }
478
479 /* negative occurrence, we scan all the list then walk back */
480 if (-occ > MAX_HDR_HISTORY)
481 return 0;
482
483 found = hist_ptr = 0;
484 while (http_find_full_header2(hname, hlen, ci_head(msg->chn), idx, ctx)) {
485 ptr_hist[hist_ptr] = ctx->line + ctx->val;
486 len_hist[hist_ptr] = ctx->vlen;
487 if (++hist_ptr >= MAX_HDR_HISTORY)
488 hist_ptr = 0;
489 found++;
490 }
491 if (-occ > found)
492 return 0;
493
494 /* OK now we have the last occurrence in [hist_ptr-1], and we need to
495 * find occurrence -occ. 0 <= hist_ptr < MAX_HDR_HISTORY, and we have
496 * -10 <= occ <= -1. So we have to check [hist_ptr%MAX_HDR_HISTORY+occ]
497 * to remain in the 0..9 range.
498 */
499 hist_ptr += occ + MAX_HDR_HISTORY;
500 if (hist_ptr >= MAX_HDR_HISTORY)
501 hist_ptr -= MAX_HDR_HISTORY;
502 *vptr = ptr_hist[hist_ptr];
503 *vlen = len_hist[hist_ptr];
504 return 1;
505}
506
Willy Tarreau538746a2018-12-11 10:59:20 +0100507/* Macros used in the HTTP/1 parser, to check for the expected presence of
508 * certain bytes (ef: LF) or to skip to next byte and yield in case of failure.
509 */
510
511/* Expects to find an LF at <ptr>. If not, set <state> to <where> and jump to
512 * <bad>.
513 */
514#define EXPECT_LF_HERE(ptr, bad, state, where) \
515 do { \
516 if (unlikely(*(ptr) != '\n')) { \
517 state = (where); \
518 goto bad; \
519 } \
520 } while (0)
521
522/* Increments pointer <ptr>, continues to label <more> if it's still below
523 * pointer <end>, or goes to <stop> and sets <state> to <where> if the end
524 * of buffer was reached.
525 */
526#define EAT_AND_JUMP_OR_RETURN(ptr, end, more, stop, state, where) \
527 do { \
528 if (likely(++(ptr) < (end))) \
529 goto more; \
530 else { \
531 state = (where); \
532 goto stop; \
533 } \
534 } while (0)
535
536/*
537 * This function parses a status line between <ptr> and <end>, starting with
538 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
539 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
540 * will give undefined results.
541 * Note that it is upon the caller's responsibility to ensure that ptr < end,
542 * and that msg->sol points to the beginning of the response.
543 * If a complete line is found (which implies that at least one CR or LF is
544 * found before <end>, the updated <ptr> is returned, otherwise NULL is
545 * returned indicating an incomplete line (which does not mean that parts have
546 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
547 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
548 * upon next call.
549 *
550 * This function was intentionally designed to be called from
551 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
552 * within its state machine and use the same macros, hence the need for same
553 * labels and variable names. Note that msg->sol is left unchanged.
554 */
555const char *http_parse_stsline(struct http_msg *msg,
556 enum h1_state state, const char *ptr, const char *end,
557 unsigned int *ret_ptr, enum h1_state *ret_state)
558{
559 const char *msg_start = ci_head(msg->chn);
560
561 switch (state) {
562 case HTTP_MSG_RPVER:
563 http_msg_rpver:
564 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
565 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpver, http_msg_ood, state, HTTP_MSG_RPVER);
566
567 if (likely(HTTP_IS_SPHT(*ptr))) {
568 msg->sl.st.v_l = ptr - msg_start;
569 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpver_sp, http_msg_ood, state, HTTP_MSG_RPVER_SP);
570 }
571 msg->err_state = HTTP_MSG_RPVER;
572 state = HTTP_MSG_ERROR;
573 break;
574
575 case HTTP_MSG_RPVER_SP:
576 http_msg_rpver_sp:
577 if (likely(!HTTP_IS_LWS(*ptr))) {
578 msg->sl.st.c = ptr - msg_start;
579 goto http_msg_rpcode;
580 }
581 if (likely(HTTP_IS_SPHT(*ptr)))
582 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpver_sp, http_msg_ood, state, HTTP_MSG_RPVER_SP);
583 /* so it's a CR/LF, this is invalid */
584 msg->err_state = HTTP_MSG_RPVER_SP;
585 state = HTTP_MSG_ERROR;
586 break;
587
588 case HTTP_MSG_RPCODE:
589 http_msg_rpcode:
590 if (likely(!HTTP_IS_LWS(*ptr)))
591 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode, http_msg_ood, state, HTTP_MSG_RPCODE);
592
593 if (likely(HTTP_IS_SPHT(*ptr))) {
594 msg->sl.st.c_l = ptr - msg_start - msg->sl.st.c;
595 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode_sp, http_msg_ood, state, HTTP_MSG_RPCODE_SP);
596 }
597
598 /* so it's a CR/LF, so there is no reason phrase */
599 msg->sl.st.c_l = ptr - msg_start - msg->sl.st.c;
600 http_msg_rsp_reason:
601 /* FIXME: should we support HTTP responses without any reason phrase ? */
602 msg->sl.st.r = ptr - msg_start;
603 msg->sl.st.r_l = 0;
604 goto http_msg_rpline_eol;
605
606 case HTTP_MSG_RPCODE_SP:
607 http_msg_rpcode_sp:
608 if (likely(!HTTP_IS_LWS(*ptr))) {
609 msg->sl.st.r = ptr - msg_start;
610 goto http_msg_rpreason;
611 }
612 if (likely(HTTP_IS_SPHT(*ptr)))
613 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode_sp, http_msg_ood, state, HTTP_MSG_RPCODE_SP);
614 /* so it's a CR/LF, so there is no reason phrase */
615 goto http_msg_rsp_reason;
616
617 case HTTP_MSG_RPREASON:
618 http_msg_rpreason:
619 if (likely(!HTTP_IS_CRLF(*ptr)))
620 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpreason, http_msg_ood, state, HTTP_MSG_RPREASON);
621 msg->sl.st.r_l = ptr - msg_start - msg->sl.st.r;
622 http_msg_rpline_eol:
623 /* We have seen the end of line. Note that we do not
624 * necessarily have the \n yet, but at least we know that we
625 * have EITHER \r OR \n, otherwise the response would not be
626 * complete. We can then record the response length and return
627 * to the caller which will be able to register it.
628 */
629 msg->sl.st.l = ptr - msg_start - msg->sol;
630 return ptr;
631
632 default:
633#ifdef DEBUG_FULL
634 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
635 exit(1);
636#endif
637 ;
638 }
639
640 http_msg_ood:
641 /* out of valid data */
642 if (ret_state)
643 *ret_state = state;
644 if (ret_ptr)
645 *ret_ptr = ptr - msg_start;
646 return NULL;
647}
648
649/*
650 * This function parses a request line between <ptr> and <end>, starting with
651 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
652 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
653 * will give undefined results.
654 * Note that it is upon the caller's responsibility to ensure that ptr < end,
655 * and that msg->sol points to the beginning of the request.
656 * If a complete line is found (which implies that at least one CR or LF is
657 * found before <end>, the updated <ptr> is returned, otherwise NULL is
658 * returned indicating an incomplete line (which does not mean that parts have
659 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
660 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
661 * upon next call.
662 *
663 * This function was intentionally designed to be called from
664 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
665 * within its state machine and use the same macros, hence the need for same
666 * labels and variable names. Note that msg->sol is left unchanged.
667 */
668const char *http_parse_reqline(struct http_msg *msg,
669 enum h1_state state, const char *ptr, const char *end,
670 unsigned int *ret_ptr, enum h1_state *ret_state)
671{
672 const char *msg_start = ci_head(msg->chn);
673
674 switch (state) {
675 case HTTP_MSG_RQMETH:
676 http_msg_rqmeth:
677 if (likely(HTTP_IS_TOKEN(*ptr)))
678 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqmeth, http_msg_ood, state, HTTP_MSG_RQMETH);
679
680 if (likely(HTTP_IS_SPHT(*ptr))) {
681 msg->sl.rq.m_l = ptr - msg_start;
682 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqmeth_sp, http_msg_ood, state, HTTP_MSG_RQMETH_SP);
683 }
684
685 if (likely(HTTP_IS_CRLF(*ptr))) {
686 /* HTTP 0.9 request */
687 msg->sl.rq.m_l = ptr - msg_start;
688 http_msg_req09_uri:
689 msg->sl.rq.u = ptr - msg_start;
690 http_msg_req09_uri_e:
691 msg->sl.rq.u_l = ptr - msg_start - msg->sl.rq.u;
692 http_msg_req09_ver:
693 msg->sl.rq.v = ptr - msg_start;
694 msg->sl.rq.v_l = 0;
695 goto http_msg_rqline_eol;
696 }
697 msg->err_state = HTTP_MSG_RQMETH;
698 state = HTTP_MSG_ERROR;
699 break;
700
701 case HTTP_MSG_RQMETH_SP:
702 http_msg_rqmeth_sp:
703 if (likely(!HTTP_IS_LWS(*ptr))) {
704 msg->sl.rq.u = ptr - msg_start;
705 goto http_msg_rquri;
706 }
707 if (likely(HTTP_IS_SPHT(*ptr)))
708 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqmeth_sp, http_msg_ood, state, HTTP_MSG_RQMETH_SP);
709 /* so it's a CR/LF, meaning an HTTP 0.9 request */
710 goto http_msg_req09_uri;
711
712 case HTTP_MSG_RQURI:
713 http_msg_rquri:
714#if defined(__x86_64__) || \
715 defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || \
716 defined(__ARM_ARCH_7A__)
717 /* speedup: skip bytes not between 0x21 and 0x7e inclusive */
718 while (ptr <= end - sizeof(int)) {
719 int x = *(int *)ptr - 0x21212121;
720 if (x & 0x80808080)
721 break;
722
723 x -= 0x5e5e5e5e;
724 if (!(x & 0x80808080))
725 break;
726
727 ptr += sizeof(int);
728 }
729#endif
730 if (ptr >= end) {
731 state = HTTP_MSG_RQURI;
732 goto http_msg_ood;
733 }
734 http_msg_rquri2:
735 if (likely((unsigned char)(*ptr - 33) <= 93)) /* 33 to 126 included */
736 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rquri2, http_msg_ood, state, HTTP_MSG_RQURI);
737
738 if (likely(HTTP_IS_SPHT(*ptr))) {
739 msg->sl.rq.u_l = ptr - msg_start - msg->sl.rq.u;
740 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rquri_sp, http_msg_ood, state, HTTP_MSG_RQURI_SP);
741 }
742
743 if (likely((unsigned char)*ptr >= 128)) {
744 /* non-ASCII chars are forbidden unless option
745 * accept-invalid-http-request is enabled in the frontend.
746 * In any case, we capture the faulty char.
747 */
748 if (msg->err_pos < -1)
749 goto invalid_char;
750 if (msg->err_pos == -1)
751 msg->err_pos = ptr - msg_start;
752 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rquri, http_msg_ood, state, HTTP_MSG_RQURI);
753 }
754
755 if (likely(HTTP_IS_CRLF(*ptr))) {
756 /* so it's a CR/LF, meaning an HTTP 0.9 request */
757 goto http_msg_req09_uri_e;
758 }
759
760 /* OK forbidden chars, 0..31 or 127 */
761 invalid_char:
762 msg->err_pos = ptr - msg_start;
763 msg->err_state = HTTP_MSG_RQURI;
764 state = HTTP_MSG_ERROR;
765 break;
766
767 case HTTP_MSG_RQURI_SP:
768 http_msg_rquri_sp:
769 if (likely(!HTTP_IS_LWS(*ptr))) {
770 msg->sl.rq.v = ptr - msg_start;
771 goto http_msg_rqver;
772 }
773 if (likely(HTTP_IS_SPHT(*ptr)))
774 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rquri_sp, http_msg_ood, state, HTTP_MSG_RQURI_SP);
775 /* so it's a CR/LF, meaning an HTTP 0.9 request */
776 goto http_msg_req09_ver;
777
778 case HTTP_MSG_RQVER:
779 http_msg_rqver:
780 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
781 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqver, http_msg_ood, state, HTTP_MSG_RQVER);
782
783 if (likely(HTTP_IS_CRLF(*ptr))) {
784 msg->sl.rq.v_l = ptr - msg_start - msg->sl.rq.v;
785 http_msg_rqline_eol:
786 /* We have seen the end of line. Note that we do not
787 * necessarily have the \n yet, but at least we know that we
788 * have EITHER \r OR \n, otherwise the request would not be
789 * complete. We can then record the request length and return
790 * to the caller which will be able to register it.
791 */
792 msg->sl.rq.l = ptr - msg_start - msg->sol;
793 return ptr;
794 }
795
796 /* neither an HTTP_VER token nor a CRLF */
797 msg->err_state = HTTP_MSG_RQVER;
798 state = HTTP_MSG_ERROR;
799 break;
800
801 default:
802#ifdef DEBUG_FULL
803 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
804 exit(1);
805#endif
806 ;
807 }
808
809 http_msg_ood:
810 /* out of valid data */
811 if (ret_state)
812 *ret_state = state;
813 if (ret_ptr)
814 *ret_ptr = ptr - msg_start;
815 return NULL;
816}
817
818/*
819 * This function parses an HTTP message, either a request or a response,
820 * depending on the initial msg->msg_state. The caller is responsible for
821 * ensuring that the message does not wrap. The function can be preempted
822 * everywhere when data are missing and recalled at the exact same location
823 * with no information loss. The message may even be realigned between two
824 * calls. The header index is re-initialized when switching from
825 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
826 * fields. Note that msg->sol will be initialized after completing the first
827 * state, so that none of the msg pointers has to be initialized prior to the
828 * first call.
829 */
830void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx)
831{
832 enum h1_state state; /* updated only when leaving the FSM */
833 register const char *ptr, *end; /* request pointers, to avoid dereferences */
834 struct buffer *buf = &msg->chn->buf;
Christopher Faulet132f7b42019-05-10 11:36:51 +0200835 char *input = ci_head(msg->chn);
Willy Tarreau538746a2018-12-11 10:59:20 +0100836
837 state = msg->msg_state;
838 ptr = input + msg->next;
839 end = b_stop(buf);
840
841 if (unlikely(ptr >= end))
842 goto http_msg_ood;
843
844 switch (state) {
845 /*
846 * First, states that are specific to the response only.
847 * We check them first so that request and headers are
848 * closer to each other (accessed more often).
849 */
850 case HTTP_MSG_RPBEFORE:
851 http_msg_rpbefore:
852 if (likely(HTTP_IS_TOKEN(*ptr))) {
853 /* we have a start of message, but we have to check
854 * first if we need to remove some CRLF. We can only
855 * do this when o=0.
856 */
857 if (unlikely(ptr != input)) {
858 if (co_data(msg->chn))
859 goto http_msg_ood;
860 /* Remove empty leading lines, as recommended by RFC2616. */
861 b_del(buf, ptr - input);
862 input = b_head(buf);
863 }
864 msg->sol = 0;
865 msg->sl.st.l = 0; /* used in debug mode */
866 hdr_idx_init(idx);
867 state = HTTP_MSG_RPVER;
868 goto http_msg_rpver;
869 }
870
871 if (unlikely(!HTTP_IS_CRLF(*ptr))) {
872 state = HTTP_MSG_RPBEFORE;
873 goto http_msg_invalid;
874 }
875
876 if (unlikely(*ptr == '\n'))
877 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpbefore, http_msg_ood, state, HTTP_MSG_RPBEFORE);
878 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpbefore_cr, http_msg_ood, state, HTTP_MSG_RPBEFORE_CR);
879 /* stop here */
880
881 case HTTP_MSG_RPBEFORE_CR:
882 http_msg_rpbefore_cr:
883 EXPECT_LF_HERE(ptr, http_msg_invalid, state, HTTP_MSG_RPBEFORE_CR);
884 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpbefore, http_msg_ood, state, HTTP_MSG_RPBEFORE);
885 /* stop here */
886
887 case HTTP_MSG_RPVER:
888 http_msg_rpver:
889 case HTTP_MSG_RPVER_SP:
890 case HTTP_MSG_RPCODE:
891 case HTTP_MSG_RPCODE_SP:
892 case HTTP_MSG_RPREASON:
893 ptr = (char *)http_parse_stsline(msg,
894 state, ptr, end,
895 &msg->next, &msg->msg_state);
896 if (unlikely(!ptr))
897 return;
898
899 /* we have a full response and we know that we have either a CR
900 * or an LF at <ptr>.
901 */
902 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
903
904 msg->sol = ptr - input;
905 if (likely(*ptr == '\r'))
906 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpline_end, http_msg_ood, state, HTTP_MSG_RPLINE_END);
907 goto http_msg_rpline_end;
908
909 case HTTP_MSG_RPLINE_END:
910 http_msg_rpline_end:
911 /* msg->sol must point to the first of CR or LF. */
912 EXPECT_LF_HERE(ptr, http_msg_invalid, state, HTTP_MSG_RPLINE_END);
913 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_first, http_msg_ood, state, HTTP_MSG_HDR_FIRST);
914 /* stop here */
915
916 /*
917 * Second, states that are specific to the request only
918 */
919 case HTTP_MSG_RQBEFORE:
920 http_msg_rqbefore:
921 if (likely(HTTP_IS_TOKEN(*ptr))) {
922 /* we have a start of message, but we have to check
923 * first if we need to remove some CRLF. We can only
924 * do this when o=0.
925 */
926 if (likely(ptr != input)) {
927 if (co_data(msg->chn))
928 goto http_msg_ood;
929 /* Remove empty leading lines, as recommended by RFC2616. */
930 b_del(buf, ptr - input);
931 input = b_head(buf);
932 }
933 msg->sol = 0;
934 msg->sl.rq.l = 0; /* used in debug mode */
935 state = HTTP_MSG_RQMETH;
936 goto http_msg_rqmeth;
937 }
938
939 if (unlikely(!HTTP_IS_CRLF(*ptr))) {
940 state = HTTP_MSG_RQBEFORE;
941 goto http_msg_invalid;
942 }
943
944 if (unlikely(*ptr == '\n'))
945 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqbefore, http_msg_ood, state, HTTP_MSG_RQBEFORE);
946 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqbefore_cr, http_msg_ood, state, HTTP_MSG_RQBEFORE_CR);
947 /* stop here */
948
949 case HTTP_MSG_RQBEFORE_CR:
950 http_msg_rqbefore_cr:
951 EXPECT_LF_HERE(ptr, http_msg_invalid, state, HTTP_MSG_RQBEFORE_CR);
952 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqbefore, http_msg_ood, state, HTTP_MSG_RQBEFORE);
953 /* stop here */
954
955 case HTTP_MSG_RQMETH:
956 http_msg_rqmeth:
957 case HTTP_MSG_RQMETH_SP:
958 case HTTP_MSG_RQURI:
959 case HTTP_MSG_RQURI_SP:
960 case HTTP_MSG_RQVER:
961 ptr = (char *)http_parse_reqline(msg,
962 state, ptr, end,
963 &msg->next, &msg->msg_state);
964 if (unlikely(!ptr))
965 return;
966
967 /* we have a full request and we know that we have either a CR
968 * or an LF at <ptr>.
969 */
970 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
971
972 msg->sol = ptr - input;
973 if (likely(*ptr == '\r'))
974 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rqline_end, http_msg_ood, state, HTTP_MSG_RQLINE_END);
975 goto http_msg_rqline_end;
976
977 case HTTP_MSG_RQLINE_END:
978 http_msg_rqline_end:
979 /* check for HTTP/0.9 request : no version information available.
980 * msg->sol must point to the first of CR or LF.
981 */
982 if (unlikely(msg->sl.rq.v_l == 0))
983 goto http_msg_last_lf;
984
985 EXPECT_LF_HERE(ptr, http_msg_invalid, state, HTTP_MSG_RQLINE_END);
986 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_first, http_msg_ood, state, HTTP_MSG_HDR_FIRST);
987 /* stop here */
988
989 /*
990 * Common states below
991 */
992 case HTTP_MSG_HDR_FIRST:
993 http_msg_hdr_first:
994 msg->sol = ptr - input;
995 if (likely(!HTTP_IS_CRLF(*ptr))) {
996 goto http_msg_hdr_name;
997 }
998
999 if (likely(*ptr == '\r'))
1000 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_last_lf, http_msg_ood, state, HTTP_MSG_LAST_LF);
1001 goto http_msg_last_lf;
1002
1003 case HTTP_MSG_HDR_NAME:
1004 http_msg_hdr_name:
1005 /* assumes msg->sol points to the first char */
1006 if (likely(HTTP_IS_TOKEN(*ptr)))
1007 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_name, http_msg_ood, state, HTTP_MSG_HDR_NAME);
1008
1009 if (likely(*ptr == ':'))
1010 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, HTTP_MSG_HDR_L1_SP);
1011
1012 if (likely(msg->err_pos < -1) || *ptr == '\n') {
1013 state = HTTP_MSG_HDR_NAME;
1014 goto http_msg_invalid;
1015 }
1016
1017 if (msg->err_pos == -1) /* capture error pointer */
1018 msg->err_pos = ptr - input; /* >= 0 now */
1019
1020 /* and we still accept this non-token character */
1021 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_name, http_msg_ood, state, HTTP_MSG_HDR_NAME);
1022
1023 case HTTP_MSG_HDR_L1_SP:
1024 http_msg_hdr_l1_sp:
1025 /* assumes msg->sol points to the first char */
1026 if (likely(HTTP_IS_SPHT(*ptr)))
1027 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, HTTP_MSG_HDR_L1_SP);
1028
1029 /* header value can be basically anything except CR/LF */
1030 msg->sov = ptr - input;
1031
1032 if (likely(!HTTP_IS_CRLF(*ptr))) {
1033 goto http_msg_hdr_val;
1034 }
1035
1036 if (likely(*ptr == '\r'))
1037 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_lf, http_msg_ood, state, HTTP_MSG_HDR_L1_LF);
1038 goto http_msg_hdr_l1_lf;
1039
1040 case HTTP_MSG_HDR_L1_LF:
1041 http_msg_hdr_l1_lf:
1042 EXPECT_LF_HERE(ptr, http_msg_invalid, state, HTTP_MSG_HDR_L1_LF);
1043 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_lws, http_msg_ood, state, HTTP_MSG_HDR_L1_LWS);
1044
1045 case HTTP_MSG_HDR_L1_LWS:
1046 http_msg_hdr_l1_lws:
1047 if (likely(HTTP_IS_SPHT(*ptr))) {
1048 /* replace HT,CR,LF with spaces */
1049 for (; input + msg->sov < ptr; msg->sov++)
1050 input[msg->sov] = ' ';
1051 goto http_msg_hdr_l1_sp;
1052 }
1053 /* we had a header consisting only in spaces ! */
1054 msg->eol = msg->sov;
1055 goto http_msg_complete_header;
1056
1057 case HTTP_MSG_HDR_VAL:
1058 http_msg_hdr_val:
1059 /* assumes msg->sol points to the first char, and msg->sov
1060 * points to the first character of the value.
1061 */
1062
1063 /* speedup: we'll skip packs of 4 or 8 bytes not containing bytes 0x0D
1064 * and lower. In fact since most of the time is spent in the loop, we
1065 * also remove the sign bit test so that bytes 0x8e..0x0d break the
1066 * loop, but we don't care since they're very rare in header values.
1067 */
1068#if defined(__x86_64__)
1069 while (ptr <= end - sizeof(long)) {
1070 if ((*(long *)ptr - 0x0e0e0e0e0e0e0e0eULL) & 0x8080808080808080ULL)
1071 goto http_msg_hdr_val2;
1072 ptr += sizeof(long);
1073 }
1074#endif
1075#if defined(__x86_64__) || \
1076 defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || \
1077 defined(__ARM_ARCH_7A__)
1078 while (ptr <= end - sizeof(int)) {
1079 if ((*(int*)ptr - 0x0e0e0e0e) & 0x80808080)
1080 goto http_msg_hdr_val2;
1081 ptr += sizeof(int);
1082 }
1083#endif
1084 if (ptr >= end) {
1085 state = HTTP_MSG_HDR_VAL;
1086 goto http_msg_ood;
1087 }
1088 http_msg_hdr_val2:
1089 if (likely(!HTTP_IS_CRLF(*ptr)))
1090 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_val2, http_msg_ood, state, HTTP_MSG_HDR_VAL);
1091
1092 msg->eol = ptr - input;
1093 /* Note: we could also copy eol into ->eoh so that we have the
1094 * real header end in case it ends with lots of LWS, but is this
1095 * really needed ?
1096 */
1097 if (likely(*ptr == '\r'))
1098 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l2_lf, http_msg_ood, state, HTTP_MSG_HDR_L2_LF);
1099 goto http_msg_hdr_l2_lf;
1100
1101 case HTTP_MSG_HDR_L2_LF:
1102 http_msg_hdr_l2_lf:
1103 EXPECT_LF_HERE(ptr, http_msg_invalid, state, HTTP_MSG_HDR_L2_LF);
1104 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l2_lws, http_msg_ood, state, HTTP_MSG_HDR_L2_LWS);
1105
1106 case HTTP_MSG_HDR_L2_LWS:
1107 http_msg_hdr_l2_lws:
1108 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1109 /* LWS: replace HT,CR,LF with spaces */
1110 for (; input + msg->eol < ptr; msg->eol++)
1111 input[msg->eol] = ' ';
1112 goto http_msg_hdr_val;
1113 }
1114 http_msg_complete_header:
1115 /*
1116 * It was a new header, so the last one is finished.
1117 * Assumes msg->sol points to the first char, msg->sov points
1118 * to the first character of the value and msg->eol to the
1119 * first CR or LF so we know how the line ends. We insert last
1120 * header into the index.
1121 */
1122 if (unlikely(hdr_idx_add(msg->eol - msg->sol, input[msg->eol] == '\r',
1123 idx, idx->tail) < 0)) {
1124 state = HTTP_MSG_HDR_L2_LWS;
1125 goto http_msg_invalid;
1126 }
1127
1128 msg->sol = ptr - input;
1129 if (likely(!HTTP_IS_CRLF(*ptr))) {
1130 goto http_msg_hdr_name;
1131 }
1132
1133 if (likely(*ptr == '\r'))
1134 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_last_lf, http_msg_ood, state, HTTP_MSG_LAST_LF);
1135 goto http_msg_last_lf;
1136
1137 case HTTP_MSG_LAST_LF:
1138 http_msg_last_lf:
1139 /* Assumes msg->sol points to the first of either CR or LF.
1140 * Sets ->sov and ->next to the total header length, ->eoh to
1141 * the last CRLF, and ->eol to the last CRLF length (1 or 2).
1142 */
1143 EXPECT_LF_HERE(ptr, http_msg_invalid, state, HTTP_MSG_LAST_LF);
1144 ptr++;
1145 msg->sov = msg->next = ptr - input;
1146 msg->eoh = msg->sol;
1147 msg->sol = 0;
1148 msg->eol = msg->sov - msg->eoh;
1149 msg->msg_state = HTTP_MSG_BODY;
1150 return;
1151
1152 case HTTP_MSG_ERROR:
1153 /* this may only happen if we call http_msg_analyser() twice with an error */
1154 break;
1155
1156 default:
1157#ifdef DEBUG_FULL
1158 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1159 exit(1);
1160#endif
1161 ;
1162 }
1163 http_msg_ood:
1164 /* out of data */
1165 msg->msg_state = state;
1166 msg->next = ptr - input;
1167 return;
1168
1169 http_msg_invalid:
1170 /* invalid message */
1171 msg->err_state = state;
1172 msg->msg_state = HTTP_MSG_ERROR;
1173 msg->next = ptr - input;
1174 return;
1175}
1176
1177/* This function skips trailers in the buffer associated with HTTP message
1178 * <msg>. The first visited position is msg->next. If the end of the trailers is
1179 * found, the function returns >0. So, the caller can automatically schedul it
1180 * to be forwarded, and switch msg->msg_state to HTTP_MSG_DONE. If not enough
1181 * data are available, the function does not change anything except maybe
1182 * msg->sol if it could parse some lines, and returns zero. If a parse error
1183 * is encountered, the function returns < 0 and does not change anything except
1184 * maybe msg->sol. Note that the message must already be in HTTP_MSG_TRAILERS
1185 * state before calling this function, which implies that all non-trailers data
1186 * have already been scheduled for forwarding, and that msg->next exactly
1187 * matches the length of trailers already parsed and not forwarded. It is also
1188 * important to note that this function is designed to be able to parse wrapped
1189 * headers at end of buffer.
1190 */
1191int http_forward_trailers(struct http_msg *msg)
1192{
1193 const struct buffer *buf = &msg->chn->buf;
1194 const char *parse = ci_head(msg->chn);
1195 const char *stop = b_tail(buf);
1196
1197 /* we have msg->next which points to next line. Look for CRLF. But
1198 * first, we reset msg->sol */
1199 msg->sol = 0;
1200 while (1) {
1201 const char *p1 = NULL, *p2 = NULL;
1202 const char *start = c_ptr(msg->chn, msg->next + msg->sol);
1203 const char *ptr = start;
1204
1205 /* scan current line and stop at LF or CRLF */
1206 while (1) {
1207 if (ptr == stop)
1208 return 0;
1209
1210 if (*ptr == '\n') {
1211 if (!p1)
1212 p1 = ptr;
1213 p2 = ptr;
1214 break;
1215 }
1216
1217 if (*ptr == '\r') {
1218 if (p1) {
1219 msg->err_pos = b_dist(buf, parse, ptr);
1220 return -1;
1221 }
1222 p1 = ptr;
1223 }
1224
1225 ptr = b_next(buf, ptr);
1226 }
1227
1228 /* after LF; point to beginning of next line */
1229 p2 = b_next(buf, p2);
1230 msg->sol += b_dist(buf, start, p2);
1231
1232 /* LF/CRLF at beginning of line => end of trailers at p2.
1233 * Everything was scheduled for forwarding, there's nothing left
1234 * from this message. */
1235 if (p1 == start)
1236 return 1;
1237
1238 /* OK, next line then */
1239 }
1240}