Thursday, June 7, 2012

Tutorial on HTML5 Application Cache


INTRODUCTION

It's becoming increasingly important for web-based applications to be accessible offline. Yes, all browsers have caching mechanisms, but they're unreliable and don't always work as you might expect. HTML5 addresses some of the annoyances of being offline with theApplicationCache interface.
Using the cache interface gives your application three advantages:
  1. Offline browsing - users can navigate your full site when they're offline
  2. Speed - cached resources are local, and therefore load faster.
  3. Reduced server load - the browser will only download resources from the server that have changed.
The Application Cache (or AppCache) allows a developer to specify which files the browser should cache and make available to offline users. Your app will load and work correctly, even if the user presses the refresh button while they're offline.

THE MANIFEST FILE

The cache manifest file is a simple text file that lists the resources the browser should cache for offline access.


Referencing a MANIFEST file

To enable the application cache for an app, include the manifest attribute on the document's html tag:

<html manifest="example.appcache">
 ...
</html>
The manifest attribute should be included on every page of your web application that you want cached. The browser does not cache a page if it does not contain the manifest attribute (unless it is explicitly listed in the manifest file itself. This means that any page the user navigates to that include a manifest will be implicitly added to the application cache. Thus, there's no need to list every page in your manifest.
The manifest attribute can point to an absolute URL or relative path, but an absolute URL must be under the same origin as the web application. A manifest file can have any file extension, but needs to be served with the correct mime-type (see below).


<html manifest="http://www.example.com/example.mf">
 ...
</html>
A manifest file must be served with the mime-type text/cache-manifest.

Here we use tomcat server, so we need to configure tomcat to serve all manifest file (Say with *.manifest extension) with text/cache-manifest.

So we need to add the following xml data into “conf/web.xml” of the tomcat server.

<mime-mapping>
   <extension>manifest</extension>
   <mime-type>text/cache-manifest</mime-type>
</mime-mapping>


Structure of a MANIFEST file


A simple manifest may look something like this:
CACHE-MANIFEST:index.html
stylesheet.css
images/logo.png
scripts/main.js


This example will cache four files on the page that specifies this manifest file.


There are a couple of things to note:

  • The CACHE MANIFEST string is the first line and is required.
  • If the manifest file or a resource specified in it fails to download, the entire cache update process fails. The browser will keep using the old application cache in the event of failure.

Lets take a look at a more complex example:


CACHE MANIFEST
# 2010-06-18:v
# Explicitly cached 'master entries'.
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js

# Resources that require the user to be online.
NETWORK:
login.php
/myapi
http://api.twitter.com

# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg
*.html /offline.html

Lines starting with a '#' are comment lines, but can also serve another purpose. An application's cache is only updated when its manifest file changes. So for example, if you edit an image resource or change a javascript function, those changes will not be re-cached. You must modify the manifest file itself to inform the browser to refresh cached files. Creating a comment line with a generated version number, hash of your files, or timestamp is one way to ensure users have the latest version of your software. 


A manifest can have three distinct sections: CACHE, NETWORK, and FALLBACK.

CACHE:
This is the default section for entries. Files listed under this header (or immediately after the CACHE MANIFEST) will be explicitly cached after they're downloaded for the first time.
NETWORK:
Files listed under this section are white-listed resources that require a connection to the server. All requests to these resources bypass the cache, even if the user is offline. Wildcards may be used.
FALLBACK:
An optional section specifying fallback pages if a resource is inaccessible. The first URI is the resource, the second is the fallback. Both URIs must be relative and from the same origin as the manifest file. Wildcards may be used.


Example(Using tomcat server):

1. Total source files used in this example are 5 in number, 1 manifest file and few images.2. The directory structure maintained in tomcat(Using Eclipse IDE) is as shown:
3. Here “homePage.jsp” is the home page for this application. The source code is as shown below.
4. As it can be seen from the above html code, there are references to 2 different files like accordion.css, main.js & prototype.js. prototype.js is a javascript library used for ajax calls. The other two files are custom code for this application.

5. The content in the css file “accordion.css”is as follows : 



.accordion {
border-bottom: 1px solid #A6C8DB; margin: 1px; background: #b6c0d6; background: -moz-linear-gradient(top, #b6c0d6 0%, #e0e8f9 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #b6c0d6), color-stop(100%, #e0e8f9) ); background: -webkit-linear-gradient(top, #b6c0d6 0%, #e0e8f9 100%); background: -o-linear-gradient(top, #b6c0d6 0%, #e0e8f9 100%); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } .accordion input { border-bottom: 1px solid #A6C8DB; margin: 1px; background: #b6c0d6; background: -moz-linear-gradient(top, #b6c0d6 0%, #e0e8f9 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b6c0d6), color-stop(100%,#e0e8f9)); background: -webkit-linear-gradient(top, #b6c0d6 0%,#e0e8f9 100%); background: -o-linear-gradient(top, #b6c0d6 0%,#e0e8f9 100%); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } .accordion button { border-bottom: 1px solid #A6C8DB; margin: 1px; background: #b6c0d6; background: -moz-linear-gradient(top, #b6c0d6 0%, #e0e8f9 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b6c0d6), color-stop(100%,#e0e8f9)); background: -webkit-linear-gradient(top, #b6c0d6 0%,#e0e8f9 100%); background: -o-linear-gradient(top, #b6c0d6 0%,#e0e8f9 100%); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }



6. The content in “main.js” javascript file is as follows:

7. In the above javascript code, there is ajax call being made to “ajax/logos.jsp”. Code is as follows:
<%
int type=Integer.parseInt(request.getParameter("type"));
if(type==1){
%>
<table class="accordion" >
<tr>
<td><button onclick="displayInfo('mozilla')" type="button" style="width: 100px; height: 60px"><img src="images/mozilla.png"/>Mozilla</button></td>
<td><button onclick="displayInfo('chrome')" type="button" style="width: 100px; height: 60px"><img src="images/chrome.png"/>Chrome</button></td>
</tr>
<tr>
<td><button onclick="displayInfo('ie')" type="button" style="width: 100px; height: 60px"><img src="images/ie.png"/>IE</button></td>
<td><button onclick="displayInfo('safari')" type="button" style="width: 100px; height: 60px"><img src="images/safari.png"/>Safari</button></td>
</tr>
</table> <%
}
else{
%>
<table class="accordion" >
<tr>
<td><button onclick="displayInfo('android')" type="button" style="width: 100px; height: 60px"><img src="images/android.jpg" height="31px" width="30px"/>Android</button></td>
<td><button onclick="displayInfo('apple')" type="button" style="width: 100px; height: 60px"><img src="images/apple.jpg"/ height="31px" width="30px">Apple</button></td>
</tr>
<tr>
<td><button onclick="displayInfo('google')" type="button" style="width: 100px; height: 60px"><img src="images/google.jpg" height="31px" width="30px"/>Google</button></td>
<td><button onclick="displayInfo('micro')" type="button" style="width: 100px; height: 60px"><img src="images/micro.jpg" height="31px" width="30px"/>Microsoft</button></td>
</tr>
</table>
<% }
%>
<div style="display: none;" id="mozilla">
Mozilla is not a web browser!
Mozilla is a framework for building better web applications using web standards.
</div>
<div style="display: none;" id="chrome">
A Free Web Browser That Runs Apps & Websites With Lightning Speed.
</div>
<div style="display: none;" id="ie">
Internet Explorer 9 is Microsoft's most aggressive attempt yet at hanging onto its lead in the browser market.
</div>
<div style="display: none;" id="safari">
Safari for Mac and PC puts the emphasis on browsing not the browser. Innovative features make your experience on the web better than it ever was.
</div>
<div style="display: none;" id="android">
Android is a Linux-based operating system for mobile devices such as smartphones and tablet computers. It is developed by the Open Handset Alliance led by Google
</div>
<div style="display: none;" id="apple">
From Ipods to Iphones to MacBooks,Apple uses "think different" approach to reframe computing, communication and more.
</div>
<div style="display: none;" id="google">
Google's mission is to organize the world's information and make it universally accessible and useful.
</div>
<div style="display: none;" id="micro">
Microsoft's ambitions are anything but small. The world's #1 software company develops and sells a variety of products used by consumers and businesses.
</div>


8. Finally we come to the manifest file named in this example as “server.manifest”. The content of that file is as follows:


9. Call to ajax page is not cached and hence need a presence of internet or server. Other resources are cached.


EXPERIMENT REPORTS

HTML5 Application cache support in Desktop Browsers

Browsers
Loading page 1st time(Server Up)
Loading page 2nd time(Server up)
Loading page (Server down)
Comments or Observations
Internet Explorer 9PassPassFailIE 9 does not support Application Cache, it doesnot request for the manifest file Refer http://people.mozilla.com/~prouget/ie9/ for more information.
Mozilla Firefox 10PassPassPassIn offline mode, cached content renders properly except Ajax call
Google ChromePassPassPassIn offline mode, cached content renders properly except Ajax call
Apple Safari 5PassPassPassIn offline mode, cached content renders properly except Ajax call
Opera 11PassPassPassIn offline mode, cached content renders properly except Ajax call



Tomcat Server used to modify the server response and check behavior on desktop browsers
FIREFOXCHROMEOPERASAFARIIE
MF : not modified
Server Response Status : 304
CACHE ERROR event fired
no impact on rendering
works fineCACHE ERROR event fired
no impact on rendering
works finenot supported
MF : OBSOLETE
Response Status : 404, 410
appcache
deleted
appcache
deleted
appcache
deleted
appcache
deleted
not supported
MF : modified
Cache-Control : no-cache not specified
Not requesting for MFworks fineworks fineworks finenot supported
MF : modified
Cache-Control : no-store
works fineworks fineworks fineworks finenot supported


How to send 304 Not modified status:

  • First time when the server sends a response, it would send a Etag value in the header.
  • Second time when the page is loaded, the GET request will contain a header called “If-none-match” with the value of the Etag. The server then checks the value and validates it. If the content is changed, a fresh response is sent by the server or else 304 Not modified status is sent to the client page.

Manifest file and AJAX calls :

  • All ajax calls with query strings will not be put in the manifest file since we cannot calculate all possible permutations of the queries available
  • AJAX calls with request for a static resource without any query string is no different than any other request but phantomJS is still not putting the resource URL in the Manifest file. Need to check.
  • phantomJS only tracks requests which are made till the pageload event is triggered, we need to see the possibility of tracking the requests made after page load to track - static AJAX requests.

Viewing appcache contents on different browsers:

  • Google Chrome: Contents of the appcache can be viewed on the following link. chrome://appcache-internals/
  • Mozilla Firefox: Contents of the appcache can be viewed on the following link.
  • Safari : Press Ctrl+Alt-C. A debugger will open(Occupies quarter or half of the browser page). Click on the “Resources” tab. Then at the left-bottom end you should be able to see an option called “Application Cache”. Open the tree to view which all resources have been cached.
Note: In Chrome, Same approach used for safari can be used. But instead of “Ctrl+Alt+C”, press “Ctrl+Shift+C”.

Upper limit of the Application Cache:

According to the statistics collected from this site: http://www.sitepoint.com/diving-deeper-into-html5-offline-browsing/#fbid=xnTJtxdd5Kh
  1. Safari desktop browser (Mac and Windows) have no limit
  2. Mobile Safari has a 10MB limit
  3. Older versions of Chrome had a 5MB limit. Newer version has more.
  4. Android browser has no limit to ApplicationCache size
  5. Firefox desktop has unlimited ApplicationCache size
  6. Opera’s ApplicationCache limit can be managed by the user, but has a default size of 50MB

Drawbacks of Application Cache:

  1. XHR(XmlHttpRequest) cannot be cached. (In other words, Ajax pages)
  2. Basically POST is not an idempotent operation. So you cannot use it for caching. GET should be an idempotent operation, so it is commonly used for caching.

Conclusion on the observations made on different browsers:

  1. When the page is loaded for the second time, the manifest file is requested from the server and it is matched with the manifest file which was previously cached. If both are same, then previously cached contents will be rendered from cache itself. But all other white-list contents will be requested from the server.
  2. When the page is loaded in offline mode (Internet down or server down), the manifest file is requested from server and it fails. So the browser will render the webpage using the cached resources. All white-list contents will try to request server and fails.
  3. A snapshot of the Chrome’s web debugger requesting for manifest file(failing in offline mode) is as shown.

  1. Suppose say the page “homePage.jsp” is loaded for the first time in the browser. Based on the manifest file contents, the browser caches the resources. Before loading it for the second time, say there are few white spaces appended in the manifest file at the line where homePage.jsp is mentioned. Then the browser sends a request to the server for manifest file and compares it with the manifest file which was previously cached. Since white spaces are appended, the browser requests the server for the resource which it assumes that it would have changed at the server end. In this case, the browser requests only for homePage.jsp.

Please feel free to add comments on my blog post.

18 comments:

  1. WOW just what I was looking for. Came here by searching for Candida Infection
    Here is my blog ... Click Here

    ReplyDelete
  2. Hey There. I found your blog using msn. This is an
    extremely well written article. I'll be sure to bookmark it and return to read more of your useful info. Thanks for the post. I'll definitely comeback.
    Feel free to visit my weblog Vic Magary scammer

    ReplyDelete
    Replies
    1. Thank you very much for your nice comments Vic. :)

      Delete
  3. hey there and thanks in your information ? I have certainly
    picked up something new from right here. I did on the other hand expertise a few technical points the usage of
    this web site, since I skilled to reload the web site
    a lot of times prior to I could get it to load correctly.
    I have been wondering in case your web host is OK?
    No longer that I am complaining, however slow loading circumstances occasions
    will often affect your placement in google and can injury your quality rating if ads and marketing with Adwords.

    Well I'm including this RSS to my email and can glance out for a lot more of your respective exciting content. Ensure that you update this again very soon..
    My web-site :: Panic Away Review

    ReplyDelete
    Replies
    1. Hey, there are 2 things which i would like to ask you.
      1> Did you reload the webpage in the absence of server(In other words, stopping the server) for the second time?
      2> Where are you finding a problem with the example being explained in my blog post?

      I hope you have configured your tomcat server which can understand manifest file MIME type.
      I didn't understand the last point that you mentioned in your comment. Can you please elaborate a little on the problem you are facing, so that i could correct my post or i could help you in finding a proper solution.

      Delete
  4. I am really happy to read this blog posts which includes tons of valuable data, thanks for providing these kinds of data.
    Also visit my web blog : 12 Hour Cure for Yeast Infection

    ReplyDelete
  5. It's hard to find educated people about this topic, however, you sound like you know what you're talking about! Thanks
    Also visit my page - ipad video lesson buy

    ReplyDelete
  6. It's an remarkable piece of writing in support of all the online users; they will take advantage from it I am sure.
    Feel free to surf my web-site ... Trick Photography and Special Effects Review

    ReplyDelete
  7. Superb, what a weblog it is! This blog presents helpful information to us, keep
    it up.
    Also visit my webpage ... Clearblue

    ReplyDelete
  8. Very nice post. I certainly appreciate this site.
    Continue the good work!
    Stop by my blog post Thomas Coleman

    ReplyDelete
  9. If some one wishes expert view on the topic of running a
    blog then i propose him/her to go to see this webpage,
    Keep up the pleasant job.
    My web site - My Site

    ReplyDelete
  10. Hey very nice blog!
    My weblog ... Download Acne No More

    ReplyDelete
  11. Do you have any video of that? I'd love to find out more details.
    My page :: John Kelby Scammer

    ReplyDelete
  12. I found the solution.. Im trying with the application just undeployed from the server rather then actualy shutdown the server.

    ReplyDelete
  13. hello sir ...i m a b.tech student . just finished my 3rd year in IT stream . can u please help me in making a project . i have no idea on wht topic to make . please help me pls .

    ReplyDelete
  14. Hi,

    Its a good tutorial to start. I want to know how to make the cache page independent of its url just by its name. Suppose i make a page cache by test.php and in offline mode it work good. If i change the url as test.php?p=1 it does not work. I want to cache the page test.php with all the query string data generated dynamically.

    ReplyDelete
  15. Nice blog Very useful information is providing by ur blog. Great beginning html tutorials Very clear and helpful for beginners.

    ReplyDelete