Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/devtools/client/jsonview/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 12 kB image not shown  

SSL converter-child.js   Sprache: JAVA

 
/* 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 lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
  NetUtil: "resource://gre/modules/NetUtil.sys.mjs",
});

const {
  getTheme,
  addThemeObserver,
  removeThemeObserver,
} = require("resource://devtools/client/shared/theme.js");

const BinaryInput = Components.Constructor(
  "@mozilla.org/binaryinputstream;1",
  "nsIBinaryInputStream",
  "setInputStream"
);
const BufferStream = Components.Constructor(
  "@mozilla.org/io/arraybuffer-input-stream;1",
  "nsIArrayBufferInputStream",
  "setData"
);

const kCSP = "default-src 'none'; script-src resource:; img-src 'self';";

// Localization
loader.lazyGetter(this"jsonViewStrings", () => {
  return Services.strings.createBundle(
    "chrome://devtools/locale/jsonview.properties"
  );
});

/**
 * This object detects 'application/vnd.mozilla.json.view' content type
 * and converts it into a JSON Viewer application that allows simple
 * JSON inspection.
 *
 * Inspired by JSON View: https://github.com/bhollis/jsonview/
 */

function Converter() {}

Converter.prototype = {
  QueryInterface: ChromeUtils.generateQI([
    "nsIStreamConverter",
    "nsIStreamListener",
    "nsIRequestObserver",
  ]),

  get wrappedJSObject() {
    return this;
  },

  /**
   * This component works as such:
   * 1. asyncConvertData captures the listener
   * 2. onStartRequest fires, initializes stuff, modifies the listener
   *    to match our output type
   * 3. onDataAvailable decodes and inserts data into a text node
   * 4. onStopRequest flushes data and spits back to the listener
   * 5. convert does nothing, it's just the synchronous version
   *    of asyncConvertData
   */

  convert(fromStream) {
    return fromStream;
  },

  asyncConvertData(fromType, toType, listener) {
    this.listener = listener;
  },
  getConvertedType(_fromType, channel) {
    if (channel instanceof Ci.nsIMultiPartChannel) {
      throw new Components.Exception(
        "JSONViewer doesn't support multipart responses.",
        Cr.NS_ERROR_FAILURE
      );
    }
    return "text/html";
  },

  onDataAvailable(request, inputStream, offset, count) {
    // Decode and insert data.
    const buffer = new ArrayBuffer(count);
    new BinaryInput(inputStream).readArrayBuffer(count, buffer);
    this.decodeAndInsertBuffer(buffer);
  },

  onStartRequest(request) {
    // Set the content type to HTML in order to parse the doctype, styles
    // and scripts. The JSON will be manually inserted as text.
    request.QueryInterface(Ci.nsIChannel);
    request.contentType = "text/html";

    // Tweak the request's principal in order to allow the related HTML document
    // used to display raw JSON to be able to load resource://devtools files
    // from the jsonview document.
    const uri = lazy.NetUtil.newURI("resource://devtools/client/jsonview/");
    const resourcePrincipal =
      Services.scriptSecurityManager.createContentPrincipal(
        uri,
        request.loadInfo.originAttributes
      );
    request.owner = resourcePrincipal;

    const headers = getHttpHeaders(request);

    // Enforce strict CSP:
    try {
      request.QueryInterface(Ci.nsIHttpChannel);
      request.setResponseHeader("Content-Security-Policy", kCSP, false);
      request.setResponseHeader(
        "Content-Security-Policy-Report-Only",
        "",
        false
      );
    } catch (ex) {
      // If this is not an HTTP channel we can't and won't do anything.
    }

    // Don't honor the charset parameter and use UTF-8 (see bug 741776).
    request.contentCharset = "UTF-8";
    this.decoder = new TextDecoder("UTF-8");

    // Changing the content type breaks saving functionality. Fix it.
    fixSave(request);

    // Start the request.
    this.listener.onStartRequest(request);

    // Initialize stuff.
    const win = getWindowForRequest(request);
    if (!win || !Components.isSuccessCode(request.status)) {
      return;
    }

    // We compare actual pointer identities here rather than using .equals(),
    // because if things went correctly then the document must have exactly
    // the principal we reset it to above. If not, something went wrong.
    if (win.document.nodePrincipal != resourcePrincipal) {
      // Whatever that document is, it's not ours.
      request.cancel(Cr.NS_BINDING_ABORTED);
      return;
    }

    this.data = exportData(win, headers);
    insertJsonData(win, this.data.json);
    win.addEventListener("contentMessage", onContentMessage, falsetrue);
    keepThemeUpdated(win);

    // Send the initial HTML code.
    const buffer = new TextEncoder().encode(initialHTML(win.document)).buffer;
    const stream = new BufferStream(buffer, 0, buffer.byteLength);
    this.listener.onDataAvailable(request, stream, 0, stream.available());
  },

  onStopRequest(request, statusCode) {
    // Flush data if we haven't been canceled.
    if (Components.isSuccessCode(statusCode)) {
      this.decodeAndInsertBuffer(new ArrayBuffer(0), true);
    }

    // Stop the request.
    this.listener.onStopRequest(request, statusCode);
    this.listener = null;
    this.decoder = null;
    this.data = null;
  },

  // Decodes an ArrayBuffer into a string and inserts it into the page.
  decodeAndInsertBuffer(buffer, flush = false) {
    // Decode the buffer into a string.
    const data = this.decoder.decode(buffer, { stream: !flush });

    // Using `appendData` instead of `textContent +=` is important to avoid
    // repainting previous data.
    this.data.json.appendData(data);
  },
};

