"Fossies" - the Fresh Open Source Software Archive

Member "haproxy-2.0.0/src/http_msg.c" (16 Jun 2019, 39716 Bytes) of package /linux/misc/haproxy-2.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "http_msg.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.9.7_vs_1.9.8.

    1 /*
    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  */
   25 int 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  */
   48 int 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  */
  114 int 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  */
  180 int 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  */
  265 int 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 
  308 int 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 
  341 int 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  */
  385 unsigned 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  */
  451 unsigned 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 
  507 /* 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  */
  555 const 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  */
  668 const 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  */
  830 void 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;
  835     char *input = ci_head(msg->chn);
  836 
  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  */
 1191 int 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 }