Web Inspector: extracting NetworkRequest from Resource (step 3)
authorpfeldman@chromium.org <pfeldman@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Apr 2012 12:15:05 +0000 (12:15 +0000)
committerpfeldman@chromium.org <pfeldman@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Apr 2012 12:15:05 +0000 (12:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=83802

Reviewed by Yury Semikhatsky.

Source/WebCore:

This change extracts NetworkRequest from the Resource. It is now clear that these two
should have super class that would be responsible for parsing URL and would define the
requestContent signature. Corresponding patch will follow.

* inspector/front-end/NetworkManager.js:
* inspector/front-end/NetworkRequest.js:
(WebInspector.NetworkRequest):
(WebInspector.NetworkRequest.prototype.get requestId):
(WebInspector.NetworkRequest.prototype.set requestId):
(WebInspector.NetworkRequest.prototype.get url):
(WebInspector.NetworkRequest.prototype.get frameId):
(WebInspector.NetworkRequest.prototype.get loaderId):
(WebInspector.NetworkRequest.prototype.get startTime):
(WebInspector.NetworkRequest.prototype.set startTime):
(WebInspector.NetworkRequest.prototype.get responseReceivedTime):
(WebInspector.NetworkRequest.prototype.set responseReceivedTime):
(WebInspector.NetworkRequest.prototype.get endTime):
(WebInspector.NetworkRequest.prototype.set endTime):
(WebInspector.NetworkRequest.prototype.get duration):
(WebInspector.NetworkRequest.prototype.get latency):
(WebInspector.NetworkRequest.prototype.get receiveDuration):
(WebInspector.NetworkRequest.prototype.get resourceSize):
(WebInspector.NetworkRequest.prototype.set resourceSize):
(WebInspector.NetworkRequest.prototype.get transferSize):
(WebInspector.NetworkRequest.prototype.increaseTransferSize):
(WebInspector.NetworkRequest.prototype.get finished):
(WebInspector.NetworkRequest.prototype.set finished):
(WebInspector.NetworkRequest.prototype.get failed):
(WebInspector.NetworkRequest.prototype.set failed):
(WebInspector.NetworkRequest.prototype.get canceled):
(WebInspector.NetworkRequest.prototype.set canceled):
(WebInspector.NetworkRequest.prototype.get cached):
(WebInspector.NetworkRequest.prototype.set cached):
(WebInspector.NetworkRequest.prototype.get timing):
(WebInspector.NetworkRequest.prototype.set timing):
(WebInspector.NetworkRequest.prototype.get mimeType):
(WebInspector.NetworkRequest.prototype.set mimeType):
(WebInspector.NetworkRequest.prototype.get displayName):
(WebInspector.NetworkRequest.prototype.get folder):
(WebInspector.NetworkRequest.prototype.get displayDomain):
(WebInspector.NetworkRequest.prototype.get type):
(WebInspector.NetworkRequest.prototype.set type):
(WebInspector.NetworkRequest.prototype.get redirectSource):
(WebInspector.NetworkRequest.prototype.set redirectSource):
(WebInspector.NetworkRequest.prototype.get requestHeaders):
(WebInspector.NetworkRequest.prototype.set requestHeaders):
(WebInspector.NetworkRequest.prototype.get requestHeadersText):
(WebInspector.NetworkRequest.prototype.set requestHeadersText):
(WebInspector.NetworkRequest.prototype.get requestHeadersSize):
(WebInspector.NetworkRequest.prototype.requestHeaderValue):
(WebInspector.NetworkRequest.prototype.get requestCookies):
(WebInspector.NetworkRequest.prototype.get requestFormData):
(WebInspector.NetworkRequest.prototype.set requestFormData):
(WebInspector.NetworkRequest.prototype.get requestHttpVersion):
(WebInspector.NetworkRequest.prototype.get responseHeaders):
(WebInspector.NetworkRequest.prototype.set responseHeaders):
(WebInspector.NetworkRequest.prototype.get responseHeadersText):
(WebInspector.NetworkRequest.prototype.set responseHeadersText):
(WebInspector.NetworkRequest.prototype.get responseHeadersSize):
(WebInspector.NetworkRequest.prototype.responseHeaderValue):
(WebInspector.NetworkRequest.prototype.get responseCookies):
(WebInspector.NetworkRequest.prototype.get queryParameters):
(WebInspector.NetworkRequest.prototype.get formParameters):
(WebInspector.NetworkRequest.prototype.get responseHttpVersion):
(WebInspector.NetworkRequest.prototype._parseParameters):
(WebInspector.NetworkRequest.prototype._headerValue):
(WebInspector.NetworkRequest.prototype.get content):
(WebInspector.NetworkRequest.prototype.get contentEncoded):
(WebInspector.NetworkRequest.prototype.requestContent):
(WebInspector.NetworkRequest.prototype.isHttpFamily):
(WebInspector.NetworkRequest.prototype.requestContentType):
(WebInspector.NetworkRequest.prototype.isPingRequest):
(WebInspector.NetworkRequest.prototype.hasErrorStatusCode):
(WebInspector.NetworkRequest.prototype.populateImageSource):
(WebInspector.NetworkRequest.prototype._contentURL):
(WebInspector.NetworkRequest.prototype._innerRequestContent.onResourceContent):
(WebInspector.NetworkRequest.prototype._innerRequestContent):
(WebInspector.NetworkRequest.prototype.setResource):
(WebInspector.NetworkRequest.prototype.resource):
* inspector/front-end/RawSourceCode.js:
(WebInspector.RawSourceCode):
(WebInspector.RawSourceCode.prototype._resourceAdded):
(WebInspector.RawSourceCode.prototype.forceUpdateSourceMapping):
(WebInspector.RawSourceCode.prototype._createContentProvider):
* inspector/front-end/Resource.js:
(WebInspector.Resource):
(WebInspector.Resource.displayName):
(WebInspector.Resource.prototype.get request):
(WebInspector.Resource.prototype.set url):
(WebInspector.Resource.prototype.get type):
(WebInspector.Resource.prototype.get mimeType):
(WebInspector.Resource.prototype.set mimeType):
(WebInspector.Resource.prototype.get content):
(WebInspector.Resource.prototype.get contentEncoded):
(WebInspector.Resource.prototype.requestContent):
(WebInspector.Resource.prototype._innerRequestContent.callback):
(WebInspector.Resource.prototype._innerRequestContent):
(WebInspector.ResourceRevision.prototype.requestContent.callbackWrapper):
(WebInspector.ResourceRevision.prototype.requestContent):
* inspector/front-end/ResourceScriptMapping.js:
(WebInspector.ResourceScriptMapping.prototype.addScript):

LayoutTests:

* http/tests/inspector/network/network-request-revision-content.html:
* inspector/debugger/raw-source-code.html:
* inspector/debugger/set-breakpoint.html:
* inspector/debugger/source-frame.html:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@114116 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/http/tests/inspector/network/network-request-revision-content.html
LayoutTests/inspector/debugger/raw-source-code.html
LayoutTests/inspector/debugger/set-breakpoint.html
LayoutTests/inspector/debugger/source-frame.html
Source/WebCore/ChangeLog
Source/WebCore/inspector/front-end/NetworkManager.js
Source/WebCore/inspector/front-end/NetworkRequest.js
Source/WebCore/inspector/front-end/RawSourceCode.js
Source/WebCore/inspector/front-end/Resource.js
Source/WebCore/inspector/front-end/ResourceScriptMapping.js

index 3bdf18e..40cecee 100644 (file)
@@ -1,3 +1,15 @@
+2012-04-13  Pavel Feldman  <pfeldman@chromium.org>
+
+        Web Inspector: extracting NetworkRequest from Resource (step 3)
+        https://bugs.webkit.org/show_bug.cgi?id=83802
+
+        Reviewed by Yury Semikhatsky.
+
+        * http/tests/inspector/network/network-request-revision-content.html:
+        * inspector/debugger/raw-source-code.html:
+        * inspector/debugger/set-breakpoint.html:
+        * inspector/debugger/source-frame.html:
+
 2012-04-13  Anton Muhin  <antonm@chromium.org>
 
         Mark test as flaky.
index 4bbfd00..e69951e 100644 (file)
@@ -14,18 +14,17 @@ function test()
     InspectorTest.addConsoleSniffer(step2, true);
     InspectorTest.evaluateInPage("loadScript()");
 
+    var resource;
     function step2(msg)
     {
         var request = WebInspector.panels.network.requests[WebInspector.panels.network.requests.length - 1];
-        var resource = request.resource();
+        resource = request.resource();
         resource.addRevision("");
         resource.history[0].requestContent(step3);
     }
 
     function step3()
     {
-        var request = WebInspector.panels.network.requests[WebInspector.panels.network.requests.length - 1];
-        var resource = request.resource();
         InspectorTest.addResult(resource.url);
         InspectorTest.addResult(resource.content);
         InspectorTest.completeTest();
index b8ea01c..e6c449d 100644 (file)
@@ -18,13 +18,19 @@ function test()
     function createRequestMock(type, finished, content)
     {
         var requestId = ++lastRequestId + "";
-        var request = new WebInspector.NetworkRequest(requestId, "http://fake.url", "", "");
+        WebInspector.resourceTreeModel._addFrame(new WebInspector.ResourceTreeFrame(WebInspector.resourceTreeModel, null, {id: "frame-id"}));
+        var request = new WebInspector.NetworkRequest(requestId, "http://fake.url", "frame-id", "loader-id");
         request.type = type === "document" ? WebInspector.resourceTypes.Document : WebInspector.resourceTypes.Script;
-        request.finished = finished;
+
+        WebInspector.networkManager._dispatcher._startNetworkRequest(request);
+        if (finished)
+            finishRequest(request);
+
         mockContentsMap[requestId] = content;
         return request;
     }
 
+    function finishRequest(request) { WebInspector.networkManager._dispatcher._finishNetworkRequest(request); }
     function createPendingRequestMock(type, content) { return createRequestMock(type, false, content); }
     function createFinishedRequestMock(type, content) { return createRequestMock(type, true, content); }
 
@@ -39,11 +45,16 @@ function test()
             finish: function() { formatter._callback(); }
         };
         return formatter;
-      };
+    };
 
     function createRawSourceCode(script, request, formatted, compilerSourceMapping)
     {
-        var rawSourceCode = new WebInspector.RawSourceCode("id", script, request, createScriptFormatterMock(), !!formatted, compilerSourceMapping);
+        var resource = null;
+        if (request && request.finished) {
+            resource = request.resource();
+            request = null;
+        }
+        var rawSourceCode = new WebInspector.RawSourceCode("id", script, resource, request, createScriptFormatterMock(), !!formatted, compilerSourceMapping);
         rawSourceCode.addEventListener(WebInspector.RawSourceCode.Events.UISourceCodeChanged, defaultUISourceCodeChangedHandler);
         return rawSourceCode;
     }