// Lets "save as" save the original JSON, not the viewer.
// To save with the proper extension we need the original content type,
// which has been replaced by application/vnd.mozilla.json.view
function fixSave(request) {
  let match;
  if (request instanceof Ci.nsIHttpChannel) {
    try {
      const header = request.getResponseHeader("Content-Type");
      match = header.match(/^(application\/(?:[^;]+\+)?json)(?:;|$)/);
    } catch (err) {
      // Handled below
    }
  } else {
    const uri = request.QueryInterface(Ci.nsIChannel).URI.spec;
    match = uri.match(/^data:(application\/(?:[^;,]+\+)?json)[;,]/);
  }
  let originalType;
  if (match) {
    originalType = match[1];
  } else {
    originalType = "application/json";
  }
  request.QueryInterface(Ci.nsIWritablePropertyBag);
  request.setProperty("contentType", originalType);
}

function getHttpHeaders(request) {
  const headers = {
    response: [],
    request: [],
  };
  // The request doesn't have to be always nsIHttpChannel
  // (e.g. in case of data: URLs)
  if (request instanceof Ci.nsIHttpChannel) {
    request.visitResponseHeaders({
      visitHeader(name, value) {
        headers.response.push({ name, value });
      },
    });
    request.visitRequestHeaders({
      visitHeader(name, value) {
        headers.request.push({ name, value });
      },
    });
  }
  return headers;
}

let jsonViewStringDict = null;
function getAllStrings() {
  if (!jsonViewStringDict) {
    jsonViewStringDict = {};
    for (const string of jsonViewStrings.getSimpleEnumeration()) {
      jsonViewStringDict[string.key] = string.value;
    }
  }
  return jsonViewStringDict;
}

// The two following methods are duplicated from NetworkHelper.sys.mjs
// to avoid pulling the whole NetworkHelper as a dependency during
// initialization.

/**
 * Gets the nsIDOMWindow that is associated with request.
 *
 * @param nsIHttpChannel request
 * @returns nsIDOMWindow or null
 */

function getWindowForRequest(request) {
  try {
    return getRequestLoadContext(request).associatedWindow;
  } catch (ex) {
    // On some request notificationCallbacks and loadGroup are both null,
    // so that we can't retrieve any nsILoadContext interface.
    // Fallback on nsILoadInfo to try to retrieve the request's window.
    // (this is covered by test_network_get.html and its CSS request)
    return request.loadInfo.loadingDocument?.defaultView;
  }
}

