Bug 391279 - Allow createInstance to work for web handlers. r=cbiesinger, sr=dmose
authorsdwilsh@shawnwilsher.com
Tue, 14 Aug 2007 09:47:41 -0700
changeset 4630 15fb12b75e014d5096ad871e6ed32c2637631929
parent 4629 68cd5cee48aec005644dad1380edd3c688badea5
child 4631 cab656b9f44b7135f05f5c32d38cee0d39405f9c
push idunknown
push userunknown
push dateunknown
reviewerscbiesinger, dmose
bugs391279
milestone1.9a8pre
Bug 391279 - Allow createInstance to work for web handlers. r=cbiesinger, sr=dmose
browser/installer/unix/packages-static
browser/installer/windows/packages-static
docshell/build/nsDocShellModule.cpp
netwerk/mime/public/nsIMIMEInfo.idl
uriloader/exthandler/Makefile.in
uriloader/exthandler/nsCExternalHandlerService.idl
uriloader/exthandler/nsExternalHelperAppService.cpp
uriloader/exthandler/nsHandlerAppImpl.cpp
uriloader/exthandler/nsHandlerAppImpl.h
uriloader/exthandler/nsLocalHandlerApp.cpp
uriloader/exthandler/nsLocalHandlerApp.h
uriloader/exthandler/nsWebHandlerApp.js
uriloader/exthandler/tests/unit/test_handlerService.js
--- a/browser/installer/unix/packages-static
+++ b/browser/installer/unix/packages-static
@@ -232,16 +232,17 @@ bin/components/libbrowsercomps.so
 bin/components/txEXSLTRegExFunctions.js
 bin/components/nsLivemarkService.js
 bin/components/nsTaggingService.js
 bin/components/nsDefaultCLH.js
 bin/components/nsContentPrefService.js
 bin/components/nsContentDispatchChooser.js
 bin/components/nsHandlerService.js
 bin/components/nsScriptableIO.js
+bin/components/nsWebHandlerApp.js
 
 ; Modules
 bin/modules/*
 
 ; Safe Browsing
 bin/components/nsSafebrowsingApplication.js
 bin/components/safebrowsing.xpt
 bin/components/nsUrlClassifierListManager.js
--- a/browser/installer/windows/packages-static
+++ b/browser/installer/windows/packages-static
@@ -232,16 +232,17 @@ bin\components\brwsrcmp.dll
 bin\components\txEXSLTRegExFunctions.js
 bin\components\nsLivemarkService.js
 bin\components\nsTaggingService.js
 bin\components\nsDefaultCLH.js
 bin\components\nsContentPrefService.js
 bin\components\nsContentDispatchChooser.js
 bin\components\nsHandlerService.js
 bin\components\nsScriptableIO.js
+bin\components\nsWebHandlerApp.js
 
 ; Modules
 bin\modules\*
 
 ; Safe Browsing
 bin\components\nsSafebrowsingApplication.js
 bin\components\safebrowsing.xpt
 bin\components\nsUrlClassifierListManager.js
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -50,17 +50,17 @@
 
 // uriloader
 #include "nsURILoader.h"
 #include "nsDocLoader.h"
 #include "nsOSHelperAppService.h"
 #include "nsExternalProtocolHandler.h"
 #include "nsPrefetchService.h"
 #include "nsOfflineCacheUpdate.h"
-#include "nsHandlerAppImpl.h"
+#include "nsLocalHandlerApp.h"
 
 // session history
 #include "nsSHEntry.h"
 #include "nsSHistory.h"
 #include "nsSHTransaction.h"
 
 // global history
 #include "nsGlobalHistoryAdapter.h"
--- a/netwerk/mime/public/nsIMIMEInfo.idl
+++ b/netwerk/mime/public/nsIMIMEInfo.idl
@@ -217,33 +217,33 @@ interface nsIHandlerApp : nsISupports {
      * Human readable name for the handler
      */
     attribute AString name;
 };
 
 /**
  * nsILocalHandlerApp is a local OS-level executable
  */
