- From: Ian Hickson <ian@hixie.ch>
- Date: Fri, 24 Aug 2007 01:42:45 +0000 (UTC)
(If you reply, please only include one of the mailing lists in your reply. Thanks.) So I read through all the offline Web app discussions: http://www.whatwg.org/issues/#filesystem http://code.google.com/apis/gears/api_localserver.html http://www.campd.org/stuff/Offline%20Cache.html ...and various others. USER INTERACTION SCENARIOS It seems like we are talking about the following kinds of scenarios: 1. User goes to a page, then, without closing the page, goes offline and uses it, then goes back online and continues to use it. The page and its subresources are always at their most up-to-date. Interactions with the page while offline are synced to the server when going online. 2. User goes to a page, then closes the browser. User restarts the browser while offline, and goes to the page. User restarts the browser again while online, and goes to the page. The page and its subresources are always at their most up-to-date. Interactions with the page while offline are synced to the server when going online. 3. Same as 1 or 2, except that the user is not online for long enough to fully download the updated resources. The application doesn't stop working, it is still usable the second time the user is offline. OTHER NEEDS We also seem to have the following requirements: * Some way to specify what pages are needed while offline, even if the page doesn't link to it. * Some way to handle two offline Web apps both using the same secondary resource, if we have some sort of versioning scheme. (So you can update the two apps independently without breaking either despite them using the same resource.) * Resilience to updates -- if the page is open when you go online and there's an update pending, or when you go online just as you're loading the page (common with wireless networks, since you're likely to take a few seconds to connect and your browser is often ready beforehand) and there's an update pending. * Resilience to broken updates. (More than the reload button?) * There needs to be a way for the application to talk to the server without talking to the offline cache. * The API should be simple, both to authors on the client side, and to authors on the server side, and to the end user, and ideally to the implementors (and to me, the spec author!). QUESTIONS * Does an app have to be multiple top-level pages, or can we assume an app is a single page? (The idea below assumes single-page apps.) * Do we really need a way to ignore the query parameters when fetching and serving from cache when offline? (The idea below assumes not. I don't really understand the use case if the answer is yes.) * Do we really need a way to check the status of cookies when fetching pages? (The idea below assumes not, since the discussion earlier seemed to establish that wasn't necessary.) IDEA Ok so here's my idea based on the existing ideas, the comments on those ideas, and so forth. One of my main goals was keeping everything as simple as possible. My proposal is that we add a new attribute to the <html> element, which flags that the page is a Web app that wants to be pinned for offline execution and that when you next fetch the file or one of its subresources while online, it should try to update all the subresources atomically. <html application> This could either trigger the different behaviour automatically, or only when requested by the user, or we could say this applies to any page, but that the user must enable it, or we could provide an API which triggers this for the page. I kind of like the explicit attribute, though. For pages that say this: * If the page is already in cache, load the page and all its resources from the cache. * If the page is not in the cache, create a new cache for it and start storing it there. Then display it from the cache (loading incrementally, so the first load is indistinguishable to the user from any other load). * Any resources it uses go into the cache. Different applications (HTML files with <html application>) that use the same resources (even if they are on other domains) result in multiple conceptual copies in different (per-app) caches, and with updates (see below) they can end up being at different revisions. This ensures that an application always has one coherent set of files from the time of its last update, with none of its components updating unexpectedly. The main UA cache should always have the latest file that was fetched, so if you visit the URL directly while offline you could see a different version than the version that a particular Web app sees. Web developer tools might offer a way to pick which app cache to use when looking at files for debugging. * The cache ignores cache expiration headers, keeping all content even when it is stale, though the headers are still used when contacting the server to update data, as described below. * Any requests other than GET always bypass the webapp cache. * Every time a file is accessed from the cache, if you're online, check that the file hasn't changed. (Possibly this could be rate-limited.) This would use normal (conditional) HTTP GET requests. Possibly, also check the main app's page for changes. * If the file has changed and is returning a 200 response, then create a new cache and a browsing context in the background. Save the new file to that cache, then load the main page in that browsing context, saving everything to the new cache. While that page is loading, the UA should indicate "downloading new version..." somewhere. If the download succeeds, and the page has an <html application> attribute, wait until that page is ready (onload="" has fired). Then, fire a "newversion" event at the body element of the page in the browsing context that the user is interacting with, passing a handle to the 'window' in the background. The page has three choices: * invoke location.reload(), which swaps in the next cache then reloads the page. * invoke a method to swap in the new cache without reloading, in which case the author is responsible for updating running scripts, etc -- this could be dangerous, as the page could end up unusable, the user could just reload... Is that good enough? * ignore the event, in which case the UA shows an infobar saying there's an update available and offering the user the option of reloading the page and warning about losing any unsaved changes. Then, blow away the background browsing context. The background browsing context is useful for two things: 1. it allows for script to decide which files to include as well as allowing the UA to download all the images, stylesheets, etc, that it finds the page using; 2. it allows for the new page to communicate to the old page before the old page decides whether to self-destruct or to stay up but just have its cache swapped out from under it. * If the update fails -- that is, if there are any DNS problems, or if any of the resources returned a 4xx or 5xx code, or if the UA went offline while downloading pages, then the download was not successful. The UA should alert the user to this fact somehow (infobar maybe) -- "An error occurred while updating the application. (( View details )) [x]" -- and then wait a few minutes (or longer if it can tell it'll fail again) before trying again. * If the update fetches a top-level page that doesn't have an <html application> header, then inform the user, e.g. an infobar saying something like "This application may no longer be available. (( View new page in a new window )) (( Delete application from cache )) (( Keep application in cache and check for updates later )) [x]". The first of these buttons would just show the background browsing context in the foreground. The second would delete the webapp cache and reload the page from the normal cache, and the third would just not do anything special. (None of the proposals I've seen really handle the case of the Web app being no longer available. This handles it for this proposal, but maybe there are better ways. Also, maybe we should do this for 404 and/or 410 responses too.) * Modal alerts (window.alert, .prompt, etc) in the background page can either raise an exception, be ignored, drop a message to a console, or possibly display a message over the top of the foreground app's browsing context. It doesn't really matter so long as we define it. * When a file is fetched by the main page loading in a background browsing context, the loads are conditional loads, so that files that haven't changed since the previous update are directly copied from the old cache. * The user hitting Reload always blows away the cache and starts over. * We provide not much of an API: * a method to add a file to the cache programatically (or check it for changes if it is already there; if there are changes, the above procedure for updating will go into play). (Asynchronous, but delays the 'load' event if called during load.) * a method for a Window to tell if it's running normally or if it's running as part of a background process updating itself. * When you navigate away from the top-level page, the cache is closed and kept for later (though UAs could still expire them if left unused, like cookies, databases, etc, could be expired too). Comments? -- Ian Hickson U+1047E )\._.,--....,'``. fL http://ln.hixie.ch/ U+263A /, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Received on Thursday, 23 August 2007 18:42:45 UTC