/**
 * Gets the nsILoadContext that is associated with request.
 *
 * @param nsIHttpChannel request
 * @returns nsILoadContext or null
 */

function getRequestLoadContext(request) {
  try {
    return request.notificationCallbacks.getInterface(Ci.nsILoadContext);
  } catch (ex) {
    // Ignore.
  }

  try {
    return request.loadGroup.notificationCallbacks.getInterface(
      Ci.nsILoadContext
    );
  } catch (ex) {
    // Ignore.
  }

  return null;
}

// Exports variables that will be accessed by the non-privileged scripts.
function exportData(win, headers) {
  const json = new win.Text();
  const JSONView = Cu.cloneInto(
    {
      headers,
      json,
      readyState: "uninitialized",
      Locale: getAllStrings(),
    },
    win,
    {
      wrapReflectors: true,
    }
  );
  try {
    Object.defineProperty(Cu.waiveXrays(win), "JSONView", {
      value: JSONView,
      configurable: true,
      enumerable: true,
      writable: true,
    });
  } catch (error) {
    console.error(error);
  }
  return { json };
}

// Builds an HTML string that will be used to load stylesheets and scripts.
function initialHTML(doc) {
  // Creates an element with the specified type, attributes and children.
  function element(type, attributes = {}, children = []) {
    const el = doc.createElement(type);
    for (const [attr, value] of Object.entries(attributes)) {
      el.setAttribute(attr, value);
    }
    el.append(...children);
    return el;
  }

  let os;
  const platform = Services.appinfo.OS;
  if (platform.startsWith("WINNT")) {
    os = "win";
  } else if (platform.startsWith("Darwin")) {
    os = "mac";
  } else {
    os = "linux";
  }

  const baseURI = "resource://devtools/client/jsonview/";

  return (
    "\n" +
    element(
      "html",
      {
        platform: os,
        class"theme-" + getTheme(),
        dir: Services.locale.isAppLocaleRTL ? "rtl" : "ltr",
      },
      [
        element("head", {}, [
          element("meta", {
            "http-equiv""Content-Security-Policy",
            content: kCSP,
          }),
          element("link", {
            rel: "stylesheet",
            type: "text/css",
            href: "chrome://devtools-jsonview-styles/content/main.css",
          }),
        ]),
        element("body", {}, [
          element("div", { id: "content" }, [element("div", { id: "json" })]),
          element("script", {
            src: baseURI + "lib/require.js",
            "data-main": baseURI + "viewer-config.js",
          }),
        ]),
      ]
    ).outerHTML
  );
}

// We insert the received data into a text node, which should be appended into
// the #json element so that the JSON is still displayed even if JS is disabled.
// However, the HTML parser is not synchronous, so this function uses a mutation
// observer to detect the creation of the element. Then the text node is appended.
function insertJsonData(win, json) {
  new win.MutationObserver(function (mutations, observer) {
    for (const { target, addedNodes } of mutations) {
      if (target.nodeType == 1 && target.id == "content") {
        for (const node of addedNodes) {
          if (node.nodeType == 1 && node.id == "json") {
            observer.disconnect();
            node.append(json);
            return;
          }
        }
      }
    }
  }).observe(win.document, {
    childList: true,
    subtree: true,
  });
}

function keepThemeUpdated(win) {
  const listener = function () {
    win.document.documentElement.className = "theme-" + getTheme();
  };
  addThemeObserver(listener);
  win.addEventListener(
    "unload",
    function () {
      removeThemeObserver(listener);
      win = null;
    },
    { once: true }
  );
}

// Chrome <-> Content communication
function onContentMessage(e) {
  // Do not handle events from different documents.
  const win = this;
  if (win != e.target) {
    return;
  }

  const value = e.detail.value;
  switch (e.detail.type) {
    case "save":
      win.docShell.messageManager.sendAsyncMessage(
        "devtools:jsonview:save",
        value
      );
  }
}

function createInstance() {
  return new Converter();
}

exports.JsonViewService = {
  createInstance,
};

95%


¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.