forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			202 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| /*
 | |
|  * Dumping ground for simple services for which the isolation of a full global
 | |
|  * is overkill. Be careful about namespace pollution, and be mindful about
 | |
|  * importing lots of JSMs in global scope, since this file will almost certainly
 | |
|  * be loaded from enough callsites that any such imports will always end up getting
 | |
|  * eagerly loaded at startup.
 | |
|  */
 | |
| 
 | |
| /* globals WebExtensionPolicy */
 | |
| 
 | |
| import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
 | |
| 
 | |
| const lazy = {};
 | |
| 
 | |
| ChromeUtils.defineESModuleGetters(lazy, {
 | |
|   NetUtil: "resource://gre/modules/NetUtil.sys.mjs",
 | |
| });
 | |
| 
 | |
| XPCOMUtils.defineLazyServiceGetter(
 | |
|   lazy,
 | |
|   "streamConv",
 | |
|   "@mozilla.org/streamConverters;1",
 | |
|   "nsIStreamConverterService"
 | |
| );
 | |
| const ArrayBufferInputStream = Components.Constructor(
 | |
|   "@mozilla.org/io/arraybuffer-input-stream;1",
 | |
|   "nsIArrayBufferInputStream",
 | |
|   "setData"
 | |
| );
 | |
| 
 | |
| /*
 | |
|  * This class provides a stream filter for locale messages in CSS files served
 | |
|  * by the moz-extension: protocol handler.
 | |
|  *
 | |
|  * See SubstituteChannel in netwerk/protocol/res/ExtensionProtocolHandler.cpp
 | |
|  * for usage.
 | |
|  */
 | |
| export function AddonLocalizationConverter() {}
 | |
| 
 | |