@@ -62,7 +73,7 @@ function test()
 
     function defaultUISourceCodeChangedHandler()
     {
-        throw "Unexpected UISourceCodeChanged event.";
+        throw new Error("Unexpected UISourceCodeChanged event.");
     }
 
     function createRawLocation(lineNumber, columnNumber)
@@ -102,8 +113,9 @@ function test()
             var rawSourceCode = createRawSourceCode(script1, request);
 
             InspectorTest.assertTrue(!rawSourceCode.uiSourceCode());
+
             waitForUISourceCodeChangedEvent(rawSourceCode, uiSourceCodeChanged);
-            request.finished = true;
+            finishRequest(request);
 
             function uiSourceCodeChanged(event)
             {
@@ -200,7 +212,7 @@ function test()
 
                 rawSourceCode.forceUpdateSourceMapping();
                 waitForUISourceCodeChangedEvent(rawSourceCode, requestContentRequest);
-                request.finished = true;
+                finishRequest(request);
             }
 
             function requestContentRequest()
@@ -289,7 +301,7 @@ function test()
             var rawSourceCode = createRawSourceCode(script, request, true);
 
             InspectorTest.assertTrue(!rawSourceCode.uiSourceCode());
-            request.finished = true;
+            finishRequest(request);
             waitForUISourceCodeChangedEvent(rawSourceCode, checkMapping);
             rawSourceCode._formatter.finish();
 
index 582b449..8a0b3dc 100644 (file)
@@ -39,7 +39,7 @@ var test = function()
             {
                 InspectorTest.addResult("Script execution paused.");
                 InspectorTest.captureStackTrace(callFrames);
-                dumpBreakpointSidebarPane()
+                dumpBreakpointSidebarPane();
                 InspectorTest.addSniffer(currentSourceFrame, "_removeBreakpointDecoration", breakpointRemoved);
                 InspectorTest.removeBreakpoint(currentSourceFrame, 16);
             }
