haproxy/reg-tests/http-rules/h1or2_to_h1c.vtc
Willy Tarreau 22731762d9 BUG/MINOR: http: skip leading zeroes in content-length values
Ben Kallus also noticed that we preserve leading zeroes on content-length
values. While this is totally valid, it would be safer to at least trim
them before passing the value, because a bogus server written to parse
using "strtol(value, NULL, 0)" could inadvertently take a leading zero
as a prefix for an octal value. While there is not much that can be done
to protect such servers in general (e.g. lack of check for overflows etc),
at least it's quite cheap to make sure the transmitted value is normalized
and not taken for an octal one.

This is not really a bug, rather a missed opportunity to sanitize the
input, but is marked as a bug so that we don't forget to backport it to
stable branches.

A combined regtest was added to h1or2_to_h1c which already validates
end-to-end syntax consistency on aggregate headers.
2023-08-09 11:28:48 +02:00

234 lines
9.6 KiB
Plaintext

varnishtest "Composite HTTP manipulation test (H1 and H2 clear to H1 clear)"
# This config tests several http-request features and their interactions.
# It extracts some samples, places them into variables, modifies some header
# fields, appends multiple identical header fields, overwrites the start line
# using several methods, then dumps the initial list of variables and the final
# one, then applies CRC32 to these values as signatures that are easy to test.
# Then it does it again in the backend after saving the current headers into
# the same names prefixed by "fe-". Then it does the same on the response path.
# If some modifications are performed, the crc values need to be adjusted based
# on the failed logs.
#
# Run it with HAPROXY_PROGRAM=$PWD/haproxy varnishtest -l -k -t 1 "$1"
feature ignore_unknown_macro
server s1 {
rxreq
txresp \
-status 234 \
-hdr "hdr1: val1" \
-hdr "hdr2: val2a" \
-hdr "hdr2: val2b" \
-hdr "hdr3: val3a, val3b" \
-hdr "hdr4:" \
-body "This is a body"
expect req.method == "GET"
expect req.http.fe-sl1-crc == 1874847043
expect req.http.fe-sl2-crc == 1142278307
expect req.http.fe-hdr-crc == 1719311923
expect req.http.be-sl1-crc == 3455320059
expect req.http.be-sl2-crc == 2509326257
expect req.http.be-hdr-crc == 3634102538
} -repeat 2 -start
haproxy h1 -conf {
defaults
mode http
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
frontend fe
bind "fd@${feh1}"
bind "fd@${feh2}" proto h2
#### requests
http-request set-var(req.method) method
http-request set-var(req.uri) url
http-request set-var(req.path) path
http-request set-var(req.query) query
http-request set-var(req.param) url_param(qs_arg)
http-request set-var(req.cl) req.fhdr(content-length)
http-request set-header sl1 "sl1: "
http-request set-method "%[str(GET)]"
http-request set-uri %[str(),concat(/bu/,req.uri,/eu)]
http-request set-path "/bp/%[var(req.path)]/ep"
http-request set-query "bq&%[var(req.query)]&eq"
http-request set-header sl2 "sl2: "
http-request set-header sl1 "%[req.fhdr(sl1)] method=<%[var(req.method)]>; uri=<%[var(req.uri)]>; path=<%[var(req.path)]>;"
http-request set-header sl1 "%[req.fhdr(sl1)] query=<%[var(req.query)]>; param=<%[var(req.param)]>"
http-request set-header sl1 "%[req.fhdr(sl1)] cl=<%[var(req.cl)]>"
http-request set-header sl2 "%[req.fhdr(sl2)] method=<%[method]>; uri=<%[url]>; path=<%[path]>; "
http-request set-header sl2 "%[req.fhdr(sl2)] query=<%[query]>; param=<%[url_param(qs_arg)]>"
http-request set-header sl2 "%[req.fhdr(sl2)] cl=<%[req.fhdr(content-length)]>"
http-request set-header hdr "%[req.fhdr(hdr)] hdr1=<%[req.hdr(hdr1)]>; fhdr1=<%[req.fhdr(hdr1)]>;"
http-request set-header hdr "%[req.fhdr(hdr)] hdr2=<%[req.hdr(hdr2)]>; fhdr2=<%[req.fhdr(hdr2)]>;"
http-request set-header hdr "%[req.fhdr(hdr)] hdr3=<%[req.hdr(hdr3)]>; fhdr3=<%[req.fhdr(hdr3)]>;"
http-request set-header hdr "%[req.fhdr(hdr)] hdr4=<%[req.hdr(hdr4)]>; fhdr4=<%[req.fhdr(hdr4)]>;"
http-request set-header sl1-crc "%[req.fhdr(sl1),crc32]"
http-request set-header sl2-crc "%[req.fhdr(sl2),crc32]"
http-request set-header hdr-crc "%[req.fhdr(hdr),crc32]"
#### responses
http-response set-header be-sl1 "%[res.fhdr(sl1)]"
http-response set-header be-sl2 "%[res.fhdr(sl2)]"
http-response set-header be-hdr "%[res.fhdr(hdr)]"
http-response set-header be-sl1-crc "%[res.fhdr(sl1-crc)]"
http-response set-header be-sl2-crc "%[res.fhdr(sl2-crc)]"
http-response set-header be-hdr-crc "%[res.fhdr(hdr-crc)]"
http-response set-var(res.status) status
http-response set-header sl1 "sl1: "
http-response set-status 200
http-response set-header sl2 "sl2: "
http-response set-header sl1 "%[res.fhdr(sl1)] status=<%[var(res.status)]>;"
http-response set-header sl2 "%[res.fhdr(sl2)] status=<%[status]>;"
http-response set-header hdr "%[res.fhdr(hdr)] hdr1=<%[res.hdr(hdr1)]>; fhdr1=<%[res.fhdr(hdr1)]>;"
http-response set-header hdr "%[res.fhdr(hdr)] hdr2=<%[res.hdr(hdr2)]>; fhdr2=<%[res.fhdr(hdr2)]>;"
http-response set-header hdr "%[res.fhdr(hdr)] hdr3=<%[res.hdr(hdr3)]>; fhdr3=<%[res.fhdr(hdr3)]>;"
http-response set-header hdr "%[res.fhdr(hdr)] hdr4=<%[res.hdr(hdr4)]>; fhdr4=<%[res.fhdr(hdr4)]>;"
http-response set-header fe-sl1-crc "%[res.fhdr(sl1),crc32]"
http-response set-header fe-sl2-crc "%[res.fhdr(sl2),crc32]"
http-response set-header fe-hdr-crc "%[res.fhdr(hdr),crc32]"
default_backend be
backend be
#### requests
http-request set-header fe-sl1 "%[req.fhdr(sl1)]"
http-request set-header fe-sl2 "%[req.fhdr(sl2)]"
http-request set-header fe-hdr "%[req.fhdr(hdr)]"
http-request set-header fe-sl1-crc "%[req.fhdr(sl1-crc)]"
http-request set-header fe-sl2-crc "%[req.fhdr(sl2-crc)]"
http-request set-header fe-hdr-crc "%[req.fhdr(hdr-crc)]"
http-request set-var(req.method) method
http-request set-var(req.uri) url
http-request set-var(req.path) path
http-request set-var(req.query) query
http-request set-var(req.param) url_param(qs_arg)
http-request set-var(req.cl) req.fhdr(content-length)
http-request set-header sl1 "sl1: "
http-request set-method "%[str(GET)]"
http-request set-uri %[str(),concat(/bu/,req.uri,/eu)]
http-request set-path "/bp/%[var(req.path)]/ep"
http-request set-query "bq&%[var(req.query)]&eq"
http-request set-header sl2 "sl2: "
http-request set-header sl1 "%[req.fhdr(sl1)] method=<%[var(req.method)]>; uri=<%[var(req.uri)]>; path=<%[var(req.path)]>;"
http-request set-header sl1 "%[req.fhdr(sl1)] query=<%[var(req.query)]>; param=<%[var(req.param)]>"
http-request set-header sl1 "%[req.fhdr(sl1)] cl=<%[var(req.cl)]>"
http-request set-header sl2 "%[req.fhdr(sl2)] method=<%[method]>; uri=<%[url]>; path=<%[path]>; "
http-request set-header sl2 "%[req.fhdr(sl2)] query=<%[query]>; param=<%[url_param(QS_arg,,i)]>"
http-request set-header sl2 "%[req.fhdr(sl2)] cl=<%[req.fhdr(content-length)]>"
http-request set-header hdr "%[req.fhdr(hdr)] hdr1=<%[req.hdr(hdr1)]>; fhdr1=<%[req.fhdr(hdr1)]>;"
http-request set-header hdr "%[req.fhdr(hdr)] hdr2=<%[req.hdr(hdr2)]>; fhdr2=<%[req.fhdr(hdr2)]>;"
http-request set-header hdr "%[req.fhdr(hdr)] hdr3=<%[req.hdr(hdr3)]>; fhdr3=<%[req.fhdr(hdr3)]>;"
http-request set-header hdr "%[req.fhdr(hdr)] hdr4=<%[req.hdr(hdr4)]>; fhdr4=<%[req.fhdr(hdr4)]>;"
http-request set-header be-sl1-crc "%[req.fhdr(sl1),crc32]"
http-request set-header be-sl2-crc "%[req.fhdr(sl2),crc32]"
http-request set-header be-hdr-crc "%[req.fhdr(hdr),crc32]"
#### responses
http-response set-var(res.status) status
http-response set-header sl1 "sl1: "
http-response set-status 200
http-response set-header sl2 "sl2: "
http-response set-header sl1 "%[res.fhdr(sl1)] status=<%[var(res.status)]>;"
http-response set-header sl2 "%[res.fhdr(sl2)] status=<%[status]>;"
http-response set-header hdr "%[res.fhdr(hdr)] hdr1=<%[res.hdr(hdr1)]>; fhdr1=<%[res.fhdr(hdr1)]>;"
http-response set-header hdr "%[res.fhdr(hdr)] hdr2=<%[res.hdr(hdr2)]>; fhdr2=<%[res.fhdr(hdr2)]>;"
http-response set-header hdr "%[res.fhdr(hdr)] hdr3=<%[res.hdr(hdr3)]>; fhdr3=<%[res.fhdr(hdr3)]>;"
http-response set-header hdr "%[res.fhdr(hdr)] hdr4=<%[res.hdr(hdr4)]>; fhdr4=<%[res.fhdr(hdr4)]>;"
http-response set-header sl1-crc "%[res.fhdr(sl1),crc32]"
http-response set-header sl2-crc "%[res.fhdr(sl2),crc32]"
http-response set-header hdr-crc "%[res.fhdr(hdr),crc32]"
http-response allow
http-response deny # must not be evaluated
server s1 ${s1_addr}:${s1_port}
} -start
client c1h1 -connect ${h1_feh1_sock} {
txreq \
-req GET \
-url /path/to/file.extension?qs_arg=qs_value \
-hdr "content-length: 000, 00" \
-hdr "hdr1: val1" \
-hdr "hdr2: val2a" \
-hdr "hdr2: val2b" \
-hdr "hdr3: val3a, val3b" \
-hdr "hdr4:"
rxresp
expect resp.status == 200
expect resp.http.be-sl1-crc == 487202719
expect resp.http.be-sl2-crc == 561949791
expect resp.http.be-hdr-crc == 1719311923
expect resp.http.fe-sl1-crc == 146151597
expect resp.http.fe-sl2-crc == 561949791
expect resp.http.fe-hdr-crc == 3634102538
expect resp.bodylen == 14
expect resp.body == "This is a body"
} -run
client c1h2 -connect ${h1_feh2_sock} {
txpri
stream 0 {
txsettings
rxsettings
txsettings -ack
rxsettings
expect settings.ack == true
} -run
stream 1 {
# warning: -req, -scheme, -url MUST be placed first otherwise
# the H2 protocol is invalid since they are pseudo-headers
txreq \
-req GET \
-scheme "https" \
-url /path/to/file.extension?qs_arg=qs_value \
-hdr "content-length" "000, 00" \
-hdr "hdr1" "val1" \
-hdr "hdr2" " val2a" \
-hdr "hdr2" " val2b" \
-hdr "hdr3" " val3a, val3b" \
-hdr "hdr4" ""
rxhdrs
expect resp.status == 200
expect resp.http.be-sl1-crc == 487202719
expect resp.http.be-sl2-crc == 561949791
expect resp.http.be-hdr-crc == 1719311923
expect resp.http.fe-sl1-crc == 146151597
expect resp.http.fe-sl2-crc == 561949791
expect resp.http.fe-hdr-crc == 3634102538
expect resp.http.content-length == 14
rxdata -all
expect resp.body == "This is a body"
} -run
} -run