|
|
|
|
| 1 |
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ |
1 |
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ |
| 2 |
/* vim: set ft= javascript ts=2 et sw=2 tw=80: */ |
2 |
/* vim: set ft= javascript ts=2 et sw=2 tw=80: */ |
| 3 |
/* This Source Code Form is subject to the terms of the Mozilla Public |
3 |
/* This Source Code Form is subject to the terms of the Mozilla Public |
| 4 |
* License, v. 2.0. If a copy of the MPL was not distributed with this |
4 |
* License, v. 2.0. If a copy of the MPL was not distributed with this |
| 5 |
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 |
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 6 |
|
6 |
|
| 7 |
"use strict"; |
7 |
"use strict"; |
| 8 |
|
8 |
|
| 9 |
const {Cc, Ci, Cu, Cr} = require("chrome"); |
9 |
const {Cc, Ci, Cu, Cr, components} = require("chrome"); |
| 10 |
const Services = require("Services"); |
10 |
const Services = require("Services"); |
| 11 |
|
11 |
|
| 12 |
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
12 |
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
| 13 |
|
13 |
|
| 14 |
loader.lazyRequireGetter(this, "NetworkHelper", |
14 |
loader.lazyRequireGetter(this, "NetworkHelper", |
| 15 |
"devtools/shared/webconsole/network-helper"); |
15 |
"devtools/shared/webconsole/network-helper"); |
| 16 |
loader.lazyRequireGetter(this, "DevToolsUtils", |
16 |
loader.lazyRequireGetter(this, "DevToolsUtils", |
| 17 |
"devtools/shared/DevToolsUtils"); |
17 |
"devtools/shared/DevToolsUtils"); |
|
|
| 32 |
const HTTP_FOUND = 302; |
32 |
const HTTP_FOUND = 302; |
| 33 |
const HTTP_SEE_OTHER = 303; |
33 |
const HTTP_SEE_OTHER = 303; |
| 34 |
const HTTP_TEMPORARY_REDIRECT = 307; |
34 |
const HTTP_TEMPORARY_REDIRECT = 307; |
| 35 |
|
35 |
|
| 36 |
// The maximum number of bytes a NetworkResponseListener can hold: 1 MB |
36 |
// The maximum number of bytes a NetworkResponseListener can hold: 1 MB |
| 37 |
const RESPONSE_BODY_LIMIT = 1048576; |
37 |
const RESPONSE_BODY_LIMIT = 1048576; |
| 38 |
|
38 |
|
| 39 |
/** |
39 |
/** |
|
|
40 |
* Check if a given network request should be logged by a network monitor |
| 41 |
* based on the specified filters. |
| 42 |
* |
| 43 |
* @param nsIHttpChannel channel |
| 44 |
* Request to check. |
| 45 |
* @param filters |
| 46 |
* NetworkMonitor filters to match against. |
| 47 |
* @return boolean |
| 48 |
* True if the network request should be logged, false otherwise. |
| 49 |
*/ |
| 50 |
function matchRequest(channel, filters) { |
| 51 |
// Log everything if no filter is specified |
| 52 |
if (!filters.topFrame && !filters.window && !filters.appId) { |
| 53 |
return true; |
| 54 |
} |
| 55 |
|
| 56 |
// Ignore requests from chrome or add-on code when we are monitoring |
| 57 |
// content. |
| 58 |
// TODO: one particular test (browser_styleeditor_fetch-from-cache.js) needs |
| 59 |
// the DevToolsUtils.testing check. We will move to a better way to serve |
| 60 |
// its needs in bug 1167188, where this check should be removed. |
| 61 |
if (!DevToolsUtils.testing && channel.loadInfo && |
| 62 |
channel.loadInfo.loadingDocument === null && |
| 63 |
channel.loadInfo.loadingPrincipal === |
| 64 |
Services.scriptSecurityManager.getSystemPrincipal()) { |
| 65 |
return false; |
| 66 |
} |
| 67 |
|
| 68 |
if (filters.window) { |
| 69 |
// Since frames support, this.window may not be the top level content |
| 70 |
// frame, so that we can't only compare with win.top. |
| 71 |
let win = NetworkHelper.getWindowForRequest(channel); |
| 72 |
while (win) { |
| 73 |
if (win == filters.window) { |
| 74 |
return true; |
| 75 |
} |
| 76 |
if (win.parent == win) { |
| 77 |
break; |
| 78 |
} |
| 79 |
win = win.parent; |
| 80 |
} |
| 81 |
} |
| 82 |
|
| 83 |
if (filters.topFrame) { |
| 84 |
let topFrame = NetworkHelper.getTopFrameForRequest(channel); |
| 85 |
if (topFrame && topFrame === filters.topFrame) { |
| 86 |
return true; |
| 87 |
} |
| 88 |
} |
| 89 |
|
| 90 |
if (filters.appId) { |
| 91 |
let appId = NetworkHelper.getAppIdForRequest(channel); |
| 92 |
if (appId && appId == filters.appId) { |
| 93 |
return true; |
| 94 |
} |
| 95 |
} |
| 96 |
|
| 97 |
// The following check is necessary because beacon channels don't come |
| 98 |
// associated with a load group. Bug 1160837 will hopefully introduce a |
| 99 |
// platform fix that will render the following code entirely useless. |
| 100 |
if (channel.loadInfo && |
| 101 |
channel.loadInfo.externalContentPolicyType == |
| 102 |
Ci.nsIContentPolicy.TYPE_BEACON) { |
| 103 |
let nonE10sMatch = filters.window && |
| 104 |
channel.loadInfo.loadingDocument === filters.window.document; |
| 105 |
const loadingPrincipal = channel.loadInfo.loadingPrincipal; |
| 106 |
let e10sMatch = filters.topFrame && |
| 107 |
filters.topFrame.contentPrincipal && |
| 108 |
filters.topFrame.contentPrincipal.equals(loadingPrincipal) && |
| 109 |
filters.topFrame.contentPrincipal.URI.spec == channel.referrer.spec; |
| 110 |
let b2gMatch = filters.appId && loadingPrincipal.appId === filters.appId; |
| 111 |
if (nonE10sMatch || e10sMatch || b2gMatch) { |
| 112 |
return true; |
| 113 |
} |
| 114 |
} |
| 115 |
|
| 116 |
return false; |
| 117 |
} |
| 118 |
|
| 119 |
function StackTraceCollector(filters) { |
| 120 |
this.filters = filters; |
| 121 |
this.stacktraces = new Map(); |
| 122 |
this._onOpeningRequest = this._onOpeningRequest.bind(this); |
| 123 |
} |
| 124 |
|
| 125 |
StackTraceCollector.prototype = { |
| 126 |
init() { |
| 127 |
Services.obs.addObserver(this._onOpeningRequest, |
| 128 |
"http-on-opening-request", false); |
| 129 |
}, |
| 130 |
|
| 131 |
destroy() { |
| 132 |
Services.obs.removeObserver(this._onOpeningRequest, |
| 133 |
"http-on-opening-request"); |
| 134 |
}, |
| 135 |
|
| 136 |
_onOpeningRequest(subject) { |
| 137 |
let channel = subject.QueryInterface(Ci.nsIHttpChannel); |
| 138 |
|
| 139 |
if (!matchRequest(channel, this.filters)) { |
| 140 |
return; |
| 141 |
} |
| 142 |
|
| 143 |
let uri = channel.URI.spec; |
| 144 |
let channelId = channel.channelId; |
| 145 |
let frame = components.stack; |
| 146 |
let stacktrace = []; |
| 147 |
if (frame && frame.caller) { |
| 148 |
frame = frame.caller; |
| 149 |
while (frame) { |
| 150 |
stacktrace.push({ |
| 151 |
filename: frame.filename, |
| 152 |
lineNumber: frame.lineNumber, |
| 153 |
columnNumber: frame.columnNumber, |
| 154 |
functionName: frame.name, |
| 155 |
asyncCause: frame.asyncCause, |
| 156 |
}); |
| 157 |
if (frame.asyncCaller) { |
| 158 |
frame = frame.asyncCaller; |
| 159 |
} else { |
| 160 |
frame = frame.caller; |
| 161 |
} |
| 162 |
} |
| 163 |
} |
| 164 |
|
| 165 |
this.stacktraces.set(channelId, stacktrace); |
| 166 |
console.log("Saved stacktrace:", channelId, uri, this.stacktraces.size); |
| 167 |
}, |
| 168 |
|
| 169 |
getStackTrace(channelId, uri) { |
| 170 |
let trace = this.stacktraces.get(channelId); |
| 171 |
this.stacktraces.delete(channelId); |
| 172 |
|
| 173 |
if (!trace) { |
| 174 |
console.error(`Stacktrace for channel ${channelId} was not saved`, uri); |
| 175 |
return null; |
| 176 |
} |
| 177 |
|
| 178 |
console.log("Retrieved stacktrace:", channelId, uri, this.stacktraces.size); |
| 179 |
return trace; |
| 180 |
} |
| 181 |
}; |
| 182 |
|
| 183 |
/** |
| 40 |
* The network response listener implements the nsIStreamListener and |
184 |
* The network response listener implements the nsIStreamListener and |
| 41 |
* nsIRequestObserver interfaces. This is used within the NetworkMonitor feature |
185 |
* nsIRequestObserver interfaces. This is used within the NetworkMonitor feature |
| 42 |
* to get the response body of the request. |
186 |
* to get the response body of the request. |
| 43 |
* |
187 |
* |
| 44 |
* The code is mostly based on code listings from: |
188 |
* The code is mostly based on code listings from: |
| 45 |
* |
189 |
* |
| 46 |
* http://www.softwareishard.com/blog/firebug/ |
190 |
* http://www.softwareishard.com/blog/firebug/ |
| 47 |
* nsitraceablechannel-intercept-http-traffic/ |
191 |
* nsitraceablechannel-intercept-http-traffic/ |
|
|
| 473 |
* - onNetworkEvent(requestInfo, channel, networkMonitor). |
617 |
* - onNetworkEvent(requestInfo, channel, networkMonitor). |
| 474 |
* This method is invoked once for every new network request and it is |
618 |
* This method is invoked once for every new network request and it is |
| 475 |
* given the following arguments: the initial network request |
619 |
* given the following arguments: the initial network request |
| 476 |
* information, and the channel. The third argument is the NetworkMonitor |
620 |
* information, and the channel. The third argument is the NetworkMonitor |
| 477 |
* instance. |
621 |
* instance. |
| 478 |
* onNetworkEvent() must return an object which holds several add*() |
622 |
* onNetworkEvent() must return an object which holds several add*() |
| 479 |
* methods which are used to add further network request/response |
623 |
* methods which are used to add further network request/response |
| 480 |
* information. |
624 |
* information. |
|
|
625 |
* @param boolean collectStackTraces |
| 626 |
* Should this network monitor be collecting stack traces? Should |
| 627 |
* happen only in non-e10s where there is only one NetworkMonitor and |
| 628 |
* there is no proxying between parent and child. In e10s, the |
| 629 |
* NetworkMonitorChild takes care of the stack trace collection. |
| 481 |
*/ |
630 |
*/ |
| 482 |
function NetworkMonitor(filters, owner) { |
631 |
function NetworkMonitor(filters, owner, collectStackTraces) { |
| 483 |
if (filters) { |
632 |
this.filters = filters; |
| 484 |
this.window = filters.window; |
|
|
| 485 |
this.appId = filters.appId; |
| 486 |
this.topFrame = filters.topFrame; |
| 487 |
} |
| 488 |
if (!this.window && !this.appId && !this.topFrame) { |
| 489 |
this._logEverything = true; |
| 490 |
} |
| 491 |
this.owner = owner; |
633 |
this.owner = owner; |
| 492 |
this.openRequests = {}; |
634 |
this.openRequests = {}; |
| 493 |
this.openResponses = {}; |
635 |
this.openResponses = {}; |
| 494 |
this._httpResponseExaminer = |
636 |
this._httpResponseExaminer = |
| 495 |
DevToolsUtils.makeInfallible(this._httpResponseExaminer).bind(this); |
637 |
DevToolsUtils.makeInfallible(this._httpResponseExaminer).bind(this); |
| 496 |
this._serviceWorkerRequest = this._serviceWorkerRequest.bind(this); |
638 |
this._serviceWorkerRequest = this._serviceWorkerRequest.bind(this); |
|
|
639 |
|
| 640 |
if (collectStackTraces) { |
| 641 |
this.stackTraceCollector = new StackTraceCollector(this.filters); |
| 642 |
this.stackTraceCollector.init(); |
| 643 |
} |
| 497 |
} |
644 |
} |
|
|
645 |
|
| 498 |
exports.NetworkMonitor = NetworkMonitor; |
646 |
exports.NetworkMonitor = NetworkMonitor; |
| 499 |
|
647 |
|
| 500 |
NetworkMonitor.prototype = { |
648 |
NetworkMonitor.prototype = { |
| 501 |
_logEverything: false, |
649 |
filters: null, |
| 502 |
window: null, |
|
|
| 503 |
appId: null, |
| 504 |
topFrame: null, |
| 505 |
|
650 |
|
| 506 |
httpTransactionCodes: { |
651 |
httpTransactionCodes: { |
| 507 |
0x5001: "REQUEST_HEADER", |
652 |
0x5001: "REQUEST_HEADER", |
| 508 |
0x5002: "REQUEST_BODY_SENT", |
653 |
0x5002: "REQUEST_BODY_SENT", |
| 509 |
0x5003: "RESPONSE_START", |
654 |
0x5003: "RESPONSE_START", |
| 510 |
0x5004: "RESPONSE_HEADER", |
655 |
0x5004: "RESPONSE_HEADER", |
| 511 |
0x5005: "RESPONSE_COMPLETE", |
656 |
0x5005: "RESPONSE_COMPLETE", |
| 512 |
0x5006: "TRANSACTION_CLOSE", |
657 |
0x5006: "TRANSACTION_CLOSE", |
|
|
| 547 |
*/ |
692 |
*/ |
| 548 |
init: function () { |
693 |
init: function () { |
| 549 |
this.responsePipeSegmentSize = Services.prefs |
694 |
this.responsePipeSegmentSize = Services.prefs |
| 550 |
.getIntPref("network.buffer.cache.size"); |
695 |
.getIntPref("network.buffer.cache.size"); |
| 551 |
this.interceptedChannels = new Set(); |
696 |
this.interceptedChannels = new Set(); |
| 552 |
|
697 |
|
| 553 |
if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT) { |
698 |
if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT) { |
| 554 |
gActivityDistributor.addObserver(this); |
699 |
gActivityDistributor.addObserver(this); |
|
|
700 |
console.log("Added observer to activity distributor"); |
| 555 |
Services.obs.addObserver(this._httpResponseExaminer, |
701 |
Services.obs.addObserver(this._httpResponseExaminer, |
| 556 |
"http-on-examine-response", false); |
702 |
"http-on-examine-response", false); |
| 557 |
Services.obs.addObserver(this._httpResponseExaminer, |
703 |
Services.obs.addObserver(this._httpResponseExaminer, |
| 558 |
"http-on-examine-cached-response", false); |
704 |
"http-on-examine-cached-response", false); |
| 559 |
} |
705 |
} |
| 560 |
// In child processes, only watch for service worker requests |
706 |
// In child processes, only watch for service worker requests |
| 561 |
// everything else only happens in the parent process |
707 |
// everything else only happens in the parent process |
| 562 |
Services.obs.addObserver(this._serviceWorkerRequest, |
708 |
Services.obs.addObserver(this._serviceWorkerRequest, |
|
|
| 597 |
(topic != "http-on-examine-response" && |
743 |
(topic != "http-on-examine-response" && |
| 598 |
topic != "http-on-examine-cached-response") || |
744 |
topic != "http-on-examine-cached-response") || |
| 599 |
!(subject instanceof Ci.nsIHttpChannel)) { |
745 |
!(subject instanceof Ci.nsIHttpChannel)) { |
| 600 |
return; |
746 |
return; |
| 601 |
} |
747 |
} |
| 602 |
|
748 |
|
| 603 |
let channel = subject.QueryInterface(Ci.nsIHttpChannel); |
749 |
let channel = subject.QueryInterface(Ci.nsIHttpChannel); |
| 604 |
|
750 |
|
| 605 |
if (!this._matchRequest(channel)) { |
751 |
if (!matchRequest(channel, this.filters)) { |
| 606 |
return; |
752 |
return; |
| 607 |
} |
753 |
} |
| 608 |
|
754 |
|
| 609 |
let response = { |
755 |
let response = { |
| 610 |
id: gSequenceId(), |
756 |
id: gSequenceId(), |
| 611 |
channel: channel, |
757 |
channel: channel, |
| 612 |
headers: [], |
758 |
headers: [], |
| 613 |
cookies: [], |
759 |
cookies: [], |
|
|
| 752 |
this._onTransactionClose(httpActivity); |
898 |
this._onTransactionClose(httpActivity); |
| 753 |
break; |
899 |
break; |
| 754 |
default: |
900 |
default: |
| 755 |
break; |
901 |
break; |
| 756 |
} |
902 |
} |
| 757 |
}), |
903 |
}), |
| 758 |
|
904 |
|
| 759 |
/** |
905 |
/** |
| 760 |
* Check if a given network request should be logged by this network monitor |
|
|
| 761 |
* instance based on the current filters. |
| 762 |
* |
| 763 |
* @private |
| 764 |
* @param nsIHttpChannel channel |
| 765 |
* Request to check. |
| 766 |
* @return boolean |
| 767 |
* True if the network request should be logged, false otherwise. |
| 768 |
*/ |
| 769 |
_matchRequest: function (channel) { |
| 770 |
if (this._logEverything) { |
| 771 |
return true; |
| 772 |
} |
| 773 |
|
| 774 |
// Ignore requests from chrome or add-on code when we are monitoring |
| 775 |
// content. |
| 776 |
// TODO: one particular test (browser_styleeditor_fetch-from-cache.js) needs |
| 777 |
// the DevToolsUtils.testing check. We will move to a better way to serve |
| 778 |
// its needs in bug 1167188, where this check should be removed. |
| 779 |
if (!DevToolsUtils.testing && channel.loadInfo && |
| 780 |
channel.loadInfo.loadingDocument === null && |
| 781 |
channel.loadInfo.loadingPrincipal === |
| 782 |
Services.scriptSecurityManager.getSystemPrincipal()) { |
| 783 |
return false; |
| 784 |
} |
| 785 |
|
| 786 |
if (this.window) { |
| 787 |
// Since frames support, this.window may not be the top level content |
| 788 |
// frame, so that we can't only compare with win.top. |
| 789 |
let win = NetworkHelper.getWindowForRequest(channel); |
| 790 |
while (win) { |
| 791 |
if (win == this.window) { |
| 792 |
return true; |
| 793 |
} |
| 794 |
if (win.parent == win) { |
| 795 |
break; |
| 796 |
} |
| 797 |
win = win.parent; |
| 798 |
} |
| 799 |
} |
| 800 |
|
| 801 |
if (this.topFrame) { |
| 802 |
let topFrame = NetworkHelper.getTopFrameForRequest(channel); |
| 803 |
if (topFrame && topFrame === this.topFrame) { |
| 804 |
return true; |
| 805 |
} |
| 806 |
} |
| 807 |
|
| 808 |
if (this.appId) { |
| 809 |
let appId = NetworkHelper.getAppIdForRequest(channel); |
| 810 |
if (appId && appId == this.appId) { |
| 811 |
return true; |
| 812 |
} |
| 813 |
} |
| 814 |
|
| 815 |
// The following check is necessary because beacon channels don't come |
| 816 |
// associated with a load group. Bug 1160837 will hopefully introduce a |
| 817 |
// platform fix that will render the following code entirely useless. |
| 818 |
if (channel.loadInfo && |
| 819 |
channel.loadInfo.externalContentPolicyType == |
| 820 |
Ci.nsIContentPolicy.TYPE_BEACON) { |
| 821 |
let nonE10sMatch = this.window && |
| 822 |
channel.loadInfo.loadingDocument === this.window.document; |
| 823 |
const loadingPrincipal = channel.loadInfo.loadingPrincipal; |
| 824 |
let e10sMatch = this.topFrame && |
| 825 |
this.topFrame.contentPrincipal && |
| 826 |
this.topFrame.contentPrincipal.equals(loadingPrincipal) && |
| 827 |
this.topFrame.contentPrincipal.URI.spec == channel.referrer.spec; |
| 828 |
let b2gMatch = this.appId && loadingPrincipal.appId === this.appId; |
| 829 |
if (nonE10sMatch || e10sMatch || b2gMatch) { |
| 830 |
return true; |
| 831 |
} |
| 832 |
} |
| 833 |
|
| 834 |
return false; |
| 835 |
}, |
| 836 |
|
| 837 |
/** |
| 838 |
* |
906 |
* |
| 839 |
*/ |
907 |
*/ |
| 840 |
_createNetworkEvent: function (channel, { timestamp, extraStringData, |
908 |
_createNetworkEvent: function (channel, { timestamp, extraStringData, |
| 841 |
fromCache, fromServiceWorker }) { |
909 |
fromCache, fromServiceWorker }) { |
| 842 |
let win = NetworkHelper.getWindowForRequest(channel); |
910 |
let win = NetworkHelper.getWindowForRequest(channel); |
| 843 |
let httpActivity = this.createActivityObject(channel); |
911 |
let httpActivity = this.createActivityObject(channel); |
| 844 |
|
912 |
|
| 845 |
// see _onRequestBodySent() |
913 |
// see _onRequestBodySent() |
|
|
| 852 |
httpActivity.timings.REQUEST_HEADER = { |
920 |
httpActivity.timings.REQUEST_HEADER = { |
| 853 |
first: timestamp, |
921 |
first: timestamp, |
| 854 |
last: timestamp |
922 |
last: timestamp |
| 855 |
}; |
923 |
}; |
| 856 |
} |
924 |
} |
| 857 |
|
925 |
|
| 858 |
let event = {}; |
926 |
let event = {}; |
| 859 |
event.method = channel.requestMethod; |
927 |
event.method = channel.requestMethod; |
|
|
928 |
event.channelId = channel.channelId; |
| 860 |
event.url = channel.URI.spec; |
929 |
event.url = channel.URI.spec; |
| 861 |
event.private = httpActivity.private; |
930 |
event.private = httpActivity.private; |
| 862 |
event.headersSize = 0; |
931 |
event.headersSize = 0; |
| 863 |
event.startedDateTime = |
932 |
event.startedDateTime = |
| 864 |
(timestamp ? new Date(Math.round(timestamp / 1000)) : new Date()) |
933 |
(timestamp ? new Date(Math.round(timestamp / 1000)) : new Date()) |
| 865 |
.toISOString(); |
934 |
.toISOString(); |
| 866 |
event.fromCache = fromCache; |
935 |
event.fromCache = fromCache; |
| 867 |
event.fromServiceWorker = fromServiceWorker; |
936 |
event.fromServiceWorker = fromServiceWorker; |
| 868 |
httpActivity.fromServiceWorker = fromServiceWorker; |
937 |
httpActivity.fromServiceWorker = fromServiceWorker; |
| 869 |
|
938 |
|
| 870 |
if (extraStringData) { |
939 |
if (extraStringData) { |
| 871 |
event.headersSize = extraStringData.length; |
940 |
event.headersSize = extraStringData.length; |
| 872 |
} |
941 |
} |
| 873 |
|
942 |
|
| 874 |
// Determine if this is an XHR request. |
943 |
// Determine the cause and if this is an XHR request. |
|
|
944 |
let causeType = channel.loadInfo.externalContentPolicyType; |
| 945 |
let loadingPrincipal = channel.loadInfo.loadingPrincipal; |
| 946 |
let causeUri = loadingPrincipal ? loadingPrincipal.URI : null; |
| 947 |
event.cause = { |
| 948 |
type: causeType, |
| 949 |
uri: causeUri ? causeUri.spec : null |
| 950 |
}; |
| 951 |
|
| 952 |
if (this.stackTraceCollector) { |
| 953 |
event.cause.stacktrace = |
| 954 |
this.stackTraceCollector.getStackTrace(event.channelId, event.url); |
| 955 |
} |
| 956 |
|
| 875 |
httpActivity.isXHR = event.isXHR = |
957 |
httpActivity.isXHR = event.isXHR = |
| 876 |
(channel.loadInfo.externalContentPolicyType === |
958 |
(causeType === Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST || |
| 877 |
Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST || |
959 |
causeType === Ci.nsIContentPolicy.TYPE_FETCH); |
| 878 |
channel.loadInfo.externalContentPolicyType === |
|
|
| 879 |
Ci.nsIContentPolicy.TYPE_FETCH); |
| 880 |
|
960 |
|
| 881 |
// Determine the HTTP version. |
961 |
// Determine the HTTP version. |
| 882 |
let httpVersionMaj = {}; |
962 |
let httpVersionMaj = {}; |
| 883 |
let httpVersionMin = {}; |
963 |
let httpVersionMin = {}; |
| 884 |
channel.QueryInterface(Ci.nsIHttpChannelInternal); |
964 |
channel.QueryInterface(Ci.nsIHttpChannelInternal); |
| 885 |
channel.getRequestVersion(httpVersionMaj, httpVersionMin); |
965 |
channel.getRequestVersion(httpVersionMaj, httpVersionMin); |
| 886 |
|
966 |
|
| 887 |
event.httpVersion = "HTTP/" + httpVersionMaj.value + "." + |
967 |
event.httpVersion = "HTTP/" + httpVersionMaj.value + "." + |
|
|
| 927 |
* |
1007 |
* |
| 928 |
* @private |
1008 |
* @private |
| 929 |
* @param nsIHttpChannel channel |
1009 |
* @param nsIHttpChannel channel |
| 930 |
* @param number timestamp |
1010 |
* @param number timestamp |
| 931 |
* @param string extraStringData |
1011 |
* @param string extraStringData |
| 932 |
* @return void |
1012 |
* @return void |
| 933 |
*/ |
1013 |
*/ |
| 934 |
_onRequestHeader: function (channel, timestamp, extraStringData) { |
1014 |
_onRequestHeader: function (channel, timestamp, extraStringData) { |
| 935 |
if (!this._matchRequest(channel)) { |
1015 |
if (!matchRequest(channel, this.filters)) { |
| 936 |
return; |
1016 |
return; |
| 937 |
} |
1017 |
} |
| 938 |
|
1018 |
|
| 939 |
this._createNetworkEvent(channel, { timestamp: timestamp, |
1019 |
this._createNetworkEvent(channel, { timestamp: timestamp, |
| 940 |
extraStringData: extraStringData }); |
1020 |
extraStringData: extraStringData }); |
| 941 |
}, |
1021 |
}, |
| 942 |
|
1022 |
|
| 943 |
/** |
1023 |
/** |
|
|
| 1218 |
"http-on-examine-response"); |
1298 |
"http-on-examine-response"); |
| 1219 |
Services.obs.removeObserver(this._httpResponseExaminer, |
1299 |
Services.obs.removeObserver(this._httpResponseExaminer, |
| 1220 |
"http-on-examine-cached-response"); |
1300 |
"http-on-examine-cached-response"); |
| 1221 |
} |
1301 |
} |
| 1222 |
|
1302 |
|
| 1223 |
Services.obs.removeObserver(this._serviceWorkerRequest, |
1303 |
Services.obs.removeObserver(this._serviceWorkerRequest, |
| 1224 |
"service-worker-synthesized-response"); |
1304 |
"service-worker-synthesized-response"); |
| 1225 |
|
1305 |
|
|
|
1306 |
if (this.stackTraceCollector) { |
| 1307 |
this.stackTraceCollector.destroy(); |
| 1308 |
} |
| 1309 |
|
| 1226 |
this.interceptedChannels.clear(); |
1310 |
this.interceptedChannels.clear(); |
| 1227 |
this.openRequests = {}; |
1311 |
this.openRequests = {}; |
| 1228 |
this.openResponses = {}; |
1312 |
this.openResponses = {}; |
| 1229 |
this.owner = null; |
1313 |
this.owner = null; |
| 1230 |
this.window = null; |
1314 |
this.filters = null; |
| 1231 |
this.topFrame = null; |
|
|
| 1232 |
}, |
1315 |
}, |
| 1233 |
}; |
1316 |
}; |
| 1234 |
|
1317 |
|
| 1235 |
/** |
1318 |
/** |
| 1236 |
* The NetworkMonitorChild is used to proxy all of the network activity of the |
1319 |
* The NetworkMonitorChild is used to proxy all of the network activity of the |
| 1237 |
* child app process from the main process. The child WebConsoleActor creates an |
1320 |
* child app process from the main process. The child WebConsoleActor creates an |
| 1238 |
* instance of this object. |
1321 |
* instance of this object. |
| 1239 |
* |
1322 |
* |
|
|
| 1250 |
* The web appId of the child process. |
1333 |
* The web appId of the child process. |
| 1251 |
* @param nsIMessageManager messageManager |
1334 |
* @param nsIMessageManager messageManager |
| 1252 |
* The nsIMessageManager to use to communicate with the parent process. |
1335 |
* The nsIMessageManager to use to communicate with the parent process. |
| 1253 |
* @param string connID |
1336 |
* @param string connID |
| 1254 |
* The connection ID to use for send messages to the parent process. |
1337 |
* The connection ID to use for send messages to the parent process. |
| 1255 |
* @param object owner |
1338 |
* @param object owner |
| 1256 |
* The WebConsoleActor that is listening for the network requests. |
1339 |
* The WebConsoleActor that is listening for the network requests. |
| 1257 |
*/ |
1340 |
*/ |
| 1258 |
function NetworkMonitorChild(appId, messageManager, connID, owner) { |
1341 |
function NetworkMonitorChild(window, appId, messageManager, connID, owner) { |
|
|
1342 |
this.window = window; |
| 1259 |
this.appId = appId; |
1343 |
this.appId = appId; |
| 1260 |
this.connID = connID; |
1344 |
this.connID = connID; |
| 1261 |
this.owner = owner; |
1345 |
this.owner = owner; |
| 1262 |
this._messageManager = messageManager; |
1346 |
this._messageManager = messageManager; |
| 1263 |
this._onNewEvent = this._onNewEvent.bind(this); |
1347 |
this._onNewEvent = this._onNewEvent.bind(this); |
| 1264 |
this._onUpdateEvent = this._onUpdateEvent.bind(this); |
1348 |
this._onUpdateEvent = this._onUpdateEvent.bind(this); |
| 1265 |
this._netEvents = new Map(); |
1349 |
this._netEvents = new Map(); |
|
|
1350 |
|
| 1351 |
this.stackTraceCollector = new StackTraceCollector({ |
| 1352 |
window: this.window, |
| 1353 |
appId: this.appId |
| 1354 |
}); |
| 1355 |
this.stackTraceCollector.init(); |
| 1266 |
} |
1356 |
} |
| 1267 |
exports.NetworkMonitorChild = NetworkMonitorChild; |
1357 |
exports.NetworkMonitorChild = NetworkMonitorChild; |
| 1268 |
|
1358 |
|
| 1269 |
NetworkMonitorChild.prototype = { |
1359 |
NetworkMonitorChild.prototype = { |
| 1270 |
appId: null, |
1360 |
appId: null, |
| 1271 |
owner: null, |
1361 |
owner: null, |
| 1272 |
_netEvents: null, |
1362 |
_netEvents: null, |
| 1273 |
_saveRequestAndResponseBodies: true, |
1363 |
_saveRequestAndResponseBodies: true, |
|
|
| 1297 |
mm.sendAsyncMessage("debug:netmonitor:" + this.connID, { |
1387 |
mm.sendAsyncMessage("debug:netmonitor:" + this.connID, { |
| 1298 |
appId: this.appId, |
1388 |
appId: this.appId, |
| 1299 |
action: "start", |
1389 |
action: "start", |
| 1300 |
}); |
1390 |
}); |
| 1301 |
}, |
1391 |
}, |
| 1302 |
|
1392 |
|
| 1303 |
_onNewEvent: DevToolsUtils.makeInfallible(function _onNewEvent(msg) { |
1393 |
_onNewEvent: DevToolsUtils.makeInfallible(function _onNewEvent(msg) { |
| 1304 |
let {id, event} = msg.data; |
1394 |
let {id, event} = msg.data; |
|
|
1395 |
|
| 1396 |
event.cause.stacktrace = |
| 1397 |
this.stackTraceCollector.getStackTrace(event.channelId, event.url); |
| 1398 |
|
| 1305 |
let actor = this.owner.onNetworkEvent(event); |
1399 |
let actor = this.owner.onNetworkEvent(event); |
| 1306 |
this._netEvents.set(id, Cu.getWeakReference(actor)); |
1400 |
this._netEvents.set(id, Cu.getWeakReference(actor)); |
| 1307 |
}), |
1401 |
}), |
| 1308 |
|
1402 |
|
| 1309 |
_onUpdateEvent: DevToolsUtils.makeInfallible(function _onUpdateEvent(msg) { |
1403 |
_onUpdateEvent: DevToolsUtils.makeInfallible(function _onUpdateEvent(msg) { |
| 1310 |
let {id, method, args} = msg.data; |
1404 |
let {id, method, args} = msg.data; |
| 1311 |
let weakActor = this._netEvents.get(id); |
1405 |
let weakActor = this._netEvents.get(id); |
| 1312 |
let actor = weakActor ? weakActor.get() : null; |
1406 |
let actor = weakActor ? weakActor.get() : null; |
|
|
| 1319 |
console.error("Received debug:netmonitor:updateEvent unsupported " + |
1413 |
console.error("Received debug:netmonitor:updateEvent unsupported " + |
| 1320 |
"method: " + method); |
1414 |
"method: " + method); |
| 1321 |
return; |
1415 |
return; |
| 1322 |
} |
1416 |
} |
| 1323 |
actor[method].apply(actor, args); |
1417 |
actor[method].apply(actor, args); |
| 1324 |
}), |
1418 |
}), |
| 1325 |
|
1419 |
|
| 1326 |
destroy: function () { |
1420 |
destroy: function () { |
|
|
1421 |
this.stackTraceCollector.destroy(); |
| 1422 |
|
| 1327 |
let mm = this._messageManager; |
1423 |
let mm = this._messageManager; |
| 1328 |
try { |
1424 |
try { |
| 1329 |
mm.removeMessageListener("debug:netmonitor:" + this.connID + ":newEvent", |
1425 |
mm.removeMessageListener("debug:netmonitor:" + this.connID + ":newEvent", |
| 1330 |
this._onNewEvent); |
1426 |
this._onNewEvent); |
| 1331 |
mm.removeMessageListener("debug:netmonitor:" + this.connID + |
1427 |
mm.removeMessageListener("debug:netmonitor:" + this.connID + |
| 1332 |
":updateEvent", |
1428 |
":updateEvent", |
| 1333 |
this._onUpdateEvent); |
1429 |
this._onUpdateEvent); |
| 1334 |
} catch (e) { |
1430 |
} catch (e) { |