From e2b4c309f60a606179506c1bb227a34719f1cba7 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Fri, 14 Jun 2019 23:06:02 -0400 Subject: [PATCH] [core] http_header_str_contains_token() --- src/http_header.c | 18 +++++++++++ src/http_header.h | 3 ++ src/mod_wstunnel.c | 17 ++-------- src/request.c | 77 ++++++---------------------------------------- 4 files changed, 32 insertions(+), 83 deletions(-) diff --git a/src/http_header.c b/src/http_header.c index 2c55de3b..02616fee 100644 --- a/src/http_header.c +++ b/src/http_header.c @@ -57,6 +57,24 @@ enum http_header_e http_header_hkey_get(const char *s, size_t slen) { } +int http_header_str_contains_token (const char * const s, const size_t slen, const char * const m, const size_t mlen) +{ + /*if (slen < mlen) return 0;*//*(possible optimizations for caller)*/ + /*if (slen == mlen && buffer_eq_icase_ssn(s, m, mlen)) return 1;*/ + size_t i = 0; + do { + while (i < slen && (s[i]==' ' || s[i]=='\t' || s[i]==',')) ++i; + if (i == slen) return 0; + if (buffer_eq_icase_ssn(s+i, m, mlen)) { + i += mlen; + if (i == slen || s[i]==' ' || s[i]=='\t' || s[i]==',' || s[i]==';') + return 1; + } + while (i < slen && s[i]!=',') ++i; + } while (i < slen); + return 0; +} + buffer * http_header_response_get(connection *con, enum http_header_e id, const char *k, size_t klen) { data_string * const ds = (id <= HTTP_HEADER_OTHER || (con->response.htags & id)) diff --git a/src/http_header.h b/src/http_header.h index 0c82f44e..bbf9ad7d 100644 --- a/src/http_header.h +++ b/src/http_header.h @@ -42,6 +42,9 @@ enum http_header_e { __attribute_pure__ enum http_header_e http_header_hkey_get(const char *s, size_t slen); +__attribute_pure__ +int http_header_str_contains_token (const char *s, size_t slen, const char *m, size_t mlen); + buffer * http_header_response_get(connection *con, enum http_header_e id, const char *k, size_t klen); void http_header_response_unset(connection *con, enum http_header_e id, const char *k, size_t klen); void http_header_response_set(connection *con, enum http_header_e id, const char *k, size_t klen, const char *v, size_t vlen); diff --git a/src/mod_wstunnel.c b/src/mod_wstunnel.c index ed5174a5..c0864719 100644 --- a/src/mod_wstunnel.c +++ b/src/mod_wstunnel.c @@ -407,19 +407,6 @@ static void mod_wstunnel_patch_connection(server *srv, connection *con, plugin_d #undef PATCH_GW #undef PATCH -static int header_contains_token (buffer *b, const char *m, size_t mlen) -{ - for (char *s = b->ptr; s; s = strchr(s, ',')) { - while (*s == ' ' || *s == '\t' || *s == ',') ++s; - if (buffer_eq_icase_ssn(s, m, mlen)) { - s += mlen; - if (*s == '\0' || *s == ' ' || *s == '\t' || *s == ',' || *s == ';') - return 1; - } - } - return 0; -} - static int wstunnel_is_allowed_origin(connection *con, handler_ctx *hctx) { /* If allowed origins is set (and not empty list), fail closed if no match. * Note that origin provided in request header has not been normalized, so @@ -594,11 +581,11 @@ static handler_t mod_wstunnel_check_extension(server *srv, connection *con, void */ vb = http_header_request_get(con, HTTP_HEADER_UPGRADE, CONST_STR_LEN("Upgrade")); if (NULL == vb - || !header_contains_token(vb, CONST_STR_LEN("websocket"))) + || !http_header_str_contains_token(CONST_BUF_LEN(vb), CONST_STR_LEN("websocket"))) return HANDLER_GO_ON; vb = http_header_request_get(con, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection")); if (NULL == vb - || !header_contains_token(vb, CONST_STR_LEN("upgrade"))) + || !http_header_str_contains_token(CONST_BUF_LEN(vb), CONST_STR_LEN("upgrade"))) return HANDLER_GO_ON; mod_wstunnel_patch_connection(srv, con, p); diff --git a/src/request.c b/src/request.c index 39cbb888..22a672ea 100644 --- a/src/request.c +++ b/src/request.c @@ -345,57 +345,6 @@ int http_request_host_policy (connection *con, buffer *b, const buffer *scheme) && 0 != http_request_host_normalize(b, scheme_port(scheme)))); } -static int http_request_split_value(array *vals, const char *current, size_t len) { - int state = 0; - const char *token_start = NULL, *token_end = NULL; - /* - * parse - * - * val1, val2, val3, val4 - * - * into a array (more or less a explode() incl. stripping of whitespaces - */ - - for (size_t i = 0; i <= len; ++i, ++current) { - switch (state) { - case 0: /* find start of a token */ - switch (*current) { - case ' ': - case '\t': /* skip white space */ - case ',': /* skip empty token */ - break; - case '\0': /* end of string */ - return 0; - default: - /* found real data, switch to state 1 to find the end of the token */ - token_start = token_end = current; - state = 1; - break; - } - break; - case 1: /* find end of token and last non white space character */ - switch (*current) { - case ' ': - case '\t': - /* space - don't update token_end */ - break; - case ',': - case '\0': /* end of string also marks the end of a token */ - array_insert_value(vals, token_start, token_end-token_start+1); - state = 0; - break; - default: - /* no white space, update token_end to include current character */ - token_end = current; - break; - } - break; - } - } - - return 0; -} - static int request_uri_is_valid_char(unsigned char c) { return (c > 32 && c != 127 && c != 255); } @@ -479,23 +428,15 @@ static int parse_single_header(server *srv, connection *con, parse_header_state } break; case HTTP_HEADER_CONNECTION: - { - array * const vals = srv->split_vals; - array_reset_data_strings(vals); - http_request_split_value(vals, v, vlen); /* split on , */ - for (size_t vi = 0; vi < vals->used; ++vi) { - data_string *dsv = (data_string *)vals->data[vi]; - if (buffer_eq_icase_slen(dsv->value, - CONST_STR_LEN("keep-alive"))) { - state->keep_alive_set = HTTP_CONNECTION_KEEPALIVE; - break; - } - else if (buffer_eq_icase_slen(dsv->value, - CONST_STR_LEN("close"))) { - state->keep_alive_set = HTTP_CONNECTION_CLOSE; - break; - } - } + /* "Connection: close" is common case if header is present */ + if ((vlen == 5 && buffer_eq_icase_ssn(v, CONST_STR_LEN("close"))) + || http_header_str_contains_token(v,vlen,CONST_STR_LEN("close"))) { + state->keep_alive_set = HTTP_CONNECTION_CLOSE; + break; + } + if (http_header_str_contains_token(v,vlen,CONST_STR_LEN("keep-alive"))){ + state->keep_alive_set = HTTP_CONNECTION_KEEPALIVE; + break; } break; case HTTP_HEADER_CONTENT_TYPE: