Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(184)

Side by Side Diff: chrome/browser/resources/net_internals/log_view_painter.js

Issue 2939273002: DO NOT SUBMIT: what chrome/browser/resources/ could eventually look like with clang-format (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // TODO(eroman): put these methods into a namespace. 5 // TODO(eroman): put these methods into a namespace.
6 6
7 var createLogEntryTablePrinter; 7 var createLogEntryTablePrinter;
8 var proxySettingsToString; 8 var proxySettingsToString;
9 var stripPrivacyInfo; 9 var stripPrivacyInfo;
10 10
11 // Start of anonymous namespace. 11 // Start of anonymous namespace.
12 (function() { 12 (function() {
13 'use strict'; 13 'use strict';
14 14
15 function canCollapseBeginWithEnd(beginEntry) { 15 function canCollapseBeginWithEnd(beginEntry) {
16 return beginEntry && beginEntry.isBegin() && beginEntry.end && 16 return beginEntry && beginEntry.isBegin() && beginEntry.end &&
17 beginEntry.end.index == beginEntry.index + 1 && 17 beginEntry.end.index == beginEntry.index + 1 &&
18 (!beginEntry.orig.params || !beginEntry.end.orig.params); 18 (!beginEntry.orig.params || !beginEntry.end.orig.params);
19 } 19 }
20 20
21 /**
22 * Creates a TablePrinter for use by the above two functions. baseTime is
23 * the time relative to which other times are displayed.
24 */
25 createLogEntryTablePrinter = function(
26 logEntries, privacyStripping, baseTime, logCreationTime) {
27 var entries = LogGroupEntry.createArrayFrom(logEntries);
28 var tablePrinter = new TablePrinter();
29 var parameterOutputter = new ParameterOutputter(tablePrinter);
30
31 if (entries.length == 0)
32 return tablePrinter;
33
34 var startTime = timeutil.convertTimeTicksToTime(entries[0].orig.time);
35
36 for (var i = 0; i < entries.length; ++i) {
37 var entry = entries[i];
38
39 // Avoid printing the END for a BEGIN that was immediately before, unless
40 // both have extra parameters.
41 if (!entry.isEnd() || !canCollapseBeginWithEnd(entry.begin)) {
42 var entryTime = timeutil.convertTimeTicksToTime(entry.orig.time);
43 addRowWithTime(tablePrinter, entryTime - baseTime, startTime - baseTime);
44
45 for (var j = entry.getDepth(); j > 0; --j)
46 tablePrinter.addCell(' ');
47
48 var eventText = getTextForEvent(entry);
49 // Get the elapsed time, and append it to the event text.
50 if (entry.isBegin()) {
51 var dt = '?';
52 // Definite time.
53 if (entry.end) {
54 dt = entry.end.orig.time - entry.orig.time;
55 } else if (logCreationTime != undefined) {
56 dt = (logCreationTime - entryTime) + '+';
57 }
58 eventText += ' [dt=' + dt + ']';
59 }
60
61 var mainCell = tablePrinter.addCell(eventText);
62 mainCell.allowOverflow = true;
63 }
64
65 // Output the extra parameters.
66 if (typeof entry.orig.params == 'object') {
67 // Those 5 skipped cells are: two for "t=", and three for "st=".
68 tablePrinter.setNewRowCellIndent(5 + entry.getDepth());
69 writeParameters(entry.orig, privacyStripping, parameterOutputter);
70
71 tablePrinter.setNewRowCellIndent(0);
72 }
73 }
74
75 // If viewing a saved log file, add row with just the time the log was
76 // created, if the event never completed.
77 var lastEntry = entries[entries.length - 1];
78 // If the last entry has a non-zero depth or is a begin event, the source is
79 // still active.
80 var isSourceActive = lastEntry.getDepth() != 0 || lastEntry.isBegin();
81 if (logCreationTime != undefined && isSourceActive) {
82 addRowWithTime(
83 tablePrinter, logCreationTime - baseTime, startTime - baseTime);
84 }
85
86 return tablePrinter;
87 };
88
89 /**
90 * Adds a new row to the given TablePrinter, and adds five cells containing
91 * information about the time an event occured.
92 * Format is '[t=<time of the event in ms>] [st=<ms since the source
93 * started>]'.
94 * @param {TablePrinter} tablePrinter The table printer to add the cells to.
95 * @param {number} eventTime The time the event occured, in milliseconds,
96 * relative to some base time.
97 * @param {number} startTime The time the first event for the source occured,
98 * relative to the same base time as eventTime.
99 */
100 function addRowWithTime(tablePrinter, eventTime, startTime) {
101 tablePrinter.addRow();
102 tablePrinter.addCell('t=');
103 var tCell = tablePrinter.addCell(eventTime);
104 tCell.alignRight = true;
105 tablePrinter.addCell(' [st=');
106 var stCell = tablePrinter.addCell(eventTime - startTime);
107 stCell.alignRight = true;
108 tablePrinter.addCell('] ');
109 }
110
111 /**
112 * |hexString| must be a string of hexadecimal characters with no whitespace,
113 * whose length is a multiple of two. Writes multiple lines to |out| with
114 * the hexadecimal characters from |hexString| on the left, in groups of
115 * two, and their corresponding ASCII characters on the right.
116 *
117 * 16 bytes will be placed on each line of the output string, split into two
118 * columns of 8.
119 */
120 function writeHexString(hexString, out) {
121 var asciiCharsPerLine = 16;
122 // Number of transferred bytes in a line of output. Length of a
123 // line is roughly 4 times larger.
124 var hexCharsPerLine = 2 * asciiCharsPerLine;
125 for (var i = 0; i < hexString.length; i += hexCharsPerLine) {
126 var hexLine = '';
127 var asciiLine = '';
128 for (var j = i; j < i + hexCharsPerLine && j < hexString.length; j += 2) {
129 // Split into two columns of 8 bytes each.
130 if (j == i + hexCharsPerLine / 2)
131 hexLine += ' ';
132 var hex = hexString.substr(j, 2);
133 hexLine += hex + ' ';
134 var charCode = parseInt(hex, 16);
135 // For ASCII codes 32 though 126, display the corresponding
136 // characters. Use a space for nulls, and a period for
137 // everything else.
138 if (charCode >= 0x20 && charCode <= 0x7E) {
139 asciiLine += String.fromCharCode(charCode);
140 } else if (charCode == 0x00) {
141 asciiLine += ' ';
142 } else {
143 asciiLine += '.';
144 }
145 }
146
147 // Make the ASCII text for the last line of output align with the previous
148 // lines.
149 hexLine +=
150 makeRepeatedString(' ', 3 * asciiCharsPerLine + 1 - hexLine.length);
151 out.writeLine(' ' + hexLine + ' ' + asciiLine);
152 }
153 }
154
155 /**
156 * Wrapper around a TablePrinter to simplify outputting lines of text for
157 * event
158 * parameters.
159 */
160 var ParameterOutputter = (function() {
21 /** 161 /**
22 * Creates a TablePrinter for use by the above two functions. baseTime is 162 * @constructor
23 * the time relative to which other times are displayed.
24 */ 163 */
25 createLogEntryTablePrinter = function( 164 function ParameterOutputter(tablePrinter) {
26 logEntries, privacyStripping, baseTime, logCreationTime) { 165 this.tablePrinter_ = tablePrinter;
27 var entries = LogGroupEntry.createArrayFrom(logEntries); 166 }
28 var tablePrinter = new TablePrinter(); 167
29 var parameterOutputter = new ParameterOutputter(tablePrinter); 168 ParameterOutputter.prototype = {
30 169 /**
31 if (entries.length == 0) 170 * Outputs a single line.
32 return tablePrinter; 171 */
33 172 writeLine: function(line) {
34 var startTime = timeutil.convertTimeTicksToTime(entries[0].orig.time); 173 this.tablePrinter_.addRow();
35 174 var cell = this.tablePrinter_.addCell(line);
36 for (var i = 0; i < entries.length; ++i) { 175 cell.allowOverflow = true;
37 var entry = entries[i]; 176 return cell;
38 177 },
39 // Avoid printing the END for a BEGIN that was immediately before, unless 178
40 // both have extra parameters. 179 /**
41 if (!entry.isEnd() || !canCollapseBeginWithEnd(entry.begin)) { 180 * Outputs a key=value line which looks like:
42 var entryTime = timeutil.convertTimeTicksToTime(entry.orig.time); 181 *
43 addRowWithTime( 182 * --> key = value
44 tablePrinter, entryTime - baseTime, startTime - baseTime); 183 */
45 184 writeArrowKeyValue: function(key, value, link) {
46 for (var j = entry.getDepth(); j > 0; --j) 185 var cell = this.writeLine(kArrow + key + ' = ' + value);
47 tablePrinter.addCell(' '); 186 cell.link = link;
48 187 },
49 var eventText = getTextForEvent(entry); 188
50 // Get the elapsed time, and append it to the event text. 189 /**
51 if (entry.isBegin()) { 190 * Outputs a key= line which looks like:
52 var dt = '?'; 191 *
53 // Definite time. 192 * --> key =
54 if (entry.end) { 193 */
55 dt = entry.end.orig.time - entry.orig.time; 194 writeArrowKey: function(key) {
56 } else if (logCreationTime != undefined) { 195 this.writeLine(kArrow + key + ' =');
57 dt = (logCreationTime - entryTime) + '+'; 196 },
58 } 197
59 eventText += ' [dt=' + dt + ']'; 198 /**
60 } 199 * Outputs multiple lines, each indented by numSpaces.
61 200 * For instance if numSpaces=8 it might look like this:
62 var mainCell = tablePrinter.addCell(eventText); 201 *
63 mainCell.allowOverflow = true; 202 * line 1
64 } 203 * line 2
65 204 * line 3
66 // Output the extra parameters. 205 */
67 if (typeof entry.orig.params == 'object') { 206 writeSpaceIndentedLines: function(numSpaces, lines) {
68 // Those 5 skipped cells are: two for "t=", and three for "st=". 207 var prefix = makeRepeatedString(' ', numSpaces);
69 tablePrinter.setNewRowCellIndent(5 + entry.getDepth()); 208 for (var i = 0; i < lines.length; ++i)
70 writeParameters(entry.orig, privacyStripping, parameterOutputter); 209 this.writeLine(prefix + lines[i]);
71 210 },
72 tablePrinter.setNewRowCellIndent(0); 211
73 } 212 /**
74 } 213 * Outputs multiple lines such that the first line has
75 214 * an arrow pointing at it, and subsequent lines
76 // If viewing a saved log file, add row with just the time the log was 215 * align with the first one. For example:
77 // created, if the event never completed. 216 *
78 var lastEntry = entries[entries.length - 1]; 217 * --> line 1
79 // If the last entry has a non-zero depth or is a begin event, the source is 218 * line 2
80 // still active. 219 * line 3
81 var isSourceActive = lastEntry.getDepth() != 0 || lastEntry.isBegin(); 220 */
82 if (logCreationTime != undefined && isSourceActive) { 221 writeArrowIndentedLines: function(lines) {
83 addRowWithTime( 222 if (lines.length == 0)
84 tablePrinter, logCreationTime - baseTime, startTime - baseTime); 223 return;
85 } 224
86 225 this.writeLine(kArrow + lines[0]);
87 return tablePrinter; 226
227 for (var i = 1; i < lines.length; ++i)
228 this.writeLine(kArrowIndentation + lines[i]);
229 }
88 }; 230 };
89 231
90 /** 232 var kArrow = ' --> ';
91 * Adds a new row to the given TablePrinter, and adds five cells containing 233 var kArrowIndentation = ' ';
92 * information about the time an event occured. 234
93 * Format is '[t=<time of the event in ms>] [st=<ms since the source 235 return ParameterOutputter;
94 * started>]'. 236 })(); // end of ParameterOutputter
95 * @param {TablePrinter} tablePrinter The table printer to add the cells to. 237
96 * @param {number} eventTime The time the event occured, in milliseconds, 238 /**
97 * relative to some base time. 239 * Formats the parameters for |entry| and writes them to |out|.
98 * @param {number} startTime The time the first event for the source occured, 240 * Certain event types have custom pretty printers. Everything else will
99 * relative to the same base time as eventTime. 241 * default to a JSON-like format.
100 */ 242 */
101 function addRowWithTime(tablePrinter, eventTime, startTime) { 243 function writeParameters(entry, privacyStripping, out) {
102 tablePrinter.addRow(); 244 if (privacyStripping) {
103 tablePrinter.addCell('t='); 245 // If privacy stripping is enabled, remove data as needed.
104 var tCell = tablePrinter.addCell(eventTime); 246 entry = stripPrivacyInfo(entry);
105 tCell.alignRight = true; 247 } else {
106 tablePrinter.addCell(' [st='); 248 // If headers are in an object, convert them to an array for better
107 var stCell = tablePrinter.addCell(eventTime - startTime); 249 // display.
108 stCell.alignRight = true; 250 entry = reformatHeaders(entry);
109 tablePrinter.addCell('] '); 251 }
110 } 252
111 253 // Use any parameter writer available for this event type.
112 /** 254 var paramsWriter = getParameterWriterForEventType(entry.type);
113 * |hexString| must be a string of hexadecimal characters with no whitespace, 255 var consumedParams = {};
114 * whose length is a multiple of two. Writes multiple lines to |out| with 256 if (paramsWriter)
115 * the hexadecimal characters from |hexString| on the left, in groups of 257 paramsWriter(entry, out, consumedParams);
116 * two, and their corresponding ASCII characters on the right. 258
117 * 259 // Write any un-consumed parameters.
118 * 16 bytes will be placed on each line of the output string, split into two 260 for (var k in entry.params) {
119 * columns of 8. 261 if (consumedParams[k])
120 */ 262 continue;
121 function writeHexString(hexString, out) { 263 defaultWriteParameter(k, entry.params[k], out);
122 var asciiCharsPerLine = 16; 264 }
123 // Number of transferred bytes in a line of output. Length of a 265 }
124 // line is roughly 4 times larger. 266
125 var hexCharsPerLine = 2 * asciiCharsPerLine; 267 /**
126 for (var i = 0; i < hexString.length; i += hexCharsPerLine) {
127 var hexLine = '';
128 var asciiLine = '';
129 for (var j = i; j < i + hexCharsPerLine && j < hexString.length; j += 2) {
130 // Split into two columns of 8 bytes each.
131 if (j == i + hexCharsPerLine / 2)
132 hexLine += ' ';
133 var hex = hexString.substr(j, 2);
134 hexLine += hex + ' ';
135 var charCode = parseInt(hex, 16);
136 // For ASCII codes 32 though 126, display the corresponding
137 // characters. Use a space for nulls, and a period for
138 // everything else.
139 if (charCode >= 0x20 && charCode <= 0x7E) {
140 asciiLine += String.fromCharCode(charCode);
141 } else if (charCode == 0x00) {
142 asciiLine += ' ';
143 } else {
144 asciiLine += '.';
145 }
146 }
147
148 // Make the ASCII text for the last line of output align with the previous
149 // lines.
150 hexLine +=
151 makeRepeatedString(' ', 3 * asciiCharsPerLine + 1 - hexLine.length);
152 out.writeLine(' ' + hexLine + ' ' + asciiLine);
153 }
154 }
155
156 /**
157 * Wrapper around a TablePrinter to simplify outputting lines of text for
158 * event
159 * parameters.
160 */
161 var ParameterOutputter = (function() {
162 /**
163 * @constructor
164 */
165 function ParameterOutputter(tablePrinter) {
166 this.tablePrinter_ = tablePrinter;
167 }
168
169 ParameterOutputter.prototype = {
170 /**
171 * Outputs a single line.
172 */
173 writeLine: function(line) {
174 this.tablePrinter_.addRow();
175 var cell = this.tablePrinter_.addCell(line);
176 cell.allowOverflow = true;
177 return cell;
178 },
179
180 /**
181 * Outputs a key=value line which looks like:
182 *
183 * --> key = value
184 */
185 writeArrowKeyValue: function(key, value, link) {
186 var cell = this.writeLine(kArrow + key + ' = ' + value);
187 cell.link = link;
188 },
189
190 /**
191 * Outputs a key= line which looks like:
192 *
193 * --> key =
194 */
195 writeArrowKey: function(key) {
196 this.writeLine(kArrow + key + ' =');
197 },
198
199 /**
200 * Outputs multiple lines, each indented by numSpaces.
201 * For instance if numSpaces=8 it might look like this:
202 *
203 * line 1
204 * line 2
205 * line 3
206 */
207 writeSpaceIndentedLines: function(numSpaces, lines) {
208 var prefix = makeRepeatedString(' ', numSpaces);
209 for (var i = 0; i < lines.length; ++i)
210 this.writeLine(prefix + lines[i]);
211 },
212
213 /**
214 * Outputs multiple lines such that the first line has
215 * an arrow pointing at it, and subsequent lines
216 * align with the first one. For example:
217 *
218 * --> line 1
219 * line 2
220 * line 3
221 */
222 writeArrowIndentedLines: function(lines) {
223 if (lines.length == 0)
224 return;
225
226 this.writeLine(kArrow + lines[0]);
227
228 for (var i = 1; i < lines.length; ++i)
229 this.writeLine(kArrowIndentation + lines[i]);
230 }
231 };
232
233 var kArrow = ' --> ';
234 var kArrowIndentation = ' ';
235
236 return ParameterOutputter;
237 })(); // end of ParameterOutputter
238
239 /**
240 * Formats the parameters for |entry| and writes them to |out|.
241 * Certain event types have custom pretty printers. Everything else will
242 * default to a JSON-like format.
243 */
244 function writeParameters(entry, privacyStripping, out) {
245 if (privacyStripping) {
246 // If privacy stripping is enabled, remove data as needed.
247 entry = stripPrivacyInfo(entry);
248 } else {
249 // If headers are in an object, convert them to an array for better
250 // display.
251 entry = reformatHeaders(entry);
252 }
253
254 // Use any parameter writer available for this event type.
255 var paramsWriter = getParameterWriterForEventType(entry.type);
256 var consumedParams = {};
257 if (paramsWriter)
258 paramsWriter(entry, out, consumedParams);
259
260 // Write any un-consumed parameters.
261 for (var k in entry.params) {
262 if (consumedParams[k])
263 continue;
264 defaultWriteParameter(k, entry.params[k], out);
265 }
266 }
267
268 /**
269 * Finds a writer to format the parameters for events of type |eventType|. 268 * Finds a writer to format the parameters for events of type |eventType|.
270 * 269 *
271 * @return {function} The returned function "writer" can be invoked 270 * @return {function} The returned function "writer" can be invoked
272 * as |writer(entry, writer, consumedParams)|. It will 271 * as |writer(entry, writer, consumedParams)|. It will
273 * output the parameters of |entry| to |out|, and fill 272 * output the parameters of |entry| to |out|, and fill
274 * |consumedParams| with the keys of the parameters 273 * |consumedParams| with the keys of the parameters
275 * consumed. If no writer is available for |eventType| then 274 * consumed. If no writer is available for |eventType| then
276 * returns null. 275 * returns null.
277 */ 276 */
278 function getParameterWriterForEventType(eventType) { 277 function getParameterWriterForEventType(eventType) {
279 switch (eventType) { 278 switch (eventType) {
280 case EventType.HTTP_TRANSACTION_SEND_REQUEST_HEADERS: 279 case EventType.HTTP_TRANSACTION_SEND_REQUEST_HEADERS:
281 case EventType.HTTP_TRANSACTION_SEND_TUNNEL_HEADERS: 280 case EventType.HTTP_TRANSACTION_SEND_TUNNEL_HEADERS:
282 case EventType.TYPE_HTTP_CACHE_CALLER_REQUEST_HEADERS: 281 case EventType.TYPE_HTTP_CACHE_CALLER_REQUEST_HEADERS:
283 return writeParamsForRequestHeaders; 282 return writeParamsForRequestHeaders;
284 283
285 case EventType.PROXY_CONFIG_CHANGED: 284 case EventType.PROXY_CONFIG_CHANGED:
286 return writeParamsForProxyConfigChanged; 285 return writeParamsForProxyConfigChanged;
287 286
288 case EventType.CERT_VERIFIER_JOB: 287 case EventType.CERT_VERIFIER_JOB:
289 case EventType.SSL_CERTIFICATES_RECEIVED: 288 case EventType.SSL_CERTIFICATES_RECEIVED:
290 return writeParamsForCertificates; 289 return writeParamsForCertificates;
291 case EventType.CERT_CT_COMPLIANCE_CHECKED: 290 case EventType.CERT_CT_COMPLIANCE_CHECKED:
292 case EventType.EV_CERT_CT_COMPLIANCE_CHECKED: 291 case EventType.EV_CERT_CT_COMPLIANCE_CHECKED:
293 return writeParamsForCheckedCertificates; 292 return writeParamsForCheckedCertificates;
294 } 293 }
295 return null; 294 return null;
296 } 295 }
297 296
298 /** 297 /**
299 * Default parameter writer that outputs a visualization of field named |key| 298 * Default parameter writer that outputs a visualization of field named |key|
300 * with value |value| to |out|. 299 * with value |value| to |out|.
301 */ 300 */
302 function defaultWriteParameter(key, value, out) { 301 function defaultWriteParameter(key, value, out) {
303 if (key == 'headers' && value instanceof Array) { 302 if (key == 'headers' && value instanceof Array) {
304 out.writeArrowIndentedLines(value); 303 out.writeArrowIndentedLines(value);
305 return; 304 return;
306 } 305 }
307 306
308 // For transferred bytes, display the bytes in hex and ASCII. 307 // For transferred bytes, display the bytes in hex and ASCII.
309 if (key == 'hex_encoded_bytes' && typeof value == 'string') { 308 if (key == 'hex_encoded_bytes' && typeof value == 'string') {
310 out.writeArrowKey(key); 309 out.writeArrowKey(key);
311 writeHexString(value, out); 310 writeHexString(value, out);
312 return; 311 return;
313 } 312 }
314 313
315 // Handle source_dependency entries - add link and map source type to 314 // Handle source_dependency entries - add link and map source type to
316 // string. 315 // string.
317 if (key == 'source_dependency' && typeof value == 'object') { 316 if (key == 'source_dependency' && typeof value == 'object') {
318 var link = '#events&s=' + value.id; 317 var link = '#events&s=' + value.id;
319 var valueStr = value.id + ' (' + EventSourceTypeNames[value.type] + ')'; 318 var valueStr = value.id + ' (' + EventSourceTypeNames[value.type] + ')';
320 out.writeArrowKeyValue(key, valueStr, link); 319 out.writeArrowKeyValue(key, valueStr, link);
321 return; 320 return;
322 } 321 }
323 322
324 if (key == 'net_error' && typeof value == 'number') { 323 if (key == 'net_error' && typeof value == 'number') {
325 var valueStr = value + ' (' + netErrorToString(value) + ')'; 324 var valueStr = value + ' (' + netErrorToString(value) + ')';
326 out.writeArrowKeyValue(key, valueStr); 325 out.writeArrowKeyValue(key, valueStr);
327 return; 326 return;
328 } 327 }
329 328
330 if (key == 'quic_error' && typeof value == 'number') { 329 if (key == 'quic_error' && typeof value == 'number') {
331 var valueStr = value + ' (' + quicErrorToString(value) + ')'; 330 var valueStr = value + ' (' + quicErrorToString(value) + ')';
332 out.writeArrowKeyValue(key, valueStr); 331 out.writeArrowKeyValue(key, valueStr);
333 return; 332 return;
334 } 333 }
335 334
336 if (key == 'quic_crypto_handshake_message' && typeof value == 'string') { 335 if (key == 'quic_crypto_handshake_message' && typeof value == 'string') {
337 var lines = value.split('\n'); 336 var lines = value.split('\n');
338 out.writeArrowIndentedLines(lines); 337 out.writeArrowIndentedLines(lines);
339 return; 338 return;
340 } 339 }
341 340
342 if (key == 'quic_rst_stream_error' && typeof value == 'number') { 341 if (key == 'quic_rst_stream_error' && typeof value == 'number') {
343 var valueStr = value + ' (' + quicRstStreamErrorToString(value) + ')'; 342 var valueStr = value + ' (' + quicRstStreamErrorToString(value) + ')';
344 out.writeArrowKeyValue(key, valueStr); 343 out.writeArrowKeyValue(key, valueStr);
345 return; 344 return;
346 } 345 }
347 346
348 if (key == 'load_flags' && typeof value == 'number') { 347 if (key == 'load_flags' && typeof value == 'number') {
349 var valueStr = value + ' (' + getLoadFlagSymbolicString(value) + ')'; 348 var valueStr = value + ' (' + getLoadFlagSymbolicString(value) + ')';
350 out.writeArrowKeyValue(key, valueStr); 349 out.writeArrowKeyValue(key, valueStr);
351 return; 350 return;
352 } 351 }
353 352
354 if (key == 'load_state' && typeof value == 'number') { 353 if (key == 'load_state' && typeof value == 'number') {
355 var valueStr = value + ' (' + getKeyWithValue(LoadState, value) + ')'; 354 var valueStr = value + ' (' + getKeyWithValue(LoadState, value) + ')';
356 out.writeArrowKeyValue(key, valueStr); 355 out.writeArrowKeyValue(key, valueStr);
357 return; 356 return;
358 } 357 }
359 358
360 if (key == 'sdch_problem_code' && typeof value == 'number') { 359 if (key == 'sdch_problem_code' && typeof value == 'number') {
361 var valueStr = value + ' (' + sdchProblemCodeToString(value) + ')'; 360 var valueStr = value + ' (' + sdchProblemCodeToString(value) + ')';
362 out.writeArrowKeyValue(key, valueStr); 361 out.writeArrowKeyValue(key, valueStr);
363 return; 362 return;
364 } 363 }
365 364
366 // Otherwise just default to JSON formatting of the value. 365 // Otherwise just default to JSON formatting of the value.
367 out.writeArrowKeyValue(key, JSON.stringify(value)); 366 out.writeArrowKeyValue(key, JSON.stringify(value));
368 } 367 }
369 368
370 /** 369 /**
371 * Returns the set of LoadFlags that make up the integer |loadFlag|. 370 * Returns the set of LoadFlags that make up the integer |loadFlag|.
372 * For example: getLoadFlagSymbolicString( 371 * For example: getLoadFlagSymbolicString(
373 */ 372 */
374 function getLoadFlagSymbolicString(loadFlag) { 373 function getLoadFlagSymbolicString(loadFlag) {
375 return getSymbolicString( 374 return getSymbolicString(
376 loadFlag, LoadFlag, getKeyWithValue(LoadFlag, loadFlag)); 375 loadFlag, LoadFlag, getKeyWithValue(LoadFlag, loadFlag));
377 } 376 }
378 377
379 /** 378 /**
380 * Returns the set of CertStatusFlags that make up the integer 379 * Returns the set of CertStatusFlags that make up the integer
381 * |certStatusFlag| 380 * |certStatusFlag|
382 */ 381 */
383 function getCertStatusFlagSymbolicString(certStatusFlag) { 382 function getCertStatusFlagSymbolicString(certStatusFlag) {
384 return getSymbolicString(certStatusFlag, CertStatusFlag, ''); 383 return getSymbolicString(certStatusFlag, CertStatusFlag, '');
385 } 384 }
386 385
387 /** 386 /**
388 * Returns a string representing the flags composing the given bitmask. 387 * Returns a string representing the flags composing the given bitmask.
389 */ 388 */
390 function getSymbolicString(bitmask, valueToName, zeroName) { 389 function getSymbolicString(bitmask, valueToName, zeroName) {
391 var matchingFlagNames = []; 390 var matchingFlagNames = [];
392 391
393 for (var k in valueToName) { 392 for (var k in valueToName) {
394 if (bitmask & valueToName[k]) 393 if (bitmask & valueToName[k])
395 matchingFlagNames.push(k); 394 matchingFlagNames.push(k);
396 } 395 }
397 396
398 // If no flags were matched, returns a special value. 397 // If no flags were matched, returns a special value.
399 if (matchingFlagNames.length == 0) 398 if (matchingFlagNames.length == 0)
400 return zeroName; 399 return zeroName;
401 400
402 return matchingFlagNames.join(' | '); 401 return matchingFlagNames.join(' | ');
403 } 402 }
404 403
405 /** 404 /**
406 * TODO(eroman): get rid of this, as it is only used by 1 callsite. 405 * TODO(eroman): get rid of this, as it is only used by 1 callsite.
407 * 406 *
408 * Indent |lines| by |start|. 407 * Indent |lines| by |start|.
409 * 408 *
410 * For example, if |start| = ' -> ' and |lines| = ['line1', 'line2', 'line3'] 409 * For example, if |start| = ' -> ' and |lines| = ['line1', 'line2', 'line3']
411 * the output will be: 410 * the output will be:
412 * 411 *
413 * " -> line1\n" + 412 * " -> line1\n" +
414 * " line2\n" + 413 * " line2\n" +
415 * " line3" 414 * " line3"
416 */ 415 */
417 function indentLines(start, lines) { 416 function indentLines(start, lines) {
418 return start + lines.join('\n' + makeRepeatedString(' ', start.length)); 417 return start + lines.join('\n' + makeRepeatedString(' ', start.length));
419 } 418 }
420 419
421 /** 420 /**
422 * If entry.param.headers exists and is an object other than an array, 421 * If entry.param.headers exists and is an object other than an array,
423 * converts 422 * converts
424 * it into an array and returns a new entry. Otherwise, just returns the 423 * it into an array and returns a new entry. Otherwise, just returns the
425 * original entry. 424 * original entry.
426 */ 425 */
427 function reformatHeaders(entry) { 426 function reformatHeaders(entry) {
428 // If there are no headers, or it is not an object other than an array, 427 // If there are no headers, or it is not an object other than an array,
429 // return |entry| without modification. 428 // return |entry| without modification.
430 if (!entry.params || entry.params.headers === undefined || 429 if (!entry.params || entry.params.headers === undefined ||
431 typeof entry.params.headers != 'object' || 430 typeof entry.params.headers != 'object' ||
432 entry.params.headers instanceof Array) { 431 entry.params.headers instanceof Array) {
433 return entry; 432 return entry;
434 } 433 }
435 434
436 // Duplicate the top level object, and |entry.params|, so the original 435 // Duplicate the top level object, and |entry.params|, so the original
437 // object 436 // object
438 // will not be modified. 437 // will not be modified.
438 entry = shallowCloneObject(entry);
439 entry.params = shallowCloneObject(entry.params);
440
441 // Convert headers to an array.
442 var headers = [];
443 for (var key in entry.params.headers)
444 headers.push(key + ': ' + entry.params.headers[key]);
445 entry.params.headers = headers;
446
447 return entry;
448 }
449
450 /**
451 * Removes a cookie or unencrypted login information from a single HTTP header
452 * line, if present, and returns the modified line. Otherwise, just returns
453 * the original line.
454 *
455 * Note: this logic should be kept in sync with
456 * net::ElideHeaderValueForNetLog in net/http/http_log_util.cc.
457 */
458 function stripCookieOrLoginInfo(line) {
459 var patterns = [
460 // Cookie patterns
461 /^set-cookie: /i, /^set-cookie2: /i, /^cookie: /i,
462
463 // Unencrypted authentication patterns
464 /^authorization: \S*\s*/i, /^proxy-authorization: \S*\s*/i
465 ];
466
467 // Prefix will hold the first part of the string that contains no private
468 // information. If null, no part of the string contains private
469 // information.
470 var prefix = null;
471 for (var i = 0; i < patterns.length; i++) {
472 var match = patterns[i].exec(line);
473 if (match != null) {
474 prefix = match[0];
475 break;
476 }
477 }
478
479 // Look for authentication information from data received from the server in
480 // multi-round Negotiate authentication.
481 if (prefix === null) {
482 var challengePatterns =
483 [/^www-authenticate: (\S*)\s*/i, /^proxy-authenticate: (\S*)\s*/i];
484 for (var i = 0; i < challengePatterns.length; i++) {
485 var match = challengePatterns[i].exec(line);
486 if (!match)
487 continue;
488
489 // If there's no data after the scheme name, do nothing.
490 if (match[0].length == line.length)
491 break;
492
493 // Ignore lines with commas, as they may contain lists of schemes, and
494 // the information we want to hide is Base64 encoded, so has no commas.
495 if (line.indexOf(',') >= 0)
496 break;
497
498 // Ignore Basic and Digest authentication challenges, as they contain
499 // public information.
500 if (/^basic$/i.test(match[1]) || /^digest$/i.test(match[1]))
501 break;
502
503 prefix = match[0];
504 break;
505 }
506 }
507
508 if (prefix) {
509 var suffix = line.slice(prefix.length);
510 // If private information has already been removed, keep the line as-is.
511 // This is often the case when viewing a loaded log.
512 if (suffix.search(/^\[[0-9]+ bytes were stripped\]$/) == -1) {
513 return prefix + '[' + suffix.length + ' bytes were stripped]';
514 }
515 }
516
517 return line;
518 }
519
520 /**
521 * Remove debug data from HTTP/2 GOAWAY frame due to privacy considerations,
522 * see
523 * https://httpwg.github.io/specs/rfc7540.html#GOAWAY.
524 *
525 * Note: this logic should be kept in sync with
526 * net::ElideGoAwayDebugDataForNetLog in net/http/http_log_util.cc.
527 */
528 function stripGoAwayDebugData(value) {
529 return '[' + value.length + ' bytes were stripped]';
530 }
531
532 /**
533 * If |entry| has headers, returns a copy of |entry| with all cookie and
534 * unencrypted login text removed. Otherwise, returns original |entry|
535 * object.
536 * This is needed so that JSON log dumps can be made without affecting the
537 * source data. Converts headers stored in objects to arrays.
538 */
539 stripPrivacyInfo = function(entry) {
540 if (!entry.params) {
541 return entry;
542 }
543
544 if (entry.type == EventType.HTTP2_SESSION_GOAWAY &&
545 entry.params.debug_data != undefined) {
546 // Duplicate the top level object, and |entry.params|. All other fields
547 // are
548 // just pointers to the original values, as they won't be modified, other
549 // than |entry.params.debug_data|.
439 entry = shallowCloneObject(entry); 550 entry = shallowCloneObject(entry);
440 entry.params = shallowCloneObject(entry.params); 551 entry.params = shallowCloneObject(entry.params);
441 552 entry.params.debug_data = stripGoAwayDebugData(entry.params.debug_data);
442 // Convert headers to an array.
443 var headers = [];
444 for (var key in entry.params.headers)
445 headers.push(key + ': ' + entry.params.headers[key]);
446 entry.params.headers = headers;
447
448 return entry; 553 return entry;
449 } 554 }
450 555
451 /** 556 if (entry.params.headers === undefined ||
452 * Removes a cookie or unencrypted login information from a single HTTP header 557 !(entry.params.headers instanceof Object)) {
453 * line, if present, and returns the modified line. Otherwise, just returns
454 * the original line.
455 *
456 * Note: this logic should be kept in sync with
457 * net::ElideHeaderValueForNetLog in net/http/http_log_util.cc.
458 */
459 function stripCookieOrLoginInfo(line) {
460 var patterns = [
461 // Cookie patterns
462 /^set-cookie: /i, /^set-cookie2: /i, /^cookie: /i,
463
464 // Unencrypted authentication patterns
465 /^authorization: \S*\s*/i, /^proxy-authorization: \S*\s*/i
466 ];
467
468 // Prefix will hold the first part of the string that contains no private
469 // information. If null, no part of the string contains private
470 // information.
471 var prefix = null;
472 for (var i = 0; i < patterns.length; i++) {
473 var match = patterns[i].exec(line);
474 if (match != null) {
475 prefix = match[0];
476 break;
477 }
478 }
479
480 // Look for authentication information from data received from the server in
481 // multi-round Negotiate authentication.
482 if (prefix === null) {
483 var challengePatterns =
484 [/^www-authenticate: (\S*)\s*/i, /^proxy-authenticate: (\S*)\s*/i];
485 for (var i = 0; i < challengePatterns.length; i++) {
486 var match = challengePatterns[i].exec(line);
487 if (!match)
488 continue;
489
490 // If there's no data after the scheme name, do nothing.
491 if (match[0].length == line.length)
492 break;
493
494 // Ignore lines with commas, as they may contain lists of schemes, and
495 // the information we want to hide is Base64 encoded, so has no commas.
496 if (line.indexOf(',') >= 0)
497 break;
498
499 // Ignore Basic and Digest authentication challenges, as they contain
500 // public information.
501 if (/^basic$/i.test(match[1]) || /^digest$/i.test(match[1]))
502 break;
503
504 prefix = match[0];
505 break;
506 }
507 }
508
509 if (prefix) {
510 var suffix = line.slice(prefix.length);
511 // If private information has already been removed, keep the line as-is.
512 // This is often the case when viewing a loaded log.
513 if (suffix.search(/^\[[0-9]+ bytes were stripped\]$/) == -1) {
514 return prefix + '[' + suffix.length + ' bytes were stripped]';
515 }
516 }
517
518 return line;
519 }
520
521 /**
522 * Remove debug data from HTTP/2 GOAWAY frame due to privacy considerations,
523 * see
524 * https://httpwg.github.io/specs/rfc7540.html#GOAWAY.
525 *
526 * Note: this logic should be kept in sync with
527 * net::ElideGoAwayDebugDataForNetLog in net/http/http_log_util.cc.
528 */
529 function stripGoAwayDebugData(value) {
530 return '[' + value.length + ' bytes were stripped]';
531 }
532
533 /**
534 * If |entry| has headers, returns a copy of |entry| with all cookie and
535 * unencrypted login text removed. Otherwise, returns original |entry|
536 * object.
537 * This is needed so that JSON log dumps can be made without affecting the
538 * source data. Converts headers stored in objects to arrays.
539 */
540 stripPrivacyInfo = function(entry) {
541 if (!entry.params) {
542 return entry;
543 }
544
545 if (entry.type == EventType.HTTP2_SESSION_GOAWAY &&
546 entry.params.debug_data != undefined) {
547 // Duplicate the top level object, and |entry.params|. All other fields
548 // are
549 // just pointers to the original values, as they won't be modified, other
550 // than |entry.params.debug_data|.
551 entry = shallowCloneObject(entry);
552 entry.params = shallowCloneObject(entry.params);
553 entry.params.debug_data = stripGoAwayDebugData(entry.params.debug_data);
554 return entry;
555 }
556
557 if (entry.params.headers === undefined ||
558 !(entry.params.headers instanceof Object)) {
559 return entry;
560 }
561
562 // Make sure entry's headers are in an array.
563 entry = reformatHeaders(entry);
564
565 // Duplicate the top level object, and |entry.params|. All other fields are
566 // just pointers to the original values, as they won't be modified, other
567 // than
568 // |entry.params.headers|.
569 entry = shallowCloneObject(entry);
570 entry.params = shallowCloneObject(entry.params);
571
572 entry.params.headers = entry.params.headers.map(stripCookieOrLoginInfo);
573 return entry; 558 return entry;
574 }; 559 }
575 560
576 /** 561 // Make sure entry's headers are in an array.
577 * Outputs the request header parameters of |entry| to |out|. 562 entry = reformatHeaders(entry);
578 */ 563
579 function writeParamsForRequestHeaders(entry, out, consumedParams) { 564 // Duplicate the top level object, and |entry.params|. All other fields are
580 var params = entry.params; 565 // just pointers to the original values, as they won't be modified, other
581 566 // than
582 if (!(typeof params.line == 'string') || 567 // |entry.params.headers|.
583 !(params.headers instanceof Array)) { 568 entry = shallowCloneObject(entry);
584 // Unrecognized params. 569 entry.params = shallowCloneObject(entry.params);
585 return; 570
586 } 571 entry.params.headers = entry.params.headers.map(stripCookieOrLoginInfo);
587 572 return entry;
588 // Strip the trailing CRLF that params.line contains. 573 };
589 var lineWithoutCRLF = params.line.replace(/\r\n$/g, ''); 574
590 out.writeArrowIndentedLines([lineWithoutCRLF].concat(params.headers)); 575 /**
591 576 * Outputs the request header parameters of |entry| to |out|.
592 consumedParams.line = true; 577 */
593 consumedParams.headers = true; 578 function writeParamsForRequestHeaders(entry, out, consumedParams) {
594 } 579 var params = entry.params;
595 580
596 function writeCertificateParam( 581 if (!(typeof params.line == 'string') || !(params.headers instanceof Array)) {
597 certs_container, out, consumedParams, paramName) { 582 // Unrecognized params.
598 if (certs_container.certificates instanceof Array) { 583 return;
599 var certs = 584 }
600 certs_container.certificates.reduce(function(previous, current) { 585
601 return previous.concat(current.split('\n')); 586 // Strip the trailing CRLF that params.line contains.
602 }, new Array()); 587 var lineWithoutCRLF = params.line.replace(/\r\n$/g, '');
603 out.writeArrowKey(paramName); 588 out.writeArrowIndentedLines([lineWithoutCRLF].concat(params.headers));
604 out.writeSpaceIndentedLines(8, certs); 589
605 consumedParams[paramName] = true; 590 consumedParams.line = true;
606 } 591 consumedParams.headers = true;
607 } 592 }
608 593
609 /** 594 function writeCertificateParam(
610 * Outputs the certificate parameters of |entry| to |out|. 595 certs_container, out, consumedParams, paramName) {
611 */ 596 if (certs_container.certificates instanceof Array) {
612 function writeParamsForCertificates(entry, out, consumedParams) { 597 var certs =
613 writeCertificateParam(entry.params, out, consumedParams, 'certificates'); 598 certs_container.certificates.reduce(function(previous, current) {
614 599 return previous.concat(current.split('\n'));
615 if (typeof(entry.params.verified_cert) == 'object') 600 }, new Array());
616 writeCertificateParam( 601 out.writeArrowKey(paramName);
617 entry.params.verified_cert, out, consumedParams, 'verified_cert'); 602 out.writeSpaceIndentedLines(8, certs);
618 603 consumedParams[paramName] = true;
619 if (typeof(entry.params.cert_status) == 'number') { 604 }
620 var valueStr = entry.params.cert_status + ' (' + 605 }
621 getCertStatusFlagSymbolicString(entry.params.cert_status) + ')'; 606
622 out.writeArrowKeyValue('cert_status', valueStr); 607 /**
623 consumedParams.cert_status = true; 608 * Outputs the certificate parameters of |entry| to |out|.
624 } 609 */
625 } 610 function writeParamsForCertificates(entry, out, consumedParams) {
626 611 writeCertificateParam(entry.params, out, consumedParams, 'certificates');
627 function writeParamsForCheckedCertificates(entry, out, consumedParams) { 612
628 if (typeof(entry.params.certificate) == 'object') 613 if (typeof(entry.params.verified_cert) == 'object')
629 writeCertificateParam( 614 writeCertificateParam(
630 entry.params.certificate, out, consumedParams, 'certificate'); 615 entry.params.verified_cert, out, consumedParams, 'verified_cert');
631 } 616
632 617 if (typeof(entry.params.cert_status) == 'number') {
633 function writeParamsForProxyConfigChanged(entry, out, consumedParams) { 618 var valueStr = entry.params.cert_status + ' (' +
634 var params = entry.params; 619 getCertStatusFlagSymbolicString(entry.params.cert_status) + ')';
635 620 out.writeArrowKeyValue('cert_status', valueStr);
636 if (typeof params.new_config != 'object') { 621 consumedParams.cert_status = true;
637 // Unrecognized params. 622 }
638 return; 623 }
639 } 624
640 625 function writeParamsForCheckedCertificates(entry, out, consumedParams) {
641 if (typeof params.old_config == 'object') { 626 if (typeof(entry.params.certificate) == 'object')
642 var oldConfigString = proxySettingsToString(params.old_config); 627 writeCertificateParam(
643 // The previous configuration may not be present in the case of 628 entry.params.certificate, out, consumedParams, 'certificate');
644 // the initial proxy settings fetch. 629 }
645 out.writeArrowKey('old_config'); 630
646 631 function writeParamsForProxyConfigChanged(entry, out, consumedParams) {
647 out.writeSpaceIndentedLines(8, oldConfigString.split('\n')); 632 var params = entry.params;
648 633
649 consumedParams.old_config = true; 634 if (typeof params.new_config != 'object') {
650 } 635 // Unrecognized params.
651 636 return;
652 var newConfigString = proxySettingsToString(params.new_config); 637 }
653 out.writeArrowKey('new_config'); 638
654 out.writeSpaceIndentedLines(8, newConfigString.split('\n')); 639 if (typeof params.old_config == 'object') {
655 640 var oldConfigString = proxySettingsToString(params.old_config);
656 consumedParams.new_config = true; 641 // The previous configuration may not be present in the case of
657 } 642 // the initial proxy settings fetch.
658 643 out.writeArrowKey('old_config');
659 function getTextForEvent(entry) { 644
660 var text = ''; 645 out.writeSpaceIndentedLines(8, oldConfigString.split('\n'));
661 646
662 if (entry.isBegin() && canCollapseBeginWithEnd(entry)) { 647 consumedParams.old_config = true;
663 // Don't prefix with '+' if we are going to collapse the END event. 648 }
664 text = ' '; 649
665 } else if (entry.isBegin()) { 650 var newConfigString = proxySettingsToString(params.new_config);
666 text = '+' + text; 651 out.writeArrowKey('new_config');
667 } else if (entry.isEnd()) { 652 out.writeSpaceIndentedLines(8, newConfigString.split('\n'));
668 text = '-' + text; 653
669 } else { 654 consumedParams.new_config = true;
670 text = ' '; 655 }
671 } 656
672 657 function getTextForEvent(entry) {
673 text += EventTypeNames[entry.orig.type]; 658 var text = '';
674 return text; 659
675 } 660 if (entry.isBegin() && canCollapseBeginWithEnd(entry)) {
676 661 // Don't prefix with '+' if we are going to collapse the END event.
677 proxySettingsToString = function(config) { 662 text = ' ';
678 if (!config) 663 } else if (entry.isBegin()) {
679 return ''; 664 text = '+' + text;
680 665 } else if (entry.isEnd()) {
681 // TODO(eroman): if |config| has unexpected properties, print it as JSON 666 text = '-' + text;
682 // rather than hide them. 667 } else {
683 668 text = ' ';
684 function getProxyListString(proxies) { 669 }
685 // Older versions of Chrome would set these values as strings, whereas 670
686 // newer 671 text += EventTypeNames[entry.orig.type];
687 // logs use arrays. 672 return text;
688 // TODO(eroman): This behavior changed in M27. Support for older logs can 673 }
689 // safely be removed circa M29. 674
690 if (Array.isArray(proxies)) { 675 proxySettingsToString = function(config) {
691 var listString = proxies.join(', '); 676 if (!config)
692 if (proxies.length > 1) 677 return '';
693 return '[' + listString + ']'; 678
694 return listString; 679 // TODO(eroman): if |config| has unexpected properties, print it as JSON
695 } 680 // rather than hide them.
696 return proxies; 681
697 } 682 function getProxyListString(proxies) {
698 683 // Older versions of Chrome would set these values as strings, whereas
699 // The proxy settings specify up to three major fallback choices 684 // newer
700 // (auto-detect, custom pac url, or manual settings). 685 // logs use arrays.
701 // We enumerate these to a list so we can later number them. 686 // TODO(eroman): This behavior changed in M27. Support for older logs can
702 var modes = []; 687 // safely be removed circa M29.
703 688 if (Array.isArray(proxies)) {
704 // Output any automatic settings. 689 var listString = proxies.join(', ');
705 if (config.auto_detect) 690 if (proxies.length > 1)
706 modes.push(['Auto-detect']); 691 return '[' + listString + ']';
707 if (config.pac_url) 692 return listString;
708 modes.push(['PAC script: ' + config.pac_url]); 693 }
709 694 return proxies;
710 // Output any manual settings. 695 }
711 if (config.single_proxy || config.proxy_per_scheme) { 696
712 var lines = []; 697 // The proxy settings specify up to three major fallback choices
713 698 // (auto-detect, custom pac url, or manual settings).
714 if (config.single_proxy) { 699 // We enumerate these to a list so we can later number them.
715 lines.push('Proxy server: ' + getProxyListString(config.single_proxy)); 700 var modes = [];
716 } else if (config.proxy_per_scheme) { 701
717 for (var urlScheme in config.proxy_per_scheme) { 702 // Output any automatic settings.
718 if (urlScheme != 'fallback') { 703 if (config.auto_detect)
719 lines.push( 704 modes.push(['Auto-detect']);
720 'Proxy server for ' + urlScheme.toUpperCase() + ': ' + 705 if (config.pac_url)
721 getProxyListString(config.proxy_per_scheme[urlScheme])); 706 modes.push(['PAC script: ' + config.pac_url]);
722 } 707
723 } 708 // Output any manual settings.
724 if (config.proxy_per_scheme.fallback) { 709 if (config.single_proxy || config.proxy_per_scheme) {
710 var lines = [];
711
712 if (config.single_proxy) {
713 lines.push('Proxy server: ' + getProxyListString(config.single_proxy));
714 } else if (config.proxy_per_scheme) {
715 for (var urlScheme in config.proxy_per_scheme) {
716 if (urlScheme != 'fallback') {
725 lines.push( 717 lines.push(
726 'Proxy server for everything else: ' + 718 'Proxy server for ' + urlScheme.toUpperCase() + ': ' +
727 getProxyListString(config.proxy_per_scheme.fallback)); 719 getProxyListString(config.proxy_per_scheme[urlScheme]));
728 } 720 }
729 } 721 }
730 722 if (config.proxy_per_scheme.fallback) {
731 // Output any proxy bypass rules. 723 lines.push(
732 if (config.bypass_list) { 724 'Proxy server for everything else: ' +
733 if (config.reverse_bypass) { 725 getProxyListString(config.proxy_per_scheme.fallback));
734 lines.push('Reversed bypass list: ');
735 } else {
736 lines.push('Bypass list: ');
737 }
738
739 for (var i = 0; i < config.bypass_list.length; ++i)
740 lines.push(' ' + config.bypass_list[i]);
741 } 726 }
742 727 }
743 modes.push(lines); 728
744 } 729 // Output any proxy bypass rules.
745 730 if (config.bypass_list) {
746 var result = []; 731 if (config.reverse_bypass) {
747 if (modes.length < 1) { 732 lines.push('Reversed bypass list: ');
748 // If we didn't find any proxy settings modes, we are using DIRECT. 733 } else {
749 result.push('Use DIRECT connections.'); 734 lines.push('Bypass list: ');
750 } else if (modes.length == 1) { 735 }
751 // If there was just one mode, don't bother numbering it. 736
752 result.push(modes[0].join('\n')); 737 for (var i = 0; i < config.bypass_list.length; ++i)
753 } else { 738 lines.push(' ' + config.bypass_list[i]);
754 // Otherwise concatenate all of the modes into a numbered list 739 }
755 // (which correspond with the fallback order). 740
756 for (var i = 0; i < modes.length; ++i) 741 modes.push(lines);
757 result.push(indentLines('(' + (i + 1) + ') ', modes[i])); 742 }
758 } 743
759 744 var result = [];
760 if (config.source != undefined && config.source != 'UNKNOWN') 745 if (modes.length < 1) {
761 result.push('Source: ' + config.source); 746 // If we didn't find any proxy settings modes, we are using DIRECT.
762 747 result.push('Use DIRECT connections.');
763 return result.join('\n'); 748 } else if (modes.length == 1) {
764 }; 749 // If there was just one mode, don't bother numbering it.
765 750 result.push(modes[0].join('\n'));
766 // End of anonymous namespace. 751 } else {
752 // Otherwise concatenate all of the modes into a numbered list
753 // (which correspond with the fallback order).
754 for (var i = 0; i < modes.length; ++i)
755 result.push(indentLines('(' + (i + 1) + ') ', modes[i]));
756 }
757
758 if (config.source != undefined && config.source != 'UNKNOWN')
759 result.push('Source: ' + config.source);
760
761 return result.join('\n');
762 };
763
764 // End of anonymous namespace.
767 })(); 765 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698