/* 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 { Ci, Cr } = require("chrome");

const {
  wildcardToRegExp,
} = require("devtools/server/actors/network-monitor/utils/wildcard-to-regexp");

loader.lazyRequireGetter(
  this,
  "NetworkHelper",
  "devtools/shared/webconsole/network-helper"
);

loader.lazyGetter(this, "tpFlagsMask", () => {
  const Services = require("Services");
  const trackingProtectionLevel2Enabled = Services.prefs
    .getStringPref("urlclassifier.trackingTable")
    .includes("content-track-digest256");

  return trackingProtectionLevel2Enabled
    ? ~Ci.nsIClassifiedChannel.CLASSIFIED_ANY_BASIC_TRACKING &
        ~Ci.nsIClassifiedChannel.CLASSIFIED_ANY_STRICT_TRACKING
    : ~Ci.nsIClassifiedChannel.CLASSIFIED_ANY_BASIC_TRACKING &
        Ci.nsIClassifiedChannel.CLASSIFIED_ANY_STRICT_TRACKING;
});

// Copied from https://searchfox.org/mozilla-central/source/__GENERATED__/xpcom/base/ErrorList.h#297
// Allows to stringify an error number
const ErrorCodes = {
  NS_OK: 0x0,
  NS_ERROR_BASE: 0xc1f30000,
  NS_ERROR_NOT_INITIALIZED: 0xc1f30001,
  NS_ERROR_ALREADY_INITIALIZED: 0xc1f30002,
  NS_ERROR_NOT_IMPLEMENTED: 0x80004001,
  NS_NOINTERFACE: 0x80004002,
  NS_ERROR_NO_INTERFACE: 0x80004002,
  NS_ERROR_ABORT: 0x80004004,
  NS_ERROR_FAILURE: 0x80004005,
  NS_ERROR_UNEXPECTED: 0x8000ffff,
  NS_ERROR_OUT_OF_MEMORY: 0x8007000e,
  NS_ERROR_ILLEGAL_VALUE: 0x80070057,
  NS_ERROR_INVALID_ARG: 0x80070057,
  NS_ERROR_INVALID_POINTER: 0x80070057,
  NS_ERROR_NULL_POINTER: 0x80070057,
  NS_ERROR_NO_AGGREGATION: 0x80040110,
  NS_ERROR_NOT_AVAILABLE: 0x80040111,
  NS_ERROR_FACTORY_NOT_REGISTERED: 0x80040154,
  NS_ERROR_FACTORY_REGISTER_AGAIN: 0x80040155,
  NS_ERROR_FACTORY_NOT_LOADED: 0x800401f8,
  NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT: 0xc1f30101,
  NS_ERROR_FACTORY_EXISTS: 0xc1f30100,
  NS_ERROR_CANNOT_CONVERT_DATA: 0x80460001,
  NS_ERROR_OBJECT_IS_IMMUTABLE: 0x80460002,
  NS_ERROR_LOSS_OF_SIGNIFICANT_DATA: 0x80460003,
  NS_ERROR_NOT_SAME_THREAD: 0x80460004,
  NS_ERROR_ILLEGAL_DURING_SHUTDOWN: 0x8046001e,
  NS_ERROR_SERVICE_NOT_AVAILABLE: 0x80460016,
  NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA: 0x460001,
  NS_SUCCESS_INTERRUPTED_TRAVERSE: 0x460002,
  NS_BASE_STREAM_CLOSED: 0x80470002,
  NS_BASE_STREAM_OSERROR: 0x80470003,
  NS_BASE_STREAM_ILLEGAL_ARGS: 0x80470004,
  NS_BASE_STREAM_NO_CONVERTER: 0x80470005,
  NS_BASE_STREAM_BAD_CONVERSION: 0x80470006,
  NS_BASE_STREAM_WOULD_BLOCK: 0x80470007,
  NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE: 0x80480001,
  NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND: 0x80480002,
  NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE: 0x80480003,
  NS_ERROR_GFX_PRINTER_STARTDOC: 0x80480004,
  NS_ERROR_GFX_PRINTER_ENDDOC: 0x80480005,
  NS_ERROR_GFX_PRINTER_STARTPAGE: 0x80480006,
  NS_ERROR_GFX_PRINTER_DOC_IS_BUSY: 0x80480007,
  NS_ERROR_GFX_CMAP_MALFORMED: 0x80480033,
  NS_SUCCESS_EVENT_CONSUMED: 0x490001,
  NS_BINDING_SUCCEEDED: 0x0,
  NS_BINDING_FAILED: 0x804b0001,
  NS_BINDING_ABORTED: 0x804b0002,
  NS_BINDING_REDIRECTED: 0x804b0003,
  NS_BINDING_RETARGETED: 0x804b0004,
  NS_ERROR_MALFORMED_URI: 0x804b000a,
  NS_ERROR_IN_PROGRESS: 0x804b000f,
  NS_ERROR_NO_CONTENT: 0x804b0011,
  NS_ERROR_UNKNOWN_PROTOCOL: 0x804b0012,
  NS_ERROR_INVALID_CONTENT_ENCODING: 0x804b001b,
  NS_ERROR_CORRUPTED_CONTENT: 0x804b001d,
  NS_ERROR_INVALID_SIGNATURE: 0x804b003a,
  NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY: 0x804b0022,
  NS_ERROR_ALREADY_OPENED: 0x804b0049,
  NS_ERROR_ALREADY_CONNECTED: 0x804b000b,
  NS_ERROR_NOT_CONNECTED: 0x804b000c,
  NS_ERROR_CONNECTION_REFUSED: 0x804b000d,
  NS_ERROR_NET_TIMEOUT: 0x804b000e,
  NS_ERROR_OFFLINE: 0x804b0010,
  NS_ERROR_PORT_ACCESS_NOT_ALLOWED: 0x804b0013,
  NS_ERROR_NET_RESET: 0x804b0014,
  NS_ERROR_NET_INTERRUPT: 0x804b0047,
  NS_ERROR_PROXY_CONNECTION_REFUSED: 0x804b0048,
  NS_ERROR_NET_PARTIAL_TRANSFER: 0x804b004c,
  NS_ERROR_NET_INADEQUATE_SECURITY: 0x804b0052,
  NS_ERROR_NET_HTTP2_SENT_GOAWAY: 0x804b0053,
  NS_ERROR_NET_HTTP3_PROTOCOL_ERROR: 0x804b0054,
  NS_ERROR_NOT_RESUMABLE: 0x804b0019,
  NS_ERROR_REDIRECT_LOOP: 0x804b001f,
  NS_ERROR_ENTITY_CHANGED: 0x804b0020,
  NS_ERROR_UNSAFE_CONTENT_TYPE: 0x804b004a,
  NS_ERROR_REMOTE_XUL: 0x804b004b,
  NS_ERROR_LOAD_SHOWED_ERRORPAGE: 0x804b004d,
  NS_ERROR_DOCSHELL_DYING: 0x804b004e,
  NS_ERROR_FTP_LOGIN: 0x804b0015,
  NS_ERROR_FTP_CWD: 0x804b0016,
  NS_ERROR_FTP_PASV: 0x804b0017,
  NS_ERROR_FTP_PWD: 0x804b0018,
  NS_ERROR_FTP_LIST: 0x804b001c,
  NS_ERROR_UNKNOWN_HOST: 0x804b001e,
  NS_ERROR_DNS_LOOKUP_QUEUE_FULL: 0x804b0021,
  NS_ERROR_UNKNOWN_PROXY_HOST: 0x804b002a,
  NS_ERROR_DEFINITIVE_UNKNOWN_HOST: 0x804b002b,
  NS_ERROR_UNKNOWN_SOCKET_TYPE: 0x804b0033,
  NS_ERROR_SOCKET_CREATE_FAILED: 0x804b0034,
  NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED: 0x804b0035,
  NS_ERROR_SOCKET_ADDRESS_IN_USE: 0x804b0036,
  NS_ERROR_CACHE_KEY_NOT_FOUND: 0x804b003d,
  NS_ERROR_CACHE_DATA_IS_STREAM: 0x804b003e,
  NS_ERROR_CACHE_DATA_IS_NOT_STREAM: 0x804b003f,
  NS_ERROR_CACHE_WAIT_FOR_VALIDATION: 0x804b0040,
  NS_ERROR_CACHE_ENTRY_DOOMED: 0x804b0041,
  NS_ERROR_CACHE_READ_ACCESS_DENIED: 0x804b0042,
  NS_ERROR_CACHE_WRITE_ACCESS_DENIED: 0x804b0043,
  NS_ERROR_CACHE_IN_USE: 0x804b0044,
  NS_ERROR_DOCUMENT_NOT_CACHED: 0x804b0046,
  NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS: 0x804b0050,
  NS_ERROR_HOST_IS_IP_ADDRESS: 0x804b0051,
  NS_SUCCESS_ADOPTED_DATA: 0x4b005a,
  NS_NET_STATUS_BEGIN_FTP_TRANSACTION: 0x4b001b,
  NS_NET_STATUS_END_FTP_TRANSACTION: 0x4b001c,
  NS_SUCCESS_AUTH_FINISHED: 0x4b0028,
  NS_NET_STATUS_READING: 0x804b0008,
  NS_NET_STATUS_WRITING: 0x804b0009,
  NS_NET_STATUS_RESOLVING_HOST: 0x804b0003,
  NS_NET_STATUS_RESOLVED_HOST: 0x804b000b,
  NS_NET_STATUS_CONNECTING_TO: 0x804b0007,
  NS_NET_STATUS_CONNECTED_TO: 0x804b0004,
  NS_NET_STATUS_TLS_HANDSHAKE_STARTING: 0x804b000c,
  NS_NET_STATUS_TLS_HANDSHAKE_ENDED: 0x804b000d,
  NS_NET_STATUS_SENDING_TO: 0x804b0005,
  NS_NET_STATUS_WAITING_FOR: 0x804b000a,
  NS_NET_STATUS_RECEIVING_FROM: 0x804b0006,
  NS_ERROR_INTERCEPTION_FAILED: 0x804b0064,
  NS_ERROR_PROXY_CODE_BASE: 0x804b03e8,
  NS_ERROR_PROXY_MULTIPLE_CHOICES: 0x804b0514,
  NS_ERROR_PROXY_MOVED_PERMANENTLY: 0x804b0515,
  NS_ERROR_PROXY_FOUND: 0x804b0516,
  NS_ERROR_PROXY_SEE_OTHER: 0x804b0517,
  NS_ERROR_PROXY_NOT_MODIFIED: 0x804b0518,
  NS_ERROR_PROXY_TEMPORARY_REDIRECT: 0x804b051b,
  NS_ERROR_PROXY_PERMANENT_REDIRECT: 0x804b051c,
  NS_ERROR_PROXY_BAD_REQUEST: 0x804b0578,
  NS_ERROR_PROXY_UNAUTHORIZED: 0x804b0579,
  NS_ERROR_PROXY_PAYMENT_REQUIRED: 0x804b057a,
  NS_ERROR_PROXY_FORBIDDEN: 0x804b057b,
  NS_ERROR_PROXY_NOT_FOUND: 0x804b057c,
  NS_ERROR_PROXY_METHOD_NOT_ALLOWED: 0x804b057d,
  NS_ERROR_PROXY_NOT_ACCEPTABLE: 0x804b057e,
  NS_ERROR_PROXY_AUTHENTICATION_FAILED: 0x804b057f,
  NS_ERROR_PROXY_REQUEST_TIMEOUT: 0x804b0580,
  NS_ERROR_PROXY_CONFLICT: 0x804b0581,
  NS_ERROR_PROXY_GONE: 0x804b0582,
  NS_ERROR_PROXY_LENGTH_REQUIRED: 0x804b0583,
  NS_ERROR_PROXY_PRECONDITION_FAILED: 0x804b0584,
  NS_ERROR_PROXY_REQUEST_ENTITY_TOO_LARGE: 0x804b0585,
  NS_ERROR_PROXY_REQUEST_URI_TOO_LONG: 0x804b0586,
  NS_ERROR_PROXY_UNSUPPORTED_MEDIA_TYPE: 0x804b0587,
  NS_ERROR_PROXY_REQUESTED_RANGE_NOT_SATISFIABLE: 0x804b0588,
  NS_ERROR_PROXY_EXPECTATION_FAILED: 0x804b0589,
  NS_ERROR_PROXY_MISDIRECTED_REQUEST: 0x804b058d,
  NS_ERROR_PROXY_TOO_EARLY: 0x804b0591,
  NS_ERROR_PROXY_UPGRADE_REQUIRED: 0x804b0592,
  NS_ERROR_PROXY_PRECONDITION_REQUIRED: 0x804b0594,
  NS_ERROR_PROXY_TOO_MANY_REQUESTS: 0x804b0595,
  NS_ERROR_PROXY_REQUEST_HEADER_FIELDS_TOO_LARGE: 0x804b0597,
  NS_ERROR_PROXY_UNAVAILABLE_FOR_LEGAL_REASONS: 0x804b05ab,
  NS_ERROR_PROXY_INTERNAL_SERVER_ERROR: 0x804b05dc,
  NS_ERROR_PROXY_NOT_IMPLEMENTED: 0x804b05dd,
  NS_ERROR_PROXY_BAD_GATEWAY: 0x804b05de,
  NS_ERROR_PROXY_SERVICE_UNAVAILABLE: 0x804b05df,
  NS_ERROR_PROXY_GATEWAY_TIMEOUT: 0x804b05e0,
  NS_ERROR_PROXY_VERSION_NOT_SUPPORTED: 0x804b05e1,
  NS_ERROR_PROXY_VARIANT_ALSO_NEGOTIATES: 0x804b05e2,
  NS_ERROR_PROXY_NOT_EXTENDED: 0x804b05e6,
  NS_ERROR_PROXY_NETWORK_AUTHENTICATION_REQUIRED: 0x804b05e7,
  NS_ERROR_PLUGINS_PLUGINSNOTCHANGED: 0x804c03e8,
  NS_ERROR_PLUGIN_DISABLED: 0x804c03e9,
  NS_ERROR_PLUGIN_BLOCKLISTED: 0x804c03ea,
  NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED: 0x804c03eb,
  NS_ERROR_PLUGIN_CLICKTOPLAY: 0x804c03ec,
  NS_OK_PARSE_SHEET: 0x4d0001,
  NS_POSITION_BEFORE_TABLE: 0x4d0003,
  NS_ERROR_HTMLPARSER_CONTINUE: 0x0,
  NS_ERROR_HTMLPARSER_EOF: 0x804e03e8,
  NS_ERROR_HTMLPARSER_UNKNOWN: 0x804e03e9,
  NS_ERROR_HTMLPARSER_CANTPROPAGATE: 0x804e03ea,
  NS_ERROR_HTMLPARSER_CONTEXTMISMATCH: 0x804e03eb,
  NS_ERROR_HTMLPARSER_BADFILENAME: 0x804e03ec,
  NS_ERROR_HTMLPARSER_BADURL: 0x804e03ed,
  NS_ERROR_HTMLPARSER_INVALIDPARSERCONTEXT: 0x804e03ee,
  NS_ERROR_HTMLPARSER_INTERRUPTED: 0x804e03ef,
  NS_ERROR_HTMLPARSER_BLOCK: 0x804e03f0,
  NS_ERROR_HTMLPARSER_BADTOKENIZER: 0x804e03f1,
  NS_ERROR_HTMLPARSER_BADATTRIBUTE: 0x804e03f2,
  NS_ERROR_HTMLPARSER_UNRESOLVEDDTD: 0x804e03f3,
  NS_ERROR_HTMLPARSER_MISPLACEDTABLECONTENT: 0x804e03f4,
  NS_ERROR_HTMLPARSER_BADDTD: 0x804e03f5,
  NS_ERROR_HTMLPARSER_BADCONTEXT: 0x804e03f6,
  NS_ERROR_HTMLPARSER_STOPPARSING: 0x804e03f7,
  NS_ERROR_HTMLPARSER_UNTERMINATEDSTRINGLITERAL: 0x804e03f8,
  NS_ERROR_HTMLPARSER_HIERARCHYTOODEEP: 0x804e03f9,
  NS_ERROR_HTMLPARSER_FAKE_ENDTAG: 0x804e03fa,
  NS_ERROR_HTMLPARSER_INVALID_COMMENT: 0x804e03fb,
  NS_RDF_ASSERTION_ACCEPTED: 0x0,
  NS_RDF_NO_VALUE: 0x4f0002,
  NS_RDF_ASSERTION_REJECTED: 0x4f0003,
  NS_RDF_STOP_VISIT: 0x4f0004,
  NS_ERROR_UCONV_NOCONV: 0x80500001,
  NS_ERROR_UDEC_ILLEGALINPUT: 0x8050000e,
  NS_OK_HAD_REPLACEMENTS: 0x500003,
  NS_OK_UDEC_MOREINPUT: 0x50000c,
  NS_OK_UDEC_MOREOUTPUT: 0x50000d,
  NS_OK_UENC_MOREOUTPUT: 0x500022,
  NS_ERROR_UENC_NOMAPPING: 0x500023,
  NS_ERROR_ILLEGAL_INPUT: 0x8050000e,
  NS_ERROR_FILE_UNRECOGNIZED_PATH: 0x80520001,
  NS_ERROR_FILE_UNRESOLVABLE_SYMLINK: 0x80520002,
  NS_ERROR_FILE_EXECUTION_FAILED: 0x80520003,
  NS_ERROR_FILE_UNKNOWN_TYPE: 0x80520004,
  NS_ERROR_FILE_DESTINATION_NOT_DIR: 0x80520005,
  NS_ERROR_FILE_TARGET_DOES_NOT_EXIST: 0x80520006,
  NS_ERROR_FILE_COPY_OR_MOVE_FAILED: 0x80520007,
  NS_ERROR_FILE_ALREADY_EXISTS: 0x80520008,
  NS_ERROR_FILE_INVALID_PATH: 0x80520009,
  NS_ERROR_FILE_DISK_FULL: 0x8052000a,
  NS_ERROR_FILE_CORRUPTED: 0x8052000b,
  NS_ERROR_FILE_NOT_DIRECTORY: 0x8052000c,
  NS_ERROR_FILE_IS_DIRECTORY: 0x8052000d,
  NS_ERROR_FILE_IS_LOCKED: 0x8052000e,
  NS_ERROR_FILE_TOO_BIG: 0x8052000f,
  NS_ERROR_FILE_NO_DEVICE_SPACE: 0x80520010,
  NS_ERROR_FILE_NAME_TOO_LONG: 0x80520011,
  NS_ERROR_FILE_NOT_FOUND: 0x80520012,
  NS_ERROR_FILE_READ_ONLY: 0x80520013,
  NS_ERROR_FILE_DIR_NOT_EMPTY: 0x80520014,
  NS_ERROR_FILE_ACCESS_DENIED: 0x80520015,
  NS_SUCCESS_FILE_DIRECTORY_EMPTY: 0x520001,
  NS_SUCCESS_AGGREGATE_RESULT: 0x520002,
  NS_ERROR_DOM_INDEX_SIZE_ERR: 0x80530001,
  NS_ERROR_DOM_HIERARCHY_REQUEST_ERR: 0x80530003,
  NS_ERROR_DOM_WRONG_DOCUMENT_ERR: 0x80530004,
  NS_ERROR_DOM_INVALID_CHARACTER_ERR: 0x80530005,
  NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR: 0x80530007,
  NS_ERROR_DOM_NOT_FOUND_ERR: 0x80530008,
  NS_ERROR_DOM_NOT_SUPPORTED_ERR: 0x80530009,
  NS_ERROR_DOM_INUSE_ATTRIBUTE_ERR: 0x8053000a,
  NS_ERROR_DOM_INVALID_STATE_ERR: 0x8053000b,
  NS_ERROR_DOM_SYNTAX_ERR: 0x8053000c,
  NS_ERROR_DOM_INVALID_MODIFICATION_ERR: 0x8053000d,
  NS_ERROR_DOM_NAMESPACE_ERR: 0x8053000e,
  NS_ERROR_DOM_INVALID_ACCESS_ERR: 0x8053000f,
  NS_ERROR_DOM_TYPE_MISMATCH_ERR: 0x80530011,
  NS_ERROR_DOM_SECURITY_ERR: 0x80530012,
  NS_ERROR_DOM_NETWORK_ERR: 0x80530013,
  NS_ERROR_DOM_ABORT_ERR: 0x80530014,
  NS_ERROR_DOM_URL_MISMATCH_ERR: 0x80530015,
  NS_ERROR_DOM_QUOTA_EXCEEDED_ERR: 0x80530016,
  NS_ERROR_DOM_TIMEOUT_ERR: 0x80530017,
  NS_ERROR_DOM_INVALID_NODE_TYPE_ERR: 0x80530018,
  NS_ERROR_DOM_DATA_CLONE_ERR: 0x80530019,
  NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR: 0x8053001c,
  NS_ERROR_DOM_UNKNOWN_ERR: 0x8053001e,
  NS_ERROR_DOM_DATA_ERR: 0x8053001f,
  NS_ERROR_DOM_OPERATION_ERR: 0x80530020,
  NS_ERROR_DOM_NOT_ALLOWED_ERR: 0x80530021,
  NS_ERROR_DOM_SECMAN_ERR: 0x805303e9,
  NS_ERROR_DOM_WRONG_TYPE_ERR: 0x805303ea,
  NS_ERROR_DOM_NOT_OBJECT_ERR: 0x805303eb,
  NS_ERROR_DOM_NOT_XPC_OBJECT_ERR: 0x805303ec,
  NS_ERROR_DOM_NOT_NUMBER_ERR: 0x805303ed,
  NS_ERROR_DOM_NOT_BOOLEAN_ERR: 0x805303ee,
  NS_ERROR_DOM_NOT_FUNCTION_ERR: 0x805303ef,
  NS_ERROR_DOM_TOO_FEW_PARAMETERS_ERR: 0x805303f0,
  NS_ERROR_DOM_PROP_ACCESS_DENIED: 0x805303f2,
  NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED: 0x805303f3,
  NS_ERROR_DOM_BAD_URI: 0x805303f4,
  NS_ERROR_DOM_RETVAL_UNDEFINED: 0x805303f5,
  NS_ERROR_UNCATCHABLE_EXCEPTION: 0x805303f7,
  NS_ERROR_DOM_MALFORMED_URI: 0x805303f8,
  NS_ERROR_DOM_INVALID_HEADER_NAME: 0x805303f9,
  NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT: 0x805303fa,
  NS_ERROR_DOM_JS_DECODING_ERROR: 0x80530402,
  NS_ERROR_DOM_IMAGE_INACTIVE_DOCUMENT: 0x80530403,
  NS_ERROR_DOM_IMAGE_INVALID_REQUEST: 0x80530404,
  NS_ERROR_DOM_IMAGE_BROKEN: 0x80530405,
  NS_ERROR_DOM_CORP_FAILED: 0x8053040c,
  NS_SUCCESS_DOM_NO_OPERATION: 0x530001,
  NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW: 0x530002,
  NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE: 0x530003,
  NS_IMAGELIB_ERROR_FAILURE: 0x80540005,
  NS_IMAGELIB_ERROR_NO_DECODER: 0x80540006,
  NS_IMAGELIB_ERROR_NOT_FINISHED: 0x80540007,
  NS_IMAGELIB_ERROR_NO_ENCODER: 0x80540009,
  NS_ERROR_EDITOR_DESTROYED: 0x80560001,
  NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE: 0x80560002,
  NS_ERROR_EDITOR_ACTION_CANCELED: 0x80560003,
  NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND: 0x560001,
  NS_SUCCESS_EDITOR_FOUND_TARGET: 0x560002,
  NS_ERROR_XPC_NOT_ENOUGH_ARGS: 0x80570001,
  NS_ERROR_XPC_NEED_OUT_OBJECT: 0x80570002,
  NS_ERROR_XPC_CANT_SET_OUT_VAL: 0x80570003,
  NS_ERROR_XPC_NATIVE_RETURNED_FAILURE: 0x80570004,
  NS_ERROR_XPC_CANT_GET_INTERFACE_INFO: 0x80570005,
  NS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFO: 0x80570006,
  NS_ERROR_XPC_CANT_GET_METHOD_INFO: 0x80570007,
  NS_ERROR_XPC_UNEXPECTED: 0x80570008,
  NS_ERROR_XPC_BAD_CONVERT_JS: 0x80570009,
  NS_ERROR_XPC_BAD_CONVERT_NATIVE: 0x8057000a,
  NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF: 0x8057000b,
  NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: 0x8057000c,
  NS_ERROR_XPC_CANT_CONVERT_WN_TO_FUN: 0x8057000d,
  NS_ERROR_XPC_CANT_DEFINE_PROP_ON_WN: 0x8057000e,
  NS_ERROR_XPC_CANT_WATCH_WN_STATIC: 0x8057000f,
  NS_ERROR_XPC_CANT_EXPORT_WN_STATIC: 0x80570010,
  NS_ERROR_XPC_SCRIPTABLE_CALL_FAILED: 0x80570011,
  NS_ERROR_XPC_SCRIPTABLE_CTOR_FAILED: 0x80570012,
  NS_ERROR_XPC_CANT_CALL_WO_SCRIPTABLE: 0x80570013,
  NS_ERROR_XPC_CANT_CTOR_WO_SCRIPTABLE: 0x80570014,
  NS_ERROR_XPC_CI_RETURNED_FAILURE: 0x80570015,
  NS_ERROR_XPC_GS_RETURNED_FAILURE: 0x80570016,
  NS_ERROR_XPC_BAD_CID: 0x80570017,
  NS_ERROR_XPC_BAD_IID: 0x80570018,
  NS_ERROR_XPC_CANT_CREATE_WN: 0x80570019,
  NS_ERROR_XPC_JS_THREW_EXCEPTION: 0x8057001a,
  NS_ERROR_XPC_JS_THREW_NATIVE_OBJECT: 0x8057001b,
  NS_ERROR_XPC_JS_THREW_JS_OBJECT: 0x8057001c,
  NS_ERROR_XPC_JS_THREW_NULL: 0x8057001d,
  NS_ERROR_XPC_JS_THREW_STRING: 0x8057001e,
  NS_ERROR_XPC_JS_THREW_NUMBER: 0x8057001f,
  NS_ERROR_XPC_JAVASCRIPT_ERROR: 0x80570020,
  NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS: 0x80570021,
  NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY: 0x80570022,
  NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY: 0x80570023,
  NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY: 0x80570024,
  NS_ERROR_XPC_CANT_GET_ARRAY_INFO: 0x80570025,
  NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING: 0x80570026,
  NS_ERROR_XPC_SECURITY_MANAGER_VETO: 0x80570027,
  NS_ERROR_XPC_INTERFACE_NOT_SCRIPTABLE: 0x80570028,
  NS_ERROR_XPC_INTERFACE_NOT_FROM_NSISUPPORTS: 0x80570029,
  NS_ERROR_XPC_CANT_SET_READ_ONLY_CONSTANT: 0x8057002b,
  NS_ERROR_XPC_CANT_SET_READ_ONLY_ATTRIBUTE: 0x8057002c,
  NS_ERROR_XPC_CANT_SET_READ_ONLY_METHOD: 0x8057002d,
  NS_ERROR_XPC_CANT_ADD_PROP_TO_WRAPPED_NATIVE: 0x8057002e,
  NS_ERROR_XPC_CALL_TO_SCRIPTABLE_FAILED: 0x8057002f,
  NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED: 0x80570030,
  NS_ERROR_XPC_BAD_ID_STRING: 0x80570031,
  NS_ERROR_XPC_BAD_INITIALIZER_NAME: 0x80570032,
  NS_ERROR_XPC_HAS_BEEN_SHUTDOWN: 0x80570033,
  NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN: 0x80570034,
  NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL: 0x80570035,
  NS_ERROR_LAUNCHED_CHILD_PROCESS: 0x805800c8,
  NS_ERROR_SHOW_PROFILE_MANAGER: 0x805800c9,
  NS_ERROR_DATABASE_CHANGED: 0x805800ca,
  NS_ERROR_XFO_VIOLATION: 0x805a0060,
  NS_ERROR_CSP_NAVIGATE_TO_VIOLATION: 0x805a0061,
  NS_ERROR_CSP_FORM_ACTION_VIOLATION: 0x805a0062,
  NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION: 0x805a0063,
  NS_ERROR_SRI_CORRUPT: 0x805a00c8,
  NS_ERROR_SRI_NOT_ELIGIBLE: 0x805a00c9,
  NS_ERROR_SRI_UNEXPECTED_HASH_TYPE: 0x805a00ca,
  NS_ERROR_SRI_IMPORT: 0x805a00cb,
  NS_ERROR_CMS_VERIFY_NOT_SIGNED: 0x805a0400,
  NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO: 0x805a0401,
  NS_ERROR_CMS_VERIFY_BAD_DIGEST: 0x805a0402,
  NS_ERROR_CMS_VERIFY_NOCERT: 0x805a0404,
  NS_ERROR_CMS_VERIFY_UNTRUSTED: 0x805a0405,
  NS_ERROR_CMS_VERIFY_ERROR_UNVERIFIED: 0x805a0407,
  NS_ERROR_CMS_VERIFY_ERROR_PROCESSING: 0x805a0408,
  NS_ERROR_CMS_VERIFY_BAD_SIGNATURE: 0x805a0409,
  NS_ERROR_CMS_VERIFY_DIGEST_MISMATCH: 0x805a040a,
  NS_ERROR_CMS_VERIFY_UNKNOWN_ALGO: 0x805a040b,
  NS_ERROR_CMS_VERIFY_UNSUPPORTED_ALGO: 0x805a040c,
  NS_ERROR_CMS_VERIFY_MALFORMED_SIGNATURE: 0x805a040d,
  NS_ERROR_CMS_VERIFY_HEADER_MISMATCH: 0x805a040e,
  NS_ERROR_CMS_VERIFY_NOT_YET_ATTEMPTED: 0x805a040f,
  NS_ERROR_CMS_VERIFY_CERT_WITHOUT_ADDRESS: 0x805a0410,
  NS_ERROR_CMS_ENCRYPT_NO_BULK_ALG: 0x805a0420,
  NS_ERROR_CMS_ENCRYPT_INCOMPLETE: 0x805a0421,
  NS_ERROR_WONT_HANDLE_CONTENT: 0x805d0001,
  NS_ERROR_MALWARE_URI: 0x805d001e,
  NS_ERROR_PHISHING_URI: 0x805d001f,
  NS_ERROR_TRACKING_URI: 0x805d0022,
  NS_ERROR_UNWANTED_URI: 0x805d0023,
  NS_ERROR_BLOCKED_URI: 0x805d0025,
  NS_ERROR_HARMFUL_URI: 0x805d0026,
  NS_ERROR_FINGERPRINTING_URI: 0x805d0029,
  NS_ERROR_CRYPTOMINING_URI: 0x805d002a,
  NS_ERROR_SOCIALTRACKING_URI: 0x805d002b,
  NS_ERROR_SAVE_LINK_AS_TIMEOUT: 0x805d0020,
  NS_ERROR_PARSED_DATA_CACHED: 0x805d0021,
  NS_REFRESHURI_HEADER_FOUND: 0x5d0002,
  NS_ERROR_CONTENT_BLOCKED: 0x805e0006,
  NS_ERROR_CONTENT_BLOCKED_SHOW_ALT: 0x805e0007,
  NS_PROPTABLE_PROP_NOT_THERE: 0x805e000a,
  NS_ERROR_CONTENT_CRASHED: 0x805e0010,
  NS_ERROR_FRAME_CRASHED: 0x805e000e,
  NS_ERROR_BUILDID_MISMATCH: 0x805e0011,
  NS_PROPTABLE_PROP_OVERWRITTEN: 0x5e000b,
  NS_FINDBROADCASTER_NOT_FOUND: 0x5e000c,
  NS_FINDBROADCASTER_FOUND: 0x5e000d,
  NS_ERROR_XPATH_INVALID_ARG: 0x80070057,
  NS_ERROR_XSLT_PARSE_FAILURE: 0x80600001,
  NS_ERROR_XPATH_PARSE_FAILURE: 0x80600002,
  NS_ERROR_XSLT_ALREADY_SET: 0x80600003,
  NS_ERROR_XSLT_EXECUTION_FAILURE: 0x80600004,
  NS_ERROR_XPATH_UNKNOWN_FUNCTION: 0x80600005,
  NS_ERROR_XSLT_BAD_RECURSION: 0x80600006,
  NS_ERROR_XSLT_BAD_VALUE: 0x80600007,
  NS_ERROR_XSLT_NODESET_EXPECTED: 0x80600008,
  NS_ERROR_XSLT_ABORTED: 0x80600009,
  NS_ERROR_XSLT_NETWORK_ERROR: 0x8060000a,
  NS_ERROR_XSLT_WRONG_MIME_TYPE: 0x8060000b,
  NS_ERROR_XSLT_LOAD_RECURSION: 0x8060000c,
  NS_ERROR_XPATH_BAD_ARGUMENT_COUNT: 0x8060000d,
  NS_ERROR_XPATH_BAD_EXTENSION_FUNCTION: 0x8060000e,
  NS_ERROR_XPATH_PAREN_EXPECTED: 0x8060000f,
  NS_ERROR_XPATH_INVALID_AXIS: 0x80600010,
  NS_ERROR_XPATH_NO_NODE_TYPE_TEST: 0x80600011,
  NS_ERROR_XPATH_BRACKET_EXPECTED: 0x80600012,
  NS_ERROR_XPATH_INVALID_VAR_NAME: 0x80600013,
  NS_ERROR_XPATH_UNEXPECTED_END: 0x80600014,
  NS_ERROR_XPATH_OPERATOR_EXPECTED: 0x80600015,
  NS_ERROR_XPATH_UNCLOSED_LITERAL: 0x80600016,
  NS_ERROR_XPATH_BAD_COLON: 0x80600017,
  NS_ERROR_XPATH_BAD_BANG: 0x80600018,
  NS_ERROR_XPATH_ILLEGAL_CHAR: 0x80600019,
  NS_ERROR_XPATH_BINARY_EXPECTED: 0x8060001a,
  NS_ERROR_XSLT_LOAD_BLOCKED_ERROR: 0x8060001b,
  NS_ERROR_XPATH_INVALID_EXPRESSION_EVALUATED: 0x8060001c,
  NS_ERROR_XPATH_UNBALANCED_CURLY_BRACE: 0x8060001d,
  NS_ERROR_XSLT_BAD_NODE_NAME: 0x8060001e,
  NS_ERROR_XSLT_VAR_ALREADY_SET: 0x8060001f,
  NS_ERROR_XSLT_CALL_TO_KEY_NOT_ALLOWED: 0x80600020,
  NS_XSLT_GET_NEW_HANDLER: 0x600001,
  NS_ERROR_TRANSPORT_INIT: 0x80610001,
  NS_ERROR_DUPLICATE_HANDLE: 0x80610002,
  NS_ERROR_BRIDGE_OPEN_PARENT: 0x80610003,
  NS_ERROR_BRIDGE_OPEN_CHILD: 0x80610004,
  NS_ERROR_STORAGE_BUSY: 0x80630001,
  NS_ERROR_STORAGE_IOERR: 0x80630002,
  NS_ERROR_STORAGE_CONSTRAINT: 0x80630003,
  NS_ERROR_DOM_FILE_NOT_FOUND_ERR: 0x80650000,
  NS_ERROR_DOM_FILE_NOT_READABLE_ERR: 0x80650001,
  NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR: 0x80660001,
  NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR: 0x80660003,
  NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR: 0x80660004,
  NS_ERROR_DOM_INDEXEDDB_DATA_ERR: 0x80660005,
  NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR: 0x80660006,
  NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR: 0x80660007,
  NS_ERROR_DOM_INDEXEDDB_ABORT_ERR: 0x80660008,
  NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR: 0x80660009,
  NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR: 0x8066000a,
  NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR: 0x8066000b,
  NS_ERROR_DOM_INDEXEDDB_VERSION_ERR: 0x8066000c,
  NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR: 0x806603e9,
  NS_ERROR_DOM_INDEXEDDB_KEY_ERR: 0x806603ea,
  NS_ERROR_DOM_INDEXEDDB_RENAME_OBJECT_STORE_ERR: 0x806603eb,
  NS_ERROR_DOM_INDEXEDDB_RENAME_INDEX_ERR: 0x806603ec,
  NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR: 0x80670001,
  NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR: 0x80670002,
  NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR: 0x80670003,
  NS_ERROR_DOM_FILEHANDLE_ABORT_ERR: 0x80670004,
  NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR: 0x80670005,
  NS_ERROR_DOM_FILEHANDLE_QUOTA_ERR: 0x80670006,
  NS_ERROR_SIGNED_JAR_NOT_SIGNED: 0x80680001,
  NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY: 0x80680002,
  NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY: 0x80680003,
  NS_ERROR_SIGNED_JAR_ENTRY_MISSING: 0x80680004,
  NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE: 0x80680005,
  NS_ERROR_SIGNED_JAR_ENTRY_TOO_LARGE: 0x80680006,
  NS_ERROR_SIGNED_JAR_ENTRY_INVALID: 0x80680007,
  NS_ERROR_SIGNED_JAR_MANIFEST_INVALID: 0x80680008,
  NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR: 0x80690001,
  NS_ERROR_DOM_FILESYSTEM_INVALID_MODIFICATION_ERR: 0x80690002,
  NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR: 0x80690003,
  NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR: 0x80690004,
  NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR: 0x80690005,
  NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR: 0x80690006,
  NS_ERROR_SIGNED_APP_MANIFEST_INVALID: 0x806b0001,
  NS_ERROR_DOM_PUSH_INVALID_REGISTRATION_ERR: 0x806d0001,
  NS_ERROR_DOM_PUSH_DENIED_ERR: 0x806d0002,
  NS_ERROR_DOM_PUSH_ABORT_ERR: 0x806d0003,
  NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE: 0x806d0004,
  NS_ERROR_DOM_PUSH_INVALID_KEY_ERR: 0x806d0005,
  NS_ERROR_DOM_PUSH_MISMATCHED_KEY_ERR: 0x806d0006,
  NS_ERROR_DOM_PUSH_GCM_DISABLED: 0x806d0007,
  NS_ERROR_DOM_MEDIA_ABORT_ERR: 0x806e0001,
  NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR: 0x806e0002,
  NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR: 0x806e0003,
  NS_ERROR_DOM_MEDIA_DECODE_ERR: 0x806e0004,
  NS_ERROR_DOM_MEDIA_FATAL_ERR: 0x806e0005,
  NS_ERROR_DOM_MEDIA_METADATA_ERR: 0x806e0006,
  NS_ERROR_DOM_MEDIA_OVERFLOW_ERR: 0x806e0007,
  NS_ERROR_DOM_MEDIA_END_OF_STREAM: 0x806e0008,
  NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA: 0x806e0009,
  NS_ERROR_DOM_MEDIA_CANCELED: 0x806e000a,
  NS_ERROR_DOM_MEDIA_MEDIASINK_ERR: 0x806e000b,
  NS_ERROR_DOM_MEDIA_DEMUXER_ERR: 0x806e000c,
  NS_ERROR_DOM_MEDIA_CDM_ERR: 0x806e000d,
  NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER: 0x806e000e,
  NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER: 0x806e000f,
  NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR: 0x806e0065,
  NS_ERROR_UC_UPDATE_UNKNOWN: 0x806f0001,
  NS_ERROR_UC_UPDATE_DUPLICATE_PREFIX: 0x806f0002,
  NS_ERROR_UC_UPDATE_INFINITE_LOOP: 0x806f0003,
  NS_ERROR_UC_UPDATE_WRONG_REMOVAL_INDICES: 0x806f0004,
  NS_ERROR_UC_UPDATE_CHECKSUM_MISMATCH: 0x806f0005,
  NS_ERROR_UC_UPDATE_MISSING_CHECKSUM: 0x806f0006,
  NS_ERROR_UC_UPDATE_SHUTDOWNING: 0x806f0007,
  NS_ERROR_UC_UPDATE_TABLE_NOT_FOUND: 0x806f0008,
  NS_ERROR_UC_UPDATE_BUILD_PREFIX_FAILURE: 0x806f0009,
  NS_ERROR_UC_UPDATE_FAIL_TO_WRITE_DISK: 0x806f000a,
  NS_ERROR_UC_UPDATE_UNEXPECTED_VERSION: 0x806f000b,
  NS_ERROR_UC_PARSER_MISSING_PARAM: 0x806f000c,
  NS_ERROR_UC_PARSER_DECODE_FAILURE: 0x806f000d,
  NS_ERROR_UC_PARSER_UNKNOWN_THREAT: 0x806f000e,
  NS_ERROR_UC_PARSER_MISSING_VALUE: 0x806f000f,
  NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION: 0x80700001,
  NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION: 0x80700002,
  NS_ERROR_INTERNAL_ERRORRESULT_EXCEPTION_ON_JSCONTEXT: 0x80700003,
  NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR: 0x80700004,
  NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR: 0x80700005,
  NS_ERROR_DOWNLOAD_COMPLETE: 0x80780001,
  NS_ERROR_DOWNLOAD_NOT_PARTIAL: 0x80780002,
  NS_ERROR_UNORM_MOREOUTPUT: 0x80780021,
  NS_ERROR_DOCSHELL_REQUEST_REJECTED: 0x807803e9,
  NS_ERROR_DOCUMENT_IS_PRINTMODE: 0x807807d1,
  NS_SUCCESS_DONT_FIXUP: 0x780001,
  NS_SUCCESS_RESTART_APP: 0x780001,
  NS_ERROR_NOT_IN_TREE: 0x80780026,
  NS_OK_NO_NAME_CLAUSE_HANDLED: 0x780022,
  NS_ERROR_BLOCKED_BY_POLICY: 0x80780003,
};

/**
 * Convert a nsIContentPolicy constant to a display string
 */
