--- /dev/null
+varnishtest "Check the escaping performed by the +json option"
+feature ignore_unknown_macro
+
+# Section 8.6 of the config manual states that only the characters from 32 to
+# 126 are emitted as-is in the logs, everything else being encoded, and the
+# JSON encoding has no reason to be more permissive than the plain one.
+# Escaping them all also makes the output valid UTF-8, which RFC 8259 #8.1
+# requires, without having to guess what the logged bytes represent: a header
+# value is arbitrary bytes, not text.
+
+haproxy h1 -conf {
+ global
+ .if feature(THREAD)
+ thread-groups 1
+ .endif
+
+ ring myring
+ size 16384
+ format raw
+
+ 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@${fe}"
+ capture request header x len 64
+ log ring@myring local0
+ log-format "{\"hdr\":%{+json}[capture.req.hdr(0)],\"bin\":%{+json}[str(Gw==),b64dec]}"
+ http-request return status 200
+} -start
+
+# an ESC, which has no two-character form, a tab, which has one, a double quote
+# and a backslash
+client c1 -connect ${h1_fe_sock} {
+ txreq -url "/ctl" -hdr "x: A\x1b[31m\tB\"C\\D"
+ rxresp
+ expect resp.status == 200
+} -run
+
+# bytes above the printable range, here a valid UTF-8 sequence and a lone
+# continuation byte, are encoded the same way: one escape per byte
+client c2 -connect ${h1_fe_sock} {
+ txreq -url "/high" -hdr "x: A\xc3\xa9B\xaaC"
+ rxresp
+ expect resp.status == 200
+} -run
+
+delay 0.2
+
+# the ESC comes out as the six-character form and the tab as the short one, in
+# both the string sample and the binary sample paths
+haproxy h1 -cli {
+ send "show events myring"
+ expect ~ "A\\\\u001B\\[31m\\\\tB"
+}
+
+haproxy h1 -cli {
+ send "show events myring"
+ expect ~ "\"bin\":\"\\\\u001B\""
+}
+
+# one escape per byte above the printable range, so the output stays plain
+# ASCII and no byte can be mistaken for a sequence introducer
+haproxy h1 -cli {
+ send "show events myring"
+ expect ~ "A\\\\u00C3\\\\u00A9B\\\\u00AAC"
+}
+
+# nothing outside 32..126 reached the ring, which "-s" would have turned into
+# a '?'
+haproxy h1 -cli {
+ send "show events myring -s"
+ expect !~ "\\?"
+}