Attachment #8752689: Part 2: collect information about request cause and stacktrace in network monitor for bug #1134073

View | Details | Raw Unified | Return to bug 1134073
Collapse All | Expand All

(-)a/devtools/server/actors/webconsole.js (-2 / +6 lines)
Line     Link Here 
 Lines 597-622   WebConsoleActor.prototype = Link Here 
597
          startedListeners.push(listener);
597
          startedListeners.push(listener);
598
          break;
598
          break;
599
        case "NetworkActivity":
599
        case "NetworkActivity":
600
          if (!this.networkMonitor) {
600
          if (!this.networkMonitor) {
601
            if (appId || messageManager) {
601
            if (appId || messageManager) {
602
              // Start a network monitor in the parent process to listen to
602
              // Start a network monitor in the parent process to listen to
603
              // most requests than happen in parent
603
              // most requests than happen in parent
604
              this.networkMonitor =
604
              this.networkMonitor =
605
                new NetworkMonitorChild(appId, messageManager,
605
                new NetworkMonitorChild(window, appId, messageManager,
606
                                        this.parentActor.actorID, this);
606
                                        this.parentActor.actorID, this);
607
              this.networkMonitor.init();
607
              this.networkMonitor.init();
608
              // Spawn also one in the child to listen to service workers
608
              // Spawn also one in the child to listen to service workers
609
              this.networkMonitorChild = new NetworkMonitor({ window: window },
609
              this.networkMonitorChild = new NetworkMonitor({ window: window },
610
                                                            this);
610
                                                            this);
611
              this.networkMonitorChild.init();
611
              this.networkMonitorChild.init();
612
            }
612
            }
613
            else {
613
            else {
614
              this.networkMonitor = new NetworkMonitor({ window: window }, this);
614
              this.networkMonitor = new NetworkMonitor({
615
                window: window,
616
              }, this, true);
615
              this.networkMonitor.init();
617
              this.networkMonitor.init();
616
            }
618
            }
617
          }
619
          }
618
          startedListeners.push(listener);
620
          startedListeners.push(listener);
619
          break;
621
          break;
620
        case "FileActivity":
622
        case "FileActivity":
621
          if (this.window instanceof Ci.nsIDOMWindow) {
623
          if (this.window instanceof Ci.nsIDOMWindow) {
622
            if (!this.consoleProgressListener) {
624
            if (!this.consoleProgressListener) {
 Lines 1823-1838   NetworkEventActor.prototype = Link Here 
1823
  {
1825
  {
1824
    return {
1826
    return {
1825
      actor: this.actorID,
1827
      actor: this.actorID,
1826
      startedDateTime: this._startedDateTime,
1828
      startedDateTime: this._startedDateTime,
1827
      timeStamp: Date.parse(this._startedDateTime),
1829
      timeStamp: Date.parse(this._startedDateTime),
1828
      url: this._request.url,
1830
      url: this._request.url,
1829
      method: this._request.method,
1831
      method: this._request.method,
1830
      isXHR: this._isXHR,
1832
      isXHR: this._isXHR,
1833
      cause: this._cause,
1831
      fromCache: this._fromCache,
1834
      fromCache: this._fromCache,
1832
      fromServiceWorker: this._fromServiceWorker,
1835
      fromServiceWorker: this._fromServiceWorker,
1833
      private: this._private,
1836
      private: this._private,
1834
    };
1837
    };
1835
  },
1838
  },
1836
1839
1837
  /**
1840
  /**
1838
   * Releases this actor from the pool.
1841
   * Releases this actor from the pool.
 Lines 1868-1883   NetworkEventActor.prototype = Link Here 
1868
   *
1871
   *
1869
   * @param object aNetworkEvent
1872
   * @param object aNetworkEvent
1870
   *        The network event associated with this actor.
1873
   *        The network event associated with this actor.
1871
   */
1874
   */
1872
  init: function NEA_init(aNetworkEvent)
1875
  init: function NEA_init(aNetworkEvent)
1873
  {
1876
  {
1874
    this._startedDateTime = aNetworkEvent.startedDateTime;
1877
    this._startedDateTime = aNetworkEvent.startedDateTime;
1875
    this._isXHR = aNetworkEvent.isXHR;
1878
    this._isXHR = aNetworkEvent.isXHR;
1879
    this._cause = aNetworkEvent.cause;
1876
    this._fromCache = aNetworkEvent.fromCache;
1880
    this._fromCache = aNetworkEvent.fromCache;
1877
    this._fromServiceWorker = aNetworkEvent.fromServiceWorker;
1881
    this._fromServiceWorker = aNetworkEvent.fromServiceWorker;
1878
1882
1879
    for (let prop of ['method', 'url', 'httpVersion', 'headersSize']) {
1883
    for (let prop of ['method', 'url', 'httpVersion', 'headersSize']) {
1880
      this._request[prop] = aNetworkEvent[prop];
1884
      this._request[prop] = aNetworkEvent[prop];
1881
    }
1885
    }
1882
1886
1883
    this._discardRequestBody = aNetworkEvent.discardRequestBody;
1887
    this._discardRequestBody = aNetworkEvent.discardRequestBody;
(-)a/devtools/shared/webconsole/client.js (+1 lines)
Line     Link Here 
 Lines 95-110   WebConsoleClient.prototype = { Link Here 
95
        discardRequestBody: true,
95
        discardRequestBody: true,
96
        discardResponseBody: true,
96
        discardResponseBody: true,
97
        startedDateTime: actor.startedDateTime,
97
        startedDateTime: actor.startedDateTime,
98
        request: {
98
        request: {
99
          url: actor.url,
99
          url: actor.url,
100
          method: actor.method,
100
          method: actor.method,
101
        },
101
        },
102
        isXHR: actor.isXHR,
102
        isXHR: actor.isXHR,
103
        cause: actor.cause,
103
        response: {},
104
        response: {},
104
        timings: {},
105
        timings: {},
105
        // track the list of network event updates
106
        // track the list of network event updates
106
        updates: [],
107
        updates: [],
107
        private: actor.private,
108
        private: actor.private,
108
        fromCache: actor.fromCache,
109
        fromCache: actor.fromCache,
109
        fromServiceWorker: actor.fromServiceWorker
110
        fromServiceWorker: actor.fromServiceWorker
110
      };
111
      };
(-)a/devtools/shared/webconsole/network-monitor.js (-102 / +198 lines)
Line     Link Here 
 Lines 1-17    Link Here 
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");
 Lines 32-47   const HTTP_MOVED_PERMANENTLY = 301; Link Here 
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/
 Lines 473-512   NetworkResponseListener.prototype = { Link Here 
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",
 Lines 547-562   NetworkMonitor.prototype = { Link Here 
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,
 Lines 597-613   NetworkMonitor.prototype = { Link Here 
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: [],
 Lines 752-845   NetworkMonitor.prototype = { Link Here 
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()
 Lines 852-887   NetworkMonitor.prototype = { Link Here 
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 + "." +
 Lines 927-943   NetworkMonitor.prototype = { Link Here 
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
  /**
 Lines 1218-1239   NetworkMonitor.prototype = { Link Here 
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
 *
 Lines 1250-1273   NetworkMonitor.prototype = { Link Here 
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,
 Lines 1297-1312   NetworkMonitorChild.prototype = { Link Here 
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;
 Lines 1319-1334   NetworkMonitorChild.prototype = { Link Here 
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) {

Return to bug 1134073