index 20299be..2982feb 100644 (file)
@@ -12,6 +12,7 @@ function addErrorToConsole()
 
 function test()
 {
+    WebInspector.inspectorView.setCurrentPanel(WebInspector.panels.resources);
     InspectorTest.runDebuggerTestSuite([
         function testSetBreakpoint(next)
         {
@@ -72,7 +73,7 @@ function test()
             function visit(resource)
             {
                 if (resource.url.indexOf("debugger-test.js") !== -1) {
-                    WebInspector.panels.network._showRequest(resource.request, 1);
+                    WebInspector.panels.resources.showResource(resource, 1);
                     return true;
                 }
             }
index 7f72154..7f56b0c 100644 (file)
@@ -1,3 +1,112 @@
+2012-04-13  Pavel Feldman  <pfeldman@chromium.org>
+
+        Web Inspector: extracting NetworkRequest from Resource (step 3)
+        https://bugs.webkit.org/show_bug.cgi?id=83802
+
+        Reviewed by Yury Semikhatsky.
+
+        This change extracts NetworkRequest from the Resource. It is now clear that these two
+        should have super class that would be responsible for parsing URL and would define the
+        requestContent signature. Corresponding patch will follow.
+
+        * inspector/front-end/NetworkManager.js:
+        * inspector/front-end/NetworkRequest.js:
+        (WebInspector.NetworkRequest):
+        (WebInspector.NetworkRequest.prototype.get requestId):
+        (WebInspector.NetworkRequest.prototype.set requestId):
+        (WebInspector.NetworkRequest.prototype.get url):
+        (WebInspector.NetworkRequest.prototype.get frameId):
+        (WebInspector.NetworkRequest.prototype.get loaderId):
+        (WebInspector.NetworkRequest.prototype.get startTime):
+        (WebInspector.NetworkRequest.prototype.set startTime):
+        (WebInspector.NetworkRequest.prototype.get responseReceivedTime):
+        (WebInspector.NetworkRequest.prototype.set responseReceivedTime):
+        (WebInspector.NetworkRequest.prototype.get endTime):
+        (WebInspector.NetworkRequest.prototype.set endTime):
+        (WebInspector.NetworkRequest.prototype.get duration):
+        (WebInspector.NetworkRequest.prototype.get latency):
+        (WebInspector.NetworkRequest.prototype.get receiveDuration):
+        (WebInspector.NetworkRequest.prototype.get resourceSize):
+        (WebInspector.NetworkRequest.prototype.set resourceSize):
+        (WebInspector.NetworkRequest.prototype.get transferSize):
+        (WebInspector.NetworkRequest.prototype.increaseTransferSize):
+        (WebInspector.NetworkRequest.prototype.get finished):
+        (WebInspector.NetworkRequest.prototype.set finished):
+        (WebInspector.NetworkRequest.prototype.get failed):
+        (WebInspector.NetworkRequest.prototype.set failed):
+        (WebInspector.NetworkRequest.prototype.get canceled):
+        (WebInspector.NetworkRequest.prototype.set canceled):
+        (WebInspector.NetworkRequest.prototype.get cached):
+        (WebInspector.NetworkRequest.prototype.set cached):
+        (WebInspector.NetworkRequest.prototype.get timing):
+        (WebInspector.NetworkRequest.prototype.set timing):
+        (WebInspector.NetworkRequest.prototype.get mimeType):
+        (WebInspector.NetworkRequest.prototype.set mimeType):
+        (WebInspector.NetworkRequest.prototype.get displayName):
+        (WebInspector.NetworkRequest.prototype.get folder):
+        (WebInspector.NetworkRequest.prototype.get displayDomain):
+        (WebInspector.NetworkRequest.prototype.get type):
+        (WebInspector.NetworkRequest.prototype.set type):
+        (WebInspector.NetworkRequest.prototype.get redirectSource):
+        (WebInspector.NetworkRequest.prototype.set redirectSource):
+        (WebInspector.NetworkRequest.prototype.get requestHeaders):
+        (WebInspector.NetworkRequest.prototype.set requestHeaders):
+        (WebInspector.NetworkRequest.prototype.get requestHeadersText):
+        (WebInspector.NetworkRequest.prototype.set requestHeadersText):
+        (WebInspector.NetworkRequest.prototype.get requestHeadersSize):
+        (WebInspector.NetworkRequest.prototype.requestHeaderValue):
+        (WebInspector.NetworkRequest.prototype.get requestCookies):
+        (WebInspector.NetworkRequest.prototype.get requestFormData):
+        (WebInspector.NetworkRequest.prototype.set requestFormData):
+        (WebInspector.NetworkRequest.prototype.get requestHttpVersion):
+        (WebInspector.NetworkRequest.prototype.get responseHeaders):
+        (WebInspector.NetworkRequest.prototype.set responseHeaders):
+        (WebInspector.NetworkRequest.prototype.get responseHeadersText):
+        (WebInspector.NetworkRequest.prototype.set responseHeadersText):
+        (WebInspector.NetworkRequest.prototype.get responseHeadersSize):
+        (WebInspector.NetworkRequest.prototype.responseHeaderValue):
+        (WebInspector.NetworkRequest.prototype.get responseCookies):
+        (WebInspector.NetworkRequest.prototype.get queryParameters):
+        (WebInspector.NetworkRequest.prototype.get formParameters):
+        (WebInspector.NetworkRequest.prototype.get responseHttpVersion):
+        (WebInspector.NetworkRequest.prototype._parseParameters):
+        (WebInspector.NetworkRequest.prototype._headerValue):
+        (WebInspector.NetworkRequest.prototype.get content):
+        (WebInspector.NetworkRequest.prototype.get contentEncoded):
+        (WebInspector.NetworkRequest.prototype.requestContent):
+        (WebInspector.NetworkRequest.prototype.isHttpFamily):
+        (WebInspector.NetworkRequest.prototype.requestContentType):
+        (WebInspector.NetworkRequest.prototype.isPingRequest):
+        (WebInspector.NetworkRequest.prototype.hasErrorStatusCode):
+        (WebInspector.NetworkRequest.prototype.populateImageSource):
+        (WebInspector.NetworkRequest.prototype._contentURL):
+        (WebInspector.NetworkRequest.prototype._innerRequestContent.onResourceContent):
+        (WebInspector.NetworkRequest.prototype._innerRequestContent):
+        (WebInspector.NetworkRequest.prototype.setResource):
+        (WebInspector.NetworkRequest.prototype.resource):
+        * inspector/front-end/RawSourceCode.js:
+        (WebInspector.RawSourceCode):
+        (WebInspector.RawSourceCode.prototype._resourceAdded):
+        (WebInspector.RawSourceCode.prototype.forceUpdateSourceMapping):
+        (WebInspector.RawSourceCode.prototype._createContentProvider):
+        * inspector/front-end/Resource.js:
+        (WebInspector.Resource):
+        (WebInspector.Resource.displayName):
+        (WebInspector.Resource.prototype.get request):
+        (WebInspector.Resource.prototype.set url):
+        (WebInspector.Resource.prototype.get type):
+        (WebInspector.Resource.prototype.get mimeType):
+        (WebInspector.Resource.prototype.set mimeType):
+        (WebInspector.Resource.prototype.get content):
+        (WebInspector.Resource.prototype.get contentEncoded):
+        (WebInspector.Resource.prototype.requestContent):
+        (WebInspector.Resource.prototype._innerRequestContent.callback):
+        (WebInspector.Resource.prototype._innerRequestContent):
+        (WebInspector.ResourceRevision.prototype.requestContent.callbackWrapper):
+        (WebInspector.ResourceRevision.prototype.requestContent):
+        * inspector/front-end/ResourceScriptMapping.js:
+        (WebInspector.ResourceScriptMapping.prototype.addScript):
+
 2012-04-13  Mike Reed  <reed@google.com>
 
         use getClipDeviceBounds, rather than (deprecated) getTotalClip
index 48f0f1a..8346737 100644 (file)
@@ -94,27 +94,6 @@ WebInspector.NetworkManager._MIMETypes = {
 }
 
 WebInspector.NetworkManager.prototype = {
-    /**
-     * @param {WebInspector.Resource} resource
-     * @param {function(?string, boolean)} callback
-     */
-    requestContent: function(resource, callback)
-    {
-        function callbackWrapper(error, content, contentEncoded)
-        {
-            if (error)
-                callback(null, false);
-            else
-                callback(content, content && contentEncoded);
-        }
-        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=61363 We should separate NetworkResource (NetworkPanel resource)
-        // from ResourceRevision (ResourcesPanel/ScriptsPanel resource) and request content accordingly.
-        if (resource.requestId)
-            NetworkAgent.getResponseBody(resource.requestId, callbackWrapper);
-        else
-            PageAgent.getResourceContent(resource.frameId, resource.url, callbackWrapper);
-    },
-
     enableResourceTracking: function()
     {
         function callback(error)
index 60afbc3..fe031c4 100644 (file)
@@ -30,7 +30,7 @@
 
 /**
  * @constructor
- * @extends {WebInspector.Resource}
+ * @extends {WebInspector.Object}
  *
  * @param {NetworkAgent.RequestId} requestId
  * @param {string} url
  */
 WebInspector.NetworkRequest = function(requestId, url, frameId, loaderId)
 {
-    // FIXME: extract request-related part from the resource and aggregate
-    // network request in the resource.
-    WebInspector.Resource.call(this, null, url, frameId, loaderId);
-    this.requestId = requestId;
+    this._requestId = requestId;
+    this._url = url;
+    this._frameId = frameId;
+    this._loaderId = loaderId;
+    this._startTime = -1;
+    this._endTime = -1;
+
+    this.statusCode = 0;
+    this.statusText = "";
+    this.requestMethod = "";
+    this.requestTime = 0;
+    this.receiveHeadersEnd = 0;
+
+    this._type = WebInspector.resourceTypes.Other;
+    this._content = undefined;
+    this._contentEncoded = false;
+    this._pendingContentCallbacks = [];
+
+    delete this._parsedQueryParameters;
+
+    var parsedURL = url.asParsedURL();
+    this.domain = parsedURL ? parsedURL.host : "";
+    this.path = parsedURL ? parsedURL.path : "";
+    this.urlFragment = parsedURL ? parsedURL.fragment : "";
+    this.lastPathComponent = parsedURL ? parsedURL.lastPathComponent : "";
 }
 
 WebInspector.NetworkRequest.Events = {
@@ -52,4 +73,726 @@ WebInspector.NetworkRequest.Events = {
     ResponseHeadersChanged: "ResponseHeadersChanged",
 }
 
-WebInspector.NetworkRequest.prototype.__proto__ = WebInspector.Resource.prototype;
+WebInspector.NetworkRequest.prototype = {
+    /**
+     * @type {NetworkAgent.RequestId}
+     */
+    get requestId()
+    {
+        return this._requestId;
+    },
+
+    set requestId(requestId)
+    {
+        this._requestId = requestId;
+    },
+
+    /**
+     * @type {string}
+     */
+    get url()
+    {
+        return this._url;
+    },
+
+    /**
+     * @type {NetworkAgent.FrameId}
+     */
+    get frameId()
+    {
+        return this._frameId;
+    },
+
+    /**
+     * @type {NetworkAgent.LoaderId}
+     */
+    get loaderId()
+    {
+        return this._loaderId;
+    },
+
+    /**
+     * @type {number}
+     */
+    get startTime()
+    {
+        return this._startTime || -1;
+    },
+
+    set startTime(x)
+    {
+        this._startTime = x;
+    },
+
+    /**
+     * @type {number}
+     */
+    get responseReceivedTime()
+    {
+        return this._responseReceivedTime || -1;
+    },
+
+    set responseReceivedTime(x)
+    {
+        this._responseReceivedTime = x;
+    },
+
+    /**
+     * @type {number}
+     */
+    get endTime()
+    {
+        return this._endTime || -1;
+    },
+
+    set endTime(x)
+    {
+        if (this.timing && this.timing.requestTime) {
+            // Check against accurate responseReceivedTime.
+            this._endTime = Math.max(x, this.responseReceivedTime);
+        } else {
+            // Prefer endTime since it might be from the network stack.
+            this._endTime = x;
+            if (this._responseReceivedTime > x)
+                this._responseReceivedTime = x;
+        }
+    },
+
+    /**
+     * @type {number}
+     */
+    get duration()
+    {
+        if (this._endTime === -1 || this._startTime === -1)
+            return -1;
+        return this._endTime - this._startTime;
+    },
+
+    /**
+     * @type {number}
+     */
+    get latency()
+    {
+        if (this._responseReceivedTime === -1 || this._startTime === -1)
+            return -1;
+        return this._responseReceivedTime - this._startTime;
+    },
+
+    /**
+     * @type {number}
+     */
+    get receiveDuration()
+    {
+        if (this._endTime === -1 || this._responseReceivedTime === -1)
+            return -1;
+        return this._endTime - this._responseReceivedTime;
+    },
+
+    /**
+     * @type {number}
+     */
+    get resourceSize()
+    {
+        return this._resourceSize || 0;
+    },
+
+    set resourceSize(x)
+    {
+        this._resourceSize = x;
+    },
+
+    /**
+     * @type {number}
+     */
+    get transferSize()
+    {
+        if (this.cached)
+            return 0;
+        if (this.statusCode === 304) // Not modified
+            return this.responseHeadersSize;
+        if (this._transferSize !== undefined)
+            return this._transferSize;
+        // If we did not receive actual transfer size from network
+        // stack, we prefer using Content-Length over resourceSize as
+        // resourceSize may differ from actual transfer size if platform's
+        // network stack performed decoding (e.g. gzip decompression).
+        // The Content-Length, though, is expected to come from raw
+        // response headers and will reflect actual transfer length.
+        // This won't work for chunked content encoding, so fall back to
+        // resourceSize when we don't have Content-Length. This still won't
+        // work for chunks with non-trivial encodings. We need a way to
+        // get actual transfer size from the network stack.
+        var bodySize = Number(this.responseHeaders["Content-Length"] || this.resourceSize);
+        return this.responseHeadersSize + bodySize;
+    },
+
+    /**
+     * @param {number} x
+     */
+    increaseTransferSize: function(x)
+    {
+        this._transferSize = (this._transferSize || 0) + x;
+    },
+
+    /**
+     * @type {boolean}
+     */
+    get finished()
+    {
+        return this._finished;
+    },
+
+    set finished(x)
+    {
+        if (this._finished === x)
+            return;
+
+        this._finished = x;
+
+        if (x) {
+            this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.FinishedLoading, this);
+            if (this._pendingContentCallbacks.length)
+                this._innerRequestContent();
+        }
+    },
+
+    /**
+     * @type {boolean}
+     */
+    get failed()
+    {
+        return this._failed;
+    },
+
+    set failed(x)
+    {
+        this._failed = x;
+    },
+
+    /**
+     * @type {boolean}
+     */
+    get canceled()
+    {
+        return this._canceled;
+    },
+
+    set canceled(x)
+    {
+        this._canceled = x;
+    },
+
+    /**
+     * @type {boolean}
+     */
+    get cached()
+    {
+        return this._cached;
+    },
+
+    set cached(x)
+    {
+        this._cached = x;
+        if (x)
+            delete this._timing;
+    },
+
+    /**
+     * @type {NetworkAgent.ResourceTiming|undefined}
+     */
+    get timing()
+    {
+        return this._timing;
+    },
+
+    set timing(x)
+    {
+        if (x && !this._cached) {
+            // Take startTime and responseReceivedTime from timing data for better accuracy.
+            // Timing's requestTime is a baseline in seconds, rest of the numbers there are ticks in millis.
+            this._startTime = x.requestTime;
+            this._responseReceivedTime = x.requestTime + x.receiveHeadersEnd / 1000.0;
+
+            this._timing = x;
+            this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.TimingChanged, this);
+        }
+    },
+
+    /**
+     * @type {string}
+     */
+    get mimeType()
+    {
+        return this._mimeType;
+    },
+
+    set mimeType(x)
+    {
+        this._mimeType = x;
+    },
+
+    /**
+     * @type {string}
+     */
+    get displayName()
+    {
+        if (this._displayName)
+            return this._displayName;
+        this._displayName = this.lastPathComponent;
+        if (!this._displayName)
+            this._displayName = this.displayDomain;
+        if (!this._displayName && this.url)
+            this._displayName = this.url.trimURL(WebInspector.inspectedPageDomain ? WebInspector.inspectedPageDomain : "");
+        if (this._displayName === "/")
+            this._displayName = this.url;
+        return this._displayName;
+    },
+
+    /**
+     * @type {string}
+     */
+    get folder()
+    {
+        var path = this.path;
+        var indexOfQuery = path.indexOf("?");
+        if (indexOfQuery !== -1)
+            path = path.substring(0, indexOfQuery);
+        var lastSlashIndex = path.lastIndexOf("/");
+        return lastSlashIndex !== -1 ? path.substring(0, lastSlashIndex) : "";
+    },
+
+    /**
+     * @type {string}
+     */
+    get displayDomain()
+    {
+        // WebInspector.Database calls this, so don't access more than this.domain.
+        if (this.domain && (!WebInspector.inspectedPageDomain || (WebInspector.inspectedPageDomain && this.domain !== WebInspector.inspectedPageDomain)))
+            return this.domain;
+        return "";
+    },
+
+    /**
+     * @type {WebInspector.ResourceType}
+     */
+    get type()
+    {
+        return this._type;
+    },
+
+    set type(x)
+    {
+        this._type = x;
+    },
+
+    /**
+     * @type {WebInspector.Resource|undefined}
+     */
+    get redirectSource()
+    {
+        if (this.redirects && this.redirects.length > 0)
+            return this.redirects[this.redirects.length - 1];
+        return this._redirectSource;
+    },
+
+    set redirectSource(x)
+    {
+        this._redirectSource = x;
+    },
+
+    /**
+     * @type {Object}
+     */
+    get requestHeaders()
+    {
+        return this._requestHeaders || {};
+    },
+
+    set requestHeaders(x)
+    {
+        this._requestHeaders = x;
+        delete this._sortedRequestHeaders;
+        delete this._requestCookies;
+
+        this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged);
+    },
+
+    /**
+     * @type {string}
+     */
+    get requestHeadersText()
+    {
+        if (this._requestHeadersText === undefined) {
+            this._requestHeadersText = this.requestMethod + " " + this.url + " HTTP/1.1\r\n";
+            for (var key in this.requestHeaders)
+                this._requestHeadersText += key + ": " + this.requestHeaders[key] + "\r\n";
+        }
+        return this._requestHeadersText;
+    },
+
+    set requestHeadersText(x)
+    {
+        this._requestHeadersText = x;
+
+        this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged);
+    },
+
+    /**
+     * @type {number}
+     */
+    get requestHeadersSize()
+    {
+        return this.requestHeadersText.length;
+    },
+
+    /**
+     * @type {Array.<Object>}
+     */
+    get sortedRequestHeaders()
+    {
+        if (this._sortedRequestHeaders !== undefined)
+            return this._sortedRequestHeaders;
+
+        this._sortedRequestHeaders = [];
+        for (var key in this.requestHeaders)
+            this._sortedRequestHeaders.push({header: key, value: this.requestHeaders[key]});
+        this._sortedRequestHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) });
+
+        return this._sortedRequestHeaders;
+    },
+
+    /**
+     * @param {string} headerName
+     * @return {string|undefined}
+     */
+    requestHeaderValue: function(headerName)
+    {
+        return this._headerValue(this.requestHeaders, headerName);
+    },
+
+    /**
+     * @type {Array.<WebInspector.Cookie>}
+     */
+    get requestCookies()
+    {
+        if (!this._requestCookies)
+            this._requestCookies = WebInspector.CookieParser.parseCookie(this.requestHeaderValue("Cookie"));
+        return this._requestCookies;
+    },
+
+    /**
+     * @type {string|undefined}
+     */
+    get requestFormData()
+    {
+        return this._requestFormData;
+    },
+
+    set requestFormData(x)
+    {
+        this._requestFormData = x;
+        delete this._parsedFormParameters;
+    },
+
+    /**
+     * @type {string|undefined}
+     */
+    get requestHttpVersion()
+    {
+        var firstLine = this.requestHeadersText.split(/\r\n/)[0];
+        var match = firstLine.match(/(HTTP\/\d+\.\d+)$/);
+        return match ? match[1] : undefined;
+    },
+
+    /**
+     * @type {Object}
+     */
+    get responseHeaders()
+    {
+        return this._responseHeaders || {};
+    },
+
+    set responseHeaders(x)
+    {
+        this._responseHeaders = x;
+        delete this._sortedResponseHeaders;
+        delete this._responseCookies;
+
+        this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged);
+    },
+
+    /**
+     * @type {string}
+     */
+    get responseHeadersText()
+    {
+        if (this._responseHeadersText === undefined) {
+            this._responseHeadersText = "HTTP/1.1 " + this.statusCode + " " + this.statusText + "\r\n";
+            for (var key in this.responseHeaders)
+                this._responseHeadersText += key + ": " + this.responseHeaders[key] + "\r\n";
+        }
+        return this._responseHeadersText;
+    },
+
+    set responseHeadersText(x)
+    {
+        this._responseHeadersText = x;
+
+        this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged);
+    },
+
+    /**
+     * @type {number}
+     */
+    get responseHeadersSize()
+    {
+        return this.responseHeadersText.length;
+    },
+
+    /**
+     * @type {Array.<Object>}
+     */
+    get sortedResponseHeaders()
+    {
+        if (this._sortedResponseHeaders !== undefined)
+            return this._sortedResponseHeaders;
+
+        this._sortedResponseHeaders = [];
+        for (var key in this.responseHeaders)
+            this._sortedResponseHeaders.push({header: key, value: this.responseHeaders[key]});
+        this._sortedResponseHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) });
+
+        return this._sortedResponseHeaders;
+    },
+
+    /**
+     * @param {string} headerName
+     * @return {string|undefined}
+     */
+    responseHeaderValue: function(headerName)
+    {
+        return this._headerValue(this.responseHeaders, headerName);
+    },
+
+    /**
+     * @type {Array.<WebInspector.Cookie>}
+     */
+    get responseCookies()
+    {
+        if (!this._responseCookies)
+            this._responseCookies = WebInspector.CookieParser.parseSetCookie(this.responseHeaderValue("Set-Cookie"));
+        return this._responseCookies;
+    },
+
+    /**
+     * @type {?Array.<Object>}
+     */
+    get queryParameters()
+    {
+        if (this._parsedQueryParameters)
+            return this._parsedQueryParameters;
+        var queryString = this.url.split("?", 2)[1];
+        if (!queryString)
+            return null;
+        queryString = queryString.split("#", 2)[0];
+        this._parsedQueryParameters = this._parseParameters(queryString);
+        return this._parsedQueryParameters;
+    },
+
+    /**
+     * @type {?Array.<Object>}
+     */
+    get formParameters()
+    {
+        if (this._parsedFormParameters)
+            return this._parsedFormParameters;
+        if (!this.requestFormData)
+            return null;
+        var requestContentType = this.requestContentType();
+        if (!requestContentType || !requestContentType.match(/^application\/x-www-form-urlencoded\s*(;.*)?$/i))
+            return null;
+        this._parsedFormParameters = this._parseParameters(this.requestFormData);
+        return this._parsedFormParameters;
+    },
+
+    /**
+     * @type {string|undefined}
+     */
+    get responseHttpVersion()
+    {
+        var match = this.responseHeadersText.match(/^(HTTP\/\d+\.\d+)/);
+        return match ? match[1] : undefined;
+    },
+
+    /**
+     * @param {string} queryString
+     * @return {Array.<Object>}
+     */
+    _parseParameters: function(queryString)
+    {
+        function parseNameValue(pair)
+        {
+            var parameter = {};
+            var splitPair = pair.split("=", 2);
+
+            parameter.name = splitPair[0];
+            if (splitPair.length === 1)
+                parameter.value = "";
+            else
+                parameter.value = splitPair[1];
+            return parameter;
+        }
+        return queryString.split("&").map(parseNameValue);
+    },
+
+    /**
+     * @param {Object} headers
+     * @param {string} headerName
+     * @return {string|undefined}
+     */
+    _headerValue: function(headers, headerName)
+    {
+        headerName = headerName.toLowerCase();
+        for (var header in headers) {
+            if (header.toLowerCase() === headerName)
+                return headers[header];
+        }
+    },
+
+    /**
+     * @type {string}
+     */
+    get content()
+    {
+        return this._content;
+    },
+
+    /**
+     * @type {string}
+     */
+    get contentEncoded()
+    {
+        return this._contentEncoded;
+    },
+
+    /**
+     * @param {function(?string, boolean)} callback
+     */
+    requestContent: function(callback)
+    {
+        // We do not support content retrieval for WebSockets at the moment.
+        // Since WebSockets are potentially long-living, fail requests immediately
+        // to prevent caller blocking until resource is marked as finished.
+        if (this.type === WebInspector.resourceTypes.WebSocket) {
+            callback(null, false);
+            return;
+        }
+        if (typeof this._content !== "undefined") {
+            callback(this.content, this._contentEncoded);
+            return;
+        }
+        this._pendingContentCallbacks.push(callback);
+        if (this.finished)
+            this._innerRequestContent();
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isHttpFamily: function()
+    {
+        return !!this.url.match(/^https?:/i);
+    },
+
+    /**
+     * @return {string|undefined}
+     */
+    requestContentType: function()
+    {
+        return this.requestHeaderValue("Content-Type");
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isPingRequest: function()
+    {
+        return "text/ping" === this.requestContentType();
+    },
+
+    /**
+     * @return {boolean}
+     */
+    hasErrorStatusCode: function()
+    {
+        return this.statusCode >= 400;
+    },
+
+    /**
+     * @param {Element} image
+     */
+    populateImageSource: function(image)
+    {
+        function onResourceContent()
+        {
+            image.src = this._contentURL();
+        }
+
+        this.requestContent(onResourceContent.bind(this));
+    },
+
+    /**
+     * @return {string}
+     */
+    _contentURL: function()
+    {
+        const maxDataUrlSize = 1024 * 1024;
+        // If resource content is not available or won't fit a data URL, fall back to using original URL.
+        if (this._content == null || this._content.length > maxDataUrlSize)
+            return this.url;
+
+        return "data:" + this.mimeType + (this._contentEncoded ? ";base64," : ",") + this._content;
+    },
+
+    _innerRequestContent: function()
+    {
+        if (this._contentRequested)
+            return;
+        this._contentRequested = true;
+
+        /**
+         * @param {?Protocol.Error} error
+         * @param {string} content
+         * @param {boolean} contentEncoded
+         */
+        function onResourceContent(error, content, contentEncoded)
+        {
+            this._content = error ? null : content;
+            this._contentEncoded = contentEncoded;
+            var callbacks = this._pendingContentCallbacks.slice();
+            for (var i = 0; i < callbacks.length; ++i)
+                callbacks[i](this._content, this._contentEncoded);
+            this._pendingContentCallbacks.length = 0;
+            delete this._contentRequested;
+        }
+        NetworkAgent.getResponseBody(this._requestId, onResourceContent.bind(this));
+    },
+
+    /**
+     * @param {WebInspector.Resource} resource
+     */
+    setResource: function(resource)
+    {
+        this._resource = resource;
+    },
+
+    /**
+     * @return {WebInspector.Resource}
+     */
+    resource: function()
+    {
+        return this._resource;
+    }
+}
+
+WebInspector.NetworkRequest.prototype.__proto__ = WebInspector.Object.prototype;
index 97b9cd6..4b95b1c 100644 (file)
  * @extends {WebInspector.Object}
  * @param {string} id
  * @param {WebInspector.Script} script
+ * @param {WebInspector.Resource} resource
  * @param {WebInspector.NetworkRequest} request
  * @param {WebInspector.ScriptFormatter} formatter
  * @param {boolean} formatted
  */
-WebInspector.RawSourceCode = function(id, script, request, formatter, formatted)
+WebInspector.RawSourceCode = function(id, script, resource, request, formatter, formatted)
 {
     this.id = id;
     this.url = script.sourceURL;
@@ -48,14 +49,15 @@ WebInspector.RawSourceCode = function(id, script, request, formatter, formatted)
     this._scripts = [script];
     this._formatter = formatter;
     this._formatted = formatted;
-    this._request = request;
+    this._resource = resource;
+    this._pendingRequest = request;
 
-    this._useTemporaryContent = this._request && !this._request.finished;
     this._hasNewScripts = true;
-    if (!this._useTemporaryContent)
+
+    if (this._pendingRequest)
+        WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, this._resourceAdded, this);
+    else
         this._updateSourceMapping();
-    else if (this._request)
-        this._request.addEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._requestFinished.bind(this));
 }
 
 WebInspector.RawSourceCode.Events = {
@@ -117,9 +119,14 @@ WebInspector.RawSourceCode.prototype = {
         this._updateSourceMapping();
     },
 
-    _requestFinished: function()
+    _resourceAdded: function(event)
     {
-        this._useTemporaryContent = false;
+        var resource = /** @type {WebInspector.Resource} */ event.data;
+        if (resource.request !== this._pendingRequest)
+            return;
+
+        this._resource = resource;
+        delete this._pendingRequest;
         this._updateSourceMapping();
     },
 
@@ -128,7 +135,7 @@ WebInspector.RawSourceCode.prototype = {
      */
     forceUpdateSourceMapping: function(script)
     {
-        if (!this._useTemporaryContent || !this._hasNewScripts)
+        if (!this._pendingRequest || !this._hasNewScripts)
             return;
         this._hasNewScripts = false;
         this._updateSourceMapping();
@@ -161,8 +168,8 @@ WebInspector.RawSourceCode.prototype = {
 
     _createContentProvider: function()
     {
-        if (this._request && this._request.finished)
-            return new WebInspector.ResourceContentProvider(this._request.resource());
+        if (this._resource)
+            return new WebInspector.ResourceContentProvider(this._resource);
         if (this._scripts.length === 1 && !this._scripts[0].lineOffset && !this._scripts[0].columnOffset)
             return new WebInspector.ScriptContentProvider(this._scripts[0]);
         return new WebInspector.ConcatenatedScriptsContentProvider(this._scripts);
index 03f456e..3a148e4 100644 (file)
  *
  * @param {?WebInspector.NetworkRequest} request
  * @param {string} url
- * @param {NetworkAgent.FrameId} frameId
- * @param {NetworkAgent.LoaderId} loaderId
+ * @param {string} frameId
+ * @param {?NetworkAgent.LoaderId} loaderId
  */
 WebInspector.Resource = function(request, url, frameId, loaderId)
 {
-    if (request)
-        return request;
-
+    this._request = request;
+    if (this._request)
+        this._request.setResource(this);
     this.url = url;
     this.frameId = frameId;
     this.loaderId = loaderId;
-    this._startTime = -1;
-    this._endTime = -1;
     this._type = WebInspector.resourceTypes.Other;
-    this._pendingContentCallbacks = [];
     this.history = [];
-    /** @type {number} */
-    this.statusCode = 0;
-    this.statusText = "";
-    this.requestMethod = "";
-    this.requestTime = 0;
-    this.receiveHeadersEnd = 0;
+
+    this._content = undefined;
+    this._contentEncoded = undefined;
+    this._pendingContentCallbacks = [];
 }
 
 /**
@@ -62,7 +57,7 @@ WebInspector.Resource = function(request, url, frameId, loaderId)
  */
 WebInspector.Resource.displayName = function(url)
 {
-    return new WebInspector.Resource(null, url, "", "").displayName;
+    return new WebInspector.Resource(null, url, "", null).displayName;
 }
 
 WebInspector.Resource._domainModelBindings = [];
@@ -163,11 +158,11 @@ WebInspector.Resource.Events = {
 
 WebInspector.Resource.prototype = {
     /**
-     * @type {WebInspector.NetworkRequest}
+     * @type {?WebInspector.NetworkRequest}
      */
     get request()
     {
-        return /** @type {WebInspector.NetworkRequest} */ this;
+        return this._request;
     },
 
     /**
@@ -192,14 +187,11 @@ WebInspector.Resource.prototype = {
             return;
 
         this._url = x;
-        delete this._parsedQueryParameters;
 
         var parsedURL = x.asParsedURL();
         this.domain = parsedURL ? parsedURL.host : "";
         this.path = parsedURL ? parsedURL.path : "";
-        this.urlFragment = parsedURL ? parsedURL.fragment : "";
         this.lastPathComponent = parsedURL ? parsedURL.lastPathComponent : "";
-        this.lastPathComponentLowerCase = this.lastPathComponent.toLowerCase();
     },
 
     /**
@@ -257,231 +249,11 @@ WebInspector.Resource.prototype = {
     },
 
     /**
-     * @type {number}
-     */
-    get startTime()
-    {
-        return this._startTime || -1;
-    },
-
-    set startTime(x)
-    {
-        this._startTime = x;
-    },
-
-    /**
-     * @type {number}
-     */
-    get responseReceivedTime()
-    {
-        return this._responseReceivedTime || -1;
-    },
-
-    set responseReceivedTime(x)
-    {
-        this._responseReceivedTime = x;
-    },
-
-    /**
-     * @type {number}
-     */
-    get endTime()
-    {
-        return this._endTime || -1;
-    },
-
-    set endTime(x)
-    {
-        if (this.timing && this.timing.requestTime) {
-            // Check against accurate responseReceivedTime.
-            this._endTime = Math.max(x, this.responseReceivedTime);
-        } else {
-            // Prefer endTime since it might be from the network stack.
-            this._endTime = x;
-            if (this._responseReceivedTime > x)
-                this._responseReceivedTime = x;
-        }
-    },
-
-    /**
-     * @type {number}
-     */
-    get duration()
-    {
-        if (this._endTime === -1 || this._startTime === -1)
-            return -1;
-        return this._endTime - this._startTime;
-    },
-
-    /**
-     * @type {number}
-     */
-    get latency()
-    {
-        if (this._responseReceivedTime === -1 || this._startTime === -1)
-            return -1;
-        return this._responseReceivedTime - this._startTime;
-    },
-
-    /**
-     * @type {number}
-     */
-    get receiveDuration()
-    {
-        if (this._endTime === -1 || this._responseReceivedTime === -1)
-            return -1;
-        return this._endTime - this._responseReceivedTime;
-    },
-
-    /**
-     * @type {number}
-     */
-    get resourceSize()
-    {
-        return this._resourceSize || 0;
-    },
-
-    set resourceSize(x)
-    {
-        this._resourceSize = x;
-    },
-
-    /**
-     * @type {number}
-     */
-    get transferSize()
-    {
-        if (this.cached)
-            return 0;
-        if (this.statusCode === 304) // Not modified
-            return this.responseHeadersSize;
-        if (this._transferSize !== undefined)
-            return this._transferSize;
-        // If we did not receive actual transfer size from network
-        // stack, we prefer using Content-Length over resourceSize as
-        // resourceSize may differ from actual transfer size if platform's
-        // network stack performed decoding (e.g. gzip decompression).
-        // The Content-Length, though, is expected to come from raw
-        // response headers and will reflect actual transfer length.
-        // This won't work for chunked content encoding, so fall back to
-        // resourceSize when we don't have Content-Length. This still won't
-        // work for chunks with non-trivial encodings. We need a way to
-        // get actual transfer size from the network stack.
-        var bodySize = Number(this.responseHeaders["Content-Length"] || this.resourceSize);
-        return this.responseHeadersSize + bodySize;
-    },
-
-    /**
-     * @param {number} x
-     */
-    increaseTransferSize: function(x)
-    {
-        this._transferSize = (this._transferSize || 0) + x;
-    },
-
-    /**
-     * @type {boolean}
-     */
-    get finished()
-    {
-        return this._finished;
-    },
-
-    set finished(x)
-    {
-        if (this._finished === x)
-            return;
-
-        this._finished = x;
-
-        if (x) {
-            this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.FinishedLoading);
-            if (this._pendingContentCallbacks.length)
-                this._innerRequestContent();
-        }
-    },
-
-    /**
-     * @type {boolean}
-     */
-    get failed()
-    {
-        return this._failed;
-    },
-
-    set failed(x)
-    {
-        this._failed = x;
-    },
-
-    /**
-     * @type {boolean}
-     */
-    get canceled()
-    {
-        return this._canceled;
-    },
-
-    set canceled(x)
-    {
-        this._canceled = x;
-    },
-
-    /**
-     * @type {boolean}
-     */
-    get cached()
-    {
-        return this._cached;
-    },
-
-    set cached(x)
-    {
-        this._cached = x;
-        if (x)
-            delete this._timing;
-    },
-
-    /**
-     * @type {NetworkAgent.ResourceTiming|undefined}
-     */
-    get timing()
-    {
-        return this._timing;
-    },
-
-    set timing(x)
-    {
-        if (x && !this._cached) {
-            // Take startTime and responseReceivedTime from timing data for better accuracy.
-            // Timing's requestTime is a baseline in seconds, rest of the numbers there are ticks in millis.
-            this._startTime = x.requestTime;
-            this._responseReceivedTime = x.requestTime + x.receiveHeadersEnd / 1000.0;
-
-            this._timing = x;
-            this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.TimingChanged);
-        }
-    },
-
-    /**
-     * @type {string}
-     */
-    get mimeType()
-    {
-        return this._mimeType;
-    },
-
-    set mimeType(x)
-    {
-        this._mimeType = x;
-    },
-
-    /**
      * @type {WebInspector.ResourceType}
      */
     get type()
     {
-        return this._type;
+        return this._request ? this._request.type : this._type;
     },
 
     set type(x)
@@ -490,277 +262,16 @@ WebInspector.Resource.prototype = {
     },
 
     /**
-     * @type {WebInspector.Resource|undefined}
-     */
-    get redirectSource()
-    {
-        if (this.redirects && this.redirects.length > 0)
-            return this.redirects[this.redirects.length - 1];
-        return this._redirectSource;
-    },
-
-    set redirectSource(x)
-    {
-        this._redirectSource = x;
-    },
-
-    /**
-     * @type {Object}
-     */
-    get requestHeaders()
-    {
-        return this._requestHeaders || {};
-    },
-
-    set requestHeaders(x)
-    {
-        this._requestHeaders = x;
-        delete this._sortedRequestHeaders;
-        delete this._requestCookies;
-
-        this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged);
-    },
-
-    /**
      * @type {string}
      */
-    get requestHeadersText()
-    {
-        if (this._requestHeadersText === undefined) {
-            this._requestHeadersText = this.requestMethod + " " + this.url + " HTTP/1.1\r\n";
-            for (var key in this.requestHeaders)
-                this._requestHeadersText += key + ": " + this.requestHeaders[key] + "\r\n";
-        }
-        return this._requestHeadersText;
-    },
-
-    set requestHeadersText(x)
-    {
-        this._requestHeadersText = x;
-
-        this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged);
-    },
-
-    /**
-     * @type {number}
-     */
-    get requestHeadersSize()
-    {
-        return this.requestHeadersText.length;
-    },
-
-    /**
-     * @type {Array.<Object>}
-     */
-    get sortedRequestHeaders()
-    {
-        if (this._sortedRequestHeaders !== undefined)
-            return this._sortedRequestHeaders;
-
-        this._sortedRequestHeaders = [];
-        for (var key in this.requestHeaders)
-            this._sortedRequestHeaders.push({header: key, value: this.requestHeaders[key]});
-        this._sortedRequestHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) });
-
-        return this._sortedRequestHeaders;
-    },
-
-    /**
-     * @param {string} headerName
-     * @return {string|undefined}
-     */
-    requestHeaderValue: function(headerName)
-    {
-        return this._headerValue(this.requestHeaders, headerName);
-    },
-
-    /**
-     * @type {Array.<WebInspector.Cookie>}
-     */
-    get requestCookies()
-    {
-        if (!this._requestCookies)
-            this._requestCookies = WebInspector.CookieParser.parseCookie(this.requestHeaderValue("Cookie"));
-        return this._requestCookies;
-    },
-
-    /**
-     * @type {string|undefined}
-     */
-    get requestFormData()
-    {
-        return this._requestFormData;
-    },
-
-    set requestFormData(x)
-    {
-        this._requestFormData = x;
-        delete this._parsedFormParameters;
-    },
-
-    /**
-     * @type {string|undefined}
-     */
-    get requestHttpVersion()
-    {
-        var firstLine = this.requestHeadersText.split(/\r\n/)[0];
-        var match = firstLine.match(/(HTTP\/\d+\.\d+)$/);
-        return match ? match[1] : undefined;
-    },
-
-    /**
-     * @type {Object}
-     */
-    get responseHeaders()
-    {
-        return this._responseHeaders || {};
-    },
-
-    set responseHeaders(x)
-    {
-        this._responseHeaders = x;
-        delete this._sortedResponseHeaders;
-        delete this._responseCookies;
-
-        this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged);
-    },
-
-    /**
-     * @type {string}
-     */
-    get responseHeadersText()
-    {
-        if (this._responseHeadersText === undefined) {
-            this._responseHeadersText = "HTTP/1.1 " + this.statusCode + " " + this.statusText + "\r\n";
-            for (var key in this.responseHeaders)
-                this._responseHeadersText += key + ": " + this.responseHeaders[key] + "\r\n";
-        }
-        return this._responseHeadersText;
-    },
-
-    set responseHeadersText(x)
-    {
-        this._responseHeadersText = x;
-
-        this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged);
-    },
-
-    /**
-     * @type {number}
-     */
-    get responseHeadersSize()
-    {
-        return this.responseHeadersText.length;
-    },
-
-    /**
-     * @type {Array.<Object>}
-     */
-    get sortedResponseHeaders()
-    {
-        if (this._sortedResponseHeaders !== undefined)
-            return this._sortedResponseHeaders;
-
-        this._sortedResponseHeaders = [];
-        for (var key in this.responseHeaders)
-            this._sortedResponseHeaders.push({header: key, value: this.responseHeaders[key]});
-        this._sortedResponseHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) });
-
-        return this._sortedResponseHeaders;
-    },
-
-    /**
-     * @param {string} headerName
-     * @return {string|undefined}
-     */
-    responseHeaderValue: function(headerName)
-    {
-        return this._headerValue(this.responseHeaders, headerName);
-    },
-
-    /**
-     * @type {Array.<WebInspector.Cookie>}
-     */
-    get responseCookies()
-    {
-        if (!this._responseCookies)
-            this._responseCookies = WebInspector.CookieParser.parseSetCookie(this.responseHeaderValue("Set-Cookie"));
-        return this._responseCookies;
-    },
-
-    /**
-     * @type {?Array.<Object>}
-     */
-    get queryParameters()
-    {
-        if (this._parsedQueryParameters)
-            return this._parsedQueryParameters;
-        var queryString = this.url.split("?", 2)[1];
-        if (!queryString)
-            return null;
-        queryString = queryString.split("#", 2)[0];
-        this._parsedQueryParameters = this._parseParameters(queryString);
-        return this._parsedQueryParameters;
-    },
-
-    /**
-     * @type {?Array.<Object>}
-     */
-    get formParameters()
-    {
-        if (this._parsedFormParameters)
-            return this._parsedFormParameters;
-        if (!this.requestFormData)
-            return null;
-        var requestContentType = this.requestContentType();
-        if (!requestContentType || !requestContentType.match(/^application\/x-www-form-urlencoded\s*(;.*)?$/i))
-            return null;
-        this._parsedFormParameters = this._parseParameters(this.requestFormData);
-        return this._parsedFormParameters;
-    },
-
-    /**
-     * @type {string|undefined}
-     */
-    get responseHttpVersion()
-    {
-        var match = this.responseHeadersText.match(/^(HTTP\/\d+\.\d+)/);
-        return match ? match[1] : undefined;
-    },
-
-    /**
-     * @param {string} queryString
-     * @return {Array.<Object>}
-     */
-    _parseParameters: function(queryString)
+    get mimeType()
     {
-        function parseNameValue(pair)
-        {
-            var parameter = {};
-            var splitPair = pair.split("=", 2);
-
-            parameter.name = splitPair[0];
-            if (splitPair.length === 1)
-                parameter.value = "";
-            else
-                parameter.value = splitPair[1];
-            return parameter;
-        }
-        return queryString.split("&").map(parseNameValue);
+        return this._request ? this._request.mimeType : this._mimeType;
     },
 