-[scriptable, uuid(e21f3d75-9103-490e-bfb9-1bf09cc3f103)]
-interface nsILocalHandlerApp: nsISupports {
+[scriptable, uuid(9812be73-273c-478c-8170-c3e0db08ae7c)]
+interface nsILocalHandlerApp : nsIHandlerApp {
 
     /**
      * Pointer to the executable file used to handle content
      */
     attribute nsIFile executable;
 };
 
 /**
  * nsIWebHandlerApp is a web-based handler, as speced by the WhatWG HTML5
  * draft.  Currently, only GET-based handlers are supported.  At some point, 
  * we probably want to work with WhatWG to spec out and implement POST-based
  * handlers as well.
  */
-[scriptable, uuid(065cd099-2f71-4ac8-9dab-17fc079e9647)]
-interface nsIWebHandlerApp: nsISupports {
+[scriptable, uuid(7521a093-c498-45ce-b462-df7ba0d882f6)]
+interface nsIWebHandlerApp : nsIHandlerApp {
 
     /**
      * Template used to construct the URI to GET.  Template is expected to have
      * a %s in it, and the escaped URI to be handled is inserted in place of 
      * that %s, as per the HTML5 spec.
      */
     attribute AUTF8String uriTemplate;
 };
--- a/uriloader/exthandler/Makefile.in
+++ b/uriloader/exthandler/Makefile.in
@@ -143,27 +143,30 @@ XPIDLSRCS = \
 ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
 XPIDLSRCS		+= nsIInternetConfigService.idl
 endif
 
 CPPSRCS	= \
 	nsExternalHelperAppService.cpp	\
 	nsExternalProtocolHandler.cpp \
 	nsMIMEInfoImpl.cpp \
-	nsHandlerAppImpl.cpp \
+	nsLocalHandlerApp.cpp \
 	$(OSHELPER) \
 	$(NULL)
 
 ifeq ($(OS_ARCH),WINNT WINCE)
 OS_LIBS		+= shell32.lib
 GARBAGE		+= nsOSHelperAppService.cpp $(srcdir)/nsOSHelperAppService.cpp \
              nsMIMEInfoWin.cpp $(srcdir)/nsMIMEInfoWin.cpp
 endif
 
-EXTRA_COMPONENTS = nsHandlerService.js
+EXTRA_COMPONENTS = \
+  nsHandlerService.js \
+  nsWebHandlerApp.js \
+  $(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 SRCS_IN_OBJDIR	= 1
 include $(topsrcdir)/config/rules.mk
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 CXXFLAGS += $(TK_CFLAGS)
--- a/uriloader/exthandler/nsCExternalHandlerService.idl
+++ b/uriloader/exthandler/nsCExternalHandlerService.idl
@@ -70,10 +70,13 @@ nsIExternalHelperAppService
 
 /* bc0017e3-2438-47be-a567-41db58f17627 */
 #define NS_LOCALHANDLERAPP_CID \
 { 0xbc0017e3, 0x2438, 0x47be, {0xa5, 0x67, 0x41, 0xdb, 0x58, 0xf1, 0x76, 0x27 } }
 
 #define NS_LOCALHANDLERAPP_CONTRACTID \
 "@mozilla.org/uriloader/local-handler-app;1"
 
+#define NS_WEBHANDLERAPP_CONTRACTID \
+"@mozilla.org/uriloader/web-handler-app;1"
+
 %}
 
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -37,16 +37,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsExternalHelperAppService.h"
+#include "nsCExternalHandlerService.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsIFile.h"
 #include "nsIFileURL.h"
 #include "nsIChannel.h"
 #include "nsIDirectoryService.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsICategoryManager.h"
@@ -119,17 +120,17 @@
 
 #include "nsIDOMWindow.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsIDocShell.h"
 
 #include "nsCRT.h"
 
 #include "nsMIMEInfoImpl.h"
-#include "nsHandlerAppImpl.h"
+#include "nsLocalHandlerApp.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* nsExternalHelperAppService::mLog = nsnull;
 #endif
 
 // Using level 3 here because the OSHelperAppServices use a log level
 // of PR_LOG_DEBUG (4), and we want less detailed output here
 // Using 3 instead of PR_LOG_WARN because we don't output warnings
@@ -819,21 +820,23 @@ nsresult nsExternalHelperAppService::Fil
       NS_ADDREF(*aHandlerApp = handlerApp);
     }
   } else {
     // if we got here, there's no path name in the RDF graph, so this must 
     // be a web app
     const PRUnichar * uriTemplate = nsnull;
     FillLiteralValueFromTarget(aSource, kNC_UriTemplate, &uriTemplate);
     if (uriTemplate && uriTemplate[0]) {
-      nsWebHandlerApp *handlerApp(new nsWebHandlerApp(appName, 
-        NS_ConvertUTF16toUTF8(uriTemplate)));
-      if (!handlerApp) {
-          return NS_ERROR_OUT_OF_MEMORY;
-      }
+      nsCOMPtr<nsIWebHandlerApp> handlerApp =
+        do_CreateInstance(NS_WEBHANDLERAPP_CONTRACTID, &rv);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      handlerApp->SetName(nsDependentString(appName));
+      handlerApp->SetUriTemplate(NS_ConvertUTF16toUTF8(uriTemplate));
+
       NS_ADDREF(*aHandlerApp = handlerApp);
     } else {
       return NS_ERROR_FAILURE; // no path name _and_ no uri template
     }
   }
 
   return rv;
 }
