[widgets] Automatic updates attempt 2

Taking into consideration the feedback we received last time, here is
a new strawman proposal for automatic updates. The proposal provides
four ways to do automatic updates:

1. Point directly to the resource on the web (and let HTTP headers and
cache control take care of the update).
2. Point to an XML file written in our custom XML format (described below).
3. From local storage
4. API call

Here is how it works in the case of 1:

In the configuration document, the author provides an <update> element
with a URL attribute that points to a widget resource. The author
optionally includes an etag attribute that represents the ETag for
that resource on the server:

<widgets xmlns="..."
 id="http:/a.com/myWidget"
>
 <update url="http:/a.com/myWidget.wgt" etag="36f4d2e876c5c51:b74"/>
</widgets>

If the author provides an etag attribute, then the widget user agent
checks for a change in the ETag via a HEAD request (following any
redirects).  If the etag has not changed, the server responds with a
304. If the ETag has changed, then the user is asked if they want to
download the new widget.  If the user wants the new version, then a
GET request is sent and the widget user agent stores the new ETag and
other relevant caching information (just like a web browser would
treat a resource). For future requests, the widget user agent can try
If-Match or If-Modified-Since or If-None-Match. The widget engine
accepts only "application/widget" as the content-type, though, as
already stated, it can be redirected to reach the appropriate
resource.

If the configuration document of the newly acquired widget contains
the same <update url> in canonical form, but a different etag
attribute value from the ETag: header acquired over HTTP, then the
etag attribute is in error and must be ignored. The ETag: value
acquired from HTTP is used for all future requests until a new widget
resource becomes available. (This is to stop the widget engine getting
into an update loop).

If the newly acquired resource contains a url attribute to a different
update location, then the widget engine again informs the user that a
new  version is available... the process repeats until no more updates
can be performed (or until the user gets bored of the update
process:)).

If no etag attribute is provided in the configuration document, the
widget is run as normal. The widget user agent may eventually ask the
the user if they want to update the widget. Once the first update is
done, the widget user agent should have enough cached info to manage
future updates.

Note: In the absence of an etag attribute, an alternative could be to
get the time of creation of the signature.xml or config.xml or a
(default) start file inside the widget resource (denoted by the 'last
mod file time/last mod file date' fields of a file entry), and use
that value for If-Modified-Since... but that might be a bit messy.

Issue: if upon download the server does not provide an etag (or other
relevant cache info), then should the widget user agent stop
attempting to download new versions?

---
And here is how it works in the case of 2 (using a custom XML format):

In the configuration document, the author provides an <update> element
that points to some URL:

<widgets xmlns="..."
 id="http:/a.com/myWidget" >
  <update url="http:/a.com/myWidget/updater.php?version=1.0"/>
</widgets>

The widget sends a request:

GET /myWidget/update.php?version=1.0
Host: a.com
User-Agent: SuperWidgetEngine
Accept: text/xml; application/widget
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7

If no update is available, server responds with a 304. Otherwise,
server responds:

HTTP/1.1 200 OK
Date: Tue, 27 May 2008 06:02:05 GMT
Content-Type: text/xml;
Content-Length: 370

<?xml version="1.0" encoding="utf-8"?>
<update xmlns="http://www.w3.com/ns/widget-updates"
 id="http:/a.com/myWidget"
 src="https://a.com/myWidget/v1.1b/awesome.wgt"
 version="1.1 beta (awesome edition)"
 bytes="1024">
     <details>We fixed some bugs and added some new APIs!</details>
     OR
     <details url="http://www.bla.com/myWidget/1.1/whatsnew"/>
     <hash type="SHA1">e56b8ec42e1898559cc9f04dfe09f1b1663a4b97</hash>
</update>

So, the widget engine then checks that <update id> matches <widget
id>and that <widget version> and <update version> are *different*. If
so,
then the user is informed that a new update is available by displaying
the content of <details>, the new version number, and the value of the
bytes attribute. If the user agrees to download the new widget, then
the widget user agent attempts to retrieve the resource indicated by
the src attribute of the update element.

Once the new resource is downloaded, if the author provided the
optional <hash> element, then the hash is calculated (using either MD5
or SHA1, as indicated by the type attribute). If all goes well, then
the widget resource is processed as normal, checking that the <widget
id> for the widget stays the same.  If all goes the place, the old
widget is either backed up or erased and the new widget takes its
place. Any previously set preferences are kept.

In the case of 3 (local storage), the widget user agent just needs to
compare the id and version of the widget the new widget to the widget
it is replacing.

Lastly, in the case of 4 (API call), widgets can attempt to update
themselves by calling the widget.update() method, which is defined in
the Widgets API spec. The method takes no arguments, and uses the
value of <update url> to ask the widget engine to attempt to perform
an update. Widget engines can control the update process by making use
of cache information or throttling, etc.

--
Marcos Caceres
http://datadriven.com.au

Received on Wednesday, 28 May 2008 08:41:23 UTC