-    /**
-     * @param {Object} headers
-     * @param {string} headerName
-     * @return {string|undefined}
-     */
-    _headerValue: function(headers, headerName)
+    set mimeType(x)
     {
-        headerName = headerName.toLowerCase();
-        for (var header in headers) {
-            if (header.toLowerCase() === headerName)
-                return headers[header];
-        }
+        this._mimeType = x;
     },
 
     /**
@@ -824,7 +335,9 @@ WebInspector.Resource.prototype = {
      */
     get content()
     {
-        return this._content;
+        if (typeof this._content !== "undefined")
+            return this._content;
+        return this._request ? this._request.content : this._content;
     },
 
     /**
@@ -832,7 +345,9 @@ WebInspector.Resource.prototype = {
      */
     get contentEncoded()
     {
-        return this._contentEncoded;
+        if (typeof this._contentEncoded !== "undefined")
+            return this._contentEncoded;
+        return this._request ? this._request.contentEncoded : this._contentEncoded;
     },
 
     /**
@@ -899,20 +414,18 @@ WebInspector.Resource.prototype = {
      */
     requestContent: function(callback)
     {
-        // We do not support content retrieval for WebSockets at the moment.
-        // Since WebSockets are potentially long-living, fail requests immediately
-        // to prevent caller blocking until resource is marked as finished.
-        if (this.type === WebInspector.resourceTypes.WebSocket) {
-            callback(null, false);
+        if (this._request) {
+            this._request.requestContent(callback);
             return;
         }
+
         if (typeof this._content !== "undefined") {
-            callback(this.content, this._contentEncoded);
+            callback(this._content, !!this._contentEncoded);
             return;
         }
+
         this._pendingContentCallbacks.push(callback);
-        if (this.finished)
-            this._innerRequestContent();
+        this._innerRequestContent();
     },
 
     /**
@@ -952,38 +465,6 @@ WebInspector.Resource.prototype = {
     },
 
     /**
-     * @return {boolean}
-     */
-    isHttpFamily: function()
-    {
-        return !!this.url.match(/^https?:/i);
-    },
-
-    /**
-     * @return {string|undefined}
-     */
-    requestContentType: function()
-    {
-        return this.requestHeaderValue("Content-Type");
-    },
-
-    /**
-     * @return {boolean}
-     */
-    isPingRequest: function()
-    {
-        return "text/ping" === this.requestContentType();
-    },
-
-    /**
-     * @return {boolean}
-     */
-    hasErrorStatusCode: function()
-    {
-        return this.statusCode >= 400;
-    },
-
-    /**
      * @return {string}
      */
     _contentURL: function()
@@ -1002,18 +483,23 @@ WebInspector.Resource.prototype = {
             return;
         this._contentRequested = true;
 
-        function onResourceContent(data, contentEncoded)
+        /**
+         * @param {?Protocol.Error} error
+         * @param {string} content
+         * @param {boolean} contentEncoded
+         */
+        function callback(error, content, contentEncoded)
         {
+            this._content = error ? null : content;
             this._contentEncoded = contentEncoded;
-            this._content = data;
-            this._originalContent = data;
+            this._originalContent = content;
             var callbacks = this._pendingContentCallbacks.slice();
             for (var i = 0; i < callbacks.length; ++i)
                 callbacks[i](this._content, this._contentEncoded);
             this._pendingContentCallbacks.length = 0;
             delete this._contentRequested;
         }
-        WebInspector.networkManager.requestContent(this, onResourceContent.bind(this));
+        PageAgent.getResourceContent(this.frameId, this.url, callback.bind(this));
     }
 }
 
