HOWTO: add a new protocol to Mozilla


Prerequisite: Some idea about component-based architecture, and XPCOM in particular.

Overview: This document gives an overview of the process needed to implement a new protocol handler in Mozilla, so that you can make it recognise new kinds of URL. (For example, you might invent a protocol called penguin. Then users would be able to retrieve some kind of document by entering URLs such as "penguin://antarctica/").

You do this by creating two components: a protocol handler and a channel. The protocol handler is Mozilla's one-stop shop for information about your protocol. When the user asks for a URL from your protocol, Mozilla will ask the protocol handler to return a channel, which is a component which can be repeatedly polled to retrieve more and more of the document.

I'm not an expert. This document may contain mistakes, though I hope it doesn't. If you find any, please let me know.

Note about Archangel: Archangel's back end is a component;1, with the interface nsIReverseGossip. This means that all the details of RGTP are kept separate from the implementation of the rgtp: protocol, which lives in the file archangel-protocol.js. You might like to follow through that file as you read this document.

The protocol handler in detail: Define a component with the contract ID;1?name=protocol
So in our example:;1?name=rgtp

This component should implement nsIProtocolHandler, which involves implementing these attributes and methods:

nsIChannel newChannel(uri)
Returns a channel which can serve the document which uri points at. See below for how to make the channel.
nsIURI newURI(original, charset, baseURI)
Returns an nsIURI object created from a string. Mostly you can just instantiate an;1 and let it do the work for you. If baseURI is set, the string is relative to another URI, which is a pain in the neck.
long defaultPort
The default port number assigned to the protocol. (Of course, users can pick their own port numbers using the :port syntax in the URL, but this is what they get if they don't.) If port numbers don't make sense with this protocol, either use -1 or use a dummy value. (Venkman's protocol "x-jsd" uses 2206, a reference to Ghostbusters).
ACstring scheme
The name of this scheme, the same as protocol in the contract ID. (I'm not sure why this is needed, because you already know the protocol if you've got this far. But there it is.)
long protocolFlags
Sum whichever of the following are relevant:
Identifier Value When to use
URI_NORELATIVE 1 This protocol can't serve up documents which contain relative links.
URI_NOAUTH 2 This protocol has no concept of usernames or passwords.
ALLOWS_PROXY 4 Socks proxies (or, if ALLOWS_PROXY_HTTP is also set, HTTP proxies) know how to deal with this protocol. If you set this, but you don't set ALLOWS_PROXY_HTTP, your component will need to implement nsIProxiedProtocolHandler as well, which is beyond the scope of this document.
ALLOWS_PROXY_HTTP 8 See ALLOWS_PROXY. If you set this, you must set ALLOWS_PROXY too.
If none are relevant, use zero ("URI_STD").
boolean allowPort(port, scheme)
The user can request an unusual port by adding :port after the hostname in the URL. However, there are certain ports that Mozilla usually won't let the user request for security reasons. This lets you override that and let the user make a request on a potentially unsafe port.

The channel in detail: The channel doesn't have to have a contract ID, because it's never requested by name, only supplied by protocol handlers. It should implement nsIChannel, though if you want to do anything particularly funky you may want to descend a new kind of channel (like nsIFTPChannel) with any extra stuff you need.

The methods and attributes you need to implement are the ordinary nsIChannel ones:

void asyncOpen(listener, context)
This should make listener (an nsIStreamListener) the place to send bits of the document as they come in. You should call its onDataAvailable method, passing in the new pieces of data. (context also gets passed in that call, unchanged.)
nsIInputStream open()
Don't bother implementing this. It's optional, can't be used in a lot of places, and callers will always use asyncOpen() instead if this isn't present. Instead, just throw NS_ERROR_NOT_IMPLEMENTED.
long contentLength
The length of the data that's coming in, if you know, or -1 if you don't.
ACString contentType
The MIME type of the data that's coming in.
ACString contentCharset
The charset of the data that's coming in, if applicable. (What format is this supposed to be in?)
The URI used to construct this channel. You can return the one that was passed to the protocol handler's newChannel().
nsIChannel owner
The owner of this channel. Not sure what good this is. Seems to work if you return null.
nsIChannel notificationCallbacks
Something to do with progress indicators and so on. Still trying to find out what. Seems to work if you return null.
nsISupports securityInfo
Don't know. Can anyone tell me? Works if you return null.

History of this page

The archangel project can be contacted through the mailing list or the member list.
Copyright © 2000-2020. All rights reserved. Terms of Use & Privacy Policy.