Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't my chrome extension auto-updating itself?

I made a really basic chrome extension and set up a simple node.js server to test the auto-update feature. The server hosts the .crx file so I can install the extension without any trouble simply by visiting http://localhost:3000/clients/chrome/extension.crx. But when I go to tools->extensions and click on Update extensions now, the extension does not fetch the new version. The server does receive the request for localhost:3000/clients/chrome/updates.xml, but doesn't receive any request for the new extension.crx file. What am I doing wrong here?


CODE

Let me just walk you through the code to make this reproductible:

$ tree

.
|-- clients
|   `-- chrome
|       |-- extension
|       |   `-- manifest.json
|       |-- extension.crx
|       |-- extension.pem
|       `-- updates.xml
`-- web.js

The extension is really just a manifest file.

manifest.json

{
  "name": "testing auto-updates",
  "version": "1.0",
  "update_url": "http://localhost:3000/clients/chrome/updates.xml"
 }

As you can see, I'm referring to an update_url to make auto-updating possible.

updates.xml

<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
  <app appid='fkphbmkcjefhhnnlhhjlnkellidponel'>
    <updatecheck codebase='http://localhost:3000/clients/chrome/extension.crx' version='1.0' />
  </app>
</gupdate>

Packaging the extension creates extension.crx and extension.pem.

I also made a simple node.js server to serve the files:

web.js

var express = require('express');

var app = express.createServer(express.logger());

/* ROUTES */

app.get('/clients/chrome/extension.crx', function(request, response)
{
    response.contentType('application/x-chrome-extension');
    response.sendfile('clients/chrome/extension.crx');
});

app.get('/clients/chrome/updates.xml', function(request, response)
{
    response.sendfile('clients/chrome/updates.xml');
});

/* ROUTES END */

var port = process.env.PORT || 3000;

app.listen(port, function() {
  console.log("Listening on " + port);
});

Ok, let's test this. First, start the server:

$ node web.js

Listening on 3000

Install the extension by visiting http://localhost:3000/clients/chrome/extension.crx. This part works perfectly on the first try. The server logs the request:

127.0.0.1 - - [Thu, 26 Apr 2012 22:25:47 GMT] "GET /clients/chrome/extension.crx HTTP/1.1" 304 - "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/11.10 Chromium/18.0.1025.151 Chrome/18.0.1025.151 Safari/535.19"

Let's modify the extension:

  1. In manifest.json, set version to 1.1 (intead of 1.0).
  2. In updates.xml, set version to 1.1 (instead of 1.0).
  3. Re-pack extension using the same extention.pem file as the first time.
  4. The new extension.crx file is created.
  5. Click on Tools->Extensions->Update extensions now

One would expect to see the extension's version number change to 1.1 in Tools->Extensions.

Instead, nothing happens. The server receives a request for updates.xml but not for extension.crx.

like image 916
Shawn Avatar asked Apr 27 '12 01:04

Shawn


1 Answers

I think the error lies in how your web.js file serves updates.xml. Here's my reasoning:

  • I duplicated your setup and saw the same lack of updates.
  • Then I did a second test, using only my public Dropbox folder, and everything went perfectly.
  • Finally, I did two more tests: one with a Node-hosted updates.xml pointing to a Dropbox-hosted file, and another with a Dropbox-hosted updates.xml pointing to a Node-hosted crx file.

The results was that whenever updates.xml was served by Node, Chrome didn't update the extension correctly, and when updates.xml was hosted by Dropbox, everything when fine, regardless of who hosted the crx file. (And I did change the update_url in the manifest and rebuilt/uploaded the extension for each trial).

Exactly why this happens is still a pretty big mystery to me. Here are the HTTP response headers I get when I fetch updates.xml in Chrome (normally, using the address bar; I'm not sniffing the actual net traffic from the update operation, just simulating it):

Dropbox:

HTTP/1.1 200 OK
Server: nginx/1.0.14
Date: ...
Content-Type: application/xml
Transfer-Encoding: chunked
Connection: keep-alive
x-robots-tag: noindex,nofollow
etag: ...
pragma: public
cache-control: max-age=0
Content-Encoding: gzip

Node.js:

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/xml
Date: ...
Cache-Control: public, max-age=0
Last-Modified: ...
ETag: "..."
Accept-Ranges: bytes
Content-Length: 284
Connection: keep-alive

I thought also it might be a problem with ports (maybe Chrome doesn't like to update from non-80 ports?), and I've now just discovered that serving updates.xml and crx file from my own Apache server on port 80 causes breakage identical to the problem observed with Node.

I wish I had an actual answer for you, but maybe you can run some tests with Dropbox and finally discover what they're doing differently that makes Chrome like their update file.

like image 102
apsillers Avatar answered Sep 25 '22 16:09

apsillers