javascript versioning without ability to change js url. Would etag work? - versioning

As part of a bookmarklet, I want to load in a script www.example.com/a.js
This file may change in the future so I want to do some versioning on it.
However, since I must hardcode the url in the bookmarklet, I can't use proper url-versioning .
What would be a good practice to do versioning instead?
I imagine using etag would probably work. I.e.: update the eTag on each version update and have the client request the file with the If-None-Match header.
Would this work?

have the client request the file with the If-None-Match header.
That I know of, there is no way to control or set the headers that a browser will use when loading a page resource such as images and script.
ETag is something that should work "out of the box". If the client sends an ETag header with the file then the browser should automatically send the If-None-Match header for the next request.
One frequently seen method to ensure a fresh file, although less efficient, is to add a time stamp or random number to the script like http://example.com/script.js?1234567. Of course that will force the client to download the script every time. You could instead use different date strings to force a download only once per day or week or month, etc.
And then there is just the good old standard caching headers expires and cache-control that you can use as well to force a fresh download every X period of time.

Related

How to properly manage an etag?

My SPA in ReactJS communicates to a backend coded in Python. They use Eve, and Eve sets an etag in its responses, so whenever trying to change some resource, an etag must be sent.
An ETag is a hash value representing the current state of the resource on the server. Consumers are not allowed to edit (PATCH or PUT) or delete (DELETE) a resource unless they provide an up-to-date ETag for the resource they are attempting to edit. This prevents overwriting items with obsolete versions.
What's the best way to manage the etag when trying to edit a resource?

How to secure file download?

I have an application written in angularjs and a dropwizard backend. All API calls are ajax, with the exception of file downloads, which is done by performing a redirect to a standard GET request.
All API calls are secured through a token which is passed as a Token header. We use SSL for all APIs.
The download GET request works but I'm having a hard time figuring out how to secure it. I have no way of setting a custom header, which is required to pass the token. So theoretically, I'm left with two options, clearly none of them acceptable: 1. Pass the token as one the GET parameters 2. Leave the download unsecured.
Any ideas how to secure file download?
Putting a secret token in a URL query parameter isn't great because URL tend to be leakable, for example through history/logging/referrers. There are ways to mitigate this: for example you could have the server side issue a download token that is only good for one use or for a limited amount of time. Or the client could pass a time-limited token created using a signature over the secret token that the server side could verify.
Alternatively you could, just for this one interface (eg path-limited, quitckly-expiring) put the token in a cookie.
Another approach is to download the whole file through AJAX, thus allowing you to set the header as normal. Then you have to present the content as a downloadable local resource, which requires a cocktail of browser-specific hacks (eg using data: or filesystem: URLs, and potentially links with the download attribute). Given the complication this isn't usually worth bothering with, especially if the file is very large which may present further storage constraints.

Caching & GZip on GAE (Community Wiki)