deleted file mode 100644
--- a/uriloader/exthandler/nsHandlerAppImpl.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim:expandtab:shiftwidth=2:tabstop=2:cin:
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla browser.
- *
- * The Initial Developer of the Original Code is 
- * the Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Dan Mosedale <dmose@mozilla.org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsHandlerAppImpl.h"
-
-// XXX why does nsMIMEInfoImpl have a threadsafe nsISupports?  do we need one 
-// here too?
-
-nsHandlerAppBase::nsHandlerAppBase()
-{
-}
-
-nsHandlerAppBase::nsHandlerAppBase(const PRUnichar *aName)
-  : mName(aName)
-{
-}
-
-nsHandlerAppBase::nsHandlerAppBase(const nsAString & aName)
-  : mName(aName)
-{
-}
-
-NS_IMPL_ISUPPORTS1(nsHandlerAppBase, nsIHandlerApp)
-
-/* AString name; */
-NS_IMETHODIMP nsHandlerAppBase::GetName(nsAString & aName)
-{
-  aName.Assign(mName);
-  
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsHandlerAppBase::SetName(const nsAString & aName)
-{
-  mName.Assign(aName);
-
-  return NS_OK;
-}
-
-NS_IMPL_ISUPPORTS_INHERITED1(nsLocalHandlerApp, nsHandlerAppBase, nsILocalHandlerApp)
-
-NS_IMETHODIMP nsLocalHandlerApp::GetName(nsAString& aName)
-{
-  if (mName.IsEmpty() && mExecutable) {
-    // Don't want to cache this, just in case someone resets the app
-    // without changing the description....
-    mExecutable->GetLeafName(aName);
-  } else {
-    aName.Assign(mName);
-  }
-  
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalHandlerApp::GetExecutable(nsIFile **aExecutable)
-{
-  NS_IF_ADDREF(*aExecutable = mExecutable);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalHandlerApp::SetExecutable(nsIFile *aExecutable)
-{
-  mExecutable = aExecutable;
-  return NS_OK;
-}
-
-
-NS_IMPL_ISUPPORTS_INHERITED1(nsWebHandlerApp, nsHandlerAppBase,
-                             nsIWebHandlerApp)
-
-
-NS_IMETHODIMP nsWebHandlerApp::GetUriTemplate(nsACString &aUriTemplate)
-{
-  aUriTemplate.Assign(mUriTemplate);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsWebHandlerApp::SetUriTemplate(const nsACString &aUriTemplate)
-{
-  mUriTemplate.Assign(aUriTemplate);
-  return NS_OK;
-}
deleted file mode 100644
--- a/uriloader/exthandler/nsHandlerAppImpl.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim:expandtab:shiftwidth=2:tabstop=2:cin:
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla browser.
- *
- * The Initial Developer of the Original Code is 
- * the Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Dan Mosedale <dmose@mozilla.org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef __nshandlerappimpl_h__
-#define __nshandlerappimpl_h__
-
-#include "nsString.h"
-#include "nsIMIMEInfo.h"
-#include "nsIFile.h"
-
-class nsHandlerAppBase : public nsIHandlerApp
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIHANDLERAPP
-
-  nsHandlerAppBase() NS_HIDDEN;
-  nsHandlerAppBase(const PRUnichar *aName) NS_HIDDEN;
-  nsHandlerAppBase(const nsAString & aName) NS_HIDDEN;
-  virtual ~nsHandlerAppBase() {}
-
-protected:
-  nsString mName;
-};
-
-class nsLocalHandlerApp : public nsHandlerAppBase, public nsILocalHandlerApp
-{
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSILOCALHANDLERAPP
-  
-  nsLocalHandlerApp() {}
-
-  nsLocalHandlerApp(const PRUnichar *aName, nsIFile *aExecutable) 
-    : nsHandlerAppBase(aName), mExecutable(aExecutable) {}
-
-  nsLocalHandlerApp(const nsAString & aName, nsIFile *aExecutable) 
-    : nsHandlerAppBase(aName), mExecutable(aExecutable) {}
-
-  virtual ~nsLocalHandlerApp() {}
-
-  // overriding to keep old caching behavior (that a useful name is returned
-  // even if none was given to the constructor)
-  NS_IMETHOD GetName(nsAString & aName);
-    
-protected: 
-  nsCOMPtr<nsIFile> mExecutable;
-};
-
-class nsWebHandlerApp : public nsHandlerAppBase, public nsIWebHandlerApp
-{
-  public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIWEBHANDLERAPP
-
-  nsWebHandlerApp(const PRUnichar *aName, const nsACString &aUriTemplate)
-    : nsHandlerAppBase(aName), mUriTemplate(aUriTemplate) { }
-
-  virtual ~nsWebHandlerApp() {}
-
-  protected:
-  nsCString mUriTemplate;
-      
-};
-
-#endif //  __nshandlerappimpl_h__
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/nsLocalHandlerApp.cpp
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim:expandtab:shiftwidth=2:tabstop=2:cin:
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla browser.
+ *
+ * The Initial Developer of the Original Code is 
+ * the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dan Mosedale <dmose@mozilla.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsLocalHandlerApp.h"
+
+// XXX why does nsMIMEInfoImpl have a threadsafe nsISupports?  do we need one 
+// here too?
+NS_IMPL_ISUPPORTS2(nsLocalHandlerApp, nsILocalHandlerApp, nsIHandlerApp)
+
+////////////////////////////////////////////////////////////////////////////////
+//// nsIHandlerApp
+
+NS_IMETHODIMP nsLocalHandlerApp::GetName(nsAString& aName)
+{
+  if (mName.IsEmpty() && mExecutable) {
+    // Don't want to cache this, just in case someone resets the app
+    // without changing the description....
+    mExecutable->GetLeafName(aName);
+  } else {
+    aName.Assign(mName);
+  }
+  
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsLocalHandlerApp::SetName(const nsAString & aName)
+{
+  mName.Assign(aName);
+
+  return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//// nsILocalHandlerApp
+
+NS_IMETHODIMP nsLocalHandlerApp::GetExecutable(nsIFile **aExecutable)
+{
+  NS_IF_ADDREF(*aExecutable = mExecutable);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsLocalHandlerApp::SetExecutable(nsIFile *aExecutable)
+{
+  mExecutable = aExecutable;
+  return NS_OK;
+}
+
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/nsLocalHandlerApp.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim:expandtab:shiftwidth=2:tabstop=2:cin:
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla browser.
+ *
+ * The Initial Developer of the Original Code is 
+ * the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dan Mosedale <dmose@mozilla.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __nsLocalHandlerAppImpl_h__
+#define __nsLocalHandlerAppImpl_h__
+
+#include "nsString.h"
+#include "nsIMIMEInfo.h"
+#include "nsIFile.h"
+
+class nsLocalHandlerApp : public nsILocalHandlerApp
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIHANDLERAPP
+  NS_DECL_NSILOCALHANDLERAPP
+
+  nsLocalHandlerApp() { }
+
+  nsLocalHandlerApp(const PRUnichar *aName, nsIFile *aExecutable) 
+    : mName(aName), mExecutable(aExecutable) { }
+
+  nsLocalHandlerApp(const nsAString & aName, nsIFile *aExecutable) 
+    : mName(aName), mExecutable(aExecutable) { }
+  virtual ~nsLocalHandlerApp() { }
+
+protected:
+  nsString mName;
+  nsCOMPtr<nsIFile> mExecutable;
+};
+
+#endif //  __nsLocalHandlerAppImpl_h__
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/nsWebHandlerApp.js
@@ -0,0 +1,98 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla browser.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Shawn Wilsher <me@shawnwilsher.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+////////////////////////////////////////////////////////////////////////////////
+//// Constants
+
+const Ci = Components.interfaces;
+
+////////////////////////////////////////////////////////////////////////////////
+//// nsWebHandler class
+
+function nsWebHandlerApp() {}
+
+nsWebHandlerApp.prototype = {
+  //////////////////////////////////////////////////////////////////////////////
+  //// nsWebHandler
+
+  classDescription: "A web handler for protocols and content",
+  classID: Components.ID("8b1ae382-51a9-4972-b930-56977a57919d"),
+  contractID: "@mozilla.org/uriloader/web-handler-app;1",
+
+  _name: null,
+  _uriTemplate: null,
+
+  //////////////////////////////////////////////////////////////////////////////
+  //// nsIHandlerApp
+
+  get name() {
+    return this._name;
+  },
+
+  set name(aName) {
+    this._name = aName;
+  },
+
+  //////////////////////////////////////////////////////////////////////////////
+  //// nsIWebHandlerApp
+
+  get uriTemplate() {
+    return this._uriTemplate;
+  },
+
+  set uriTemplate(aURITemplate) {
+    this._uriTemplate = aURITemplate;
+  },
+
+  //////////////////////////////////////////////////////////////////////////////
+  //// nsISupports
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebHandlerApp, Ci.nsIHandlerApp])
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//// Module
+
+let components = [nsWebHandlerApp];
+
+function NSGetModule(compMgr, fileSpec)
+{
+  return XPCOMUtils.generateModule(components);
+}
+
--- a/uriloader/exthandler/tests/unit/test_handlerService.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService.js
@@ -48,26 +48,20 @@ function run_test() {
     interfaces: [Ci.nsIHandlerApp, Ci.nsILocalHandlerApp, Ci.nsISupports],
     QueryInterface: function(iid) {
       if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
         throw Cr.NS_ERROR_NO_INTERFACE;
       return this;
     }
   };
   
-  var webHandler = {
-    name: "Web Handler",
-    uriTemplate: "http://www.example.com/?%s",
-    interfaces: [Ci.nsIHandlerApp, Ci.nsIWebHandlerApp, Ci.nsISupports],
-    QueryInterface: function(iid) {
-      if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      return this;
-    }
-  };
+  var webHandler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
+                   createInstance(Ci.nsIWebHandlerApp);
+  webHandler.name = "Web Handler";
+  webHandler.uriTemplate = "http://www.example.com/?%s";
   
   var handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].
                    getService(Ci.nsIHandlerService);
 
   var mimeSvc = Cc["@mozilla.org/uriloader/external-helper-app-service;1"].
                 getService(Ci.nsIMIMEService);