HTTP Cache-Control header works only on localhost - ajax

I'm trying to configure caching with Cache-Control for a REST endpoint in my webapp, it works locally, but when I deploy on our production server the browser just won't cache the responses.
The endpoint is queried via a parametrized ajax request (as shown below).
Some relevant notes :
I use a cache buster parameter (_) that is a unix timestamp generated at page load. It doesn't change across ajax requests.
localhost is on HTTP whereas production is on HTTPS. The certificate is valid and there are no related errors.
Both Firefox 59.0.2 and Chrome 66.0.3359.139 exhibit this behavior, so I assume this is something in the configuration.
Localhost
Request URL: http://localhost:8080/webapp/rest/events?_=1525720266960&start=2018-04-29&end=2018-06-10
Request Method: GET
Status Code: 200 OK
Referrer Policy: no-referrer-when-downgrade
=== Request ===
Accept: application/json, text/javascript, */*; q=0.01
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: JSESSIONID=<token>
Host: localhost:8080
Referer: http://localhost:8080/webapp/
X-Requested-With: XMLHttpRequest
=== Response ===
Cache-Control: no-transform, max-age=300, private
Connection: keep-alive
Content-Length: 5935
Content-Type: application/json
Following requests (for the same parameters) are effectively loaded from cache with the only difference being : Status Code: 200 OK (from disk cache)
Which seems fine, since I don't want to revalidate. The resource should only be fetched again, without validation, once it has gone stale after the duration of max-age specified by Cache-Control.
Production
Request URL: https://www.example.org/webapp/rest/events?_=1525720216575&start=2018-04-29&end=2018-06-10
Request Method: GET
Status Code: 200 OK
Referrer Policy: no-referrer-when-downgrade
=== Request ===
Accept: application/json, text/javascript, */*; q=0.01
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: JSESSIONID=<token>
Host: www.example.org
Referer: https://www.example.org/webapp/
X-Requested-With: XMLHttpRequest
=== Response ===
Cache-Control: no-transform, max-age=300, private
Connection: close
Content-Length: 5935
Content-Type: application/json
In this case, the response is never loaded from cache afterwards.
I've stripped some headers that I thought superfluous (Server, X-Powered-By, User-Agent, Date).
Question
What prevents the reponses to be cached by the browser when talking to the production server ?

