зеркало из https://github.com/mozilla/gecko-dev.git
228 строки
6.4 KiB
JavaScript
228 строки
6.4 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/. */
|
|
|
|
"use strict";
|
|
|
|
const Cm = Components.manager;
|
|
|
|
const { XPCOMUtils } = ChromeUtils.import(
|
|
"resource://gre/modules/XPCOMUtils.jsm"
|
|
);
|
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
|
|
// Load JsonView services lazily.
|
|
XPCOMUtils.defineLazyGetter(this, "JsonViewService", function() {
|
|
const { require } = ChromeUtils.import(
|
|
"resource://devtools/shared/Loader.jsm"
|
|
);
|
|
const {
|
|
// eslint-disable-next-line no-shadow
|
|
JsonViewService,
|
|
} = require("devtools/client/jsonview/converter-child");
|
|
return JsonViewService;
|
|
});
|
|
|
|
// Constants
|
|
const JSON_VIEW_PREF = "devtools.jsonview.enabled";
|
|
const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view";
|
|
const JSON_VIEW_CONTRACT_ID =
|
|
"@mozilla.org/streamconv;1?from=" + JSON_VIEW_MIME_TYPE + "&to=*/*";
|
|
const JSON_VIEW_CLASS_ID = Components.ID(
|
|
"{d8c9acee-dec5-11e4-8c75-1681e6b88ec1}"
|
|
);
|
|
const JSON_VIEW_CLASS_DESCRIPTION = "JSONView converter";
|
|
|
|
const JSON_SNIFFER_CONTRACT_ID = "@mozilla.org/devtools/jsonview-sniffer;1";
|
|
const JSON_SNIFFER_CLASS_ID = Components.ID(
|
|
"{4148c488-dca1-49fc-a621-2a0097a62422}"
|
|
);
|
|
const JSON_SNIFFER_CLASS_DESCRIPTION = "JSONView content sniffer";
|
|
const JSON_VIEW_TYPE = "JSON View";
|
|
const CONTENT_SNIFFER_CATEGORY = "net-content-sniffers";
|
|
|
|
/**
|
|
* This component represents a sniffer (implements nsIContentSniffer
|
|
* interface) responsible for changing top level 'application/json'
|
|
* document types to: 'application/vnd.mozilla.json.view'.
|
|
*
|
|
* This internal type is consequently rendered by JSON View component
|
|
* that represents the JSON through a viewer interface.
|
|
*
|
|
* This is done in the .js file rather than a .jsm to avoid creating
|
|
* a compartment at startup when no JSON is being viewed.
|
|
*/
|
|
function JsonViewSniffer() {}
|
|
|
|
JsonViewSniffer.prototype = {
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIContentSniffer]),
|
|
|
|
get wrappedJSObject() {
|
|
return this;
|
|
},
|
|
|
|
isTopLevelLoad: function(request) {
|
|
const loadInfo = request.loadInfo;
|
|
if (loadInfo?.isTopLevelLoad) {
|
|
return request.loadFlags & Ci.nsIChannel.LOAD_DOCUMENT_URI;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
getMIMETypeFromContent: function(request, data, length) {
|
|
if (request instanceof Ci.nsIChannel) {
|
|
// JSON View is enabled only for top level loads only.
|
|
if (!this.isTopLevelLoad(request)) {
|
|
if (request.contentType === JSON_VIEW_MIME_TYPE) {
|
|
return "application/json";
|
|
}
|
|
return "";
|
|
}
|
|
try {
|
|
if (
|
|
request.contentDisposition == Ci.nsIChannel.DISPOSITION_ATTACHMENT
|
|
) {
|
|
return "";
|
|
}
|
|
} catch (e) {
|
|
// Channel doesn't support content dispositions
|
|
}
|
|
|
|
// Check the response content type and if it's a valid type
|
|
// such as application/json or application/manifest+json
|
|
// change it to new internal type consumed by JSON View.
|
|
if (/^application\/(?:.+\+)?json$/.test(request.contentType)) {
|
|
return JSON_VIEW_MIME_TYPE;
|
|
}
|
|
}
|
|
|
|
return "";
|
|
},
|
|
};
|
|
|
|
/*
|
|
* Create instances of the JSON view sniffer.
|
|
*/
|
|
const JsonSnifferFactory = {
|
|
createInstance: function(outer, iid) {
|
|
if (outer) {
|
|
throw Cr.NS_ERROR_NO_AGGREGATION;
|
|
}
|
|
return new JsonViewSniffer().QueryInterface(iid);
|
|
},
|
|
};
|
|
|
|
/*
|
|
* Create instances of the JSON view converter.
|
|
* This is done in the .js file rather than a .jsm to avoid creating
|
|
* a compartment at startup when no JSON is being viewed.
|
|
*/
|
|
const JsonViewFactory = {
|
|
createInstance: function(outer, iid) {
|
|
if (outer) {
|
|
throw Cr.NS_ERROR_NO_AGGREGATION;
|
|
}
|
|
return JsonViewService.createInstance().QueryInterface(iid);
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Listen for 'devtools.jsonview.enabled' preference changes and
|
|
* register/unregister the JSON View XPCOM services as appropriate.
|
|
*/
|
|
function ConverterObserver() {}
|
|
|
|
ConverterObserver.prototype = {
|
|
initialize: function() {
|
|
// Only the DevEdition has this feature available by default.
|
|
// Users need to manually flip 'devtools.jsonview.enabled' preference
|
|
// to have it available in other distributions.
|
|
if (this.isEnabled()) {
|
|
this.register();
|
|
}
|
|
|
|
Services.prefs.addObserver(JSON_VIEW_PREF, this);
|
|
Services.obs.addObserver(this, "xpcom-shutdown");
|
|
},
|
|
|
|
observe: function(subject, topic, data) {
|
|
switch (topic) {
|
|
case "xpcom-shutdown":
|
|
this.onShutdown();
|
|
break;
|
|
case "nsPref:changed":
|
|
this.onPrefChanged();
|
|
break;
|
|
}
|
|
},
|
|
|
|
onShutdown: function() {
|
|
Services.prefs.removeObserver(JSON_VIEW_PREF, observer);
|
|
Services.obs.removeObserver(observer, "xpcom-shutdown");
|
|
},
|
|
|
|
onPrefChanged: function() {
|
|
if (this.isEnabled()) {
|
|
this.register();
|
|
} else {
|
|
this.unregister();
|
|
}
|
|
},
|
|
|
|
register: function() {
|
|
const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
|
|
|
if (!registrar.isCIDRegistered(JSON_SNIFFER_CLASS_ID)) {
|
|
registrar.registerFactory(
|
|
JSON_SNIFFER_CLASS_ID,
|
|
JSON_SNIFFER_CLASS_DESCRIPTION,
|
|
JSON_SNIFFER_CONTRACT_ID,
|
|
JsonSnifferFactory
|
|
);
|
|
Services.catMan.addCategoryEntry(
|
|
CONTENT_SNIFFER_CATEGORY,
|
|
JSON_VIEW_TYPE,
|
|
JSON_SNIFFER_CONTRACT_ID,
|
|
false,
|
|
false
|
|
);
|
|
}
|
|
|
|
if (!registrar.isCIDRegistered(JSON_VIEW_CLASS_ID)) {
|
|
registrar.registerFactory(
|
|
JSON_VIEW_CLASS_ID,
|
|
JSON_VIEW_CLASS_DESCRIPTION,
|
|
JSON_VIEW_CONTRACT_ID,
|
|
JsonViewFactory
|
|
);
|
|
}
|
|
},
|
|
|
|
unregister: function() {
|
|
const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
|
|
|
if (registrar.isCIDRegistered(JSON_SNIFFER_CLASS_ID)) {
|
|
registrar.unregisterFactory(JSON_SNIFFER_CLASS_ID, JsonSnifferFactory);
|
|
Services.catMan.deleteCategoryEntry(
|
|
CONTENT_SNIFFER_CATEGORY,
|
|
JSON_VIEW_TYPE,
|
|
false
|
|
);
|
|
}
|
|
|
|
if (registrar.isCIDRegistered(JSON_VIEW_CLASS_ID)) {
|
|
registrar.unregisterFactory(JSON_VIEW_CLASS_ID, JsonViewFactory);
|
|
}
|
|
},
|
|
|
|
isEnabled: function() {
|
|
return Services.prefs.getBoolPref(JSON_VIEW_PREF);
|
|
},
|
|
};
|
|
|
|
// Listen to JSON View 'enable' pref and perform dynamic
|
|
// registration or unregistration of the main application
|
|
// component.
|
|
var observer = new ConverterObserver();
|
|
observer.initialize();
|