I'm creating a HTTP Web API where some of my resources will be cacheable. A cacheable resource will have two operations, GET & PUT. The GET will return response headers of Cache-Control: public,max-age=3600 & Etag: "2kuSN7rMzfGcB2DKt67EqDWQELA". The PUT will require the If-Match header which will contain the Etag value from a GET of the same resource. My goal is to have the browser cache invalidate a resource when I PUT to that resource. This works fine until I add the If-Match header to the PUT request. When the PUT request contains the If-Match header, subsequent GET requests will fetch from the cache which would be stale data. This is the behavior I've been experiencing with Chrome. Firefox doesn't behave like this, and works as I assume it should. Is this a bug in Chrome or am I misunderstanding some part of the HTTP spec?
Here are some example requests to show behavior:
//correctly fetchs from origin server (returns 200)
GET http://localhost/api/my-number/1
Response Headers
cache-control: public,max-age=3600
etag: "2kuSN7rMzfGcB2DKt67EqDWQELA"
Response Body
7
//correctly fetchs from disk cache (returns 200)
GET http://localhost/api/my-number/1
Response Headers
cache-control: public,max-age=3600
etag: "2kuSN7rMzfGcB2DKt67EqDWQELA"
Response Body
7
//correctly updates origin server (returns 200)
PUT http://localhost/api/my-number/1
Request Headers
if-match: "2kuSN7rMzfGcB2DKt67EqDWQELA"
Request Body
8
//incorrectly still fetches from disk cache (returns 200)
GET http://localhost/api/my-number/1
Response Headers
cache-control: public,max-age=3600
etag: "2kuSN7rMzfGcB2DKt67EqDWQELA"
Response Body
7
This is indeed incorrect behavior. RFC 7234 says:
A cache MUST invalidate the effective Request URI... as well as the URI(s) in the Location and Content-Location
response header fields (if present) when a non-error status code is
received in response to an unsafe request method.
Given that, the bug report you filed looks appropriate to me.
Related
A dynamic-post-form that should be cached using eTag. Navigation:
A user browse to the form form.html and recieve the status 200 having the new eTag "DNEI297" within the response from the server. Now the browser caches this document in the cache.
The user enters some values and finally post the form-data to form.html (browser to server) and recieve from the server the HTTP status code 205 (accepted/reset form data) and the unchanged eTag "DNEI297".
Since the 205 response is empty in this case, the browser reload the page form.html using the eTag "DNEI297". The server compares the eTag with his eTag and decide that neither the form nor the eTag changed and the browser already have cached the correct version of the form.html and send a 304 (unchanged).
Now the Problem: Since the Server sent a 304 the Browser took the last request and decide to use the cached version. But the cached version is the answer of the post-request having status-code 205 and the eTag "DNEI297".
Finally after the submit of the form the document http-status is 205. How to avoid the wrong code? It makes trouble and produce alerts from antivirus-plugins.
The server in this case erred by sending the same ETag—or any ETag—in its 205 response to the form submission.
RFC 7232 describes when it's appropriate to use an ETag:
A "strong validator" is representation metadata that changes value
whenever a change occurs to the representation data that would be
observable in the payload body of a 200 (OK) response to GET.
So you should not send an ETag along with the empty 205 response, since that's not what you'd get by doing a successful GET to that URL.
when I try to Respond with on HTTP 204 Status, my Chrome browser is starting an Download that fails.
Request:
Request URL: https://dummy.page/dummyRequest
Request Method: GET
Status Code: 204
Remote Address: [dummy]:443
Referrer Policy: no-referrer-when-downgrade
Response:
date: Fri, 08 Mar 2019 08:24:05 GMT
server:
status: 204
When I use Dev-Tool to inspect the response, chrome says "faild to load response data" and in firefox I can see one empty line.
My server returns a Response via Java:
return Response.noContent().build();
I also tried to return NULL at this point but that did not change anything.
The whole thing is working fine in Firefox but when I try in Chrome it starts an Download of "dummyRequest" (from the URL) which fails.
So what I want to know: why is Chrome starting a download and what could I do against?
Thanks for helping ;)
I came across the same issue with 204 responses. What worked for me was checking the Content-Type response header on the server-side before sending the response.
My 204 responses were sending a default Content-Type of application/octet-stream (from the link: "An unknown file type should use this type. Browsers pay a particular care when manipulating these files"). When switching the Content-Type to something different (I chose text/html), the trigger for downloads stopped.
I'm currently working with Angular 5.1.2 and i'm trying to get objects from http requests.
In order to verify my code, I've hardcoded a JSON response and created a Python Anywhere's web service, here's what I did :
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=UTF-8
{"Computer":[{
"ip":"192.168.0.142",
"mac":"39-D7-98-9E-5A-DC",
"name":"PC-DE-JEAN-CLAUDE"
},
{
"ip":"192.168.0.50",
"mac":"4D-49-98-30-8A-F5",
"name":"LIVEBOX-684J"
}]}
However, why my Angular app is saying that "No 'Access-Control-Allow-Origin' header is present on the requested resource" ?
Thanks
It is related to CORS issue. It happens when server and client are running on different addresses. To make it run, server need to return Access-Control-Allow-Origin as a Key:Value pair in their header response.
Access-Control-Allow-Origin: *
Specifying value as * means that the content of the address can be accessed by any other address.
It's one of the layer in securing the Internet applications.
This is a server-side problem due to CORS to prevent XSS. In order to fix, make sure your server responds with the header Access-Control-Allow-Origin: * After verifying this fixes the problem, set this header to your website URL
How should an HTTP Agent make decisions about using cached response when a request has the same path but different headers?
Take for example this HTTP request/response:
GET /resource HTTP/1.1
Host: example.org
X-Filter: foo=bar
HTTP/1.1 200 OK
Cache-Control: max-age=3600
Content-Type: application/json
Content-Length: 13
{"foo":"bar"}
Should the agent consider the response valid for a second request with a different X-Filter header? For example:
GET /resource HTTP/1.1
Host: example.org
X-Filter: foo=baz
then within an hour from the first request, should the agent request a fresh response since the request header differs, or should use the cached response from the first request, ignoring the header?
I'm asking this because I noticed that Google Chrome makes a new request, Microsoft Edge instead use the cached response.
You should use the cached version unless changed header appears in the list provided by the (optional) Vary response header.
For example, a response that contains
Vary: accept-encoding, accept-language
indicates that the origin server might have used the request's
Accept-Encoding and Accept-Language fields (or lack thereof) as
determining factors while choosing the content for this response.
I have a web page that returns the following header when I access material:
HTTP/1.1 200 OK
Date: Sat, 29 Jun 2013 15:57:25 GMT
Server: Apache
Content-Length: 2247515
Cache-Control: no-cache, no-store, must-revalidate, max-age=-1
Pragma: no-cache, no-store
Expires: -1
Connection: close
Using a chrome extension, I want to modify this response header so that the material is actually cached instead of wasting bandwidth.
I have the following sample code:
chrome.webRequest.onHeadersReceived.addListener(function(details)
{
// Delete the required elements
removeHeader(details.responseHeaders, 'pragma');
removeHeader(details.responseHeaders, 'expires');
// Modify cache-control
updateHeader(details.responseHeaders, 'cache-control', 'max-age=3600;')
console.log(details.url);
console.log(details.responseHeaders);
return{responseHeaders: details.responseHeaders};
},
{urls: ["<all_urls>"]}, ['blocking', 'responseHeaders']
);
Which correctly modifies the header to something like this (based on the console.log() output):
HTTP/1.1 200 OK
Date: Sat, 29 Jun 2013 15:57:25 GMT
Server: Apache
Content-Length: 2247515
Cache-Control: max-age=3600
Connection: close
But based on everything I have tried to check this, I cannot see any evidence whatsoever that this has actually happened:
The cache does not contain an entry for this file
The Network tab in the Developer Console shows no change at all to the HTTP response (I have tried changing it to even trivial modifications just for the sake of ensuring that its not a error, but still no change).
The only real hints I can find are this question which suggests that my approach still works and this paragraph on the webRequest API documentation which suggests that this won't work (but doesn't explain why I can't get any changes whatsoever):
Note that the web request API presents an abstraction of the network
stack to the extension. Internally, one URL request can be split into
several HTTP requests (for example to fetch individual byte ranges
from a large file) or can be handled by the network stack without
communicating with the network. For this reason, the API does not
provide the final HTTP headers that are sent to the network. For
example, all headers that are related to caching are invisible to the
extension.
Nothing is working whatsoever (I can't modify the HTTP response header at all) so I think that's my first concern.
Any suggestions at where I could be going wrong or how to go about finding what is going wrong here?
If its not possible, are there any other ways to achieve what I am trying to achieve?
I have recently spent some hours on trying to get a file cached, and discovered that the chrome.webRequest and chrome.declarativeWebRequest APIs cannot force resources to be cached. In no way.
The Cache-Control (and other) response headers can be changed, but it will only be visible in the getResponseHeader method. Not in the caching behaviour.