diff --git a/Makefile b/Makefile index ddc32df4d..f3e69762d 100644 --- a/Makefile +++ b/Makefile @@ -842,7 +842,7 @@ OBJS = src/cfgparse.o src/proto_http.o src/stats.o src/server.o src/stream.o \ src/regex.o src/queue.o src/frontend.o src/arg.o src/proto_uxst.o \ src/raw_sock.o src/lb_chash.o src/lb_fwlc.o src/lb_fwrr.o \ src/lb_fas.o src/applet.o src/hdr_idx.o src/ev_select.o src/hash.o \ - src/lb_map.o src/base64.o src/protocol.o + src/lb_map.o src/base64.o src/protocol.o src/h1.o EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o \ $(EBTREE_DIR)/eb32tree.o $(EBTREE_DIR)/eb64tree.o \ diff --git a/include/proto/h1.h b/include/proto/h1.h new file mode 100644 index 000000000..7dff09612 --- /dev/null +++ b/include/proto/h1.h @@ -0,0 +1,125 @@ +/* + * include/proto/h1.h + * This file contains HTTP/1 protocol definitions. + * + * Copyright (C) 2000-2017 Willy Tarreau - w@1wt.eu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _PROTO_H1_H +#define _PROTO_H1_H + +#include +#include +#include + +extern const uint8_t h1_char_classes[256]; + +#define H1_FLG_CTL 0x01 +#define H1_FLG_SEP 0x02 +#define H1_FLG_LWS 0x04 +#define H1_FLG_SPHT 0x08 +#define H1_FLG_CRLF 0x10 +#define H1_FLG_TOK 0x20 +#define H1_FLG_VER 0x40 + +#define HTTP_IS_CTL(x) (h1_char_classes[(uint8_t)(x)] & H1_FLG_CTL) +#define HTTP_IS_SEP(x) (h1_char_classes[(uint8_t)(x)] & H1_FLG_SEP) +#define HTTP_IS_LWS(x) (h1_char_classes[(uint8_t)(x)] & H1_FLG_LWS) +#define HTTP_IS_SPHT(x) (h1_char_classes[(uint8_t)(x)] & H1_FLG_SPHT) +#define HTTP_IS_CRLF(x) (h1_char_classes[(uint8_t)(x)] & H1_FLG_CRLF) +#define HTTP_IS_TOKEN(x) (h1_char_classes[(uint8_t)(x)] & H1_FLG_TOK) +#define HTTP_IS_VER_TOKEN(x) (h1_char_classes[(uint8_t)(x)] & H1_FLG_VER) + + +/* Macros used in the HTTP/1 parser, to check for the expected presence of + * certain bytes (ef: LF) or to skip to next byte and yield in case of failure. + */ + + +/* Expects to find an LF at . If not, set to and jump to + * . + */ +#define EXPECT_LF_HERE(ptr, bad, state, where) \ + do { \ + if (unlikely(*(ptr) != '\n')) { \ + state = (where); \ + goto bad; \ + } \ + } while (0) + +/* Increments pointer , continues to label if it's still below + * pointer , or goes to and sets to if the end + * of buffer was reached. + */ +#define EAT_AND_JUMP_OR_RETURN(ptr, end, more, stop, state, where) \ + do { \ + if (likely(++(ptr) < (end))) \ + goto more; \ + else { \ + state = (where); \ + goto stop; \ + } \ + } while (0) + +/* for debugging, reports the HTTP/1 message state name */ +static inline const char *h1_msg_state_str(enum h1_state msg_state) +{ + switch (msg_state) { + case HTTP_MSG_RQBEFORE: return "MSG_RQBEFORE"; + case HTTP_MSG_RQBEFORE_CR: return "MSG_RQBEFORE_CR"; + case HTTP_MSG_RQMETH: return "MSG_RQMETH"; + case HTTP_MSG_RQMETH_SP: return "MSG_RQMETH_SP"; + case HTTP_MSG_RQURI: return "MSG_RQURI"; + case HTTP_MSG_RQURI_SP: return "MSG_RQURI_SP"; + case HTTP_MSG_RQVER: return "MSG_RQVER"; + case HTTP_MSG_RQLINE_END: return "MSG_RQLINE_END"; + case HTTP_MSG_RPBEFORE: return "MSG_RPBEFORE"; + case HTTP_MSG_RPBEFORE_CR: return "MSG_RPBEFORE_CR"; + case HTTP_MSG_RPVER: return "MSG_RPVER"; + case HTTP_MSG_RPVER_SP: return "MSG_RPVER_SP"; + case HTTP_MSG_RPCODE: return "MSG_RPCODE"; + case HTTP_MSG_RPCODE_SP: return "MSG_RPCODE_SP"; + case HTTP_MSG_RPREASON: return "MSG_RPREASON"; + case HTTP_MSG_RPLINE_END: return "MSG_RPLINE_END"; + case HTTP_MSG_HDR_FIRST: return "MSG_HDR_FIRST"; + case HTTP_MSG_HDR_NAME: return "MSG_HDR_NAME"; + case HTTP_MSG_HDR_COL: return "MSG_HDR_COL"; + case HTTP_MSG_HDR_L1_SP: return "MSG_HDR_L1_SP"; + case HTTP_MSG_HDR_L1_LF: return "MSG_HDR_L1_LF"; + case HTTP_MSG_HDR_L1_LWS: return "MSG_HDR_L1_LWS"; + case HTTP_MSG_HDR_VAL: return "MSG_HDR_VAL"; + case HTTP_MSG_HDR_L2_LF: return "MSG_HDR_L2_LF"; + case HTTP_MSG_HDR_L2_LWS: return "MSG_HDR_L2_LWS"; + case HTTP_MSG_LAST_LF: return "MSG_LAST_LF"; + case HTTP_MSG_ERROR: return "MSG_ERROR"; + case HTTP_MSG_BODY: return "MSG_BODY"; + case HTTP_MSG_100_SENT: return "MSG_100_SENT"; + case HTTP_MSG_CHUNK_SIZE: return "MSG_CHUNK_SIZE"; + case HTTP_MSG_DATA: return "MSG_DATA"; + case HTTP_MSG_CHUNK_CRLF: return "MSG_CHUNK_CRLF"; + case HTTP_MSG_TRAILERS: return "MSG_TRAILERS"; + case HTTP_MSG_ENDING: return "MSG_ENDING"; + case HTTP_MSG_DONE: return "MSG_DONE"; + case HTTP_MSG_CLOSING: return "MSG_CLOSING"; + case HTTP_MSG_CLOSED: return "MSG_CLOSED"; + case HTTP_MSG_TUNNEL: return "MSG_TUNNEL"; + default: return "MSG_??????"; + } +} + + +#endif /* _PROTO_H1_H */ diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 0fe779090..d046f536a 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -27,6 +27,7 @@ #include #include #include +#include /* * some macros used for the request parsing. @@ -42,55 +43,6 @@ * ver_token = 'H', 'P', 'T', '/', '.', and digits. */ -extern const unsigned char http_char_classes[256]; - -#define HTTP_FLG_CTL 0x01 -#define HTTP_FLG_SEP 0x02 -#define HTTP_FLG_LWS 0x04 -#define HTTP_FLG_SPHT 0x08 -#define HTTP_FLG_CRLF 0x10 -#define HTTP_FLG_TOK 0x20 -#define HTTP_FLG_VER 0x40 - -#define HTTP_IS_CTL(x) (http_char_classes[(unsigned char)(x)] & HTTP_FLG_CTL) -#define HTTP_IS_SEP(x) (http_char_classes[(unsigned char)(x)] & HTTP_FLG_SEP) -#define HTTP_IS_LWS(x) (http_char_classes[(unsigned char)(x)] & HTTP_FLG_LWS) -#define HTTP_IS_SPHT(x) (http_char_classes[(unsigned char)(x)] & HTTP_FLG_SPHT) -#define HTTP_IS_CRLF(x) (http_char_classes[(unsigned char)(x)] & HTTP_FLG_CRLF) -#define HTTP_IS_TOKEN(x) (http_char_classes[(unsigned char)(x)] & HTTP_FLG_TOK) -#define HTTP_IS_VER_TOKEN(x) (http_char_classes[(unsigned char)(x)] & HTTP_FLG_VER) - -/* Macros used in the HTTP parser, to check for the expected presence of - * certain bytes (ef: LF) or to skip to next byte and yield in case of failure. - */ - - -/* Expects to find an LF at . If not, set to and jump to - * . - */ -#define EXPECT_LF_HERE(ptr, bad, state, where) \ - do { \ - if (unlikely(*(ptr) != '\n')) { \ - state = (where); \ - goto bad; \ - } \ - } while (0) - -/* Increments pointer , continues to label if it's still below - * pointer , or goes to and sets to if the end - * of buffer was reached. - */ -#define EAT_AND_JUMP_OR_RETURN(ptr, end, more, stop, state, where) \ - do { \ - if (likely(++(ptr) < (end))) \ - goto more; \ - else { \ - state = (where); \ - goto stop; \ - } \ - } while (0) - - extern const int http_err_codes[HTTP_ERR_SIZE]; extern struct chunk http_err_chunks[HTTP_ERR_SIZE]; extern const char *HTTP_302; @@ -147,7 +99,7 @@ void http_perform_server_redirect(struct stream *s, struct stream_interface *si) void http_return_srv_error(struct stream *s, struct stream_interface *si); void http_capture_bad_message(struct error_snapshot *es, struct stream *s, struct http_msg *msg, - enum ht_state state, struct proxy *other_end); + enum h1_state state, struct proxy *other_end); unsigned int http_get_hdr(const struct http_msg *msg, const char *hname, int hlen, struct hdr_idx *idx, int occ, struct hdr_ctx *ctx, char **vptr, int *vlen); @@ -282,52 +234,6 @@ static inline int http_trk_idx(int trk_action) return trk_action - ACT_ACTION_TRK_SC0; } -/* for debugging, reports the HTTP message state name */ -static inline const char *http_msg_state_str(int msg_state) -{ - switch (msg_state) { - case HTTP_MSG_RQBEFORE: return "MSG_RQBEFORE"; - case HTTP_MSG_RQBEFORE_CR: return "MSG_RQBEFORE_CR"; - case HTTP_MSG_RQMETH: return "MSG_RQMETH"; - case HTTP_MSG_RQMETH_SP: return "MSG_RQMETH_SP"; - case HTTP_MSG_RQURI: return "MSG_RQURI"; - case HTTP_MSG_RQURI_SP: return "MSG_RQURI_SP"; - case HTTP_MSG_RQVER: return "MSG_RQVER"; - case HTTP_MSG_RQLINE_END: return "MSG_RQLINE_END"; - case HTTP_MSG_RPBEFORE: return "MSG_RPBEFORE"; - case HTTP_MSG_RPBEFORE_CR: return "MSG_RPBEFORE_CR"; - case HTTP_MSG_RPVER: return "MSG_RPVER"; - case HTTP_MSG_RPVER_SP: return "MSG_RPVER_SP"; - case HTTP_MSG_RPCODE: return "MSG_RPCODE"; - case HTTP_MSG_RPCODE_SP: return "MSG_RPCODE_SP"; - case HTTP_MSG_RPREASON: return "MSG_RPREASON"; - case HTTP_MSG_RPLINE_END: return "MSG_RPLINE_END"; - case HTTP_MSG_HDR_FIRST: return "MSG_HDR_FIRST"; - case HTTP_MSG_HDR_NAME: return "MSG_HDR_NAME"; - case HTTP_MSG_HDR_COL: return "MSG_HDR_COL"; - case HTTP_MSG_HDR_L1_SP: return "MSG_HDR_L1_SP"; - case HTTP_MSG_HDR_L1_LF: return "MSG_HDR_L1_LF"; - case HTTP_MSG_HDR_L1_LWS: return "MSG_HDR_L1_LWS"; - case HTTP_MSG_HDR_VAL: return "MSG_HDR_VAL"; - case HTTP_MSG_HDR_L2_LF: return "MSG_HDR_L2_LF"; - case HTTP_MSG_HDR_L2_LWS: return "MSG_HDR_L2_LWS"; - case HTTP_MSG_LAST_LF: return "MSG_LAST_LF"; - case HTTP_MSG_ERROR: return "MSG_ERROR"; - case HTTP_MSG_BODY: return "MSG_BODY"; - case HTTP_MSG_100_SENT: return "MSG_100_SENT"; - case HTTP_MSG_CHUNK_SIZE: return "MSG_CHUNK_SIZE"; - case HTTP_MSG_DATA: return "MSG_DATA"; - case HTTP_MSG_CHUNK_CRLF: return "MSG_CHUNK_CRLF"; - case HTTP_MSG_TRAILERS: return "MSG_TRAILERS"; - case HTTP_MSG_ENDING: return "MSG_ENDING"; - case HTTP_MSG_DONE: return "MSG_DONE"; - case HTTP_MSG_CLOSING: return "MSG_CLOSING"; - case HTTP_MSG_CLOSED: return "MSG_CLOSED"; - case HTTP_MSG_TUNNEL: return "MSG_TUNNEL"; - default: return "MSG_??????"; - } -} - #endif /* _PROTO_PROTO_HTTP_H */ /* diff --git a/include/types/h1.h b/include/types/h1.h new file mode 100644 index 000000000..8a146c3ca --- /dev/null +++ b/include/types/h1.h @@ -0,0 +1,85 @@ +/* + * include/types/h1.h + * This file contains HTTP/1 protocol definitions. + * + * Copyright (C) 2000-2017 Willy Tarreau - w@1wt.eu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _TYPES_H1_H +#define _TYPES_H1_H + +/* Possible states while parsing HTTP/1 messages (request|response) */ +enum h1_state { + HTTP_MSG_RQBEFORE = 0, // request: leading LF, before start line + HTTP_MSG_RQBEFORE_CR = 1, // request: leading CRLF, before start line + /* these ones define a request start line */ + HTTP_MSG_RQMETH = 2, // parsing the Method + HTTP_MSG_RQMETH_SP = 3, // space(s) after the Method + HTTP_MSG_RQURI = 4, // parsing the Request URI + HTTP_MSG_RQURI_SP = 5, // space(s) after the Request URI + HTTP_MSG_RQVER = 6, // parsing the Request Version + HTTP_MSG_RQLINE_END = 7, // end of request line (CR or LF) + + HTTP_MSG_RPBEFORE = 8, // response: leading LF, before start line + HTTP_MSG_RPBEFORE_CR = 9, // response: leading CRLF, before start line + + /* these ones define a response start line */ + HTTP_MSG_RPVER = 10, // parsing the Response Version + HTTP_MSG_RPVER_SP = 11, // space(s) after the Response Version + HTTP_MSG_RPCODE = 12, // response code + HTTP_MSG_RPCODE_SP = 13, // space(s) after the response code + HTTP_MSG_RPREASON = 14, // response reason + HTTP_MSG_RPLINE_END = 15, // end of response line (CR or LF) + + /* common header processing */ + HTTP_MSG_HDR_FIRST = 16, // waiting for first header or last CRLF (no LWS possible) + HTTP_MSG_HDR_NAME = 17, // parsing header name + HTTP_MSG_HDR_COL = 18, // parsing header colon + HTTP_MSG_HDR_L1_SP = 19, // parsing header LWS (SP|HT) before value + HTTP_MSG_HDR_L1_LF = 20, // parsing header LWS (LF) before value + HTTP_MSG_HDR_L1_LWS = 21, // checking whether it's a new header or an LWS + HTTP_MSG_HDR_VAL = 22, // parsing header value + HTTP_MSG_HDR_L2_LF = 23, // parsing header LWS (LF) inside/after value + HTTP_MSG_HDR_L2_LWS = 24, // checking whether it's a new header or an LWS + + HTTP_MSG_LAST_LF = 25, // parsing last LF + + /* error state : must be before HTTP_MSG_BODY so that (>=BODY) always indicates + * that data are being processed. + */ + HTTP_MSG_ERROR = 26, // an error occurred + /* Body processing. + * The state HTTP_MSG_BODY is a delimiter to know if we're waiting for headers + * or body. All the sub-states below also indicate we're processing the body, + * with some additional information. + */ + HTTP_MSG_BODY = 27, // parsing body at end of headers + HTTP_MSG_100_SENT = 28, // parsing body after a 100-Continue was sent + HTTP_MSG_CHUNK_SIZE = 29, // parsing the chunk size (RFC7230 #4.1) + HTTP_MSG_DATA = 30, // skipping data chunk / content-length data + HTTP_MSG_CHUNK_CRLF = 31, // skipping CRLF after data chunk + HTTP_MSG_TRAILERS = 32, // trailers (post-data entity headers) + /* we enter this state when we've received the end of the current message */ + HTTP_MSG_ENDING = 33, // message end received, wait that the filters end too + HTTP_MSG_DONE = 34, // message end received, waiting for resync or close + HTTP_MSG_CLOSING = 35, // shutdown_w done, not all bytes sent yet + HTTP_MSG_CLOSED = 36, // shutdown_w done, all bytes sent + HTTP_MSG_TUNNEL = 37, // tunneled data after DONE +} __attribute__((packed)); + + +#endif /* _TYPES_H1_H */ diff --git a/include/types/hlua.h b/include/types/hlua.h index c7405a356..bff29d061 100644 --- a/include/types/hlua.h +++ b/include/types/hlua.h @@ -62,7 +62,7 @@ struct hlua_consistency { union { struct { int dir; - enum ht_state state; + enum h1_state state; } http; } data; }; diff --git a/include/types/proto_http.h b/include/types/proto_http.h index 1d378acac..3f99df74a 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -124,65 +125,6 @@ * */ -/* Possible states while parsing HTTP messages (request|response) */ -enum ht_state { - HTTP_MSG_RQBEFORE = 0, // request: leading LF, before start line - HTTP_MSG_RQBEFORE_CR = 1, // request: leading CRLF, before start line - /* these ones define a request start line */ - HTTP_MSG_RQMETH = 2, // parsing the Method - HTTP_MSG_RQMETH_SP = 3, // space(s) after the Method - HTTP_MSG_RQURI = 4, // parsing the Request URI - HTTP_MSG_RQURI_SP = 5, // space(s) after the Request URI - HTTP_MSG_RQVER = 6, // parsing the Request Version - HTTP_MSG_RQLINE_END = 7, // end of request line (CR or LF) - - HTTP_MSG_RPBEFORE = 8, // response: leading LF, before start line - HTTP_MSG_RPBEFORE_CR = 9, // response: leading CRLF, before start line - - /* these ones define a response start line */ - HTTP_MSG_RPVER = 10, // parsing the Response Version - HTTP_MSG_RPVER_SP = 11, // space(s) after the Response Version - HTTP_MSG_RPCODE = 12, // response code - HTTP_MSG_RPCODE_SP = 13, // space(s) after the response code - HTTP_MSG_RPREASON = 14, // response reason - HTTP_MSG_RPLINE_END = 15, // end of response line (CR or LF) - - /* common header processing */ - HTTP_MSG_HDR_FIRST = 16, // waiting for first header or last CRLF (no LWS possible) - HTTP_MSG_HDR_NAME = 17, // parsing header name - HTTP_MSG_HDR_COL = 18, // parsing header colon - HTTP_MSG_HDR_L1_SP = 19, // parsing header LWS (SP|HT) before value - HTTP_MSG_HDR_L1_LF = 20, // parsing header LWS (LF) before value - HTTP_MSG_HDR_L1_LWS = 21, // checking whether it's a new header or an LWS - HTTP_MSG_HDR_VAL = 22, // parsing header value - HTTP_MSG_HDR_L2_LF = 23, // parsing header LWS (LF) inside/after value - HTTP_MSG_HDR_L2_LWS = 24, // checking whether it's a new header or an LWS - - HTTP_MSG_LAST_LF = 25, // parsing last LF - - /* error state : must be before HTTP_MSG_BODY so that (>=BODY) always indicates - * that data are being processed. - */ - HTTP_MSG_ERROR = 26, // an error occurred - /* Body processing. - * The state HTTP_MSG_BODY is a delimiter to know if we're waiting for headers - * or body. All the sub-states below also indicate we're processing the body, - * with some additional information. - */ - HTTP_MSG_BODY = 27, // parsing body at end of headers - HTTP_MSG_100_SENT = 28, // parsing body after a 100-Continue was sent - HTTP_MSG_CHUNK_SIZE = 29, // parsing the chunk size (RFC7230 #4.1) - HTTP_MSG_DATA = 30, // skipping data chunk / content-length data - HTTP_MSG_CHUNK_CRLF = 31, // skipping CRLF after data chunk - HTTP_MSG_TRAILERS = 32, // trailers (post-data entity headers) - /* we enter this state when we've received the end of the current message */ - HTTP_MSG_ENDING = 33, // message end received, wait that the filters end too - HTTP_MSG_DONE = 34, // message end received, waiting for resync or close - HTTP_MSG_CLOSING = 35, // shutdown_w done, not all bytes sent yet - HTTP_MSG_CLOSED = 36, // shutdown_w done, all bytes sent - HTTP_MSG_TUNNEL = 37, // tunneled data after DONE -} __attribute__((packed)); - /* * HTTP message status flags (msg->flags) */ @@ -323,8 +265,8 @@ enum { * care for wrapping (no addition overflow nor subtract underflow). */ struct http_msg { - enum ht_state msg_state; /* where we are in the current message parsing */ - enum ht_state err_state; /* the state where the parsing error was detected, only is MSG_ERROR */ + enum h1_state msg_state; /* where we are in the current message parsing */ + enum h1_state err_state; /* the state where the parsing error was detected, only is MSG_ERROR */ unsigned char flags; /* flags describing the message (HTTP version, ...) */ /* 5 bytes unused here */ struct channel *chn; /* pointer to the channel transporting the message */ diff --git a/src/h1.c b/src/h1.c new file mode 100644 index 000000000..044709aa9 --- /dev/null +++ b/src/h1.c @@ -0,0 +1,155 @@ +/* + * HTTP/1 protocol analyzer + * + * Copyright 2000-2017 Willy Tarreau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include + +#include + +/* It is about twice as fast on recent architectures to lookup a byte in a + * table than to perform a boolean AND or OR between two tests. Refer to + * RFC2616/RFC5234/RFC7230 for those chars. A token is any ASCII char that is + * neither a separator nor a CTL char. An http ver_token is any ASCII which can + * be found in an HTTP version, which includes 'H', 'T', 'P', '/', '.' and any + * digit. Note: please do not overwrite values in assignment since gcc-2.95 + * will not handle them correctly. It's worth noting that chars 128..255 are + * nothing, not even control chars. + */ +const unsigned char h1_char_classes[256] = { + [ 0] = H1_FLG_CTL, + [ 1] = H1_FLG_CTL, + [ 2] = H1_FLG_CTL, + [ 3] = H1_FLG_CTL, + [ 4] = H1_FLG_CTL, + [ 5] = H1_FLG_CTL, + [ 6] = H1_FLG_CTL, + [ 7] = H1_FLG_CTL, + [ 8] = H1_FLG_CTL, + [ 9] = H1_FLG_SPHT | H1_FLG_LWS | H1_FLG_SEP | H1_FLG_CTL, + [ 10] = H1_FLG_CRLF | H1_FLG_LWS | H1_FLG_CTL, + [ 11] = H1_FLG_CTL, + [ 12] = H1_FLG_CTL, + [ 13] = H1_FLG_CRLF | H1_FLG_LWS | H1_FLG_CTL, + [ 14] = H1_FLG_CTL, + [ 15] = H1_FLG_CTL, + [ 16] = H1_FLG_CTL, + [ 17] = H1_FLG_CTL, + [ 18] = H1_FLG_CTL, + [ 19] = H1_FLG_CTL, + [ 20] = H1_FLG_CTL, + [ 21] = H1_FLG_CTL, + [ 22] = H1_FLG_CTL, + [ 23] = H1_FLG_CTL, + [ 24] = H1_FLG_CTL, + [ 25] = H1_FLG_CTL, + [ 26] = H1_FLG_CTL, + [ 27] = H1_FLG_CTL, + [ 28] = H1_FLG_CTL, + [ 29] = H1_FLG_CTL, + [ 30] = H1_FLG_CTL, + [ 31] = H1_FLG_CTL, + [' '] = H1_FLG_SPHT | H1_FLG_LWS | H1_FLG_SEP, + ['!'] = H1_FLG_TOK, + ['"'] = H1_FLG_SEP, + ['#'] = H1_FLG_TOK, + ['$'] = H1_FLG_TOK, + ['%'] = H1_FLG_TOK, + ['&'] = H1_FLG_TOK, + [ 39] = H1_FLG_TOK, + ['('] = H1_FLG_SEP, + [')'] = H1_FLG_SEP, + ['*'] = H1_FLG_TOK, + ['+'] = H1_FLG_TOK, + [','] = H1_FLG_SEP, + ['-'] = H1_FLG_TOK, + ['.'] = H1_FLG_TOK | H1_FLG_VER, + ['/'] = H1_FLG_SEP | H1_FLG_VER, + ['0'] = H1_FLG_TOK | H1_FLG_VER, + ['1'] = H1_FLG_TOK | H1_FLG_VER, + ['2'] = H1_FLG_TOK | H1_FLG_VER, + ['3'] = H1_FLG_TOK | H1_FLG_VER, + ['4'] = H1_FLG_TOK | H1_FLG_VER, + ['5'] = H1_FLG_TOK | H1_FLG_VER, + ['6'] = H1_FLG_TOK | H1_FLG_VER, + ['7'] = H1_FLG_TOK | H1_FLG_VER, + ['8'] = H1_FLG_TOK | H1_FLG_VER, + ['9'] = H1_FLG_TOK | H1_FLG_VER, + [':'] = H1_FLG_SEP, + [';'] = H1_FLG_SEP, + ['<'] = H1_FLG_SEP, + ['='] = H1_FLG_SEP, + ['>'] = H1_FLG_SEP, + ['?'] = H1_FLG_SEP, + ['@'] = H1_FLG_SEP, + ['A'] = H1_FLG_TOK, + ['B'] = H1_FLG_TOK, + ['C'] = H1_FLG_TOK, + ['D'] = H1_FLG_TOK, + ['E'] = H1_FLG_TOK, + ['F'] = H1_FLG_TOK, + ['G'] = H1_FLG_TOK, + ['H'] = H1_FLG_TOK | H1_FLG_VER, + ['I'] = H1_FLG_TOK, + ['J'] = H1_FLG_TOK, + ['K'] = H1_FLG_TOK, + ['L'] = H1_FLG_TOK, + ['M'] = H1_FLG_TOK, + ['N'] = H1_FLG_TOK, + ['O'] = H1_FLG_TOK, + ['P'] = H1_FLG_TOK | H1_FLG_VER, + ['Q'] = H1_FLG_TOK, + ['R'] = H1_FLG_TOK | H1_FLG_VER, + ['S'] = H1_FLG_TOK | H1_FLG_VER, + ['T'] = H1_FLG_TOK | H1_FLG_VER, + ['U'] = H1_FLG_TOK, + ['V'] = H1_FLG_TOK, + ['W'] = H1_FLG_TOK, + ['X'] = H1_FLG_TOK, + ['Y'] = H1_FLG_TOK, + ['Z'] = H1_FLG_TOK, + ['['] = H1_FLG_SEP, + [ 92] = H1_FLG_SEP, + [']'] = H1_FLG_SEP, + ['^'] = H1_FLG_TOK, + ['_'] = H1_FLG_TOK, + ['`'] = H1_FLG_TOK, + ['a'] = H1_FLG_TOK, + ['b'] = H1_FLG_TOK, + ['c'] = H1_FLG_TOK, + ['d'] = H1_FLG_TOK, + ['e'] = H1_FLG_TOK, + ['f'] = H1_FLG_TOK, + ['g'] = H1_FLG_TOK, + ['h'] = H1_FLG_TOK, + ['i'] = H1_FLG_TOK, + ['j'] = H1_FLG_TOK, + ['k'] = H1_FLG_TOK, + ['l'] = H1_FLG_TOK, + ['m'] = H1_FLG_TOK, + ['n'] = H1_FLG_TOK, + ['o'] = H1_FLG_TOK, + ['p'] = H1_FLG_TOK, + ['q'] = H1_FLG_TOK, + ['r'] = H1_FLG_TOK, + ['s'] = H1_FLG_TOK, + ['t'] = H1_FLG_TOK, + ['u'] = H1_FLG_TOK, + ['v'] = H1_FLG_TOK, + ['w'] = H1_FLG_TOK, + ['x'] = H1_FLG_TOK, + ['y'] = H1_FLG_TOK, + ['z'] = H1_FLG_TOK, + ['{'] = H1_FLG_SEP, + ['|'] = H1_FLG_TOK, + ['}'] = H1_FLG_SEP, + ['~'] = H1_FLG_TOK, + [127] = H1_FLG_CTL, +}; diff --git a/src/proto_http.c b/src/proto_http.c index c83e9428b..a599f659d 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -511,146 +512,6 @@ const struct http_method_name http_known_methods[HTTP_METH_OTHER] = { [HTTP_METH_CONNECT] = { "CONNECT", 7 }, }; -/* It is about twice as fast on recent architectures to lookup a byte in a - * table than to perform a boolean AND or OR between two tests. Refer to - * RFC2616/RFC5234/RFC7230 for those chars. A token is any ASCII char that is - * neither a separator nor a CTL char. An http ver_token is any ASCII which can - * be found in an HTTP version, which includes 'H', 'T', 'P', '/', '.' and any - * digit. Note: please do not overwrite values in assignment since gcc-2.95 - * will not handle them correctly. It's worth noting that chars 128..255 are - * nothing, not even control chars. - */ -const unsigned char http_char_classes[256] = { - [ 0] = HTTP_FLG_CTL, - [ 1] = HTTP_FLG_CTL, - [ 2] = HTTP_FLG_CTL, - [ 3] = HTTP_FLG_CTL, - [ 4] = HTTP_FLG_CTL, - [ 5] = HTTP_FLG_CTL, - [ 6] = HTTP_FLG_CTL, - [ 7] = HTTP_FLG_CTL, - [ 8] = HTTP_FLG_CTL, - [ 9] = HTTP_FLG_SPHT | HTTP_FLG_LWS | HTTP_FLG_SEP | HTTP_FLG_CTL, - [ 10] = HTTP_FLG_CRLF | HTTP_FLG_LWS | HTTP_FLG_CTL, - [ 11] = HTTP_FLG_CTL, - [ 12] = HTTP_FLG_CTL, - [ 13] = HTTP_FLG_CRLF | HTTP_FLG_LWS | HTTP_FLG_CTL, - [ 14] = HTTP_FLG_CTL, - [ 15] = HTTP_FLG_CTL, - [ 16] = HTTP_FLG_CTL, - [ 17] = HTTP_FLG_CTL, - [ 18] = HTTP_FLG_CTL, - [ 19] = HTTP_FLG_CTL, - [ 20] = HTTP_FLG_CTL, - [ 21] = HTTP_FLG_CTL, - [ 22] = HTTP_FLG_CTL, - [ 23] = HTTP_FLG_CTL, - [ 24] = HTTP_FLG_CTL, - [ 25] = HTTP_FLG_CTL, - [ 26] = HTTP_FLG_CTL, - [ 27] = HTTP_FLG_CTL, - [ 28] = HTTP_FLG_CTL, - [ 29] = HTTP_FLG_CTL, - [ 30] = HTTP_FLG_CTL, - [ 31] = HTTP_FLG_CTL, - [' '] = HTTP_FLG_SPHT | HTTP_FLG_LWS | HTTP_FLG_SEP, - ['!'] = HTTP_FLG_TOK, - ['"'] = HTTP_FLG_SEP, - ['#'] = HTTP_FLG_TOK, - ['$'] = HTTP_FLG_TOK, - ['%'] = HTTP_FLG_TOK, - ['&'] = HTTP_FLG_TOK, - [ 39] = HTTP_FLG_TOK, - ['('] = HTTP_FLG_SEP, - [')'] = HTTP_FLG_SEP, - ['*'] = HTTP_FLG_TOK, - ['+'] = HTTP_FLG_TOK, - [','] = HTTP_FLG_SEP, - ['-'] = HTTP_FLG_TOK, - ['.'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['/'] = HTTP_FLG_SEP | HTTP_FLG_VER, - ['0'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['1'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['2'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['3'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['4'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['5'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['6'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['7'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['8'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['9'] = HTTP_FLG_TOK | HTTP_FLG_VER, - [':'] = HTTP_FLG_SEP, - [';'] = HTTP_FLG_SEP, - ['<'] = HTTP_FLG_SEP, - ['='] = HTTP_FLG_SEP, - ['>'] = HTTP_FLG_SEP, - ['?'] = HTTP_FLG_SEP, - ['@'] = HTTP_FLG_SEP, - ['A'] = HTTP_FLG_TOK, - ['B'] = HTTP_FLG_TOK, - ['C'] = HTTP_FLG_TOK, - ['D'] = HTTP_FLG_TOK, - ['E'] = HTTP_FLG_TOK, - ['F'] = HTTP_FLG_TOK, - ['G'] = HTTP_FLG_TOK, - ['H'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['I'] = HTTP_FLG_TOK, - ['J'] = HTTP_FLG_TOK, - ['K'] = HTTP_FLG_TOK, - ['L'] = HTTP_FLG_TOK, - ['M'] = HTTP_FLG_TOK, - ['N'] = HTTP_FLG_TOK, - ['O'] = HTTP_FLG_TOK, - ['P'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['Q'] = HTTP_FLG_TOK, - ['R'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['S'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['T'] = HTTP_FLG_TOK | HTTP_FLG_VER, - ['U'] = HTTP_FLG_TOK, - ['V'] = HTTP_FLG_TOK, - ['W'] = HTTP_FLG_TOK, - ['X'] = HTTP_FLG_TOK, - ['Y'] = HTTP_FLG_TOK, - ['Z'] = HTTP_FLG_TOK, - ['['] = HTTP_FLG_SEP, - [ 92] = HTTP_FLG_SEP, - [']'] = HTTP_FLG_SEP, - ['^'] = HTTP_FLG_TOK, - ['_'] = HTTP_FLG_TOK, - ['`'] = HTTP_FLG_TOK, - ['a'] = HTTP_FLG_TOK, - ['b'] = HTTP_FLG_TOK, - ['c'] = HTTP_FLG_TOK, - ['d'] = HTTP_FLG_TOK, - ['e'] = HTTP_FLG_TOK, - ['f'] = HTTP_FLG_TOK, - ['g'] = HTTP_FLG_TOK, - ['h'] = HTTP_FLG_TOK, - ['i'] = HTTP_FLG_TOK, - ['j'] = HTTP_FLG_TOK, - ['k'] = HTTP_FLG_TOK, - ['l'] = HTTP_FLG_TOK, - ['m'] = HTTP_FLG_TOK, - ['n'] = HTTP_FLG_TOK, - ['o'] = HTTP_FLG_TOK, - ['p'] = HTTP_FLG_TOK, - ['q'] = HTTP_FLG_TOK, - ['r'] = HTTP_FLG_TOK, - ['s'] = HTTP_FLG_TOK, - ['t'] = HTTP_FLG_TOK, - ['u'] = HTTP_FLG_TOK, - ['v'] = HTTP_FLG_TOK, - ['w'] = HTTP_FLG_TOK, - ['x'] = HTTP_FLG_TOK, - ['y'] = HTTP_FLG_TOK, - ['z'] = HTTP_FLG_TOK, - ['{'] = HTTP_FLG_SEP, - ['|'] = HTTP_FLG_TOK, - ['}'] = HTTP_FLG_SEP, - ['~'] = HTTP_FLG_TOK, - [127] = HTTP_FLG_CTL, -}; - /* * Adds a header and its CRLF at the tail of the message's buffer, just before * the last CRLF. Text length is measured first, so it cannot be NULL. @@ -1392,8 +1253,8 @@ void capture_headers(char *som, struct hdr_idx *idx, * labels and variable names. Note that msg->sol is left unchanged. */ const char *http_parse_stsline(struct http_msg *msg, - enum ht_state state, const char *ptr, const char *end, - unsigned int *ret_ptr, enum ht_state *ret_state) + enum h1_state state, const char *ptr, const char *end, + unsigned int *ret_ptr, enum h1_state *ret_state) { const char *msg_start = msg->chn->buf->p; @@ -1505,8 +1366,8 @@ const char *http_parse_stsline(struct http_msg *msg, * labels and variable names. Note that msg->sol is left unchanged. */ const char *http_parse_reqline(struct http_msg *msg, - enum ht_state state, const char *ptr, const char *end, - unsigned int *ret_ptr, enum ht_state *ret_state) + enum h1_state state, const char *ptr, const char *end, + unsigned int *ret_ptr, enum h1_state *ret_state) { const char *msg_start = msg->chn->buf->p; @@ -1750,7 +1611,7 @@ get_http_auth(struct stream *s) */ void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx) { - enum ht_state state; /* updated only when leaving the FSM */ + enum h1_state state; /* updated only when leaving the FSM */ register char *ptr, *end; /* request pointers, to avoid dereferences */ struct buffer *buf; @@ -5570,8 +5431,8 @@ void http_resync_states(struct stream *s) DPRINTF(stderr,"[%u] %s: stream=%p old=%s,%s cur=%s,%s " "req->analysers=0x%08x res->analysers=0x%08x\n", now_ms, __FUNCTION__, s, - http_msg_state_str(old_req_state), http_msg_state_str(old_res_state), - http_msg_state_str(txn->req.msg_state), http_msg_state_str(txn->rsp.msg_state), + h1_msg_state_str(old_req_state), h1_msg_state_str(old_res_state), + h1_msg_state_str(txn->req.msg_state), h1_msg_state_str(txn->rsp.msg_state), s->req.analysers, s->res.analysers); @@ -8622,7 +8483,7 @@ int stats_check_uri(struct stream_interface *si, struct http_txn *txn, struct pr */ void http_capture_bad_message(struct error_snapshot *es, struct stream *s, struct http_msg *msg, - enum ht_state state, struct proxy *other_end) + enum h1_state state, struct proxy *other_end) { struct session *sess = strm_sess(s); struct channel *chn = msg->chn; @@ -13242,7 +13103,7 @@ static int cli_io_handler_show_errors(struct appctx *appctx) es->srv ? es->srv->id : "", es->srv ? es->srv->puid : -1, es->ev_id, pn, port, es->sid, es->s_flags, - http_msg_state_str(es->state), es->state, es->m_flags, es->t_flags, + h1_msg_state_str(es->state), es->state, es->m_flags, es->t_flags, es->m_clen, es->m_blen, es->b_flags, es->b_out, es->b_tot, es->len, es->b_wrap, es->pos); diff --git a/src/stream.c b/src/stream.c index fe01639d2..aae0d331f 100644 --- a/src/stream.c +++ b/src/stream.c @@ -2803,7 +2803,7 @@ static int stats_dump_full_strm_to_buffer(struct stream_interface *si, struct st chunk_appendf(&trash, " txn=%p flags=0x%x meth=%d status=%d req.st=%s rsp.st=%s waiting=%d\n", strm->txn, strm->txn->flags, strm->txn->meth, strm->txn->status, - http_msg_state_str(strm->txn->req.msg_state), http_msg_state_str(strm->txn->rsp.msg_state), !LIST_ISEMPTY(&strm->buffer_wait.list)); + h1_msg_state_str(strm->txn->req.msg_state), h1_msg_state_str(strm->txn->rsp.msg_state), !LIST_ISEMPTY(&strm->buffer_wait.list)); chunk_appendf(&trash, " si[0]=%p (state=%s flags=0x%02x endp0=%s:%p exp=%s, et=0x%03x)\n",