@@ -1022,7 +508,7 @@ WebInspector.Resource.prototype.__proto__ = WebInspector.Object.prototype;
 /**
  * @constructor
  * @param {WebInspector.Resource} resource
- * @param {string} content
+ * @param {string|undefined} content
  * @param {number} timestamp
  */
 WebInspector.ResourceRevision = function(resource, content, timestamp)
@@ -1067,7 +553,7 @@ WebInspector.ResourceRevision.prototype = {
     },
 
     /**
-     * @param {function(string)} callback
+     * @param {function(?string)} callback
      */
     requestContent: function(callback)
     {
@@ -1083,13 +569,22 @@ WebInspector.ResourceRevision.prototype = {
             return;
         }
 
-        // If unsuccessful, request the content.
-        function mycallback(content)
+        /**
+         * @param {?Protocol.Error} error
+         * @param {string} content
+         * @param {boolean} contentEncoded
+         */
+        function callbackWrapper(error, content, contentEncoded)
         {
-            this._content = content;
-            callback(content);
+            callback(error ? null : content);
         }
-        WebInspector.networkManager.requestContent(this._resource, mycallback.bind(this));
+
+        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=61363 We should separate NetworkResource (NetworkPanel resource)
+        // from ResourceRevision (ResourcesPanel/ScriptsPanel resource) and request content accordingly.
+        if (this._resource.request)
+            NetworkAgent.getResponseBody(this._resource.request.requestId, callbackWrapper);
+        else
+            PageAgent.getResourceContent(this._resource.frameId, this._resource.url, callbackWrapper);
     }
 }
 