Why does it seem like Google App Engine isn’t setting appropriate cache-friendly headers (like far-future expiration dates) on my CSS stylesheets and JavaScript files? When does GAE gzip those files? My app.yaml marks the respective directories as static_dirs, so the lack of far-future expiration dates is kind of surprising to me.
This is a community wiki to showcase the best practices regarding static file caching and gzipping on GAE!
How does GAE handle caching?
It seems GAE sets near-future cache expiration times, but does use the etag header. This is used so browsers can ask, “Has this file changed since when it had a etag of X68f0o?” and hear “Nope – 304 Not Modified” back in response.
As opposed to far-future expiration dates, this has the following trade-offs:
Your end users will get the latest copies of your resources, even if they have the same name (unlike far-future expiration). This is good.
Your end users will however still have to make a request to check on the status of that file. This does slow down your site, and is “pure overhead” when the content hasn’t changed. This is not ideal.
Opting for far-future cache expiration instead of (just) etag
To use far-future expiration dates takes two steps and a bit of understanding.
You have to manually update your app to request new versions of resources, by e.g. naming files like mysitesstyles.2011-02-11T0411.css instead of mysitestyles.css. There are tools to help automate this, but I’m not aware of any that directly relate to GAE.
Configure GAE to set the expiration times you want by using default_expiration and/or expiration in app.yaml. GAE docs on static files
A third option: Application manifests
Cache manifests are an HTML5 feature that overrides cache headers. MDN article, DiveIntoHTML5, W3C. This affects more than just your script and style files' caching, however. Use with care!
When does GAE gzip?
According to Google’s FAQ,
Google App Engine does its best to serve gzipped content to browsers that support it. Taking advantage of this scheme is automatic and requires no modifications to applications.
We use a combination of request headers (Accept-Encoding, User-Agent) and response headers (Content-Type) to determine whether or not the end-user can take advantage of gzipped content. This approach avoids some well-known bugs with gzipped content in popular browsers. To force gzipped content to be served, clients may supply 'gzip' as the value of both the Accept-Encoding and User-Agent request headers. Content will never be gzipped if no Accept-Encoding header is present.
This is covered further in the runtime environment documentation (Java | Python).
Some real-world observations do show this to generally be true. Assuming a gzip-capable browser:
GAE gzips actual pages (if they have proper content-type headers like text/html; charset=utf-8)
GAE gzips scripts and styles in static_dirs (defined in app.yaml).
Note that you should not expect GAE to gzip images like GIFs or JPEGs as they are already compressed.

XAP Expires after half a Day?

Im just wondering what would be causing my xap to expire every half day (approx). What i mean is that in the morning a user hits the website and it downloads a copy of the xap, by the afternoon if that user goes back to the website and the website downloads another copy of the xap for them.
I would hope that the only reason that a user should need to download a new copy of the xap would be when they have cleared their browser cache or ive put a new copy up on the server.
Any ideas on what would be the problem and fix?
I ran fiddler on the XAP download and got the following lines from the cache tab of the xap download entry in fiddler.
HTTP/200 responses are cacheable by default, unless Expires, Pragma, or Cache-Control headers are present and forbid caching.
HTTP/1.1 ETAG Header is present: "2ad1d6bfdd43cb1:0"
HTTP Last-Modified Header is present: Tue, 24 Aug 2010 22:43:19 GMT
No Explicit HTTP Expiration information was provided. Most browsers utilize heuristic expiration policies:
10% of the delta between Last-Modified and Date is '02:53:34' so this response will heuristically expire 26/08/2010 4:39:26 PM.
Would this be what the problem is? Where do I set explicit HTTP expiration?
First thing to do is:-
install a copy of Fiddler.
Drop your temporary internet files.
Run Fiddler.
Visit your host web page.
Find the HTTP session in fiddler that represents the Xap download
Add the Raw response headers to your question above.
This will provide a very important set of clues to what the real problem is.
What happens when you refresh? Do you see the second XAP HTTP session return a status 304 response? If you get a 200 add the raw Request headers for this second attempt and its raw response headers to your question.
If you do get a 304, leave it for the appropriate amount of time then try again, is it still give a status 304? If not do the same as above.
This data will give us a lot of info to provide a diagnosis.
I think what HiTech Magic was hinting at was you need to be able to adjust this setting in IIS. From what Fiddler said it seems like your IIS does not have content expiration set, which I think is the default.
here is how to do it in IIS 6: http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/0fc16fe7-be45-4033-a5aa-d7fda3c993ff.mspx?mfr=true
here is how to do it in IIS 7:
h'ttp://technet.microsoft.com/en-us/library/cc770661(WS.10).aspx
If you're using ASP.Net (can you edit your post to let us know what your backend is?), try using Response.Cache.SetCacheability. There are some gotchas, tho.

What is the best way to ensure that web-page contents are redownloaded from your web-site instead of using cached temporary internet files?