const LOAD_CAUSE_STRINGS = {
  [Ci.nsIContentPolicy.TYPE_INVALID]: "invalid",
  [Ci.nsIContentPolicy.TYPE_OTHER]: "other",
  [Ci.nsIContentPolicy.TYPE_SCRIPT]: "script",
  [Ci.nsIContentPolicy.TYPE_IMAGE]: "img",
  [Ci.nsIContentPolicy.TYPE_STYLESHEET]: "stylesheet",
  [Ci.nsIContentPolicy.TYPE_OBJECT]: "object",
  [Ci.nsIContentPolicy.TYPE_DOCUMENT]: "document",
  [Ci.nsIContentPolicy.TYPE_SUBDOCUMENT]: "subdocument",
  [Ci.nsIContentPolicy.TYPE_PING]: "ping",
  [Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST]: "xhr",
  [Ci.nsIContentPolicy.TYPE_OBJECT_SUBREQUEST]: "objectSubdoc",
  [Ci.nsIContentPolicy.TYPE_DTD]: "dtd",
  [Ci.nsIContentPolicy.TYPE_FONT]: "font",
  [Ci.nsIContentPolicy.TYPE_MEDIA]: "media",
  [Ci.nsIContentPolicy.TYPE_WEBSOCKET]: "websocket",
  [Ci.nsIContentPolicy.TYPE_CSP_REPORT]: "csp",
  [Ci.nsIContentPolicy.TYPE_XSLT]: "xslt",
  [Ci.nsIContentPolicy.TYPE_BEACON]: "beacon",
  [Ci.nsIContentPolicy.TYPE_FETCH]: "fetch",
  [Ci.nsIContentPolicy.TYPE_IMAGESET]: "imageset",
  [Ci.nsIContentPolicy.TYPE_WEB_MANIFEST]: "webManifest",
};