index c567212..ffd6401 100644 (file)
@@ -85,15 +85,22 @@ WebInspector.ResourceScriptMapping.prototype = {
      */
     addScript: function(script)
     {
+        var resource = null;
         var request = null;
         var isInlineScript = false;
         if (script.isInlineScript()) {
-            request = WebInspector.networkManager.inflightRequestForURL(script.sourceURL);
-            if (!request) {
-                var resource = WebInspector.resourceForURL(script.sourceURL);
-                request = resource ? resource.request : null;
+            // First lookup the resource that has already been loaded. We are only interested in Document resources.
+            resource = WebInspector.resourceForURL(script.sourceURL);
+            if (resource && resource.type !== WebInspector.resourceTypes.Document)
+                resource = null;
+            if (!resource) {
+                // When there is no resource, lookup in-flight requests of type Document.
+                request = WebInspector.networkManager.inflightRequestForURL(script.sourceURL);
+                if (request && request.type !== WebInspector.resourceTypes.Document)
+                    request = null;
             }
-            if (request && request.type === WebInspector.resourceTypes.Document) {
+            // If either of these exists, we bind script to the resource.
+            if (request || resource) {
                 isInlineScript = true;
                 var rawSourceCode = this._rawSourceCodeForDocumentURL[script.sourceURL];
                 if (rawSourceCode) {
@@ -104,7 +111,7 @@ WebInspector.ResourceScriptMapping.prototype = {
             }
         }
 
-        var rawSourceCode = new WebInspector.RawSourceCode(script.scriptId, script, request, this._formatter, this._formatSource);
+        var rawSourceCode = new WebInspector.RawSourceCode(script.scriptId, script, resource, request, this._formatter, this._formatSource);
         this._rawSourceCodes.push(rawSourceCode);
         this._bindScriptToRawSourceCode(script, rawSourceCode);