2 days later I try again and caching works properly. (I swear I'm not insane)
Same request, same headers, same response.
I suspect that it falls into some kind of heuristic that overrides the response Cache-Control.
It certainly has to do with the fact that this endpoint did not specify Cache-Control before, so the browser overlooks the header since the heuristic favored refetching instead of caching, it can't go wrong about being more cautious.
RFC2616
13.2.2 Heuristic Expiration
Since origin servers do not always provide explicit expiration times,
HTTP caches typically assign heuristic expiration times, employing
algorithms that use other header values (such as the Last-Modified
time) to estimate a plausible expiration time. The HTTP/1.1
specification does not provide specific algorithms, but does impose
worst-case constraints on their results. Since heuristic expiration
times might compromise semantic transparency, they ought to used
cautiously, and we encourage origin servers to provide explicit
expiration times as much as possible.
All in all, this is the best explanation I have.

Related

should we close the connection of a pre-flight Cors request while sending response?

As I know that if cors request comes with some extra headers set, first server needs to process it.
With CORS, the server must send the Access-Control-Allow-Headers header to allow uncommon request headers from the client.
Access-Control-Allow-Headers ... - Comma-delimited list of the supported request headers.
e.g suppose my pre-flight request is
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
Then from server-side I will send response
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
My question is -
should I close the connection on server side while we send pre-flight response to client?
One more thing how can I cached pre-flight request for all other distinct subsequent requests?
Thanks
You could cache the OPTIONS request using the
Access-Control-Max-Age
header.
Attach it to the headers collection of the OPTIONS response.
But nevertheless an initial OPTIONS request by the user agent (browser) has to be made, you cannot avoid this.
But all further OPTIONS requests are cached and not issued to the server.
No need to close the connection.
Access-Control-Allow-Origin: http://hello-world.example
Access-Control-Max-Age: 3628800
Access-Control-Allow-Methods: PUT
as explained here, search for
could have the following headers specified
to get to the designated text section.

CORS XMLHttpRequest using POST to send multipart form-data to Softlayer object storage fails

I have been encountering error in storing a file to Object Storage using HTTP POST method sent using Async XMLHttpRequest. The request is a CORS HTTP request sent to the Object storage public URL with required headers set. The error message says: Reason: CORS header Access-Control-Allow-Origin missing.
The error seems to happen with multipart form data send request using POST. If PUT is used to create the file, the required file (resource) gets created. The response to the PUT request contains the required Access-Control-Allow-Origin header, whereas the response to POST does not contain despite the meta data attributes being set on the container.
I have even tried using X_AUTH_TOKEN header instead of X_STORAGE_TOKEN, but the failure continues to happen.
Raised the ticket with Softlayer support, but have not received a solution. Any ideas to resolve the above would be helpful.
The details are below:
The container prod_file has following meta data attributes set:
access-control-expose-headers: Access-Control-Allow-Origin
access-control-allow-origin : *
The Firefox browser version is: Mozilla Firefox 46.0
Client OS is: Linux 3.16.0-71-generic #91~14.04.1-Ubuntu SMP Mon Apr 18 1K9:43:36 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Request URL: https://*****.objectstorage.softlayer.net/v1/AUTH_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/prod_file/6ffb51fc-e40f-4cf5-982c-44cb5c342851.fl.file.orig.txt
Request HTTP Method: POST
Mechanism used: Async XMLHttpRequest
Request Headers:
Host: *****.objectstorage.softlayer.net
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
X-Storage-Token: AUTH_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Referer: http://*****myorg******.com/organization/572680760cf26af856c7432c/resources
Content-Length: 4500
Content-Type: multipart/form-data; boundary=---------------------------2139255891192408661525197545
Origin: http://*****myorg******.com
Connection: keep-alive
Response Headers:
Connection: keep-alive
Content-Length: 50
Content-Type: text/plain
Date: Sat, 14 May 2016 14:57:02 GMT
X-Trans-Id: *****Some Transaction Id********
The error response has the following message:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://*****.objectstorage.softlayer.net/v1/AUTH_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/prod_file/6ffb51fc-e40f-4cf5-982c-44cb5c342851.fl.file.orig.txt. (Reason: CORS header 'Access-Control-Allow-Origin' missing)
Thanks for the help in advance.
It looks like you set wrong the headers for your container, please take a look this documentation and try it:
http://docs.openstack.org/developer/swift/cors.html
https://swiftstack.com/blog/2013/04/02/using-cors-with-swift/
Renember that softlayer object storage is based in Open Stack.
Let me know if you are still having troubles
Regards

Redirect from a Servlet filter, when an AJAX request is made [duplicate]

While trying to redirect user to a URL, it works with GET requests but not with postback requests.
Through firebug's Network window, I can see the redirect response received by browser after the postback request (that should cause redirect) completes. The browser seemingly initiates a GET request for the redirect URL but doesn't actually successfully redirect. It remains there on the same page.
 I use JSF server side. The initiated GET request is not received at all by the server. However initiated by the browser on server's demand. I guess problem is somewhere client side only 
Can anyone please explain how to make redirect work successfully ? Let me know incase I should provide any more information.
Edit:
Request header for redirect:
GET /Px10Application/welcome.xhtml HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20100101 Firefox/20.0
Accept: application/xml, text/xml, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://localhost:8080/Px10Application/channelPages.xhtml?channelId=-3412&type=Group
X-Requested-With: XMLHttpRequest
Faces-Request: partial/ajax
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Cookie: hb8=wq::db6a8873-f1dc-4dcc-a784-4514ee9ef83b; JSESSIONID=d40337b14ad665f4ec02f102bb41; oam.Flash.RENDERMAP.TOKEN=-1258fu7hp9
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Response header for redirect:
HTTP/1.1 200 OK
X-Powered-By: Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 3.1 Java/Sun Microsystems Inc./1.6)
Server: GlassFish Server Open Source Edition 3.1
Set-Cookie: oam.Flash.RENDERMAP.TOKEN=-1258fu7hp8; Path=/Px10Application
Pragma: no-cache
Cache-Control: no-cache
Expires: -1
Content-Type: text/xml;charset=UTF-8
Content-Length: 262
Date: Wed, 22 May 2013 17:18:56 GMT
X-Requested-With: XMLHttpRequest
Faces-Request: partial/ajax
You're thus attempting to send a redirect on a JSF ajax request using "plain vanilla" Servlet API's HttpServletResponse#sendRedirect(). This is not right. The XMLHttpRequest does not treat a 302 response as a new window.location, but just as a new ajax request. However as you're returning a complete plain vanilla HTML page as ajax response instead of a predefined XML document with instructions which HTML parts to update, the JSF ajax engine has no clues what to do with the response of the redirected ajax request. You end up with a JS error (didn't you see it in the JS console?) and no form of visual feedback if you don't have the jsf.ajax.onError() handler configured.
In order to instruct the JSF ajax engine to change the window.location, you need to return a special XML response. If you have used ExternalContext#redirect() instead, then it would have taken place fully transparently.
externalContext.redirect(redirectURL);
However, if you're not inside JSF context, e.g. in a servlet filter or so, and thus don't have the FacesContext at hands, then you should be manually creating and returning the special XML response.
if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
response.setContentType("text/xml");
response.getWriter()
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
.printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>", redirectURL);
} else {
response.sendRedirect(redirectURL);
}
If you happen to use JSF utility library OmniFaces, then you can also use Servlets#facesRedirect() for the job:
Servlets.facesRedirect(request, response, redirectURL);
See also:
Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same
JSF Filter not redirecting After Initial Redirect

