9

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.

Shawn
  • 10,931
  • 18
  • 81
  • 126

2 Answers2

2

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.

apsillers
  • 112,806
  • 17
  • 235
  • 239
  • At least my success with Dropbox rules out the possibility of an undocumented Chrome-enforced HTTPS requirement, which was one of my earlier guesses, since Dropbox worked equally well over HTTP and HTTPS. – apsillers Apr 30 '12 at 06:15
  • It's the strangest thing: I was about to try this out with various headers and see what difference it makes, but then the thing just worked on the first try, without any modification... I'll post back if I find out what I screwed up in the first attempt.. – Shawn May 02 '12 at 00:13
  • My only other theory is that the 1.1 CRX file needs to be named something different from the original 1.0 file? That's the only thing I can think of that I didn't check for and may have done differently in my tests. – apsillers May 03 '12 at 21:21
1

Since it gets your XML and doesn't update the extension it doesn't like something in your update xml probably. My best guess is that your 'appid' does not match the App ID of the installed Extension. On the page chrome://extensions view the 'ID' of the installed extension and verify that that value matches what is in the update.xml

  • Actually the problem is gone without me changing anything (that I know of). In other words, I solved it but I don't know how. You're theory makes perfect sense obviously, but I don't remember changing the appid so I can't confirm... – Shawn May 03 '12 at 20:57