Introduction
This article is to show you how to create a new protocol for Mozilla Firefox browser. Mozilla Firefox supports the generic web protocols, such as HTTP and FTP and it also support protocols like Chrome of its own. It is sometime required to make a custom protocol for your project which will be plugged with the existing Firefox installation.
To create a new protocol, you�ll need to implement an XPCOM component. XPCOM is very similar to MS COM (and in this article basics of the XPCOM will not be covered, you can find so many good articles and online books on XPCOM). You can use JavaScript or C++ to implement XPCOM. I�ve found a very good article written by Doron Rosenberg which tells you how to build a new protocol for Mozilla by using JavaScript.
In this article we�ll use C++ to build the XPCOM for the protocol. The intension of this article is to give you a very simple sample of custom protocol written in C++ when ever you are in hurry to create a custom protocol for Mozilla Firefox and you can reuse most of the code and can concentrate on your logic about the functionality of your protocol rather than searching here and there about the basic framework of a Mozilla protocol.
One other place you can find implementation of protocol in C++ is in Mozilla�s site and it is a little bit complex and less documented.
What does this sample protocol do?
The sample for this article builds will be �find:� protocol which will use the user's default search engine to initiate a search, same as the �x-search:� protocol which Doron Rosenberg created in JavaScript.
When this protocol is installed in Mozilla Firefox, it can be called by typing
find:<search term>
Or
find:
into the URL bar and pressing enter.
How to install this protocol?
Just download the file �findprotocol.xpi� and open it with Mozilla Firefox. Firefox will install this as a new protocol. .xpi file is nothing but a .zip file renamed as .xpi.
Alternatively, you can copy the XPCOM which is a DLL file to �components� folder of existing Mozilla Firefox installation and then delete the �Compreg.dat� file from �C:\Documents and Settings\<user>\application Data\Mozilla\Firefox\Profiles\<wtimmm.default>" and restart Firefox, Firefox will register the new XPCOM DLL.
How to compile the source?
This sample is compiled with VC++ 6 with service pack 5 installed. You need to build Mozilla Firefox because after building the Firefox you�ll get all the headers and libs you need to create XPCOM. Building Mozilla is not a trivial task, you can find many guidelines on net to build Mozilla. After you build Mozilla it�ll product a folder called �Dist� which will contain all the libs and headers which are to be linked with your code to build this.
Note:- This code compiles cleanly without any warnings at the Warning level 3. It flashes warning at the Warning level 4.
Using the code
To create a new protocol, you have to implement nsIProtocolHandler
interface. The protocol handler is a class which implements nsIProtocolHandler
. It is responsible for returning basic information about the protocol to the network library (such as the default port and URI format) and for creating the appropriate type of channel to handle the request.
Here it is implemented in nsFindHandler.h:
#ifndef nsFindHandler_h___
#define nsFindHandler_h___
#include "nsIProtocolHandler.h"
#define FIND_PORT -1
#define NS_FINDHANDLER_CID \
{ 0x7F1D8DA4, 0x668F, 0x4c3c, \
{0xBD, 0x7B, 0xEA, 0x95, 0xB2, 0x8D, 0x5A, 0xD0} }
#define kPROTOCOL_CONTRACTID "@mozilla.org/network/protocol;1?name=find"
#define kIOSERVICE_CONTRACTID "@mozilla.org/network/io-service;1"
class nsFindHandler : public nsIProtocolHandler
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPROTOCOLHANDLER
nsFindHandler();
virtual ~nsFindHandler();
static NS_METHOD Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult);
private:
char *pStr;
};
#endif
The NS_FINDHANDLER_CID
should be unique; you can generate it with GUIDgen.exe.
Here is nsFindHandler.cpp.
#ifndef XP_WIN
#define XP_WIN
#endif
#include <Windows.h>
#include "nspr.h"
#include "nsFindHandler.h"
#include "nsIURL.h"
#include "nsCRT.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIProgressEventSink.h"
#include "nsNetCID.h"
#include "nsIIOService.h"
#include "nsIChannel.h"
#include "nsEmbedString.h"
#include "BuildSearchString.h"
static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
nsFindHandler::nsFindHandler() {
}
nsFindHandler::~nsFindHandler() {
}
NS_IMPL_ISUPPORTS1(nsFindHandler, nsIProtocolHandler);
NS_METHOD
nsFindHandler::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) {
nsFindHandler* ph = new nsFindHandler();
if (ph == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(ph);
nsresult rv = ph->QueryInterface(aIID, aResult);
NS_RELEASE(ph);
return rv;
}
NS_IMETHODIMP
nsFindHandler::GetScheme(nsACString &result) {
result = "find";
return NS_OK;
}
NS_IMETHODIMP
nsFindHandler::GetDefaultPort(PRInt32 *result) {
*result = FIND_PORT;
return NS_OK;
}
NS_IMETHODIMP
nsFindHandler::NewURI(const nsACString &aSpec,
const char *aCharset,
nsIURI *aBaseURI,
nsIURI **result) {
const char* data;
NS_CStringGetData(aSpec, &data);
pStr = _strdup( data );
nsresult rv;
nsIURI* url;
rv = CallCreateInstance(kSimpleURICID, &url);
if (NS_FAILED(rv)) return rv;
rv = url->SetSpec(aSpec);
if (NS_FAILED(rv)) {
NS_RELEASE(url);
return rv;
}
*result = url;
return rv;
}
NS_IMETHODIMP
nsFindHandler::NewChannel(nsIURI* aURI, nsIChannel* *result)
{
nsCOMPtr<nsIServiceManager> servMan;
nsresult rv=NS_GetServiceManager(getter_AddRefs(servMan));
if(NS_FAILED(rv))
{
MessageBox(0,"Service Manager failed...","Err",0);
return rv;
}
nsCOMPtr<nsIIOService> ioser;
rv=servMan->GetServiceByContractID("@mozilla.org/network/io-service;1",
NS_GET_IID(nsIIOService),getter_AddRefs(ioser));
if(NS_FAILED(rv))
{
MessageBox(0,"IO failed....","err",0);
return rv;
}
CBuildSearchString asStr;
char *strFinalURL;
asStr.BuildString (pStr,&strFinalURL);
free( pStr );
nsCOMPtr<nsIChannel> tempChannel;
ioser->NewChannel(nsEmbedCString(strFinalURL),nsnull,
nsnull, getter_AddRefs(tempChannel));
NS_ENSURE_TRUE (tempChannel, NS_ERROR_FAILURE);
*result =tempChannel.get();
NS_ADDREF(*result);
delete [] strFinalURL;
return NS_OK;
}
NS_IMETHODIMP
nsFindHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
{
if (port == FIND_PORT)
*_retval = PR_TRUE;
else
*_retval = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsFindHandler::GetProtocolFlags(PRUint32 *result) {
*result = URI_NORELATIVE | URI_NOAUTH | ALLOWS_PROXY;
return NS_OK;
}
Most of the code can be reused for your custom protocol.
There are four areas you may need to customize to use this for your protocol:
GetScheme
Change this to return the prefix that your protocol uses.
GetDefaultPort
Change this to return the default port that your protocol runs on. For protocols that do not use a port, you can return -1. This example doesn�t use any port so it is given -1.
NewURI
Here NS_SIMPLEURI_CID
is used, which parses simple URLs, such as those without a path. This function gets the whole typed URL. When ever user types �find://<anything>�, this function will be called by Firefox and the string will be on the first parameter of this function. Here is the code:
NS_IMETHODIMP
nsFindHandler::NewURI(const nsACString &aSpec,
const char *aCharset,
nsIURI *aBaseURI,
nsIURI **result) {
const char* data;
NS_CStringGetData(aSpec, &data);
pStr = _strdup( data );
NewChannel
You�ll have to return a channel here that is one pointer to nsIChannel
interface. This is the code from NewChannel
function:
nsCOMPtr<NSICHANNEL>
tempChannel;ioser->NewChannel(nsEmbedCString(strFinalURL),nsnull,
nsnull, getter_AddRefs(tempChannel));
NS_ENSURE_TRUE (tempChannel, NS_ERROR_FAILURE);
*result =tempChannel.get();
You can also implement nsIChannel
like the finger protocol example. There is another class used here in this sample, CBuildSearchString
, to extract the search term from the total URL and to build the final URL string.
Conclusion
I hope you guys find this sample helpful when you are going to prepare a protocol for Mozilla Firefox. You can contact me, if you have anything to ask or whatever.
Credits/Acknowledgements
- Mr. Brian Ryner, for the implementation of finger protocol. It is the only model protocol available on net which uses C++.
- Mr. Doron Rosenberg, for the simple implementation of a protocol in JavaScript.
- Mr. Prasadarao and Mr. Dileep C. George for building Mozilla Firefox.