Can't get Access-Control-Allow-Origin header to work as I expected

There are a lot of questions on this subject, but I still can't seem to resolve my issue.
I have a game that I'm trying to get working with HTML 5 in Chrome. Link here.
The game is written using libgdx and I'm posting json data from my app engine hosted back end. I've done quite a bit of reading and I think I understand the issue with cross domain access, I also think I understand how to resolve it but can't.
The full error is
XMLHttpRequest cannot load http://1-1-51.wordbuzzweb.appspot.com/Login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://wordbuzzhtml5.appspot.com' is therefore not allowed access.
As you can see, this says No 'Access-Control-Allow-Origin' header is present on the requested resource.. But if I look at the headers for the requested resource, they are as follows.
Date: Thu, 18 Jun 2015 21:59:34 GMT
Content-Encoding: gzip
Server: Google Frontend
Vary: Accept-Encoding
Access-Control-Allow-Methods: GET, POST
Content-Type: application/json
Access-Control-Allow-Origin: *
Alternate-Protocol: 80:quic,p=0
Cache-Control: private
Access-Control-Allow-Headers: Content-Type
Content-Length: 127
As you can see, there is an Access-Control-Allow-Origin header included.
If someone could please tell me what I'm doing wrong, that'd be appreciated.
The request header is as follows using the POST method.
Host: 192.168.254.1:8081
Pragma: no-cache
Cache-Control: no-cache
Origin: http://localhost:8080/
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.52 Safari/537.36
Accept: */*
Referer: http://localhost:8080/html/
Accept-Language: en-GB,en;q=0.8
Content-Length: 25
Content-Type: application/json
Since you are getting some headers back in the response, that's a good indication that the request IS reaching the server, however, the fact that it isn't hitting your server route points to the problem being the request being made doesn't match any of your routes. The request is likely an OPTIONS request rather than a POST request, which commonly happens when you make a CORS request from the browser that isn't a "simple request".
The solution would be to either make it a "simple request", or to have your server respond to OPTIONS requests. It's far easier to just make your server respond to OPTIONS requests, because sometimes even "simple requests" still send OPTIONS requests.

Firefox CORS Cross Domain Resource Sharing Pre-Flight Debugging

I'm trying to get Firefox to allow me to make an XmlHttpRequest for data from an application port.
I can see that the initial send triggers an OPTIONS message, and I have trapped this using NetMon, and I can see the HTTP fields...
OPTIONS /any.htm HTTP/1.1
Host: www.mysite.co.uk:10090
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Origin: http://www.mysite.co.uk
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
I respond to this with an OK to tell FireFox to get a move on and send me the data in the XHR request...
HTTP/1.1 200 OK
Access-Control-Allow-Methods: POST,-GET,-OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 172800000
Server: Kawasu-OrderSub
Date: Wed, 23 Jan 2013 15:00:50 GMT
But the POST is never sent, which I assume means that FireFox is not happy with the 200 OK response. The POST sends data with a Content-Type of "application/json"
I've got FireBug and the Net tab has the XHR button, but this will only show the XHR after the pre-flight check has been passed.
Main Question: How can I see (and debug) what FireFox does not like about the server response?
Much obliged for any help in advance.
You need to include the Access-Control-Allow-Headers: content-type response header. This is because the request has the Access-Control-Request-Headers: content-type header, and this value needs to be included in the response.

Resources