mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-04 02:57:38 +00:00
3250d94dc2
Differential Revision: https://phabricator.services.mozilla.com/D220572
259 lines
7.3 KiB
JavaScript
259 lines
7.3 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/. */
|
|
|
|
const lazy = {};
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
NetworkUtils:
|
|
"resource://devtools/shared/network-observer/NetworkUtils.sys.mjs",
|
|
});
|
|
|
|
/**
|
|
* The NetworkResponse class is a wrapper around the internal channel which
|
|
* provides getters and methods closer to fetch's response concept
|
|
* (https://fetch.spec.whatwg.org/#concept-response).
|
|
*/
|
|
export class NetworkResponse {
|
|
#channel;
|
|
#decodedBodySize;
|
|
#encodedBodySize;
|
|
#fromCache;
|
|
#fromServiceWorker;
|
|
#isCachedCSS;
|
|
#isDataURL;
|
|
#headersTransmittedSize;
|
|
#status;
|
|
#statusMessage;
|
|
#totalTransmittedSize;
|
|
#wrappedChannel;
|
|
|
|
/**
|
|
*
|
|
* @param {nsIChannel} channel
|
|
* The channel for the response.
|
|
* @param {object} params
|
|
* @param {boolean} params.fromCache
|
|
* Whether the response was read from the cache or not.
|
|
* @param {boolean} params.fromServiceWorker
|
|
* Whether the response is coming from a service worker or not.
|
|
* @param {boolean} params.isCachedCSS
|
|
* Whether the response is coming from a cached css file.
|
|
* @param {string=} params.rawHeaders
|
|
* The response's raw (ie potentially compressed) headers
|
|
*/
|
|
constructor(channel, params) {
|
|
this.#channel = channel;
|
|
const {
|
|
fromCache,
|
|
fromServiceWorker,
|
|
isCachedCSS,
|
|
rawHeaders = "",
|
|
} = params;
|
|
this.#fromCache = fromCache;
|
|
this.#fromServiceWorker = fromServiceWorker;
|
|
this.#isCachedCSS = isCachedCSS;
|
|
this.#isDataURL = this.#channel instanceof Ci.nsIDataChannel;
|
|
this.#wrappedChannel = ChannelWrapper.get(channel);
|
|
|
|
this.#decodedBodySize = 0;
|
|
this.#encodedBodySize = 0;
|
|
this.#headersTransmittedSize = rawHeaders.length;
|
|
this.#totalTransmittedSize = rawHeaders.length;
|
|
|
|
// See https://github.com/w3c/webdriver-bidi/issues/761
|
|
// For 304 responses, the response will be replaced by the cached response
|
|
// between responseStarted and responseCompleted, which will effectively
|
|
// change the status and statusMessage.
|
|
// Until the issue linked above has been discussed and closed, we will
|
|
// cache the status/statusMessage in order to ensure consistent values
|
|
// between responseStarted and responseCompleted.
|
|
this.#status = this.#isDataURL ? 200 : this.#channel.responseStatus;
|
|
this.#statusMessage =
|
|
this.#isDataURL || this.#isCachedCSS
|
|
? "OK"
|
|
: this.#channel.responseStatusText;
|
|
}
|
|
|
|
get decodedBodySize() {
|
|
return this.#decodedBodySize;
|
|
}
|
|
|
|
get encodedBodySize() {
|
|
return this.#encodedBodySize;
|
|
}
|
|
|
|
get headers() {
|
|
return this.#getHeadersList();
|
|
}
|
|
|
|
get headersTransmittedSize() {
|
|
return this.#headersTransmittedSize;
|
|
}
|
|
|
|
get fromCache() {
|
|
return this.#fromCache;
|
|
}
|
|
|
|
get fromServiceWorker() {
|
|
return this.#fromServiceWorker;
|
|
}
|
|
|
|
get mimeType() {
|
|
return this.#getComputedMimeType();
|
|
}
|
|
|
|
get protocol() {
|
|
return lazy.NetworkUtils.getProtocol(this.#channel);
|
|
}
|
|
|
|
get serializedURL() {
|
|
return this.#channel.URI.spec;
|
|
}
|
|
|
|
get status() {
|
|
return this.#status;
|
|
}
|
|
|
|
get statusMessage() {
|
|
return this.#statusMessage;
|
|
}
|
|
|
|
get totalTransmittedSize() {
|
|
return this.#totalTransmittedSize;
|
|
}
|
|
|
|
/**
|
|
* Clear a response header from the responses's headers list.
|
|
*
|
|
* @param {string} name
|
|
* The header's name.
|
|
*/
|
|
clearResponseHeader(name) {
|
|
this.#channel.setResponseHeader(
|
|
name, // aName
|
|
"", // aValue="" as an empty value
|
|
false // aMerge=false to force clearing the header
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Set a response header
|
|
*
|
|
* @param {string} name
|
|
* The header's name.
|
|
* @param {string} value
|
|
* The header's value.
|
|
* @param {object} options
|
|
* @param {boolean} options.merge
|
|
* True if the value should be merged with the existing value, false if it
|
|
* should override it. Defaults to false.
|
|
*/
|
|
setResponseHeader(name, value, options) {
|
|
const { merge = false } = options;
|
|
this.#channel.setResponseHeader(name, value, merge);
|
|
}
|
|
|
|
setResponseStatus(options) {
|
|
let { status, statusText } = options;
|
|
if (status === null) {
|
|
status = this.#channel.responseStatus;
|
|
}
|
|
|
|
if (statusText === null) {
|
|
statusText = this.#channel.responseStatusText;
|
|
}
|
|
|
|
this.#channel.setResponseStatus(status, statusText);
|
|
|
|
// Update the cached status and statusMessage.
|
|
this.#status = this.#channel.responseStatus;
|
|
this.#statusMessage = this.#channel.responseStatusText;
|
|
}
|
|
|
|
/**
|
|
* Set the various response sizes for this response. Depending on how the
|
|
* completion was monitored (DevTools NetworkResponseListener or ChannelWrapper
|
|
* event), sizes need to be retrieved differently.
|
|
* There this is a simple setter and the actual logic to retrieve sizes is in
|
|
* NetworkEventRecord.
|
|
*
|
|
* @param {object} sizes
|
|
* @param {number} sizes.decodedBodySize
|
|
* The decoded body size.
|
|
* @param {number} sizes.encodedBodySize
|
|
* The encoded body size.
|
|
* @param {number} sizes.totalTransmittedSize
|
|
* The total transmitted size.
|
|
*/
|
|
setResponseSizes(sizes) {
|
|
const { decodedBodySize, encodedBodySize, totalTransmittedSize } = sizes;
|
|
this.#decodedBodySize = decodedBodySize;
|
|
this.#encodedBodySize = encodedBodySize;
|
|
this.#totalTransmittedSize = totalTransmittedSize;
|
|
}
|
|
|
|
/**
|
|
* Return a static version of the class instance.
|
|
* This method is used to prepare the data to be sent with the events for cached resources
|
|
* generated from the content process but need to be sent to the parent.
|
|
*/
|
|
toJSON() {
|
|
return {
|
|
decodedBodySize: this.decodedBodySize,
|
|
headers: this.headers,
|
|
headersTransmittedSize: this.headersTransmittedSize,
|
|
encodedBodySize: this.encodedBodySize,
|
|
fromCache: this.fromCache,
|
|
mimeType: this.mimeType,
|
|
protocol: this.protocol,
|
|
serializedURL: this.serializedURL,
|
|
status: this.status,
|
|
statusMessage: this.statusMessage,
|
|
totalTransmittedSize: this.totalTransmittedSize,
|
|
};
|
|
}
|
|
|
|
#getComputedMimeType() {
|
|
// TODO: DevTools NetworkObserver is computing a similar value in
|
|
// addResponseContent, but uses an inconsistent implementation in
|
|
// addResponseStart. This approach can only be used as early as in
|
|
// addResponseHeaders. We should move this logic to the NetworkObserver and
|
|
// expose mimeType in addResponseStart. Bug 1809670.
|
|
let mimeType = "";
|
|
|
|
try {
|
|
if (this.#isDataURL || this.#isCachedCSS) {
|
|
mimeType = this.#channel.contentType;
|
|
} else {
|
|
mimeType = this.#wrappedChannel.contentType;
|
|
}
|
|
const contentCharset = this.#channel.contentCharset;
|
|
if (contentCharset) {
|
|
mimeType += `;charset=${contentCharset}`;
|
|
}
|
|
} catch (e) {
|
|
// Ignore exceptions when reading contentType/contentCharset
|
|
}
|
|
|
|
return mimeType;
|
|
}
|
|
|
|
#getHeadersList() {
|
|
const headers = [];
|
|
|
|
// According to the fetch spec for data URLs we can just hardcode
|
|
// "Content-Type" header.
|
|
if (this.#isDataURL) {
|
|
headers.push(["Content-Type", this.#channel.contentType]);
|
|
} else {
|
|
this.#channel.visitResponseHeaders({
|
|
visitHeader(name, value) {
|
|
headers.push([name, value]);
|
|
},
|
|
});
|
|
}
|
|
|
|
return headers;
|
|
}
|
|
}
|