summaryrefslogtreecommitdiffstats
path: root/chrome/browser/resources/net_internals/source_tracker.js
blob: 969d0d24c7248f9f8fad74df2bf66cd5e9fb3c63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * This class keeps track of all NetLog events.
 * It receives events from the browser and when loading a log file, and passes
 * them on to all its observers.
 *
 * @constructor
 */
function SourceTracker() {
  this.observers_ = [];

  // True when cookies and authentication information should be removed from
  // displayed events.  When true, such information should be hidden from
  // all pages.
  this.enableSecurityStripping_ = true;

  this.clearEntries_();
}

/**
 * Clears all log entries and SourceEntries and related state.
 */
SourceTracker.prototype.clearEntries_ = function() {
  // Used for sorting entries with automatically assigned IDs.
  this.maxReceivedSourceId_ = 0;

  // Next unique id to be assigned to a log entry without a source.
  // Needed to simplify deletion, identify associated GUI elements, etc.
  this.nextSourcelessEventId_ = -1;

  this.numPassivelyCapturedEvents_ = 0;

  // Ordered list of log entries.  Needed to maintain original order when
  // generating log dumps
  this.capturedEvents_ = [];

  this.sourceEntries_ = {};
};

/**
 * Returns a list of all captured events.
 */
SourceTracker.prototype.getAllCapturedEvents = function() {
  return this.capturedEvents_;
};

/**
 * Returns a list of all SourceEntries.
 */
SourceTracker.prototype.getAllSourceEntries = function() {
  return this.sourceEntries_;
};

/**
 * Returns the number of events that were captured while we were
 * listening for events.
 */
SourceTracker.prototype.getNumActivelyCapturedEvents = function() {
  return this.capturedEvents_.length - this.numPassivelyCapturedEvents_;
};

/**
 * Returns the number of events that were captured passively by the
 * browser prior to when the net-internals page was started.
 */
SourceTracker.prototype.getNumPassivelyCapturedEvents = function() {
  return this.numPassivelyCapturedEvents_;
};

/**
 * Returns the specified SourceEntry.
 */
SourceTracker.prototype.getSourceEntry = function(id) {
  return this.sourceEntries_[id];
};

SourceTracker.prototype.onReceivedPassiveLogEntries = function(logEntries) {
  // Due to an expected race condition, it is possible to receive actively
  // captured log entries before the passively logged entries are received.
  //
  // When that happens, we create a copy of the actively logged entries, delete
  // all entries, and, after handling all the passively logged entries, add back
  // the deleted actively logged entries.
  var earlyActivelyCapturedEvents = this.capturedEvents_.slice(0);
  if (earlyActivelyCapturedEvents.length > 0)
    this.deleteAllSourceEntries();

  this.numPassivelyCapturedEvents_ = logEntries.length;
  for (var i = 0; i < logEntries.length; ++i)
    logEntries[i].wasPassivelyCaptured = true;

  this.onReceivedLogEntries(logEntries);

  // Add back early actively captured events, if any.
  if (earlyActivelyCapturedEvents.length)
    this.onReceivedLogEntries(earlyActivelyCapturedEvents);
};

/**
 * Sends each entry to all log observers, and updates |capturedEvents_|.
 * Also assigns unique ids to log entries without a source.
 */
SourceTracker.prototype.onReceivedLogEntries = function(logEntries) {
  // List source entries with new log entries.  Sorted chronologically, by
  // first new log entry.
  var updatedSourceEntries = [];

  var updatedSourceEntryIdMap = {};

  for (var e = 0; e < logEntries.length; ++e) {
    var logEntry = logEntries[e];

    // Assign unique ID, if needed.
    if (logEntry.source.id == 0) {
      logEntry.source.id = this.nextSourcelessEventId_;
      --this.nextSourcelessEventId_;
    } else if (this.maxReceivedSourceId_ < logEntry.source.id) {
      this.maxReceivedSourceId_ = logEntry.source.id;
    }

    // Create/update SourceEntry object.
    var sourceEntry = this.sourceEntries_[logEntry.source.id];
    if (!sourceEntry) {
      sourceEntry = new SourceEntry(logEntry, this.maxReceivedSourceId_);
      this.sourceEntries_[logEntry.source.id] = sourceEntry;
    } else {
      sourceEntry.update(logEntry);
    }

    // Add to updated SourceEntry list, if not already in it.
    if (!updatedSourceEntryIdMap[logEntry.source.id]) {
      updatedSourceEntryIdMap[logEntry.source.id] = sourceEntry;
      updatedSourceEntries.push(sourceEntry);
    }
  }

  this.capturedEvents_ = this.capturedEvents_.concat(logEntries);
  for (var i = 0; i < this.observers_.length; ++i)
    this.observers_[i].onSourceEntriesUpdated(updatedSourceEntries);
};

/**
 * Deletes captured events with source IDs in |sourceEntryIds|.
 */
SourceTracker.prototype.deleteSourceEntries = function(sourceEntryIds) {
  var sourceIdDict = {};
  for (var i = 0; i < sourceEntryIds.length; i++) {
    sourceIdDict[sourceEntryIds[i]] = true;
    delete this.sourceEntries_[sourceEntryIds[i]];
  }

  var newEventList = [];
  for (var i = 0; i < this.capturedEvents_.length; ++i) {
    var id = this.capturedEvents_[i].source.id;
    if (id in sourceIdDict) {
      if (this.capturedEvents_[i].wasPassivelyCaptured)
        --this.numPassivelyCapturedEvents_;
      continue;
    }
    newEventList.push(this.capturedEvents_[i]);
  }
  this.capturedEvents_ = newEventList;

  for (var i = 0; i < this.observers_.length; ++i)
    this.observers_[i].onSourceEntriesDeleted(sourceEntryIds);
};

/**
 * Deletes all captured events.
 */
SourceTracker.prototype.deleteAllSourceEntries = function() {
  this.clearEntries_();
  for (var i = 0; i < this.observers_.length; ++i)
    this.observers_[i].onAllSourceEntriesDeleted();
};

/**
 * Sets the value of |enableSecurityStripping_| and informs log observers
 * of the change.
 */
SourceTracker.prototype.setSecurityStripping =
    function(enableSecurityStripping) {
  this.enableSecurityStripping_ = enableSecurityStripping;
  for (var i = 0; i < this.observers_.length; ++i) {
    if (this.observers_[i].onSecurityStrippingChanged)
      this.observers_[i].onSecurityStrippingChanged();
  }
};

/**
 * Returns whether or not cookies and authentication information should be
 * displayed for events that contain them.
 */
SourceTracker.prototype.getSecurityStripping = function() {
  return this.enableSecurityStripping_;
};

/**
 * Adds a listener of log entries. |observer| will be called back when new log
 * data arrives, source entries are deleted, or security stripping changes
 * through:
 *
 *   observer.onSourceEntriesUpdated(sourceEntries)
 *   observer.deleteSourceEntries(sourceEntryIds)
 *   ovserver.deleteAllSourceEntries()
 *   observer.onSecurityStrippingChanged()
 */
SourceTracker.prototype.addObserver = function(observer) {
  this.observers_.push(observer);
};