network-content.js (4943B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { Actor } = require("resource://devtools/shared/protocol.js"); 8 const { 9 networkContentSpec, 10 } = require("resource://devtools/shared/specs/network-content.js"); 11 12 const lazy = {}; 13 14 ChromeUtils.defineESModuleGetters( 15 lazy, 16 { 17 NetUtil: "resource://gre/modules/NetUtil.sys.mjs", 18 NetworkUtils: 19 "resource://devtools/shared/network-observer/NetworkUtils.sys.mjs", 20 }, 21 { global: "contextual" } 22 ); 23 24 loader.lazyRequireGetter( 25 this, 26 "WebConsoleUtils", 27 "resource://devtools/server/actors/webconsole/utils.js", 28 true 29 ); 30 31 const { 32 TYPES: { NETWORK_EVENT_STACKTRACE }, 33 getResourceWatcher, 34 } = require("resource://devtools/server/actors/resources/index.js"); 35 36 /** 37 * This actor manages all network functionality runnning 38 * in the content process. 39 * 40 * @class 41 */ 42 class NetworkContentActor extends Actor { 43 constructor(conn, targetActor) { 44 super(conn, networkContentSpec); 45 this.targetActor = targetActor; 46 } 47 48 get networkEventStackTraceWatcher() { 49 return getResourceWatcher(this.targetActor, NETWORK_EVENT_STACKTRACE); 50 } 51 52 /** 53 * Send an HTTP request 54 * 55 * @param {object} request 56 * The details of the HTTP Request. 57 * @return {number} 58 * The channel id for the request 59 */ 60 async sendHTTPRequest(request) { 61 return new Promise(resolve => { 62 const { url, method, headers, body, cause, securityFlags } = request; 63 // Set the loadingNode and loadGroup to the target document - otherwise the 64 // request won't show up in the opened netmonitor. 65 const doc = this.targetActor.window.document; 66 const channelURI = lazy.NetUtil.newURI(url); 67 68 const channel = lazy.NetUtil.newChannel({ 69 uri: channelURI, 70 loadingNode: doc, 71 securityFlags: 72 securityFlags || 73 Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT, 74 contentPolicyType: 75 lazy.NetworkUtils.stringToCauseType(cause.type) || 76 Ci.nsIContentPolicy.TYPE_OTHER, 77 }); 78 79 // If the load is of TYPE_DOCUMENT, we have to annotate the loadinfo 80 // with the appropriate HTTPS Telemetry information. 81 if ( 82 channel.loadInfo.externalContentPolicyType == 83 Ci.nsIContentPolicy.TYPE_DOCUMENT 84 ) { 85 channel.loadInfo.httpsUpgradeTelemetry = channelURI.schemeIs("https") 86 ? Ci.nsILoadInfo.ALREADY_HTTPS 87 : Ci.nsILoadInfo.NO_UPGRADE; 88 } 89 90 channel.QueryInterface(Ci.nsIHttpChannel); 91 channel.loadGroup = doc.documentLoadGroup; 92 channel.loadFlags |= 93 Ci.nsIRequest.LOAD_BYPASS_CACHE | 94 Ci.nsIRequest.INHIBIT_CACHING | 95 Ci.nsIRequest.LOAD_ANONYMOUS; 96 97 if (method == "CONNECT") { 98 throw new Error( 99 "The CONNECT method is restricted and cannot be sent by devtools" 100 ); 101 } 102 channel.requestMethod = method; 103 104 if (headers) { 105 for (const { name, value } of headers) { 106 if (name.toLowerCase() == "referer") { 107 // The referer header and referrerInfo object should always match. So 108 // if we want to set the header from privileged context, we should set 109 // referrerInfo. The referrer header will get set internally. 110 channel.setNewReferrerInfo( 111 value, 112 Ci.nsIReferrerInfo.UNSAFE_URL, 113 true 114 ); 115 } else { 116 channel.setRequestHeader(name, value, false); 117 } 118 } 119 } 120 121 if (body) { 122 channel.QueryInterface(Ci.nsIUploadChannel2); 123 const bodyStream = Cc[ 124 "@mozilla.org/io/string-input-stream;1" 125 ].createInstance(Ci.nsIStringInputStream); 126 bodyStream.setByteStringData(body); 127 channel.explicitSetUploadStream(bodyStream, null, -1, method, false); 128 } 129 130 // Make sure the fetch has completed before sending the channel id, 131 // so that there is a higher possibilty that the request get into the 132 // redux store beforehand (but this does not gurantee that). 133 lazy.NetUtil.asyncFetch(channel, () => 134 resolve({ channelId: channel.channelId }) 135 ); 136 }); 137 } 138 139 /** 140 * Gets the stacktrace for the specified network resource. 141 * 142 * @param {number} resourceId 143 * The id for the network resource 144 * @return {object} 145 * The response packet - stack trace. 146 */ 147 getStackTrace(resourceId) { 148 if (!this.networkEventStackTraceWatcher) { 149 throw new Error("Not listening for network event stacktraces"); 150 } 151 const stacktrace = 152 this.networkEventStackTraceWatcher.getStackTrace(resourceId); 153 return WebConsoleUtils.removeFramesAboveDebuggerEval(stacktrace); 154 } 155 } 156 157 exports.NetworkContentActor = NetworkContentActor;