1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); 6 7ChromeUtils.defineModuleGetter( 8 this, 9 "PrivateBrowsingUtils", 10 "resource://gre/modules/PrivateBrowsingUtils.jsm" 11); 12 13function nsWebHandlerApp() {} 14 15nsWebHandlerApp.prototype = { 16 classDescription: "A web handler for protocols and content", 17 classID: Components.ID("8b1ae382-51a9-4972-b930-56977a57919d"), 18 contractID: "@mozilla.org/uriloader/web-handler-app;1", 19 QueryInterface: ChromeUtils.generateQI(["nsIWebHandlerApp", "nsIHandlerApp"]), 20 21 _name: null, 22 _detailedDescription: null, 23 _uriTemplate: null, 24 25 // nsIHandlerApp 26 27 get name() { 28 return this._name; 29 }, 30 31 set name(aName) { 32 this._name = aName; 33 }, 34 35 get detailedDescription() { 36 return this._detailedDescription; 37 }, 38 39 set detailedDescription(aDesc) { 40 this._detailedDescription = aDesc; 41 }, 42 43 equals(aHandlerApp) { 44 if (!aHandlerApp) { 45 throw Components.Exception("", Cr.NS_ERROR_NULL_POINTER); 46 } 47 48 if ( 49 aHandlerApp instanceof Ci.nsIWebHandlerApp && 50 aHandlerApp.uriTemplate && 51 this.uriTemplate && 52 aHandlerApp.uriTemplate == this.uriTemplate 53 ) { 54 return true; 55 } 56 return false; 57 }, 58 59 launchWithURI(aURI, aBrowsingContext) { 60 // XXX need to strip passwd & username from URI to handle, as per the 61 // WhatWG HTML5 draft. nsSimpleURL, which is what we're going to get, 62 // can't do this directly. Ideally, we'd fix nsStandardURL to make it 63 // possible to turn off all of its quirks handling, and use that... 64 65 // encode the URI to be handled 66 var escapedUriSpecToHandle = encodeURIComponent(aURI.spec); 67 68 // insert the encoded URI and create the object version. 69 var uriSpecToSend = this.uriTemplate.replace("%s", escapedUriSpecToHandle); 70 var uriToSend = Services.io.newURI(uriSpecToSend); 71 72 let policy = WebExtensionPolicy.getByURI(uriToSend); 73 let privateAllowed = !policy || policy.privateBrowsingAllowed; 74 75 // If we're in a frame, check if we're a built-in scheme, in which case, 76 // override the target browsingcontext. It's not a good idea to try to 77 // load mail clients or other apps with potential for logged in data into 78 // iframes, and in any case it's unlikely to work due to framing 79 // restrictions employed by the target site. 80 if (aBrowsingContext && aBrowsingContext != aBrowsingContext.top) { 81 let { scheme } = aURI; 82 if (!scheme.startsWith("web+") && !scheme.startsWith("ext+")) { 83 aBrowsingContext = null; 84 } 85 } 86 87 // if we have a context, use the URI loader to load there 88 if (aBrowsingContext) { 89 if (aBrowsingContext.usePrivateBrowsing && !privateAllowed) { 90 throw Components.Exception( 91 "Extension not allowed in private windows.", 92 Cr.NS_ERROR_FILE_NOT_FOUND 93 ); 94 } 95 96 let triggeringPrincipal = Services.scriptSecurityManager.getSystemPrincipal(); 97 Services.tm.dispatchToMainThread(() => 98 aBrowsingContext.loadURI(uriSpecToSend, { triggeringPrincipal }) 99 ); 100 return; 101 } 102 103 let win = Services.wm.getMostRecentWindow("navigator:browser"); 104 105 // If this is an extension handler, check private browsing access. 106 if (!privateAllowed && PrivateBrowsingUtils.isWindowPrivate(win)) { 107 throw Components.Exception( 108 "Extension not allowed in private windows.", 109 Cr.NS_ERROR_FILE_NOT_FOUND 110 ); 111 } 112 113 // If we get an exception, there are several possible reasons why: 114 // a) this gecko embedding doesn't provide an nsIBrowserDOMWindow 115 // implementation (i.e. doesn't support browser-style functionality), 116 // so we need to kick the URL out to the OS default browser. This is 117 // the subject of bug 394479. 118 // b) this embedding does provide an nsIBrowserDOMWindow impl, but 119 // there doesn't happen to be a browser window open at the moment; one 120 // should be opened. It's not clear whether this situation will really 121 // ever occur in real life. If it does, the only API that I can find 122 // that seems reasonably likely to work for most embedders is the 123 // command line handler. 124 // c) something else went wrong 125 // 126 // It's not clear how one would differentiate between the three cases 127 // above, so for now we don't catch the exception. 128 129 // openURI 130 win.browserDOMWindow.openURI( 131 uriToSend, 132 null, // no window.opener 133 Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, 134 Ci.nsIBrowserDOMWindow.OPEN_NEW, 135 Services.scriptSecurityManager.getSystemPrincipal() 136 ); 137 }, 138 139 // nsIWebHandlerApp 140 141 get uriTemplate() { 142 return this._uriTemplate; 143 }, 144 145 set uriTemplate(aURITemplate) { 146 this._uriTemplate = aURITemplate; 147 }, 148}; 149 150var EXPORTED_SYMBOLS = ["nsWebHandlerApp"]; 151