diff options
Diffstat (limited to 'src/h1.c')
-rw-r--r-- | src/h1.c | 164 |
1 files changed, 75 insertions, 89 deletions
@@ -183,11 +183,11 @@ int h1_parse_xfer_enc_header(struct h1m *h1m, struct ist value) * is hast header, its value is normalized. 0 is returned on success, -1 if the * authority is invalid and -2 if the host is invalid. */ -static int h1_validate_connect_authority(struct ist authority, struct ist *host_hdr) +static int h1_validate_connect_authority(struct ist scheme, struct ist authority, struct ist *host_hdr) { struct ist uri_host, uri_port, host, host_port; - if (!isttest(authority)) + if (isttest(scheme) || !isttest(authority)) goto invalid_authority; uri_host = authority; uri_port = http_get_host_port(authority); @@ -575,12 +575,7 @@ int h1_headers_to_hdr_list(char *start, const char *stop, #ifdef HA_UNALIGNED_LE /* speedup: skip bytes not between 0x24 and 0x7e inclusive */ while (ptr <= end - sizeof(int)) { - int x = *(int *)ptr - 0x24242424; - if (x & 0x80808080) - break; - - x -= 0x5b5b5b5b; - if (!(x & 0x80808080)) + if (is_char4_outside(*(uint *)ptr, 0x24, 0x7e)) break; ptr += sizeof(int); @@ -930,14 +925,14 @@ int h1_headers_to_hdr_list(char *start, const char *stop, */ #ifdef HA_UNALIGNED_LE64 while (ptr <= end - sizeof(long)) { - if ((*(long *)ptr - 0x0e0e0e0e0e0e0e0eULL) & 0x8080808080808080ULL) + if (is_char8_below_opt(*(ulong *)ptr, 0x0e)) goto http_msg_hdr_val2; ptr += sizeof(long); } #endif #ifdef HA_UNALIGNED_LE while (ptr <= end - sizeof(int)) { - if ((*(int*)ptr - 0x0e0e0e0e) & 0x80808080) + if (is_char4_below_opt(*(uint *)ptr, 0x0e)) goto http_msg_hdr_val2; ptr += sizeof(int); } @@ -1105,46 +1100,88 @@ int h1_headers_to_hdr_list(char *start, const char *stop, if (!(h1m->flags & (H1_MF_HDRS_ONLY|H1_MF_RESP))) { struct http_uri_parser parser = http_uri_parser_init(sl.rq.u); - struct ist scheme, authority; + struct ist scheme, authority = IST_NULL; int ret; - scheme = http_parse_scheme(&parser); - authority = http_parse_authority(&parser, 1); - if (sl.rq.meth == HTTP_METH_CONNECT) { - struct ist *host = ((host_idx != -1) ? &hdr[host_idx].v : NULL); - - ret = h1_validate_connect_authority(authority, host); - if (ret < 0) { - if (h1m->err_pos < -1) { - state = H1_MSG_LAST_LF; - /* WT: gcc seems to see a path where sl.rq.u.ptr was used - * uninitialized, but it doesn't know that the function is - * called with initial states making this impossible. - */ - ALREADY_CHECKED(sl.rq.u.ptr); - ptr = ((ret == -1) ? sl.rq.u.ptr : host->ptr); /* Set ptr on the error */ - goto http_msg_invalid; - } - if (h1m->err_pos == -1) /* capture the error pointer */ - h1m->err_pos = ((ret == -1) ? sl.rq.u.ptr : host->ptr) - start + skip; /* >= 0 now */ + /* WT: gcc seems to see a path where sl.rq.u.ptr was used + * uninitialized, but it doesn't know that the function is + * called with initial states making this impossible. + */ + ALREADY_CHECKED(sl.rq.u.ptr); + switch (parser.format) { + case URI_PARSER_FORMAT_ASTERISK: + /* We must take care "PRI * HTTP/2.0" is supported here. check for OTHER methods here is enough */ + if ((sl.rq.meth != HTTP_METH_OTHER && sl.rq.meth != HTTP_METH_OPTIONS) || istlen(sl.rq.u) != 1) { + ptr = sl.rq.u.ptr; /* Set ptr on the error */ + goto http_msg_invalid; } - } - else if (host_idx != -1 && istlen(authority)) { - struct ist host = hdr[host_idx].v; + break; + + case URI_PARSER_FORMAT_ABSPATH: + if (sl.rq.meth == HTTP_METH_CONNECT) { + ptr = sl.rq.u.ptr; /* Set ptr on the error */ + goto http_msg_invalid; + } + break; - /* For non-CONNECT method, the authority must match the host header value */ - if (!isteqi(authority, host)) { - ret = h1_validate_mismatch_authority(scheme, authority, host); + case URI_PARSER_FORMAT_ABSURI_OR_AUTHORITY: + scheme = http_parse_scheme(&parser); + if (!isttest(scheme)) { /* scheme not found: MUST be an authority */ + struct ist *host = NULL; + + if (sl.rq.meth != HTTP_METH_CONNECT) { + ptr = sl.rq.u.ptr; /* Set ptr on the error */ + goto http_msg_invalid; + } + if (host_idx != -1) + host = &hdr[host_idx].v; + authority = http_parse_authority(&parser, 1); + ret = h1_validate_connect_authority(scheme, authority, host); if (ret < 0) { if (h1m->err_pos < -1) { state = H1_MSG_LAST_LF; - ptr = host.ptr; /* Set ptr on the error */ + /* WT: gcc seems to see a path where sl.rq.u.ptr was used + * uninitialized, but it doesn't know that the function is + * called with initial states making this impossible. + */ + ALREADY_CHECKED(sl.rq.u.ptr); + ptr = ((ret == -1) ? sl.rq.u.ptr : host->ptr); /* Set ptr on the error */ goto http_msg_invalid; } if (h1m->err_pos == -1) /* capture the error pointer */ - h1m->err_pos = v.ptr - start + skip; /* >= 0 now */ + h1m->err_pos = ((ret == -1) ? sl.rq.u.ptr : host->ptr) - start + skip; /* >= 0 now */ + } + } + else { /* Scheme found: MUST be an absolute-URI */ + struct ist host = IST_NULL; + + if (sl.rq.meth == HTTP_METH_CONNECT) { + ptr = sl.rq.u.ptr; /* Set ptr on the error */ + goto http_msg_invalid; + } + + if (host_idx != -1) + host = hdr[host_idx].v; + authority = http_parse_authority(&parser, 1); + /* For non-CONNECT method, the authority must match the host header value */ + if (isttest(host) && !isteqi(authority, host)) { + ret = h1_validate_mismatch_authority(scheme, authority, host); + if (ret < 0) { + if (h1m->err_pos < -1) { + state = H1_MSG_LAST_LF; + ptr = host.ptr; /* Set ptr on the error */ + goto http_msg_invalid; + } + if (h1m->err_pos == -1) /* capture the error pointer */ + h1m->err_pos = v.ptr - start + skip; /* >= 0 now */ + } } } + break; + + default: + ptr = sl.rq.u.ptr; /* Set ptr on the error */ + goto http_msg_invalid; } } @@ -1227,57 +1264,6 @@ int h1_headers_to_hdr_list(char *start, const char *stop, goto try_again; } -/* This function performs a very minimal parsing of the trailers block present - * at offset <ofs> in <buf> for up to <max> bytes, and returns the number of - * bytes to delete to skip the trailers. It may return 0 if it's missing some - * input data, or < 0 in case of parse error (in which case the caller may have - * to decide how to proceed, possibly eating everything). - */ -int h1_measure_trailers(const struct buffer *buf, unsigned int ofs, unsigned int max) -{ - const char *stop = b_peek(buf, ofs + max); - int count = ofs; - - while (1) { - const char *p1 = NULL, *p2 = NULL; - const char *start = b_peek(buf, count); - const char *ptr = start; - - /* scan current line and stop at LF or CRLF */ - while (1) { - if (ptr == stop) - return 0; - - if (*ptr == '\n') { - if (!p1) - p1 = ptr; - p2 = ptr; - break; - } - - if (*ptr == '\r') { - if (p1) - return -1; - p1 = ptr; - } - - ptr = b_next(buf, ptr); - } - - /* after LF; point to beginning of next line */ - p2 = b_next(buf, p2); - count += b_dist(buf, start, p2); - - /* LF/CRLF at beginning of line => end of trailers at p2. - * Everything was scheduled for forwarding, there's nothing left - * from this message. */ - if (p1 == start) - break; - /* OK, next line then */ - } - return count - ofs; -} - /* Generate a random key for a WebSocket Handshake in respect with rfc6455 * The key is 128-bits long encoded as a base64 string in <key_out> parameter * (25 bytes long). |