/**
 * Given a platform error code numer, return the name of it as a string
 *
 * @param {Number} code The error code to translate.
 * @return {String} The error's name.
 */
exports.getErrorCodeString = function(code) {
  for (const name in ErrorCodes) {
    if (ErrorCodes[name] == code) {
      return name;
    }
  }
  return "NS_UNKNOWN_ERROR_CODE-" + code;
};

exports.causeTypeToString = function(
  causeType,
  loadFlags,
  internalContentPolicyType
) {
  let prefix = "";
  if (
    (causeType == Ci.nsIContentPolicy.TYPE_IMAGESET ||
      internalContentPolicyType == Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE) &&
    loadFlags & Ci.nsIRequest.LOAD_BACKGROUND
  ) {
    prefix = "lazy-";
  }

  return prefix + LOAD_CAUSE_STRINGS[causeType] || "unknown";
};

exports.stringToCauseType = function(value) {
  return Object.keys(LOAD_CAUSE_STRINGS).find(
    key => LOAD_CAUSE_STRINGS[key] === value
  );
};

/**
 * Get the browsing context id for the channel.
 *
 * @param {*} channel
 * @returns {number}
 */
exports.getChannelBrowsingContextID = function(channel) {
  if (channel.loadInfo.browsingContextID) {
    return channel.loadInfo.browsingContextID;
  }
  // At least WebSocket channel aren't having a browsingContextID set on their loadInfo
  // We fallback on top frame element, which works, but will be wrong for WebSocket
  // in same-process iframes...
  const topFrame = NetworkHelper.getTopFrameForRequest(channel);
  // topFrame is typically null for some chrome requests like favicons
  if (topFrame && topFrame.browsingContext) {
    return topFrame.browsingContext.id;
  }
  return null;
};