I have noticed that when updating my web content files (in this case, a silverlight XAP file) the browser does not detect that the file has been updated, and continues to reads the locally cached file. These files will only be updated rarely, so reading from the cached temporary internet files should occur most of the time.
My question is whether there is a programmatic way to ensure that files are downloaded from the website, rather than read from the local cache, but only when these files have changed? Is there a widely accepted process for handling this scenario? I don't want every user of this web product to have to delete their temporary internet files when an update is installed.
These files will only be updated during the execution of an installer, so can I possibly programmatically set something to ensure that this will happen?
You can append a random number or datetime value to the querystring.
The problem occurs most of the time an AJAX call is made. To avoid taking values from the cache you can build a querystring.
Eg:
var xmlPath = "www.domain.com?vers="+new Date().getTime();+"";
Lots of programatic solutions so far. The solution however is to simply configure the ClientBin direcotry (or whatever folder you store your XAPs in) on the server.
Assuming IIS you need to explicitly specify the the ClientBin folder Expires Immediately. This will cause the correct cache configuration headers to be sent when the XAP is retrieved. In turn the browser will attempt to retireve the XAP each time its needed but in the vast majority of cases will simply get a 304 Unmodified response and it can continue to use its cached copy.
My guess is you are seeing the classic IE heuristic problem. In the absence of any cache configuration headers IE makes up its own mind whether to even bother to re-request a resource according to its own internal algorithms. By ensuring the correct expiry headers are sent IE will honor the servers instructions.
Edit
It seems that I need to make the operation of this approach clearer. This approach does not leave the XAP resource uncached and in need of fetching everytime its needed.
By specifying the Expire Immediately feature in IIS we get these headers in the Response:-
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Length: 22359
Content-Type: application/octet-stream
Last-Modified: Tue, 21 Jul 2009 11:59:28 GMT
ETag: "fe734cb3fa9ca1:1352"
This does not prevent the XAP from being cached it merely indicates the browser may not used the cached XAP without first requesting it from the server. Note the Last-Modified and ETag headers.
A subsequent request looks like this:-
GET /clientBin/SomeApp.xap HTTP/1.1
If-Modified-Since: Tue, 21 Jul 2009 11:59:28 GMT
If-None-Match: "fe734cb3fa9ca1:135a"
Host: myhost.com
The response is:-
HTTP/1.1 304 Not Modified
Cache-Control: no-cache
Last-Modified: Tue, 21 Jul 2009 11:59:28 GMT
Tag: "fe734cb3fa9ca1:135a"
This response carries no entity body, it gives the browser permission to go ahead and use the existing XAP in the cache.
If the XAP is large then it is possible that the browser will not actually cache it with the Cache-Control specified as no-cache. Hence it may actually be better to be more explicit.
Instead of using the Expires Immediately box use configure the Cache-Control header using the Custom header list. Specify:-
Cache-Control: max-age=0
This will cause the browser to cache large XAPs whilst immediately expirying them.
Your question is a little vague, as I don't know what tools you are using. I'll give examples in PHP.
You'll want to set the Cache-Control header to specify the max age that the file can be cached. The value is specified in seconds.
e.g.
<?php
header("Cache-Control","max-age=86400");
You would set this header before sending the XAP file to the user. 86400 seconds = 1 day.
Another alternative is to use different filenames for each version of the file. You can do this one of two ways.
Embedding a version # in the file name:
some_file_1_1.xap
some_file_1_2.xap
Or, my preference is to append the version number to the filename as a query string:
some_file.xap?20090719
some_file.xap?20090720
You would reference these files with the appropriate "version" number in your HTML, and when the version # changes, the browser considers this a change in filename and will force redownloading. You can use whatever you want for the "version" string - options may include: revision #, last modified datestring, etc.
If you decide to go with changing the filename on every revision, then I'd suggest using "far future" caching. Ensuring the file is cached for an insanely long time will decrease the load on your server. You can do this as shown above with PHP, and here's a few examples to do it with mod_expires in Apache 2.0.
ExpiresActive on
ExpiresByType application/x-silverlight-app “access plus 5 years”
FileETag none
I think you can do something like this as well: Obviously do this in a base class that each page will use. So create like a PageBase which inherits System.Web.UI.Page and have all your code behinds inherit from PageBase.
or do it in the Master Page.
protected void Page_Init(object sender, EventArgs e) {
Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
}

Resources