--- /dev/null
+varnishtest "HTTP request tests: H1 request target parsing"
+
+feature ignore_unknown_macro
+
+#REQUIRE_VERSION=3.0
+
+haproxy h1 -conf {
+ global
+ # WT: limit false-positives causing "HTTP header incomplete" due to
+ # idle server connections being randomly used and randomly expiring
+ # under us.
+ tune.idle-pool.shared off
+
+ defaults
+ mode http
+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+
+ listen li1
+ bind "fd@${li1}"
+ http-request return status 200
+} -start
+
+client c1 -connect ${h1_li1_sock} {
+ txreq -req "OPTIONS" -url "*"
+ rxresp
+ expect resp.status == 200
+
+} -run
+
+client c2 -connect ${h1_li1_sock} {
+ txreq -req "OPTIONS" -url "/"
+ rxresp
+ expect resp.status == 200
+
+} -run
+
+client c3 -connect ${h1_li1_sock} {
+ txreq -req "OPTIONS" -url "http://haproxy.org" \
+ -hdr "Host: haproxy.org"
+ rxresp
+ expect resp.status == 200
+
+} -run
+
+client c4 -connect ${h1_li1_sock} {
+ txreq -req "OPTIONS" -url "*/test"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c5 -connect ${h1_li1_sock} {
+ txreq -req "GET" -url "*"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c6 -connect ${h1_li1_sock} {
+ txreq -req "CONNECT" -url "haproxy.org:80" \
+ -hdr "Host: haproxy.org"
+ rxresp
+ expect resp.status == 200
+
+} -run
+
+client c7 -connect ${h1_li1_sock} {
+ txreq -req "CONNECT" -url "haproxy.org" \
+ -hdr "Host: haproxy.org"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c8 -connect ${h1_li1_sock} {
+ txreq -req "CONNECT" -url "/"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c9 -connect ${h1_li1_sock} {
+ txreq -req "CONNECT" -url "http://haproxy.org:80" \
+ -hdr "Host: haproxy.org"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c11 -connect ${h1_li1_sock} {
+ txreq -req "GET" -url "/" \
+ -hdr "Host: haproxy.org"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c12 -connect ${h1_li1_sock} {
+ txreq -req "GET" -url "haproxy.org:80" \
+ -hdr "Host: haproxy.org"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c13 -connect ${h1_li1_sock} {
+ txreq -req "GET" -url "admin"
+ rxresp
+ expect resp.status == 400
+} -run
+
+client c14 -connect ${h1_li1_sock} {
+ txreq -req "GET" -url "admin/a/b"
+ rxresp
+ expect resp.status == 400
+} -run
struct ist scheme, authority = IST_NULL;
int ret;
- scheme = http_parse_scheme(&parser);
- if (istlen(scheme) || sl.rq.meth == HTTP_METH_CONNECT) {
- /* Expect an authority if for CONNECT method or if there is a scheme */
- authority = http_parse_authority(&parser, 1);
- }
+ /* 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;
+ }
+ break;
- if (sl.rq.meth == HTTP_METH_CONNECT) {
- struct ist *host = ((host_idx != -1) ? &hdr[host_idx].v : NULL);
-
- ret = h1_validate_connect_authority(scheme, 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 */
+ 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;
}
- }
- else if (host_idx != -1 && istlen(authority)) {
- struct ist host = hdr[host_idx].v;
+ break;
+
+ 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;
- /* For non-CONNECT method, the authority must match the host header value */
- if (!isteqi(authority, host)) {
- ret = h1_validate_mismatch_authority(scheme, authority, host);
+ 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;
}
}