Vendor-provided user agent extensions are gone… now what do we do?

Scenario: A corporate extension modifies the user agent by a general.useragent.extra.foo preference. The sole purpose is for the web page to know whether that extension’s installed or not.

With Firefox 4.0, that’s no longer practical. Someone helpfully removed support for adding extra parameters to the user agent string. So now, the corporate office finds itself in a pickle.

We need some other way of informing a web page that our extension is enabled. (Not every web page, though – a selective list.) So far, we’ve considered a few options:

  • Set the general.useragent.override preference. This is just wrong
  • Adding a new HTTP header
  • Injecting a node into the target web page.
  • Firing a custom DOM event at the target web page.

I’d like your recommendations on the best way for a chrome extension to notify a web page of its existence (or non-existence). If it’s one of the three options above, please say which one. If you have your own ideas, please post them as a reply, with reasoning behind it.

Please, no comments suggesting we should never, ever inform a web page of our extension’s existence. If we develop both the webpage and the extension, knowing the extension’s there can be really important.

16 thoughts on “Vendor-provided user agent extensions are gone… now what do we do?”

  1. I’m glad you’re no longer broadcasting the extension’s existence to every web site!
    A site-specific header, DOM event, or injected JS object would all work. I wouldn’t recommend injecting a node into the document tree; that seems complicated and the timing is likely to be fragile.
    For one of my own extensions, I inject a JS object from a content-document-global-created observer. It works quite well on trunk.

  2. I personally like the HTTP header idea (and I use it).
    I like that I can make it only show up on the pages I want it to or all pages.
    I like that it’s easily read server side, so web pages can make early decisions based on it.

  3. If the set of pages that need this information can be known in advance and wired into the extension, then I would go with the custom HTTP request header, since this presents the information to server-side scripts with minimal hassle. If it’s a dynamic set, so that pages need to notify the extension of their interest, then I’d go with the custom DOM event, and make sure that everything that depended on it was expressed as client-side scripts.

  4. An HTTP header makes most sense to me. It’s unlikely to break any existing code, plus it more easily allows for server side logic to make decisions based on the existence of the extension.

  5. The point of the removal of arbitrary UA string appending was that it was announcing everything to everyone, usually for no good reason, and causing privacy issues or sometimes outright breaking things in the process. Having an extension talk to just the pages it needs to talk to, on the other hand, is good.
    My opinion: go with the custom event route. It’s simple and not only could you only send the event to pages that could need it, but the page could decide for itself if it needs the extension in return rather easily.
    The HTTP header route also might make sense, but again, only if only sent to the servers that actually need it. You’d also want to make sure to only send it once, rather than with every HTTP request if you can. If you’re going to handle things in the client-side page, I’d suggest the custom event instead.
    The node injection route could be problematic as you’re actually modifying the DOM rather than just sending a message. If the DOM you’re modifying changes you might accidentally introduce a problem. Might be able to do it, but events and header lines sound safer.

  6. How about just defining a property named myCoolExtensionIsInstalled or whatever on the window for the relevant web page(s)?

  7. Don’t modify the UA string. We removed that capability for a reason. 🙂
    If you want to advertise your extension to a particular domain, use a cookie — see nsICookieManager2.add. Then listen for the notifications described in nsICookieService.idl. You’ll need to listen for the “deleted”, “changed”, “cleared”, and “batch-deleted” data values so you can re-set your cookie if one of those occurs. (For instance, when the user clears cookies, or a regular purge takes place.)

  8. Adding a new HTTP header works great as long as you only need the extension to work in firefox. Some browsers don’t give you access to headers in extensions.
    Custom DOM events work pretty well, but only being able to sniff in the client loses a lot of flexibility in comparison to sniffing in your server code.
    For long term supportability I’ve found that moving extension interactions into a javascript api that is exported by the extension (and stubbed out by pure js if the extension isn’t installed) has been the real winner.

  9. Well, the DOM Event approach seems reasonable. Or adding some object exposed to the content script (I don’t know if it is possible add such an element only to specific sites easily). But that would be only accessible client side, not server side.
    You could also also observe the http-on-modify-request topic and modify the UA there (get/setRequestHeader) or set an extra header. You can check nsIChannel.URI to see if you should modify/add headers.
    Exposing the existence of such an extension to the whole world, not just the intranet or any other specific target audience sites, isn’t the best thing to do anyway…

  10. My bank uses something like this for FF: <embed name=”name” type=”application/sign-plugin” hidden=”true”></embed> and then it tries to run some custom method provided by that object (that method returns version number, status, etc…). For IE it uses the same logic and activex “object” instead of “embed” and for other browsers – java applet.

  11. My vote for the cookie, as Dan Witte suggested.
    If your extension has a firstrun URL (a webpage that is opened when the extension is installed), the website can even set the cookie itself, so no toolbar changes (using Mozilla cookies API) necessary.
    Note that an HTTP header defeats the purpose of UA string restrictions. Oanopticlick or any other site (your competitor?) could still use this header to identify your users.
    Custom events are ugly. Avoid them whenever possible.

  12. The HTTP header approach has two advantages: 1. It’s electrolysis-agnostic 2. You can detect it server-side. (If you’re really clever you can probably override the UA header just for that one server.)
    I don’t like the node injection idea, but the global object injection would make it easy for your page to communicate with your extension.
    As for firing a custom DOM event, you would be better off getting the page to fire the event at the browser for the extension to intercept.

Comments are closed.