/**
 * Does this channel represent a Preload request.
 *
 * @param {*} channel
 * @returns {boolean}
 */
exports.isPreloadRequest = function(channel) {
  const type = channel.loadInfo.internalContentPolicyType;
  return (
    type == Ci.nsIContentPolicy.TYPE_INTERNAL_SCRIPT_PRELOAD ||
    type == Ci.nsIContentPolicy.TYPE_INTERNAL_MODULE_PRELOAD ||
    type == Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_PRELOAD ||
    type == Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET_PRELOAD ||
    type == Ci.nsIContentPolicy.TYPE_INTERNAL_FONT_PRELOAD
  );
};

/**
 * Creates a network event based on the channel.
 *
 * @param {*} channel
 * @return {Object} event - The network event
 */
exports.createNetworkEvent = function(
  channel,
  {
    timestamp,
    fromCache,
    fromServiceWorker,
    extraStringData,
    blockedReason,
    blockingExtension = null,
    blockedURLs = [],
    saveRequestAndResponseBodies = false,
  }
) {
  channel.QueryInterface(Ci.nsIPrivateBrowsingChannel);

  const event = {};
  event.method = channel.requestMethod;
  event.channelId = channel.channelId;
  event.browsingContextID = this.getChannelBrowsingContextID(channel);
  event.url = channel.URI.spec;
  event.private = channel.isChannelPrivate;
  event.headersSize = extraStringData ? extraStringData.length : 0;
  event.startedDateTime = (timestamp
    ? new Date(Math.round(timestamp / 1000))
    : new Date()
  ).toISOString();
  event.fromCache = fromCache;
  event.fromServiceWorker = fromServiceWorker;
  // Only consider channels classified as level-1 to be trackers if our preferences
  // would not cause such channels to be blocked in strict content blocking mode.
  // Make sure the value produced here is a boolean.
  if (channel instanceof Ci.nsIClassifiedChannel) {
    event.isThirdPartyTrackingResource = !!(
      channel.isThirdPartyTrackingResource() &&
      (channel.thirdPartyClassificationFlags & tpFlagsMask) == 0
    );
  }
  const referrerInfo = channel.referrerInfo;
  event.referrerPolicy = referrerInfo
    ? referrerInfo.getReferrerPolicyString()
    : "";

  // Determine the cause and if this is an XHR request.
  let causeType = Ci.nsIContentPolicy.TYPE_OTHER;
  let causeUri = null;

  if (channel.loadInfo) {
    causeType = channel.loadInfo.externalContentPolicyType;
    const { loadingPrincipal } = channel.loadInfo;
    if (loadingPrincipal) {
      causeUri = loadingPrincipal.spec;
    }
  }

  // Show the right WebSocket URL in case of WS channel.
  if (channel.notificationCallbacks) {
    let wsChannel = null;
    try {
      wsChannel = channel.notificationCallbacks.QueryInterface(
        Ci.nsIWebSocketChannel
      );
    } catch (e) {
      // Not all channels implement nsIWebSocketChannel.
    }
    if (wsChannel) {
      event.url = wsChannel.URI.spec;
      event.serial = wsChannel.serial;
    }
  }

  event.cause = {
    type: this.causeTypeToString(
      causeType,
      channel.loadFlags,
      channel.loadInfo.internalContentPolicyType
    ),
    loadingDocumentUri: causeUri,
    stacktrace: undefined,
  };

  event.isXHR =
    causeType === Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST ||
    causeType === Ci.nsIContentPolicy.TYPE_FETCH;

  // Determine the HTTP version.
  const httpVersionMaj = {};
  const httpVersionMin = {};

  channel.QueryInterface(Ci.nsIHttpChannelInternal);
  channel.getRequestVersion(httpVersionMaj, httpVersionMin);

  event.httpVersion =
    "HTTP/" + httpVersionMaj.value + "." + httpVersionMin.value;

  event.discardRequestBody = !saveRequestAndResponseBodies;
  event.discardResponseBody = !saveRequestAndResponseBodies;

  // Check the request URL with ones manually blocked by the user in DevTools.
  // If it's meant to be blocked, we cancel the request and annotate the event.
  if (!blockedReason) {
    if (blockedReason !== undefined) {
      // We were definitely blocked, but the blocker didn't say why.
      event.blockedReason = "unknown";
    } else if (blockedURLs.some(url => wildcardToRegExp(url).test(event.url))) {
      channel.cancel(Cr.NS_BINDING_ABORTED);
      event.blockedReason = "devtools";
    }
  } else {
    event.blockedReason = blockedReason;
    if (blockingExtension) {
      event.blockingExtension = blockingExtension;
    }
  }

  // isNavigationRequest is true for the one request used to load a new top level document
  // of a given tab, or top level window. It will typically be false for navigation requests
  // of iframes, i.e. the request loading another document in an iframe.
  event.isNavigationRequest =
    channel.isMainDocumentChannel && channel.loadInfo.isTopLevelLoad;

  return event;
};

/**
 * For a given channel, with its associated http activity object,
 * fetch the request's headers and cookies.
 * This data is passed to the owner, i.e. the NetworkEventActor,
 * so that the frontend can later fetch it via getRequestHeaders/getRequestCookies.
 *
 * @param {*} channel
 * @param {*} owner - The network event actor
 * @param {Object} extraStringData - The uncached response headers.
 */
exports.fetchRequestHeadersAndCookies = function(
  channel,
  owner,
  { extraStringData = "" }
) {
  const headers = [];
  let cookies = [];
  let cookieHeader = null;

  // Copy the request header data.
  channel.visitRequestHeaders({
    visitHeader: function(name, value) {
      if (name == "Cookie") {
        cookieHeader = value;
      }
      headers.push({ name: name, value: value });
    },
  });

  if (cookieHeader) {
    cookies = NetworkHelper.parseCookieHeader(cookieHeader);
  }

  owner.addRequestHeaders(headers, extraStringData);
  owner.addRequestCookies(cookies);
};
