1 /* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /** 32 * @constructor 33 * @extends {WebInspector.SDKObject} 34 * @implements {WebInspector.ContentProvider} 35 * @param {!NetworkAgent.RequestId} requestId 36 * @param {!WebInspector.Target} target 37 * @param {string} url 38 * @param {string} documentURL 39 * @param {!PageAgent.FrameId} frameId 40 * @param {!NetworkAgent.LoaderId} loaderId 41 * @param {?NetworkAgent.Initiator} initiator 42 */ 43 WebInspector.NetworkRequest = function(target, requestId, url, documentURL, frameId, loaderId, initiator) 44 { 45 WebInspector.SDKObject.call(this, target); 46 47 this._requestId = requestId; 48 this.url = url; 49 this._documentURL = documentURL; 50 this._frameId = frameId; 51 this._loaderId = loaderId; 52 /** @type {?NetworkAgent.Initiator} */ 53 this._initiator = initiator; 54 this._startTime = -1; 55 this._endTime = -1; 56 57 this.statusCode = 0; 58 this.statusText = ""; 59 this.requestMethod = ""; 60 this.requestTime = 0; 61 62 this._type = WebInspector.resourceTypes.Other; 63 this._contentEncoded = false; 64 this._pendingContentCallbacks = []; 65 /** @type {!Array.<!WebInspector.NetworkRequest.WebSocketFrame>} */ 66 this._frames = []; 67 68 this._responseHeaderValues = {}; 69 70 this._remoteAddress = ""; 71 72 /** @type {string} */ 73 this.connectionId = "0"; 74 } 75 76 WebInspector.NetworkRequest.Events = { 77 FinishedLoading: "FinishedLoading", 78 TimingChanged: "TimingChanged", 79 RemoteAddressChanged: "RemoteAddressChanged", 80 RequestHeadersChanged: "RequestHeadersChanged", 81 ResponseHeadersChanged: "ResponseHeadersChanged", 82 } 83 84 /** @enum {string} */ 85 WebInspector.NetworkRequest.InitiatorType = { 86 Other: "other", 87 Parser: "parser", 88 Redirect: "redirect", 89 Script: "script" 90 } 91 92 /** @typedef {!{name: string, value: string}} */ 93 WebInspector.NetworkRequest.NameValue; 94 95 /** @enum {string} */ 96 WebInspector.NetworkRequest.WebSocketFrameType = { 97 Send: "send", 98 Receive: "receive", 99 Error: "error" 100 } 101 102 /** @typedef {!{type: WebInspector.NetworkRequest.WebSocketFrameType, time: number, text: string, opCode: number, mask: boolean}} */ 103 WebInspector.NetworkRequest.WebSocketFrame; 104 105 WebInspector.NetworkRequest.prototype = { 106 /** 107 * @param {!WebInspector.NetworkRequest} other 108 * @return {number} 109 */ 110 indentityCompare: function(other) { 111 if (this._requestId > other._requestId) 112 return 1; 113 if (this._requestId < other._requestId) 114 return -1; 115 return 0; 116 }, 117 118 /** 119 * @return {!NetworkAgent.RequestId} 120 */ 121 get requestId() 122 { 123 return this._requestId; 124 }, 125 126 set requestId(requestId) 127 { 128 this._requestId = requestId; 129 }, 130 131 /** 132 * @return {string} 133 */ 134 get url() 135 { 136 return this._url; 137 }, 138 139 set url(x) 140 { 141 if (this._url === x) 142 return; 143 144 this._url = x; 145 this._parsedURL = new WebInspector.ParsedURL(x); 146 delete this._queryString; 147 delete this._parsedQueryParameters; 148 delete this._name; 149 delete this._path; 150 }, 151 152 /** 153 * @return {string} 154 */ 155 get documentURL() 156 { 157 return this._documentURL; 158 }, 159 160 get parsedURL() 161 { 162 return this._parsedURL; 163 }, 164 165 /** 166 * @return {!PageAgent.FrameId} 167 */ 168 get frameId() 169 { 170 return this._frameId; 171 }, 172 173 /** 174 * @return {!NetworkAgent.LoaderId} 175 */ 176 get loaderId() 177 { 178 return this._loaderId; 179 }, 180 181 /** 182 * @param {string} ip 183 * @param {number} port 184 */ 185 setRemoteAddress: function(ip, port) 186 { 187 if (ip.indexOf(":") !== -1) 188 ip = "[" + ip + "]"; 189 this._remoteAddress = ip + ":" + port; 190 this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RemoteAddressChanged, this); 191 }, 192 193 /** 194 * @return {string} 195 */ 196 remoteAddress: function() 197 { 198 return this._remoteAddress; 199 }, 200 201 /** 202 * @return {number} 203 */ 204 get startTime() 205 { 206 return this._startTime || -1; 207 }, 208 209 set startTime(x) 210 { 211 this._startTime = x; 212 }, 213 214 /** 215 * @return {number} 216 */ 217 get responseReceivedTime() 218 { 219 return this._responseReceivedTime || -1; 220 }, 221 222 set responseReceivedTime(x) 223 { 224 this._responseReceivedTime = x; 225 }, 226 227 /** 228 * @return {number} 229 */ 230 get endTime() 231 { 232 return this._endTime || -1; 233 }, 234 235 set endTime(x) 236 { 237 if (this.timing && this.timing.requestTime) { 238 // Check against accurate responseReceivedTime. 239 this._endTime = Math.max(x, this.responseReceivedTime); 240 } else { 241 // Prefer endTime since it might be from the network stack. 242 this._endTime = x; 243 if (this._responseReceivedTime > x) 244 this._responseReceivedTime = x; 245 } 246 this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.TimingChanged, this); 247 }, 248 249 /** 250 * @return {number} 251 */ 252 get duration() 253 { 254 if (this._endTime === -1 || this._startTime === -1) 255 return -1; 256 return this._endTime - this._startTime; 257 }, 258 259 /** 260 * @return {number} 261 */ 262 get latency() 263 { 264 if (this._responseReceivedTime === -1 || this._startTime === -1) 265 return -1; 266 return this._responseReceivedTime - this._startTime; 267 }, 268 269 /** 270 * @return {number} 271 */ 272 get resourceSize() 273 { 274 return this._resourceSize || 0; 275 }, 276 277 set resourceSize(x) 278 { 279 this._resourceSize = x; 280 }, 281 282 /** 283 * @return {number} 284 */ 285 get transferSize() 286 { 287 return this._transferSize || 0; 288 }, 289 290 /** 291 * @param {number} x 292 */ 293 increaseTransferSize: function(x) 294 { 295 this._transferSize = (this._transferSize || 0) + x; 296 }, 297 298 /** 299 * @param {number} x 300 */ 301 setTransferSize: function(x) 302 { 303 this._transferSize = x; 304 }, 305 306 /** 307 * @return {boolean} 308 */ 309 get finished() 310 { 311 return this._finished; 312 }, 313 314 set finished(x) 315 { 316 if (this._finished === x) 317 return; 318 319 this._finished = x; 320 321 if (x) { 322 this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.FinishedLoading, this); 323 if (this._pendingContentCallbacks.length) 324 this._innerRequestContent(); 325 } 326 }, 327 328 /** 329 * @return {boolean} 330 */ 331 get failed() 332 { 333 return this._failed; 334 }, 335 336 set failed(x) 337 { 338 this._failed = x; 339 }, 340 341 /** 342 * @return {boolean} 343 */ 344 get canceled() 345 { 346 return this._canceled; 347 }, 348 349 set canceled(x) 350 { 351 this._canceled = x; 352 }, 353 354 /** 355 * @return {boolean} 356 */ 357 get cached() 358 { 359 return !!this._cached && !this._transferSize; 360 }, 361 362 set cached(x) 363 { 364 this._cached = x; 365 if (x) 366 delete this._timing; 367 }, 368 369 /** 370 * @return {boolean} 371 */ 372 get fetchedViaServiceWorker() 373 { 374 return this._fetchedViaServiceWorker; 375 }, 376 377 set fetchedViaServiceWorker(x) 378 { 379 this._fetchedViaServiceWorker = x; 380 }, 381 382 /** 383 * @return {!NetworkAgent.ResourceTiming|undefined} 384 */ 385 get timing() 386 { 387 return this._timing; 388 }, 389 390 set timing(x) 391 { 392 if (x && !this._cached) { 393 // Take startTime and responseReceivedTime from timing data for better accuracy. 394 // Timing's requestTime is a baseline in seconds, rest of the numbers there are ticks in millis. 395 this._startTime = x.requestTime; 396 this._responseReceivedTime = x.requestTime + x.receiveHeadersEnd / 1000.0; 397 398 this._timing = x; 399 this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.TimingChanged, this); 400 } 401 }, 402 403 /** 404 * @return {string} 405 */ 406 get mimeType() 407 { 408 return this._mimeType; 409 }, 410 411 set mimeType(x) 412 { 413 this._mimeType = x; 414 }, 415 416 /** 417 * @return {string} 418 */ 419 get displayName() 420 { 421 return this._parsedURL.displayName; 422 }, 423 424 /** 425 * @return {string} 426 */ 427 name: function() 428 { 429 if (this._name) 430 return this._name; 431 this._parseNameAndPathFromURL(); 432 return this._name; 433 }, 434 435 /** 436 * @return {string} 437 */ 438 path: function() 439 { 440 if (this._path) 441 return this._path; 442 this._parseNameAndPathFromURL(); 443 return this._path; 444 }, 445 446 _parseNameAndPathFromURL: function() 447 { 448 if (this._parsedURL.isDataURL()) { 449 this._name = this._parsedURL.dataURLDisplayName(); 450 this._path = ""; 451 } else if (this._parsedURL.isAboutBlank()) { 452 this._name = this._parsedURL.url; 453 this._path = ""; 454 } else { 455 this._path = this._parsedURL.host + this._parsedURL.folderPathComponents; 456 this._path = this._path.trimURL(this.target().resourceTreeModel.inspectedPageDomain()); 457 if (this._parsedURL.lastPathComponent || this._parsedURL.queryParams) 458 this._name = this._parsedURL.lastPathComponent + (this._parsedURL.queryParams ? "?" + this._parsedURL.queryParams : ""); 459 else if (this._parsedURL.folderPathComponents) { 460 this._name = this._parsedURL.folderPathComponents.substring(this._parsedURL.folderPathComponents.lastIndexOf("/") + 1) + "/"; 461 this._path = this._path.substring(0, this._path.lastIndexOf("/")); 462 } else { 463 this._name = this._parsedURL.host; 464 this._path = ""; 465 } 466 } 467 }, 468 469 /** 470 * @return {string} 471 */ 472 get folder() 473 { 474 var path = this._parsedURL.path; 475 var indexOfQuery = path.indexOf("?"); 476 if (indexOfQuery !== -1) 477 path = path.substring(0, indexOfQuery); 478 var lastSlashIndex = path.lastIndexOf("/"); 479 return lastSlashIndex !== -1 ? path.substring(0, lastSlashIndex) : ""; 480 }, 481 482 /** 483 * @return {!WebInspector.ResourceType} 484 */ 485 get type() 486 { 487 return this._type; 488 }, 489 490 set type(x) 491 { 492 this._type = x; 493 }, 494 495 /** 496 * @return {string} 497 */ 498 get domain() 499 { 500 return this._parsedURL.host; 501 }, 502 503 /** 504 * @return {string} 505 */ 506 get scheme() 507 { 508 return this._parsedURL.scheme; 509 }, 510 511 /** 512 * @return {?WebInspector.NetworkRequest} 513 */ 514 get redirectSource() 515 { 516 if (this.redirects && this.redirects.length > 0) 517 return this.redirects[this.redirects.length - 1]; 518 return this._redirectSource; 519 }, 520 521 set redirectSource(x) 522 { 523 this._redirectSource = x; 524 delete this._initiatorInfo; 525 }, 526 527 /** 528 * @return {!Array.<!WebInspector.NetworkRequest.NameValue>} 529 */ 530 requestHeaders: function() 531 { 532 return this._requestHeaders || []; 533 }, 534 535 /** 536 * @param {!Array.<!WebInspector.NetworkRequest.NameValue>} headers 537 */ 538 setRequestHeaders: function(headers) 539 { 540 this._requestHeaders = headers; 541 delete this._requestCookies; 542 543 this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged); 544 }, 545 546 /** 547 * @return {string|undefined} 548 */ 549 requestHeadersText: function() 550 { 551 return this._requestHeadersText; 552 }, 553 554 /** 555 * @param {string} text 556 */ 557 setRequestHeadersText: function(text) 558 { 559 this._requestHeadersText = text; 560 561 this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged); 562 }, 563 564 /** 565 * @param {string} headerName 566 * @return {string|undefined} 567 */ 568 requestHeaderValue: function(headerName) 569 { 570 return this._headerValue(this.requestHeaders(), headerName); 571 }, 572 573 /** 574 * @return {!Array.<!WebInspector.Cookie>} 575 */ 576 get requestCookies() 577 { 578 if (!this._requestCookies) 579 this._requestCookies = WebInspector.CookieParser.parseCookie(this.requestHeaderValue("Cookie")); 580 return this._requestCookies; 581 }, 582 583 /** 584 * @return {string|undefined} 585 */ 586 get requestFormData() 587 { 588 return this._requestFormData; 589 }, 590 591 set requestFormData(x) 592 { 593 this._requestFormData = x; 594 delete this._parsedFormParameters; 595 }, 596 597 /** 598 * @return {string} 599 */ 600 requestHttpVersion: function() 601 { 602 var headersText = this.requestHeadersText(); 603 if (!headersText) 604 return this.requestHeaderValue("version") || this.requestHeaderValue(":version") || "unknown"; 605 var firstLine = headersText.split(/\r\n/)[0]; 606 var match = firstLine.match(/(HTTP\/\d+\.\d+)$/); 607 return match ? match[1] : "HTTP/0.9"; 608 }, 609 610 /** 611 * @return {!Array.<!WebInspector.NetworkRequest.NameValue>} 612 */ 613 get responseHeaders() 614 { 615 return this._responseHeaders || []; 616 }, 617 618 set responseHeaders(x) 619 { 620 this._responseHeaders = x; 621 delete this._sortedResponseHeaders; 622 delete this._responseCookies; 623 this._responseHeaderValues = {}; 624 625 this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged); 626 }, 627 628 /** 629 * @return {string} 630 */ 631 get responseHeadersText() 632 { 633 return this._responseHeadersText; 634 }, 635 636 set responseHeadersText(x) 637 { 638 this._responseHeadersText = x; 639 640 this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged); 641 }, 642 643 /** 644 * @return {!Array.<!WebInspector.NetworkRequest.NameValue>} 645 */ 646 get sortedResponseHeaders() 647 { 648 if (this._sortedResponseHeaders !== undefined) 649 return this._sortedResponseHeaders; 650 651 this._sortedResponseHeaders = this.responseHeaders.slice(); 652 this._sortedResponseHeaders.sort(function(a, b) { return a.name.toLowerCase().compareTo(b.name.toLowerCase()); }); 653 return this._sortedResponseHeaders; 654 }, 655 656 /** 657 * @param {string} headerName 658 * @return {string|undefined} 659 */ 660 responseHeaderValue: function(headerName) 661 { 662 var value = this._responseHeaderValues[headerName]; 663 if (value === undefined) { 664 value = this._headerValue(this.responseHeaders, headerName); 665 this._responseHeaderValues[headerName] = (value !== undefined) ? value : null; 666 } 667 return (value !== null) ? value : undefined; 668 }, 669 670 /** 671 * @return {!Array.<!WebInspector.Cookie>} 672 */ 673 get responseCookies() 674 { 675 if (!this._responseCookies) 676 this._responseCookies = WebInspector.CookieParser.parseSetCookie(this.responseHeaderValue("Set-Cookie")); 677 return this._responseCookies; 678 }, 679 680 /** 681 * @return {?string} 682 */ 683 queryString: function() 684 { 685 if (this._queryString !== undefined) 686 return this._queryString; 687 688 var queryString = null; 689 var url = this.url; 690 var questionMarkPosition = url.indexOf("?"); 691 if (questionMarkPosition !== -1) { 692 queryString = url.substring(questionMarkPosition + 1); 693 var hashSignPosition = queryString.indexOf("#"); 694 if (hashSignPosition !== -1) 695 queryString = queryString.substring(0, hashSignPosition); 696 } 697 this._queryString = queryString; 698 return this._queryString; 699 }, 700 701 /** 702 * @return {?Array.<!WebInspector.NetworkRequest.NameValue>} 703 */ 704 get queryParameters() 705 { 706 if (this._parsedQueryParameters) 707 return this._parsedQueryParameters; 708 var queryString = this.queryString(); 709 if (!queryString) 710 return null; 711 this._parsedQueryParameters = this._parseParameters(queryString); 712 return this._parsedQueryParameters; 713 }, 714 715 /** 716 * @return {?Array.<!WebInspector.NetworkRequest.NameValue>} 717 */ 718 get formParameters() 719 { 720 if (this._parsedFormParameters) 721 return this._parsedFormParameters; 722 if (!this.requestFormData) 723 return null; 724 var requestContentType = this.requestContentType(); 725 if (!requestContentType || !requestContentType.match(/^application\/x-www-form-urlencoded\s*(;.*)?$/i)) 726 return null; 727 this._parsedFormParameters = this._parseParameters(this.requestFormData); 728 return this._parsedFormParameters; 729 }, 730 731 /** 732 * @return {string} 733 */ 734 responseHttpVersion: function() 735 { 736 var headersText = this._responseHeadersText; 737 if (!headersText) 738 return this.responseHeaderValue("version") || this.responseHeaderValue(":version") || "unknown"; 739 var firstLine = headersText.split(/\r\n/)[0]; 740 var match = firstLine.match(/^(HTTP\/\d+\.\d+)/); 741 return match ? match[1] : "HTTP/0.9"; 742 }, 743 744 /** 745 * @param {string} queryString 746 * @return {!Array.<!WebInspector.NetworkRequest.NameValue>} 747 */ 748 _parseParameters: function(queryString) 749 { 750 function parseNameValue(pair) 751 { 752 var position = pair.indexOf("="); 753 if (position === -1) 754 return {name: pair, value: ""}; 755 else 756 return {name: pair.substring(0, position), value: pair.substring(position + 1)}; 757 } 758 return queryString.split("&").map(parseNameValue); 759 }, 760 761 /** 762 * @param {!Array.<!WebInspector.NetworkRequest.NameValue>} headers 763 * @param {string} headerName 764 * @return {string|undefined} 765 */ 766 _headerValue: function(headers, headerName) 767 { 768 headerName = headerName.toLowerCase(); 769 770 var values = []; 771 for (var i = 0; i < headers.length; ++i) { 772 if (headers[i].name.toLowerCase() === headerName) 773 values.push(headers[i].value); 774 } 775 if (!values.length) 776 return undefined; 777 // Set-Cookie values should be separated by '\n', not comma, otherwise cookies could not be parsed. 778 if (headerName === "set-cookie") 779 return values.join("\n"); 780 return values.join(", "); 781 }, 782 783 /** 784 * @return {?string|undefined} 785 */ 786 get content() 787 { 788 return this._content; 789 }, 790 791 /** 792 * @return {?Protocol.Error|undefined} 793 */ 794 contentError: function() 795 { 796 return this._contentError; 797 }, 798 799 /** 800 * @return {boolean} 801 */ 802 get contentEncoded() 803 { 804 return this._contentEncoded; 805 }, 806 807 /** 808 * @return {string} 809 */ 810 contentURL: function() 811 { 812 return this._url; 813 }, 814 815 /** 816 * @return {!WebInspector.ResourceType} 817 */ 818 contentType: function() 819 { 820 return this._type; 821 }, 822 823 /** 824 * @param {function(?string)} callback 825 */ 826 requestContent: function(callback) 827 { 828 // We do not support content retrieval for WebSockets at the moment. 829 // Since WebSockets are potentially long-living, fail requests immediately 830 // to prevent caller blocking until resource is marked as finished. 831 if (this.type === WebInspector.resourceTypes.WebSocket) { 832 callback(null); 833 return; 834 } 835 if (typeof this._content !== "undefined") { 836 callback(this.content || null); 837 return; 838 } 839 this._pendingContentCallbacks.push(callback); 840 if (this.finished) 841 this._innerRequestContent(); 842 }, 843 844 /** 845 * @param {string} query 846 * @param {boolean} caseSensitive 847 * @param {boolean} isRegex 848 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback 849 */ 850 searchInContent: function(query, caseSensitive, isRegex, callback) 851 { 852 callback([]); 853 }, 854 855 /** 856 * @return {boolean} 857 */ 858 isHttpFamily: function() 859 { 860 return !!this.url.match(/^https?:/i); 861 }, 862 863 /** 864 * @return {string|undefined} 865 */ 866 requestContentType: function() 867 { 868 return this.requestHeaderValue("Content-Type"); 869 }, 870 871 /** 872 * @return {boolean} 873 */ 874 hasErrorStatusCode: function() 875 { 876 return this.statusCode >= 400; 877 }, 878 879 /** 880 * @param {!Element} image 881 */ 882 populateImageSource: function(image) 883 { 884 /** 885 * @this {WebInspector.NetworkRequest} 886 * @param {?string} content 887 */ 888 function onResourceContent(content) 889 { 890 var imageSrc = this.asDataURL(); 891 if (imageSrc === null) 892 imageSrc = this.url; 893 image.src = imageSrc; 894 } 895 896 this.requestContent(onResourceContent.bind(this)); 897 }, 898 899 /** 900 * @return {?string} 901 */ 902 asDataURL: function() 903 { 904 return WebInspector.Resource.contentAsDataURL(this._content, this.mimeType, this._contentEncoded); 905 }, 906 907 _innerRequestContent: function() 908 { 909 if (this._contentRequested) 910 return; 911 this._contentRequested = true; 912 913 /** 914 * @param {?Protocol.Error} error 915 * @param {string} content 916 * @param {boolean} contentEncoded 917 * @this {WebInspector.NetworkRequest} 918 */ 919 function onResourceContent(error, content, contentEncoded) 920 { 921 this._content = error ? null : content; 922 this._contentError = error; 923 this._contentEncoded = contentEncoded; 924 var callbacks = this._pendingContentCallbacks.slice(); 925 for (var i = 0; i < callbacks.length; ++i) 926 callbacks[i](this._content); 927 this._pendingContentCallbacks.length = 0; 928 delete this._contentRequested; 929 } 930 NetworkAgent.getResponseBody(this._requestId, onResourceContent.bind(this)); 931 }, 932 933 /** 934 * @return {?NetworkAgent.Initiator} 935 */ 936 initiator: function() 937 { 938 return this._initiator; 939 }, 940 941 /** 942 * @return {!{type: !WebInspector.NetworkRequest.InitiatorType, url: string, lineNumber: number, columnNumber: number}} 943 */ 944 initiatorInfo: function() 945 { 946 if (this._initiatorInfo) 947 return this._initiatorInfo; 948 949 var type = WebInspector.NetworkRequest.InitiatorType.Other; 950 var url = ""; 951 var lineNumber = -Infinity; 952 var columnNumber = -Infinity; 953 var initiator = this._initiator; 954 955 if (this.redirectSource) { 956 type = WebInspector.NetworkRequest.InitiatorType.Redirect; 957 url = this.redirectSource.url; 958 } else if (initiator) { 959 if (initiator.type === NetworkAgent.InitiatorType.Parser) { 960 type = WebInspector.NetworkRequest.InitiatorType.Parser; 961 url = initiator.url ? initiator.url : url; 962 lineNumber = initiator.lineNumber ? initiator.lineNumber : lineNumber; 963 } else if (initiator.type === NetworkAgent.InitiatorType.Script) { 964 var topFrame = initiator.stackTrace[0]; 965 if (topFrame.url) { 966 type = WebInspector.NetworkRequest.InitiatorType.Script; 967 url = topFrame.url; 968 lineNumber = topFrame.lineNumber; 969 columnNumber = topFrame.columnNumber; 970 } 971 } 972 } 973 974 this._initiatorInfo = {type: type, url: url, lineNumber: lineNumber, columnNumber: columnNumber}; 975 return this._initiatorInfo; 976 }, 977 978 /** 979 * @return {!Array.<!WebInspector.NetworkRequest.WebSocketFrame>} 980 */ 981 frames: function() 982 { 983 return this._frames; 984 }, 985 986 /** 987 * @param {string} errorMessage 988 * @param {number} time 989 */ 990 addFrameError: function(errorMessage, time) 991 { 992 this._frames.push({ type: WebInspector.NetworkRequest.WebSocketFrameType.Error, text: errorMessage, time: time, opCode: -1, mask: false }); 993 }, 994 995 /** 996 * @param {!NetworkAgent.WebSocketFrame} response 997 * @param {number} time 998 * @param {boolean} sent 999 */ 1000 addFrame: function(response, time, sent) 1001 { 1002 var type = sent ? WebInspector.NetworkRequest.WebSocketFrameType.Send : WebInspector.NetworkRequest.WebSocketFrameType.Receive; 1003 this._frames.push({ type: type, text: response.payloadData, time: time, opCode: response.opcode, mask: response.mask }); 1004 }, 1005 1006 replayXHR: function() 1007 { 1008 this.target().networkAgent().replayXHR(this.requestId); 1009 }, 1010 1011 __proto__: WebInspector.SDKObject.prototype 1012 } 1013