Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/autonome/Jetpack-Modules. Various Jetpack modules I've made.
Something went wrong. Try again.
Jetpack-Modules protocol.js
8.0 kB · 217 lines
JavaScript
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218'use strict'
const { Cc, Ci, Cu, Cm } = require("chrome") , { MatchPattern } = require('match-pattern') , { Trait } = require("light-traits") , xpcom = require("xpcom")
, { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm")
, IOService = Cc["@mozilla.org/network/io-service;1"]. getService(Ci.nsIIOService) , uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]. getService(Ci.nsIUUIDGenerator) , streamChannel = Cc["@mozilla.org/network/input-stream-channel;1"] , inputStream = Cc["@mozilla.org/io/string-input-stream;1"] , SimpleURI = Cc["@mozilla.org/network/simple-uri;1"] , securityManager = Cc["@mozilla.org/scriptsecuritymanager;1"]. getService(Ci.nsIScriptSecurityManager)
function identity(value) value
const TXPCOM = Trait.compose( Trait({ interfaces: Trait.required, contractID: Trait.required, }), { QueryInterface: { get: function QueryInterface() { Object.defineProperty(this, 'QueryInterface', { value: XPCOMUtils.generateQI(this.interfaces), configurable: false }) return this.QueryInterface }, configurable: true }, classID: { get: function classID() { Object.defineProperty(this, 'classID', { value: uuidGenerator.generateUUID(), configurable: false }) return this.classID }, configurable: true }, classDescription: { get: function classDescription() { Object.defineProperty(this, 'classDescription', { value: this.description || "Jetpack generated class", configurable: false }) return this.classDescription }, configurable: true } })
/** * Function takes `handler` object implementing a protocol, and `uri` from * that protocol, performs request operation on handler and returns `response` * object that contains `channel` of the requested `uri`. * @param {Object} handler * Protocol handler * @param {nsIURI|String} uri * Requested URI * @param {nsIURI} [baseURI] * Base URI. Necessary when given `uri` is relative. */function request(handler, uri, baseURI, charset) { // Creating `request` and `response` objects that are passed to a `handler`'s // `onRequest` method. Also note that `response` object inherits from // `request`, this way `response`'s properties will fall back to the // `request`'s same named properties. let channel, request = {}, response = Object.create(request) // If `baseURI` is provided then given `uri` is relative to it, there for // we set `referer` property on request to allow protocol handler to resolve // absolute URI. if (baseURI) request.referer = baseURI.spec // Stringifying `uri` to a string and setting it as property on `request`. request.uri = request.originalURI = uri.spec || uri
handler.onRequest(request, response)
// If response contains `content` property it's not a simple redirect. In // this case we create channel from the given content. if (response.content) { // Creating input stream out of the `response.content` and then creating // `channel` with that content stream. let stream = inputStream.createInstance(Ci.nsIStringInputStream) let content = response.content stream.setData(content, response.contentLength || content.length) channel = streamChannel.createInstance(Ci.nsIInputStreamChannel) channel.contentStream = stream channel.QueryInterface(Ci.nsIChannel) // If `uri.spec` is different form `response.uri` it means that either // `request` was just redirected to a different uri from the existing // protocol or given `uri` was string, in both cases we need to create // `uri` that is `nsIURI` since it has to be set on the `channel`. if (uri.spec !== response.uri) { uri = SimpleURI.createInstance(Ci.nsIURI) uri.spec = response.uri } // Setting response URI on the channel. channel.setURI(uri) } // Otherwise it's a redirect to an URI from the existing protocol, in such // case we just use `nsIIOService` to create `channel` straight out of // `response.uri` else { if (response.uri !== request.uri) uri = IOService.newURI(response.uri, null, null) channel = IOService.newChannel(response.uri, null, null) }
// Also setting `contentType` and `contentLength` if they were provided to the // response. if (response.contentType) channel.contentType = response.contentType if (response.contentLength) channel.contentLength = response.contentLength
return Object.create(response, { channel: { value: channel }, uri: { value: uri } })}
const THandler = Trait({ onRequest: Trait.required, listen: function listen(options) { let handler if (options.about) { handler = Object.create(this, { about: { value: options.about } }) handler = TAboutHandler.create(handler) } else { handler = Object.create(this, { scheme: { value: options.scheme } }) handler = TProtocolHandler.create(handler) }
xpcom.register({ uuid: handler.classID, name: handler.classDescription, contractID: handler.contractID, create: identity.bind(null, handler) }) }})
const TAboutHandler = Trait.compose( TXPCOM, Trait({ about: Trait.required, onRequest: Trait.required, interfaces: [ Ci.nsIAboutModule ], get description() { return 'Protocol handler for "about:' + this.about + '"' }, get contractID() { return "@mozilla.org/network/protocol/about;1?what=" + this.about }, getURIFlags: function(uri) { return Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT }, newChannel: function(uri) { return request(this, uri).channel } }))
const TProtocolHandler = Trait.compose( TXPCOM, Trait({ scheme: Trait.required, onRequest: Trait.required, interfaces: [ Ci.nsIProtocolHandler ], // For more information on what these flags mean, // see caps/src/nsScriptSecurityManager.cpp. protocolFlags: Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE | Ci.nsIProtocolHandler.URI_STD | Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD, defaultPort: -1, allowPort: function allowPort(port, scheme) false, newURI: function newURI(relativeURI, charset, baseURI) { let response = request(this, relativeURI, baseURI, charset) // If handler have not redirected to another protocol we know that // `newChannel` method will be called later so we save response so that // it will be able to use it and then delete it. if (response.uri.scheme == this.scheme) (this.responses || (this.responses = {}))[response.uri.spec] = response
return response.uri }, newChannel: function newChannel(uri) { // Taking response for this request (`newURI` saved it) from the responses // map and removing it after, since we don't need memory leaks. let response = this.responses[uri.spec] let channel = response.channel delete this.responses[uri.spec] // If `originalURI` of the response is different from the `uri` either // it means that handler just maps `originalURI`. In such case we set // owner of the channel to the same principal as `originalURI` has in // order to allow access to the other mapped resources. if (response.originalURI !== response.uri) { let originalURI = IOService.newURI(response.originalURI, null, null) channel.originalURI = originalURI channel.owner = securityManager.getCodebasePrincipal(originalURI) } return channel }, get contractID() { return "@mozilla.org/network/protocol;1?name=" + this.scheme }, get description() { return 'Protocol handler for "' + this.scheme + ':*"' } }))
exports.Handler = function Handler(options) { return THandler.create(options)}