summaryrefslogtreecommitdiffstats
path: root/src/h1.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-03 05:11:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-03 05:11:10 +0000
commitcff6d757e3ba609c08ef2aaa00f07e53551e5bf6 (patch)
tree08c4fc3255483ad397d712edb4214ded49149fd9 /src/h1.c
parentAdding upstream version 2.9.7. (diff)
downloadhaproxy-cff6d757e3ba609c08ef2aaa00f07e53551e5bf6.tar.xz
haproxy-cff6d757e3ba609c08ef2aaa00f07e53551e5bf6.zip
Adding upstream version 3.0.0.upstream/3.0.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/h1.c')
-rw-r--r--src/h1.c164
1 files changed, 75 insertions, 89 deletions
diff --git a/src/h1.c b/src/h1.c
index e251e74..bbaa2f6 100644
--- a/src/h1.c
+++ b/src/h1.c
@@ -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).