| AddonLocalizationConverter.prototype = {
 | |
|   QueryInterface: ChromeUtils.generateQI(["nsIStreamConverter"]),
 | |
| 
 | |
|   FROM_TYPE: "application/vnd.mozilla.webext.unlocalized",
 | |
|   TO_TYPE: "text/css",
 | |
| 
 | |
|   checkTypes(aFromType, aToType) {
 | |
|     if (aFromType != this.FROM_TYPE) {
 | |
|       throw Components.Exception(
 | |
|         "Invalid aFromType value",
 | |
|         Cr.NS_ERROR_INVALID_ARG,
 | |
|         Components.stack.caller.caller
 | |
|       );
 | |
|     }
 | |
|     if (aToType != this.TO_TYPE) {
 | |
|       throw Components.Exception(
 | |
|         "Invalid aToType value",
 | |
|         Cr.NS_ERROR_INVALID_ARG,
 | |
|         Components.stack.caller.caller
 | |
|       );
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   // aContext must be a nsIURI object for a valid moz-extension: URL.
 | |
|   getAddon(aContext) {
 | |
|     // In this case, we want the add-on ID even if the URL is web accessible,
 | |
|     // so check the root rather than the exact path.
 | |
|     let uri = Services.io.newURI("/", null, aContext);
 | |
| 
 | |
|     let addon = WebExtensionPolicy.getByURI(uri);
 | |
|     if (!addon) {
 | |
|       throw new Components.Exception(
 | |
|         "Invalid context",
 | |
|         Cr.NS_ERROR_INVALID_ARG
 | |
|       );
 | |
|     }
 | |
|     return addon;
 | |
|   },
 | |
| 
 | |
|   convertToStream(aAddon, aString) {
 | |
|     aString = aAddon.localize(aString);
 | |
|     let bytes = new TextEncoder().encode(aString).buffer;
 | |
|     return new ArrayBufferInputStream(bytes, 0, bytes.byteLength);
 | |
|   },
 | |
| 
 | |
|   convert(aStream, aFromType, aToType, aContext) {
 | |
|     this.checkTypes(aFromType, aToType);
 | |
|     let addon = this.getAddon(aContext);
 | |
| 
 | |
|     let count = aStream.available();
 | |
|     let string = count
 | |
|       ? new TextDecoder().decode(lazy.NetUtil.readInputStream(aStream, count))
 | |
|       : "";
 | |
|     return this.convertToStream(addon, string);
 | |
|   },
 | |
| 
 | |
|   asyncConvertData(aFromType, aToType, aListener, aContext) {
 | |
|     this.checkTypes(aFromType, aToType);
 | |
|     this.addon = this.getAddon(aContext);
 | |
|     this.listener = aListener;
 | |
|   },
 | |
| 
 | |
|   onStartRequest() {
 | |
|     this.parts = [];
 | |
|     this.decoder = new TextDecoder();
 | |
|   },
 | |
| 
 | |
|   onDataAvailable(aRequest, aInputStream, aOffset, aCount) {
 | |
|     let bytes = lazy.NetUtil.readInputStream(aInputStream, aCount);
 | |
|     this.parts.push(this.decoder.decode(bytes, { stream: true }));
 | |
|   },
 | |
| 
 | |
|   onStopRequest(aRequest, aStatusCode) {
 | |
|     try {
 | |
|       this.listener.onStartRequest(aRequest, null);
 | |
|       if (Components.isSuccessCode(aStatusCode)) {
 | |
|         this.parts.push(this.decoder.decode());
 | |
|         let string = this.parts.join("");
 | |
|         let stream = this.convertToStream(this.addon, string);
 | |
| 
 | |
|         this.listener.onDataAvailable(aRequest, stream, 0, stream.available());
 | |
|       }
 | |
|     } catch (e) {
 | |
|       aStatusCode = e.result || Cr.NS_ERROR_FAILURE;
 | |
|     }
 | |
|     this.listener.onStopRequest(aRequest, aStatusCode);
 | |
|   },
 | |
| };
 | |
| 
 | |
| export function HttpIndexViewer() {}
 | |
| 
 | |
| HttpIndexViewer.prototype = {
 | |
|   QueryInterface: ChromeUtils.generateQI(["nsIDocumentLoaderFactory"]),
 | |
| 
 | |
|   createInstance(
 | |
|     aCommand,
 | |
|     aChannel,
 | |
|     aLoadGroup,
 | |
|     aContentType,
 | |
|     aContainer,
 | |
|     aExtraInfo,
 | |
|     aDocListenerResult
 | |
|   ) {
 | |
|     // Bug 1824325: application/http-index-format is deprecated for almost all
 | |
|     // sites, we only allow it for urls with a inner scheme of "file" or
 | |
|     // "moz-gio" (specified in network.http_index_format.allowed_schemes).
 | |
|     // This also includes jar: and resource:// uris, as jar: uris has a inner
 | |
|     // scheme of "file", and resource:// uris have been turned into either a
 | |
|     // jar: or file:// uri by the point where we are checking them here.
 | |
| 
 | |
|     let uri = aChannel.URI;
 | |
|     if (uri instanceof Ci.nsINestedURI) {
 | |
|       uri = uri.QueryInterface(Ci.nsINestedURI).innermostURI;
 | |
|     }
 | |
| 
 | |
|     const allowedSchemes = Services.prefs.getStringPref(
 | |
|       "network.http_index_format.allowed_schemes",
 | |
|       ""
 | |
|     );
 | |
|     let isFile =
 | |
|       allowedSchemes === "*" || allowedSchemes.split(",").some(uri.schemeIs);
 | |
|     let contentType = isFile ? "text/html" : "text/plain";
 | |
| 
 | |
|     aChannel.contentType = contentType;
 | |
| 
 | |
|     let contract = Services.catMan.getCategoryEntry(
 | |
|       "Gecko-Content-Viewers",
 | |
|       contentType
 | |
|     );
 | |
|     let factory = Cc[contract].getService(Ci.nsIDocumentLoaderFactory);
 | |
| 
 | |
|     let listener = {};
 | |
|     let res = factory.createInstance(
 | |
|       "view",
 | |
|       aChannel,
 | |
|       aLoadGroup,
 | |
|       contentType,
 | |
|       aContainer,
 | |
|       aExtraInfo,
 | |
|       listener
 | |
|     );
 | |
| 
 | |
|     if (isFile) {
 | |
|       aDocListenerResult.value = lazy.streamConv.asyncConvertData(
 | |
|         "application/http-index-format",
 | |
|         "text/html",
 | |
|         listener.value,
 | |
|         null
 | |
|       );
 | |
|     } else {
 | |
|       aDocListenerResult.value = listener.value;
 | |
|       aChannel.loadInfo.browsingContext.window.console.warn(
 | |
|         "application/http-index-format is deprecated, content will display as plain text"
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     return res;
 | |
|   },
 | |
| };
 | 
