|resources:||Home Installation Source Bugs Screenshots Roadmap RGTP URLs|
HOWTO: add a new protocol to Mozilla
STILL BEING WRITTEN.
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 "
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
@marnanel.org/archangel/client;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
So in our example:
This component should implement nsIProtocolHandler, which involves implementing these attributes and methods:
- 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 @mozilla.org/network/standard-url;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.
- The default port number assigned to the protocol. (Of course, users can pick their own port numbers using the
:portsyntax 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).
- 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.)
- Sum whichever of the following are relevant:
Identifier Value When to use
1 This protocol can't serve up documents which contain relative links.
2 This protocol has no concept of usernames or passwords.
4 Socks proxies (or, if
ALLOWS_PROXY_HTTPis 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. If you set this, you must set
boolean allowPort(port, scheme)
- The user can request an unusual port by adding
:portafter 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
onDataAvailablemethod, passing in the new pieces of data. (context also gets passed in that call, unchanged.)
- 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
- The length of the data that's coming in, if you know, or -1 if you don't.
- The MIME type of the data that's coming in.
- 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
- The owner of this channel. Not sure what good this is. Seems to work if you return null.
- Something to do with progress indicators and so on. Still trying to find out what. Seems to work if you return null.
- Don't know. Can anyone tell me? Works if you return null.