You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
7.9 KiB

  1. commit eaf650083924a697cde3379703984c5e7a5ebd41
  2. Author: Tim Duesterhus <tim@bastelstu.be>
  3. Date: Mon Jun 17 16:10:07 2019 +0200
  4. BUG/MEDIUM: compression: Set Vary: Accept-Encoding for compressed responses
  5. Make HAProxy set the `Vary: Accept-Encoding` response header if it compressed
  6. the server response.
  7. Technically the `Vary` header SHOULD also be set for responses that would
  8. normally be compressed based off the current configuration, but are not due
  9. to a missing or invalid `Accept-Encoding` request header or due to the
  10. maximum compression rate being exceeded.
  11. Not setting the header in these cases does no real harm, though: An
  12. uncompressed response might be returned by a Cache, even if a compressed
  13. one could be retrieved from HAProxy. This increases the traffic to the end
  14. user if the cache is unable to compress itself, but it saves another
  15. roundtrip to HAProxy.
  16. see the discussion on the mailing list: https://www.mail-archive.com/haproxy@formilux.org/msg34221.html
  17. Message-ID: 20190617121708.GA2964@1wt.eu
  18. A small issue remains: The User-Agent is not added to the `Vary` header,
  19. despite being relevant to the response. Adding the User-Agent header would
  20. make responses effectively uncacheable and it's unlikely to see a Mozilla/4
  21. in the wild in 2019.
  22. Add a reg-test to ensure the behaviour as described in this commit message.
  23. see issue #121
  24. Should be backported to all branches with compression (i.e. 1.6+).
  25. (cherry picked from commit 721d686bd10dc6993859f9026ad907753d1d2064)
  26. Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
  27. diff --git a/reg-tests/compression/vary.vtc b/reg-tests/compression/vary.vtc
  28. new file mode 100644
  29. index 00000000..0a060e4b
  30. --- /dev/null
  31. +++ b/reg-tests/compression/vary.vtc
  32. @@ -0,0 +1,187 @@
  33. +varnishtest "Compression sets Vary header"
  34. +
  35. +#REQUIRE_VERSION=1.9
  36. +#REQUIRE_OPTION=ZLIB|SLZ
  37. +
  38. +feature ignore_unknown_macro
  39. +
  40. +server s1 {
  41. + rxreq
  42. + expect req.url == "/plain/accept-encoding-gzip"
  43. + expect req.http.accept-encoding == "gzip"
  44. + txresp \
  45. + -hdr "Content-Type: text/plain" \
  46. + -bodylen 100
  47. +
  48. + rxreq
  49. + expect req.url == "/plain/accept-encoding-invalid"
  50. + expect req.http.accept-encoding == "invalid"
  51. + txresp \
  52. + -hdr "Content-Type: text/plain" \
  53. + -bodylen 100
  54. +
  55. + rxreq
  56. + expect req.url == "/plain/accept-encoding-null"
  57. + expect req.http.accept-encoding == "<undef>"
  58. + txresp \
  59. + -hdr "Content-Type: text/plain" \
  60. + -bodylen 100
  61. +
  62. + rxreq
  63. + expect req.url == "/html/accept-encoding-gzip"
  64. + expect req.http.accept-encoding == "gzip"
  65. + txresp \
  66. + -hdr "Content-Type: text/html" \
  67. + -bodylen 100
  68. +
  69. + rxreq
  70. + expect req.url == "/html/accept-encoding-invalid"
  71. + expect req.http.accept-encoding == "invalid"
  72. + txresp \
  73. + -hdr "Content-Type: text/html" \
  74. + -bodylen 100
  75. +
  76. +
  77. + rxreq
  78. + expect req.url == "/html/accept-encoding-null"
  79. + expect req.http.accept-encoding == "<undef>"
  80. + txresp \
  81. + -hdr "Content-Type: text/html" \
  82. + -bodylen 100
  83. +
  84. + rxreq
  85. + expect req.url == "/dup-etag/accept-encoding-gzip"
  86. + expect req.http.accept-encoding == "gzip"
  87. + txresp \
  88. + -hdr "Content-Type: text/plain" \
  89. + -hdr "ETag: \"123\"" \
  90. + -hdr "ETag: \"123\"" \
  91. + -bodylen 100
  92. +} -repeat 2 -start
  93. +
  94. +
  95. +haproxy h1 -conf {
  96. + defaults
  97. + mode http
  98. + ${no-htx} option http-use-htx
  99. + timeout connect 1s
  100. + timeout client 1s
  101. + timeout server 1s
  102. +
  103. + frontend fe-gzip
  104. + bind "fd@${fe_gzip}"
  105. + default_backend be-gzip
  106. +
  107. + backend be-gzip
  108. + compression algo gzip
  109. + compression type text/plain
  110. + server www ${s1_addr}:${s1_port}
  111. +
  112. + frontend fe-nothing
  113. + bind "fd@${fe_nothing}"
  114. + default_backend be-nothing
  115. +
  116. + backend be-nothing
  117. + server www ${s1_addr}:${s1_port}
  118. +} -start
  119. +
  120. +client c1 -connect ${h1_fe_gzip_sock} {
  121. + txreq -url "/plain/accept-encoding-gzip" \
  122. + -hdr "Accept-Encoding: gzip"
  123. + rxresp
  124. + expect resp.status == 200
  125. + expect resp.http.content-encoding == "gzip"
  126. + expect resp.http.vary == "Accept-Encoding"
  127. + gunzip
  128. + expect resp.bodylen == 100
  129. +
  130. + txreq -url "/plain/accept-encoding-invalid" \
  131. + -hdr "Accept-Encoding: invalid"
  132. + rxresp
  133. + expect resp.status == 200
  134. + expect resp.http.vary == "<undef>"
  135. + expect resp.bodylen == 100
  136. +
  137. + txreq -url "/plain/accept-encoding-null"
  138. + rxresp
  139. + expect resp.status == 200
  140. + expect resp.http.vary == "<undef>"
  141. + expect resp.bodylen == 100
  142. +
  143. + txreq -url "/html/accept-encoding-gzip" \
  144. + -hdr "Accept-Encoding: gzip"
  145. + rxresp
  146. + expect resp.status == 200
  147. + expect resp.http.vary == "<undef>"
  148. + expect resp.bodylen == 100
  149. +
  150. + txreq -url "/html/accept-encoding-invalid" \
  151. + -hdr "Accept-Encoding: invalid"
  152. + rxresp
  153. + expect resp.status == 200
  154. + expect resp.http.vary == "<undef>"
  155. + expect resp.bodylen == 100
  156. +
  157. + txreq -url "/html/accept-encoding-null"
  158. + rxresp
  159. + expect resp.status == 200
  160. + expect resp.http.vary == "<undef>"
  161. + expect resp.bodylen == 100
  162. +
  163. + txreq -url "/dup-etag/accept-encoding-gzip" \
  164. + -hdr "Accept-Encoding: gzip"
  165. + rxresp
  166. + expect resp.status == 200
  167. + expect resp.http.vary == "<undef>"
  168. + expect resp.bodylen == 100
  169. +} -run
  170. +
  171. +# This Client duplicates c1, against the "nothing" frontend, ensuring no Vary header is ever set.
  172. +client c2 -connect ${h1_fe_nothing_sock} {
  173. + txreq -url "/plain/accept-encoding-gzip" \
  174. + -hdr "Accept-Encoding: gzip"
  175. + rxresp
  176. + expect resp.status == 200
  177. + expect resp.http.vary == "<undef>"
  178. + expect resp.bodylen == 100
  179. +
  180. + txreq -url "/plain/accept-encoding-invalid" \
  181. + -hdr "Accept-Encoding: invalid"
  182. + rxresp
  183. + expect resp.status == 200
  184. + expect resp.http.vary == "<undef>"
  185. + expect resp.bodylen == 100
  186. +
  187. + txreq -url "/plain/accept-encoding-null"
  188. + rxresp
  189. + expect resp.status == 200
  190. + expect resp.http.vary == "<undef>"
  191. + expect resp.bodylen == 100
  192. +
  193. + txreq -url "/html/accept-encoding-gzip" \
  194. + -hdr "Accept-Encoding: gzip"
  195. + rxresp
  196. + expect resp.status == 200
  197. + expect resp.http.vary == "<undef>"
  198. + expect resp.bodylen == 100
  199. +
  200. + txreq -url "/html/accept-encoding-invalid" \
  201. + -hdr "Accept-Encoding: invalid"
  202. + rxresp
  203. + expect resp.status == 200
  204. + expect resp.http.vary == "<undef>"
  205. + expect resp.bodylen == 100
  206. +
  207. + txreq -url "/html/accept-encoding-null"
  208. + rxresp
  209. + expect resp.status == 200
  210. + expect resp.http.vary == "<undef>"
  211. + expect resp.bodylen == 100
  212. +
  213. + txreq -url "/dup-etag/accept-encoding-gzip" \
  214. + -hdr "Accept-Encoding: gzip"
  215. + rxresp
  216. + expect resp.status == 200
  217. + expect resp.http.vary == "<undef>"
  218. + expect resp.bodylen == 100
  219. +} -run
  220. diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c
  221. index b04dcd14..37f237fe 100644
  222. --- a/src/flt_http_comp.c
  223. +++ b/src/flt_http_comp.c
  224. @@ -523,6 +523,9 @@ http_set_comp_reshdr(struct comp_state *st, struct stream *s, struct http_msg *m
  225. }
  226. }
  227. + if (http_header_add_tail2(msg, &txn->hdr_idx, "Vary: Accept-Encoding", 21) < 0)
  228. + goto error;
  229. +
  230. return 1;
  231. error:
  232. @@ -577,6 +580,9 @@ htx_set_comp_reshdr(struct comp_state *st, struct stream *s, struct http_msg *ms
  233. }
  234. }
  235. + if (!http_add_header(htx, ist("Vary"), ist("Accept-Encoding")))
  236. + goto error;
  237. +
  238. return 1;
  239. error: