Shielding adds duplicated `If-Modified-Since` and `If-None-Match` headers which nginx does not like


Got a very strange issue, searched here and the google and couldn’t find it anywhere.

I have a config with shielding enabled. All works perfectly normal. Then when the first object ttl are reached, the backend requests suddenly were returned with that:

<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>

after some debugging I saw in the nginx debug log:

2016/12/07 23:56:32 [debug] 15241#15241: *16 http header: "If-Modified-Since: Wed, 07 Dec 2016 22:39:47 GMT"
2016/12/07 23:56:32 [info] 15241#15241: *16 client sent duplicate header line: "If-Modified-Since: Wed, 07 Dec 2016 22:39:55 GMT", previous value: "If-Modified-Since: Wed, 07 Dec 2016 22:39:47 GMT" while reading client request headers, client:, server:, request: "POST /graphql HTTP/1.1", host: ""
2016/12/07 23:56:32 [debug] 15241#15241: *16 http finalize request: 400, "/graphql?" a:1, c:1
2016/12/07 23:56:32 [debug] 15241#15241: *16 http special response: 400, "/graphql?"
2016/12/07 23:56:32 [debug] 15241#15241: *16 http set discard body
2016/12/07 23:56:32 [debug] 15241#15241: *16 uploadprogress error-tracker error: 400
2016/12/07 23:56:32 [debug] 15241#15241: *16 uploadprogress error-tracker not tracking in this location
2016/12/07 23:56:32 [debug] 15241#15241: *16 xslt filter header
2016/12/07 23:56:32 [debug] 15241#15241: *16 HTTP/1.1 400 Bad Request
Server: nginx
Date: Wed, 07 Dec 2016 22:56:32 GMT
Content-Type: text/html
Content-Length: 166
Connection: close

which basically means the header If-Modified-Since was sent twice and nginx doesn’t like that at all and returns an 400.
There is no way inside nginx to disable that, as this is hardcoded in nginx:

I was able to fix it with an custom VCL:

sub vcl_miss {
#FASTLY miss

  # unsetting If-Modified-Since and If-None-Match as this can appear twice in the backend request and nginx doesn't like that at all
  unset bereq.http.If-Modified-Since;
  unset bereq.http.If-None-Match;

(as you can see had to unset If-None-Match as well, as this also was double available)

So I’m assuming that Varnish does a request with If-Modified-Since and If-None-Match after the TTL of an object is reached in order to allow the backend to return with an 304 not modified, which is great. Just it appears twice if shielding is enabled.

Not sure if anybody else had that before and if that is maybe something that should be fixed in the default config of the Fastly VCL?


When I see the nginx log, the client address is and this is private address.
Would it be possible to get global source ips of these duplicate IMS requests?