1/*
2 * Copyright (C) 2011 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#include "config.h"
32#include "InspectorResourceAgent.h"
33
34#if ENABLE(INSPECTOR)
35
36#include "CachedRawResource.h"
37#include "CachedResource.h"
38#include "CachedResourceLoader.h"
39#include "Document.h"
40#include "DocumentLoader.h"
41#include "DocumentThreadableLoader.h"
42#include "ExceptionCodePlaceholder.h"
43#include "Frame.h"
44#include "FrameLoader.h"
45#include "HTTPHeaderMap.h"
46#include "HTTPHeaderNames.h"
47#include "IconController.h"
48#include "InspectorClient.h"
49#include "InspectorPageAgent.h"
50#include "InspectorWebFrontendDispatchers.h"
51#include "InstrumentingAgents.h"
52#include "JSMainThreadExecState.h"
53#include "MemoryCache.h"
54#include "NetworkResourcesData.h"
55#include "Page.h"
56#include "ProgressTracker.h"
57#include "ResourceBuffer.h"
58#include "ResourceError.h"
59#include "ResourceLoader.h"
60#include "ResourceRequest.h"
61#include "ResourceResponse.h"
62#include "ScriptableDocumentParser.h"
63#include "SubresourceLoader.h"
64#include "ThreadableLoaderClient.h"
65#include "URL.h"
66#include "WebSocketFrame.h"
67#include "XMLHttpRequest.h"
68#include <inspector/IdentifiersFactory.h>
69#include <inspector/InspectorValues.h>
70#include <inspector/ScriptCallStack.h>
71#include <inspector/ScriptCallStackFactory.h>
72#include <wtf/CurrentTime.h>
73#include <wtf/RefPtr.h>
74#include <wtf/text/StringBuilder.h>
75
76using namespace Inspector;
77
78typedef Inspector::InspectorNetworkBackendDispatcherHandler::LoadResourceCallback LoadResourceCallback;
79
80namespace WebCore {
81
82namespace {
83
84class InspectorThreadableLoaderClient final : public ThreadableLoaderClient {
85    WTF_MAKE_NONCOPYABLE(InspectorThreadableLoaderClient);
86public:
87    InspectorThreadableLoaderClient(PassRefPtr<LoadResourceCallback> callback)
88        : m_callback(callback) { }
89
90    virtual ~InspectorThreadableLoaderClient() { }
91
92    virtual void didReceiveResponse(unsigned long, const ResourceResponse& response) override
93    {
94        m_mimeType = response.mimeType();
95        m_statusCode = response.httpStatusCode();
96
97        // FIXME: This assumes text only responses. We should support non-text responses as well.
98        TextEncoding textEncoding(response.textEncodingName());
99        bool useDetector = false;
100        if (!textEncoding.isValid()) {
101            textEncoding = UTF8Encoding();
102            useDetector = true;
103        }
104
105        m_decoder = TextResourceDecoder::create(ASCIILiteral("text/plain"), textEncoding, useDetector);
106    }
107
108    virtual void didReceiveData(const char* data, int dataLength) override
109    {
110        if (!dataLength)
111            return;
112
113        if (dataLength == -1)
114            dataLength = strlen(data);
115
116        m_responseText.append(m_decoder->decode(data, dataLength));
117    }
118
119    virtual void didFinishLoading(unsigned long, double) override
120    {
121        if (m_decoder)
122            m_responseText.append(m_decoder->flush());
123
124        m_callback->sendSuccess(m_responseText.toString(), m_mimeType, m_statusCode);
125        dispose();
126    }
127
128    virtual void didFail(const ResourceError&) override
129    {
130        m_callback->sendFailure(ASCIILiteral("Loading resource for inspector failed"));
131        dispose();
132    }
133
134    virtual void didFailRedirectCheck() override
135    {
136        m_callback->sendFailure(ASCIILiteral("Loading resource for inspector failed redirect check"));
137        dispose();
138    }
139
140    void didFailLoaderCreation()
141    {
142        m_callback->sendFailure(ASCIILiteral("Could not create a loader"));
143        dispose();
144    }
145
146    void setLoader(PassRefPtr<ThreadableLoader> loader)
147    {
148        m_loader = loader;
149    }
150
151private:
152    void dispose()
153    {
154        m_loader = nullptr;
155        delete this;
156    }
157
158    RefPtr<LoadResourceCallback> m_callback;
159    RefPtr<ThreadableLoader> m_loader;
160    RefPtr<TextResourceDecoder> m_decoder;
161    String m_mimeType;
162    StringBuilder m_responseText;
163    int m_statusCode;
164};
165
166} // namespace
167
168InspectorResourceAgent::InspectorResourceAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorClient* client)
169    : InspectorAgentBase(ASCIILiteral("Network"), instrumentingAgents)
170    , m_pageAgent(pageAgent)
171    , m_client(client)
172    , m_resourcesData(std::make_unique<NetworkResourcesData>())
173    , m_enabled(false)
174    , m_cacheDisabled(false)
175    , m_loadingXHRSynchronously(false)
176    , m_isRecalculatingStyle(false)
177{
178}
179
180void InspectorResourceAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
181{
182    m_frontendDispatcher = std::make_unique<InspectorNetworkFrontendDispatcher>(frontendChannel);
183    m_backendDispatcher = InspectorNetworkBackendDispatcher::create(backendDispatcher, this);
184}
185
186void InspectorResourceAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
187{
188    m_frontendDispatcher = nullptr;
189    m_backendDispatcher.clear();
190
191    ErrorString error;
192    disable(&error);
193}
194
195static PassRefPtr<InspectorObject> buildObjectForHeaders(const HTTPHeaderMap& headers)
196{
197    RefPtr<InspectorObject> headersObject = InspectorObject::create();
198
199    for (const auto& header : headers)
200        headersObject->setString(header.key, header.value);
201    return headersObject;
202}
203
204static PassRefPtr<Inspector::TypeBuilder::Network::ResourceTiming> buildObjectForTiming(const ResourceLoadTiming& timing, DocumentLoader* loader)
205{
206    return Inspector::TypeBuilder::Network::ResourceTiming::create()
207        .setNavigationStart(loader->timing()->navigationStart())
208        .setDomainLookupStart(timing.domainLookupStart)
209        .setDomainLookupEnd(timing.domainLookupEnd)
210        .setConnectStart(timing.connectStart)
211        .setConnectEnd(timing.connectEnd)
212        .setSecureConnectionStart(timing.secureConnectionStart)
213        .setRequestStart(timing.requestStart)
214        .setResponseStart(timing.responseStart)
215        .release();
216}
217
218static PassRefPtr<Inspector::TypeBuilder::Network::Request> buildObjectForResourceRequest(const ResourceRequest& request)
219{
220    RefPtr<Inspector::TypeBuilder::Network::Request> requestObject = Inspector::TypeBuilder::Network::Request::create()
221        .setUrl(request.url().string())
222        .setMethod(request.httpMethod())
223        .setHeaders(buildObjectForHeaders(request.httpHeaderFields()));
224    if (request.httpBody() && !request.httpBody()->isEmpty())
225        requestObject->setPostData(request.httpBody()->flattenToString());
226    return requestObject;
227}
228
229static PassRefPtr<Inspector::TypeBuilder::Network::Response> buildObjectForResourceResponse(const ResourceResponse& response, DocumentLoader* loader)
230{
231    if (response.isNull())
232        return nullptr;
233
234    double status = response.httpStatusCode();
235    RefPtr<InspectorObject> headers = buildObjectForHeaders(response.httpHeaderFields());
236
237    RefPtr<Inspector::TypeBuilder::Network::Response> responseObject = Inspector::TypeBuilder::Network::Response::create()
238        .setUrl(response.url().string())
239        .setStatus(status)
240        .setStatusText(response.httpStatusText())
241        .setHeaders(headers)
242        .setMimeType(response.mimeType())
243        .setConnectionReused(response.connectionReused())
244        .setConnectionId(response.connectionID());
245
246    responseObject->setFromDiskCache(response.wasCached());
247    responseObject->setTiming(buildObjectForTiming(response.resourceLoadTiming(), loader));
248
249    return responseObject;
250}
251
252static PassRefPtr<Inspector::TypeBuilder::Network::CachedResource> buildObjectForCachedResource(CachedResource* cachedResource, DocumentLoader* loader)
253{
254    RefPtr<Inspector::TypeBuilder::Network::CachedResource> resourceObject = Inspector::TypeBuilder::Network::CachedResource::create()
255        .setUrl(cachedResource->url())
256        .setType(InspectorPageAgent::cachedResourceTypeJson(*cachedResource))
257        .setBodySize(cachedResource->encodedSize());
258
259    RefPtr<Inspector::TypeBuilder::Network::Response> resourceResponse = buildObjectForResourceResponse(cachedResource->response(), loader);
260    if (resourceResponse)
261        resourceObject->setResponse(resourceResponse);
262
263    String sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(cachedResource);
264    if (!sourceMappingURL.isEmpty())
265        resourceObject->setSourceMapURL(sourceMappingURL);
266
267    return resourceObject;
268}
269
270InspectorResourceAgent::~InspectorResourceAgent()
271{
272    if (m_enabled) {
273        ErrorString error;
274        disable(&error);
275    }
276    ASSERT(!m_instrumentingAgents->inspectorResourceAgent());
277}
278
279void InspectorResourceAgent::willSendRequest(unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse)
280{
281    if (request.hiddenFromInspector()) {
282        m_hiddenRequestIdentifiers.add(identifier);
283        return;
284    }
285
286    String requestId = IdentifiersFactory::requestId(identifier);
287    m_resourcesData->resourceCreated(requestId, m_pageAgent->loaderId(loader));
288
289    CachedResource* cachedResource = loader ? InspectorPageAgent::cachedResource(loader->frame(), request.url()) : nullptr;
290    InspectorPageAgent::ResourceType type = cachedResource ? InspectorPageAgent::cachedResourceType(*cachedResource) : m_resourcesData->resourceType(requestId);
291    if (type == InspectorPageAgent::OtherResource) {
292        if (m_loadingXHRSynchronously)
293            type = InspectorPageAgent::XHRResource;
294        else if (equalIgnoringFragmentIdentifier(request.url(), loader->frameLoader()->icon().url()))
295            type = InspectorPageAgent::ImageResource;
296        else if (equalIgnoringFragmentIdentifier(request.url(), loader->url()) && !loader->isCommitted())
297            type = InspectorPageAgent::DocumentResource;
298    }
299
300    m_resourcesData->setResourceType(requestId, type);
301
302    if (m_extraRequestHeaders) {
303        InspectorObject::const_iterator end = m_extraRequestHeaders->end();
304        for (InspectorObject::const_iterator it = m_extraRequestHeaders->begin(); it != end; ++it) {
305            String value;
306            if (it->value->asString(&value))
307                request.setHTTPHeaderField(it->key, value);
308        }
309    }
310
311    request.setReportLoadTiming(true);
312    request.setReportRawHeaders(true);
313
314    if (m_cacheDisabled) {
315        request.setHTTPHeaderField(HTTPHeaderName::Pragma, "no-cache");
316        request.setCachePolicy(ReloadIgnoringCacheData);
317        request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache");
318    }
319
320    Inspector::TypeBuilder::Page::ResourceType::Enum resourceType = InspectorPageAgent::resourceTypeJson(type);
321
322    RefPtr<Inspector::TypeBuilder::Network::Initiator> initiatorObject = buildInitiatorObject(loader->frame() ? loader->frame()->document() : nullptr);
323    m_frontendDispatcher->requestWillBeSent(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), loader->url().string(), buildObjectForResourceRequest(request), currentTime(), initiatorObject, buildObjectForResourceResponse(redirectResponse, loader), type != InspectorPageAgent::OtherResource ? &resourceType : nullptr);
324}
325
326void InspectorResourceAgent::markResourceAsCached(unsigned long identifier)
327{
328    if (m_hiddenRequestIdentifiers.contains(identifier))
329        return;
330
331    m_frontendDispatcher->requestServedFromCache(IdentifiersFactory::requestId(identifier));
332}
333
334void InspectorResourceAgent::didReceiveResponse(unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
335{
336    if (m_hiddenRequestIdentifiers.contains(identifier))
337        return;
338
339    String requestId = IdentifiersFactory::requestId(identifier);
340    RefPtr<Inspector::TypeBuilder::Network::Response> resourceResponse = buildObjectForResourceResponse(response, loader);
341
342    bool isNotModified = response.httpStatusCode() == 304;
343
344    CachedResource* cachedResource = nullptr;
345    if (resourceLoader && resourceLoader->isSubresourceLoader() && !isNotModified)
346        cachedResource = static_cast<SubresourceLoader*>(resourceLoader)->cachedResource();
347    if (!cachedResource)
348        cachedResource = InspectorPageAgent::cachedResource(loader->frame(), response.url());
349
350    if (cachedResource) {
351        // Use mime type from cached resource in case the one in response is empty.
352        if (resourceResponse && response.mimeType().isEmpty())
353            resourceResponse->setString(Inspector::TypeBuilder::Network::Response::MimeType, cachedResource->response().mimeType());
354        m_resourcesData->addCachedResource(requestId, cachedResource);
355    }
356
357    InspectorPageAgent::ResourceType type = m_resourcesData->resourceType(requestId);
358    InspectorPageAgent::ResourceType newType = cachedResource ? InspectorPageAgent::cachedResourceType(*cachedResource) : type;
359
360    // FIXME: XHRResource is returned for CachedResource::RawResource, it should be OtherResource unless it truly is an XHR.
361    // RawResource is used for loading worker scripts, and those should stay as ScriptResource and not change to XHRResource.
362    if (type != newType && newType != InspectorPageAgent::XHRResource && newType != InspectorPageAgent::OtherResource)
363        type = newType;
364
365    m_resourcesData->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), response);
366    m_resourcesData->setResourceType(requestId, type);
367
368    m_frontendDispatcher->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), currentTime(), InspectorPageAgent::resourceTypeJson(type), resourceResponse);
369
370    // If we revalidated the resource and got Not modified, send content length following didReceiveResponse
371    // as there will be no calls to didReceiveData from the network stack.
372    if (isNotModified && cachedResource && cachedResource->encodedSize())
373        didReceiveData(identifier, nullptr, cachedResource->encodedSize(), 0);
374}
375
376static bool isErrorStatusCode(int statusCode)
377{
378    return statusCode >= 400;
379}
380
381void InspectorResourceAgent::didReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
382{
383    if (m_hiddenRequestIdentifiers.contains(identifier))
384        return;
385
386    String requestId = IdentifiersFactory::requestId(identifier);
387
388    if (data) {
389        NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
390        if (resourceData && !m_loadingXHRSynchronously && (!resourceData->cachedResource() || resourceData->cachedResource()->dataBufferingPolicy() == DoNotBufferData || isErrorStatusCode(resourceData->httpStatusCode())))
391            m_resourcesData->maybeAddResourceData(requestId, data, dataLength);
392    }
393
394    m_frontendDispatcher->dataReceived(requestId, currentTime(), dataLength, encodedDataLength);
395}
396
397void InspectorResourceAgent::didFinishLoading(unsigned long identifier, DocumentLoader* loader, double finishTime)
398{
399    if (m_hiddenRequestIdentifiers.remove(identifier))
400        return;
401
402    String requestId = IdentifiersFactory::requestId(identifier);
403    if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource) {
404        RefPtr<ResourceBuffer> buffer = loader->frameLoader()->documentLoader()->mainResourceData();
405        m_resourcesData->addResourceSharedBuffer(requestId, buffer ? buffer->sharedBuffer() : nullptr, loader->frame()->document()->inputEncoding());
406    }
407
408    m_resourcesData->maybeDecodeDataToContent(requestId);
409
410    // FIXME: The finishTime that is passed in is from the NetworkProcess and is more accurate.
411    // However, all other times passed to the Inspector are generated from the web process. Mixing
412    // times from different processes can cause the finish time to be earlier than the response
413    // received time due to inter-process communication lag.
414    finishTime = currentTime();
415
416    String sourceMappingURL;
417    NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
418    if (resourceData && resourceData->cachedResource())
419        sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(resourceData->cachedResource());
420
421    m_frontendDispatcher->loadingFinished(requestId, finishTime, !sourceMappingURL.isEmpty() ? &sourceMappingURL : nullptr);
422}
423
424void InspectorResourceAgent::didFailLoading(unsigned long identifier, DocumentLoader* loader, const ResourceError& error)
425{
426    if (m_hiddenRequestIdentifiers.remove(identifier))
427        return;
428
429    String requestId = IdentifiersFactory::requestId(identifier);
430
431    if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource) {
432        Frame* frame = loader ? loader->frame() : nullptr;
433        if (frame && frame->loader().documentLoader() && frame->document()) {
434            RefPtr<ResourceBuffer> buffer = frame->loader().documentLoader()->mainResourceData();
435            m_resourcesData->addResourceSharedBuffer(requestId, buffer ? buffer->sharedBuffer() : nullptr, frame->document()->inputEncoding());
436        }
437    }
438
439    bool canceled = error.isCancellation();
440    m_frontendDispatcher->loadingFailed(requestId, currentTime(), error.localizedDescription(), canceled ? &canceled : nullptr);
441}
442
443void InspectorResourceAgent::didLoadResourceFromMemoryCache(DocumentLoader* loader, CachedResource* resource)
444{
445    String loaderId = m_pageAgent->loaderId(loader);
446    String frameId = m_pageAgent->frameId(loader->frame());
447    unsigned long identifier = loader->frame()->page()->progress().createUniqueIdentifier();
448    String requestId = IdentifiersFactory::requestId(identifier);
449    m_resourcesData->resourceCreated(requestId, loaderId);
450    m_resourcesData->addCachedResource(requestId, resource);
451    if (resource->type() == CachedResource::RawResource) {
452        CachedRawResource* rawResource = toCachedRawResource(resource);
453        String rawRequestId = IdentifiersFactory::requestId(rawResource->identifier());
454        m_resourcesData->reuseXHRReplayData(requestId, rawRequestId);
455    }
456
457    RefPtr<Inspector::TypeBuilder::Network::Initiator> initiatorObject = buildInitiatorObject(loader->frame() ? loader->frame()->document() : nullptr);
458
459    m_frontendDispatcher->requestServedFromMemoryCache(requestId, frameId, loaderId, loader->url().string(), currentTime(), initiatorObject, buildObjectForCachedResource(resource, loader));
460}
461
462void InspectorResourceAgent::setInitialScriptContent(unsigned long identifier, const String& sourceString)
463{
464    m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
465}
466
467void InspectorResourceAgent::didReceiveScriptResponse(unsigned long identifier)
468{
469    m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::ScriptResource);
470}
471
472void InspectorResourceAgent::documentThreadableLoaderStartedLoadingForClient(unsigned long identifier, ThreadableLoaderClient* client)
473{
474    if (!client)
475        return;
476
477    PendingXHRReplayDataMap::iterator it = m_pendingXHRReplayData.find(client);
478    if (it == m_pendingXHRReplayData.end())
479        return;
480
481    XHRReplayData* xhrReplayData = it->value.get();
482    String requestId = IdentifiersFactory::requestId(identifier);
483    m_resourcesData->setXHRReplayData(requestId, xhrReplayData);
484}
485
486void InspectorResourceAgent::willLoadXHR(ThreadableLoaderClient* client, const String& method, const URL& url, bool async, PassRefPtr<FormData> formData, const HTTPHeaderMap& headers, bool includeCredentials)
487{
488    RefPtr<XHRReplayData> xhrReplayData = XHRReplayData::create(method, url, async, formData, headers, includeCredentials);
489
490    m_pendingXHRReplayData.set(client, WTF::move(xhrReplayData));
491}
492
493void InspectorResourceAgent::didFailXHRLoading(ThreadableLoaderClient* client)
494{
495    m_pendingXHRReplayData.remove(client);
496}
497
498void InspectorResourceAgent::didFinishXHRLoading(ThreadableLoaderClient* client, unsigned long identifier, const String& sourceString)
499{
500    // For Asynchronous XHRs, the inspector can grab the data directly off of the CachedResource. For sync XHRs, we need to
501    // provide the data here, since no CachedResource was involved.
502    if (m_loadingXHRSynchronously)
503        m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
504    m_pendingXHRReplayData.remove(client);
505}
506
507void InspectorResourceAgent::didReceiveXHRResponse(unsigned long identifier)
508{
509    m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::XHRResource);
510}
511
512void InspectorResourceAgent::willLoadXHRSynchronously()
513{
514    m_loadingXHRSynchronously = true;
515}
516
517void InspectorResourceAgent::didLoadXHRSynchronously()
518{
519    m_loadingXHRSynchronously = false;
520}
521
522void InspectorResourceAgent::willDestroyCachedResource(CachedResource* cachedResource)
523{
524    Vector<String> requestIds = m_resourcesData->removeCachedResource(cachedResource);
525    if (!requestIds.size())
526        return;
527
528    String content;
529    bool base64Encoded;
530    if (!InspectorPageAgent::cachedResourceContent(cachedResource, &content, &base64Encoded))
531        return;
532    Vector<String>::iterator end = requestIds.end();
533    for (Vector<String>::iterator it = requestIds.begin(); it != end; ++it)
534        m_resourcesData->setResourceContent(*it, content, base64Encoded);
535}
536
537void InspectorResourceAgent::willRecalculateStyle()
538{
539    m_isRecalculatingStyle = true;
540}
541
542void InspectorResourceAgent::didRecalculateStyle()
543{
544    m_isRecalculatingStyle = false;
545    m_styleRecalculationInitiator = nullptr;
546}
547
548void InspectorResourceAgent::didScheduleStyleRecalculation(Document* document)
549{
550    if (!m_styleRecalculationInitiator)
551        m_styleRecalculationInitiator = buildInitiatorObject(document);
552}
553
554PassRefPtr<Inspector::TypeBuilder::Network::Initiator> InspectorResourceAgent::buildInitiatorObject(Document* document)
555{
556    RefPtr<ScriptCallStack> stackTrace = createScriptCallStack(JSMainThreadExecState::currentState(), ScriptCallStack::maxCallStackSizeToCapture);
557    if (stackTrace && stackTrace->size() > 0) {
558        RefPtr<Inspector::TypeBuilder::Network::Initiator> initiatorObject = Inspector::TypeBuilder::Network::Initiator::create()
559            .setType(Inspector::TypeBuilder::Network::Initiator::Type::Script);
560        initiatorObject->setStackTrace(stackTrace->buildInspectorArray());
561        return initiatorObject;
562    }
563
564    if (document && document->scriptableDocumentParser()) {
565        RefPtr<Inspector::TypeBuilder::Network::Initiator> initiatorObject = Inspector::TypeBuilder::Network::Initiator::create()
566            .setType(Inspector::TypeBuilder::Network::Initiator::Type::Parser);
567        initiatorObject->setUrl(document->url().string());
568        initiatorObject->setLineNumber(document->scriptableDocumentParser()->textPosition().m_line.oneBasedInt());
569        return initiatorObject;
570    }
571
572    if (m_isRecalculatingStyle && m_styleRecalculationInitiator)
573        return m_styleRecalculationInitiator;
574
575    return Inspector::TypeBuilder::Network::Initiator::create()
576        .setType(Inspector::TypeBuilder::Network::Initiator::Type::Other)
577        .release();
578}
579
580#if ENABLE(WEB_SOCKETS)
581
582void InspectorResourceAgent::didCreateWebSocket(unsigned long identifier, const URL& requestURL)
583{
584    m_frontendDispatcher->webSocketCreated(IdentifiersFactory::requestId(identifier), requestURL.string());
585}
586
587void InspectorResourceAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, const ResourceRequest& request)
588{
589    RefPtr<Inspector::TypeBuilder::Network::WebSocketRequest> requestObject = Inspector::TypeBuilder::Network::WebSocketRequest::create()
590        .setHeaders(buildObjectForHeaders(request.httpHeaderFields()));
591    m_frontendDispatcher->webSocketWillSendHandshakeRequest(IdentifiersFactory::requestId(identifier), currentTime(), requestObject);
592}
593
594void InspectorResourceAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const ResourceResponse& response)
595{
596    RefPtr<Inspector::TypeBuilder::Network::WebSocketResponse> responseObject = Inspector::TypeBuilder::Network::WebSocketResponse::create()
597        .setStatus(response.httpStatusCode())
598        .setStatusText(response.httpStatusText())
599        .setHeaders(buildObjectForHeaders(response.httpHeaderFields()));
600    m_frontendDispatcher->webSocketHandshakeResponseReceived(IdentifiersFactory::requestId(identifier), currentTime(), responseObject);
601}
602
603void InspectorResourceAgent::didCloseWebSocket(unsigned long identifier)
604{
605    m_frontendDispatcher->webSocketClosed(IdentifiersFactory::requestId(identifier), currentTime());
606}
607
608void InspectorResourceAgent::didReceiveWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
609{
610    RefPtr<Inspector::TypeBuilder::Network::WebSocketFrame> frameObject = Inspector::TypeBuilder::Network::WebSocketFrame::create()
611        .setOpcode(frame.opCode)
612        .setMask(frame.masked)
613        .setPayloadData(String(frame.payload, frame.payloadLength));
614    m_frontendDispatcher->webSocketFrameReceived(IdentifiersFactory::requestId(identifier), currentTime(), frameObject);
615}
616
617void InspectorResourceAgent::didSendWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
618{
619    RefPtr<Inspector::TypeBuilder::Network::WebSocketFrame> frameObject = Inspector::TypeBuilder::Network::WebSocketFrame::create()
620        .setOpcode(frame.opCode)
621        .setMask(frame.masked)
622        .setPayloadData(String(frame.payload, frame.payloadLength));
623    m_frontendDispatcher->webSocketFrameSent(IdentifiersFactory::requestId(identifier), currentTime(), frameObject);
624}
625
626void InspectorResourceAgent::didReceiveWebSocketFrameError(unsigned long identifier, const String& errorMessage)
627{
628    m_frontendDispatcher->webSocketFrameError(IdentifiersFactory::requestId(identifier), currentTime(), errorMessage);
629}
630
631#endif // ENABLE(WEB_SOCKETS)
632
633void InspectorResourceAgent::enable(ErrorString*)
634{
635    enable();
636}
637
638void InspectorResourceAgent::enable()
639{
640    if (!m_frontendDispatcher)
641        return;
642    m_enabled = true;
643    m_instrumentingAgents->setInspectorResourceAgent(this);
644}
645
646void InspectorResourceAgent::disable(ErrorString*)
647{
648    m_enabled = false;
649    m_instrumentingAgents->setInspectorResourceAgent(nullptr);
650    m_resourcesData->clear();
651    m_extraRequestHeaders.clear();
652}
653
654void InspectorResourceAgent::setExtraHTTPHeaders(ErrorString*, const RefPtr<InspectorObject>& headers)
655{
656    m_extraRequestHeaders = headers;
657}
658
659void InspectorResourceAgent::getResponseBody(ErrorString* errorString, const String& requestId, String* content, bool* base64Encoded)
660{
661    NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
662    if (!resourceData) {
663        *errorString = "No resource with given identifier found";
664        return;
665    }
666
667    if (resourceData->hasContent()) {
668        *base64Encoded = resourceData->base64Encoded();
669        *content = resourceData->content();
670        return;
671    }
672
673    if (resourceData->isContentEvicted()) {
674        *errorString = "Request content was evicted from inspector cache";
675        return;
676    }
677
678    if (resourceData->buffer() && !resourceData->textEncodingName().isNull()) {
679        *base64Encoded = false;
680        if (InspectorPageAgent::sharedBufferContent(resourceData->buffer(), resourceData->textEncodingName(), *base64Encoded, content))
681            return;
682    }
683
684    if (resourceData->cachedResource()) {
685        if (InspectorPageAgent::cachedResourceContent(resourceData->cachedResource(), content, base64Encoded))
686            return;
687    }
688
689    *errorString = "No data found for resource with given identifier";
690}
691
692void InspectorResourceAgent::replayXHR(ErrorString*, const String& requestId)
693{
694    RefPtr<XMLHttpRequest> xhr = XMLHttpRequest::create(*m_pageAgent->mainFrame()->document());
695    String actualRequestId = requestId;
696
697    XHRReplayData* xhrReplayData = m_resourcesData->xhrReplayData(requestId);
698    if (!xhrReplayData)
699        return;
700
701    ResourceRequest request(xhrReplayData->url());
702#if ENABLE(CACHE_PARTITIONING)
703    request.setCachePartition(m_pageAgent->mainFrame()->document()->topOrigin()->cachePartition());
704#endif
705
706    CachedResource* cachedResource = memoryCache()->resourceForRequest(request, m_pageAgent->page()->sessionID());
707    if (cachedResource)
708        memoryCache()->remove(cachedResource);
709
710    xhr->open(xhrReplayData->method(), xhrReplayData->url(), xhrReplayData->async(), IGNORE_EXCEPTION);
711    for (const auto& header : xhrReplayData->headers())
712        xhr->setRequestHeader(header.key, header.value, IGNORE_EXCEPTION);
713    xhr->sendForInspectorXHRReplay(xhrReplayData->formData(), IGNORE_EXCEPTION);
714}
715
716void InspectorResourceAgent::canClearBrowserCache(ErrorString*, bool* result)
717{
718    *result = m_client->canClearBrowserCache();
719}
720
721void InspectorResourceAgent::clearBrowserCache(ErrorString*)
722{
723    m_client->clearBrowserCache();
724}
725
726void InspectorResourceAgent::canClearBrowserCookies(ErrorString*, bool* result)
727{
728    *result = m_client->canClearBrowserCookies();
729}
730
731void InspectorResourceAgent::clearBrowserCookies(ErrorString*)
732{
733    m_client->clearBrowserCookies();
734}
735
736void InspectorResourceAgent::setCacheDisabled(ErrorString*, bool cacheDisabled)
737{
738    m_cacheDisabled = cacheDisabled;
739    if (cacheDisabled)
740        memoryCache()->evictResources();
741}
742
743void InspectorResourceAgent::loadResource(ErrorString* errorString, const String& frameId, const String& urlString, PassRefPtr<LoadResourceCallback> prpCallback)
744{
745    Frame* frame = m_pageAgent->assertFrame(errorString, frameId);
746    if (!frame)
747        return;
748
749    Document* document = frame->document();
750    if (!document) {
751        *errorString = ASCIILiteral("No Document instance for the specified frame");
752        return;
753    }
754
755    RefPtr<LoadResourceCallback> callback = prpCallback;
756
757    URL url = document->completeURL(urlString);
758    ResourceRequest request(url);
759    request.setHTTPMethod(ASCIILiteral("GET"));
760    request.setHiddenFromInspector(true);
761
762    ThreadableLoaderOptions options;
763    options.setSendLoadCallbacks(SendCallbacks); // So we remove this from m_hiddenRequestIdentifiers on completion.
764    options.setAllowCredentials(AllowStoredCredentials);
765    options.crossOriginRequestPolicy = AllowCrossOriginRequests;
766
767    // InspectorThreadableLoaderClient deletes itself when the load completes.
768    InspectorThreadableLoaderClient* inspectorThreadableLoaderClient = new InspectorThreadableLoaderClient(callback);
769
770    RefPtr<DocumentThreadableLoader> loader = DocumentThreadableLoader::create(*document, *inspectorThreadableLoaderClient, request, options);
771    if (!loader) {
772        inspectorThreadableLoaderClient->didFailLoaderCreation();
773        return;
774    }
775
776    loader->setDefersLoading(false);
777
778    // If the load already completed, inspectorThreadableLoaderClient will have been deleted and we will have already called the callback.
779    if (!callback->isActive())
780        return;
781
782    inspectorThreadableLoaderClient->setLoader(loader.release());
783}
784
785void InspectorResourceAgent::mainFrameNavigated(DocumentLoader* loader)
786{
787    if (m_cacheDisabled)
788        memoryCache()->evictResources();
789
790    m_resourcesData->clear(m_pageAgent->loaderId(loader));
791}
792
793} // namespace WebCore
794
795#endif // ENABLE(INSPECTOR)
796