Click here to Skip to main content
15,860,972 members
Articles / Desktop Programming / MFC
Article

Creating a new protocol for Mozilla Firefox in C++

Rate me:
Please Sign up or sign in to vote.
4.31/5 (12 votes)
18 Feb 20054 min read 94K   1.2K   32   15
New protocol for Firefox.

Sample Image - FirefoxProtocol.jpg

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://<search term>

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 


//this is the UUID
#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 methods:
    nsFindHandler();
    virtual ~nsFindHandler();

    // Define a Create method to be used with a factory:
    static NS_METHOD Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult);

private:
 

    char *pStr;//for holding the total url typed
};

#endif /* nsFindHandler_h___ */

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;
}
    
////////////////////////////////////////////////////////////////////////////////
// nsIProtocolHandler methods:

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, // ignore charset info
                         nsIURI *aBaseURI,
                         nsIURI **result) {
     
    

    const char* data;
    NS_CStringGetData(aSpec, &data);

    //Copy the whole url in pStr
    pStr = _strdup( data );


    //standard implementation
    //***********************************
     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;
 }

//******************************************************
//function:- NewChannel
//This is the most important function 
//You'll have to return a Channel(pointer
//of nsIChannel, so that the protocol works
//******************************************************
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;
    }

    //Create a smart pointer to  nsIIOService
    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;
    }


    //We need to extract the search
    //term from the total typed url
    CBuildSearchString asStr;



    char  *strFinalURL;
    //get the final searching url
    asStr.BuildString (pStr,&strFinalURL);

    free( pStr );

        
    //create a new channel
    nsCOMPtr<nsIChannel> tempChannel;

    ioser->NewChannel(nsEmbedCString(strFinalURL),nsnull, 
                                       nsnull, getter_AddRefs(tempChannel));

    NS_ENSURE_TRUE (tempChannel, NS_ERROR_FAILURE);

    //Now the Channel is returned
    *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, // ignore charset info
                             nsIURI *aBaseURI,
                             nsIURI **result) {
         
        const char* data;
        NS_CStringGetData(aSpec, &data);
    
        //Copy the whole url in pStr
        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:

    //create a new channel
        nsCOMPtr<NSICHANNEL> 
    
        tempChannel;ioser->NewChannel(nsEmbedCString(strFinalURL),nsnull, 
                                        nsnull, getter_AddRefs(tempChannel));
    
        NS_ENSURE_TRUE (tempChannel, NS_ERROR_FAILURE);
    
        //Now the Channel is returned
        *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

  1. Mr. Brian Ryner, for the implementation of finger protocol. It is the only model protocol available on net which uses C++.
  2. Mr. Doron Rosenberg, for the simple implementation of a protocol in JavaScript.
  3. Mr. Prasadarao and Mr. Dileep C. George for building Mozilla Firefox.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
India India
Anindya Sengupta is a Software Developer from the eastern part of India, working on C/C++/VC++/MFC/COM/ATL/DirectX. When he is not writing code he may be listening to some songs of R.E.M or Green Day.

Comments and Discussions

 
General#error: Internal string headers are not available from external-linkage code. Pin
Urbanique12-Aug-09 2:55
Urbanique12-Aug-09 2:55 
Questioncompile in linux? Pin
ianopolous123426-Oct-07 12:52
ianopolous123426-Oct-07 12:52 
Generalmozilla 2.0.0.X and up Pin
suiram4024-Oct-07 6:55
suiram4024-Oct-07 6:55 
GeneralLanuch application from a given path Pin
nvngyl24-Apr-07 21:16
nvngyl24-Apr-07 21:16 
GeneralRe: Lanuch application from a given path Pin
anindya_sengupta25-Apr-07 19:19
anindya_sengupta25-Apr-07 19:19 
Why not? Use ShellExecute or CreateProcess from NewChannel with which exe u want to spwan...
GeneralRe: Lanuch application from a given path Pin
nvngyl25-Apr-07 20:17
nvngyl25-Apr-07 20:17 
GeneralGecko can be used to create an XPCOM Component Pin
angzi198417-Jan-07 15:21
angzi198417-Jan-07 15:21 
GeneralRe: Gecko can be used to create an XPCOM Component Pin
pvogel16-Mar-07 13:29
pvogel16-Mar-07 13:29 
QuestionCompilation error Pin
nishantsaxena16-Oct-05 22:45
nishantsaxena16-Oct-05 22:45 
QuestionCompilation error Pin
nishantsaxena16-Oct-05 22:44
nishantsaxena16-Oct-05 22:44 
AnswerRe: Compilation error Pin
anindya_sengupta8-Dec-05 2:40
anindya_sengupta8-Dec-05 2:40 
Generalcan't compile Pin
araud14-May-05 4:02
araud14-May-05 4:02 
GeneralRe: can't compile Pin
Anonymous15-May-05 19:00
Anonymous15-May-05 19:00 
GeneralUnsafe code Pin
Rolf Schaeuble19-Feb-05 6:40
Rolf Schaeuble19-Feb-05 6:40 
GeneralRe: Unsafe code Pin
anindya_sengupta20-Feb-05 20:10
anindya_sengupta20-Feb-05 20:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.