Add WTF::move()
[WebKit-https.git] / Source / WebCore / inspector / InspectorResourceAgent.cpp
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
76 using namespace Inspector;
77
78 typedef Inspector::InspectorNetworkBackendDispatcherHandler::LoadResourceCallback LoadResourceCallback;
79
80 namespace WebCore {
81
82 namespace {
83
84 class InspectorThreadableLoaderClient final : public ThreadableLoaderClient {
85     WTF_MAKE_NONCOPYABLE(InspectorThreadableLoaderClient);
86 public:
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
151 private:
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
168 InspectorResourceAgent::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
180 void 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
186 void InspectorResourceAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
187 {
188     m_frontendDispatcher = nullptr;
189     m_backendDispatcher.clear();
190
191     ErrorString error;
192     disable(&error);
193 }
194
195 static 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
204 static 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
218 static 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
229 static 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
252 static 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
270 InspectorResourceAgent::~InspectorResourceAgent()
271 {
272     if (m_enabled) {
273         ErrorString error;
274         disable(&error);
275     }
276     ASSERT(!m_instrumentingAgents->inspectorResourceAgent());
277 }
278
279 void 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
326 void InspectorResourceAgent::markResourceAsCached(unsigned long identifier)
327 {
328     if (m_hiddenRequestIdentifiers.contains(identifier))
329         return;
330
331     m_frontendDispatcher->requestServedFromCache(IdentifiersFactory::requestId(identifier));
332 }
333
334 void 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
376 static bool isErrorStatusCode(int statusCode)
377 {
378     return statusCode >= 400;
379 }
380
381 void 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
397 void 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
424 void 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
443 void 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
462 void InspectorResourceAgent::setInitialScriptContent(unsigned long identifier, const String& sourceString)
463 {
464     m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
465 }
466
467 void InspectorResourceAgent::didReceiveScriptResponse(unsigned long identifier)
468 {
469     m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::ScriptResource);
470 }
471
472 void 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
486 void 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
493 void InspectorResourceAgent::didFailXHRLoading(ThreadableLoaderClient* client)
494 {
495     m_pendingXHRReplayData.remove(client);
496 }
497
498 void 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
507 void InspectorResourceAgent::didReceiveXHRResponse(unsigned long identifier)
508 {
509     m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::XHRResource);
510 }
511
512 void InspectorResourceAgent::willLoadXHRSynchronously()
513 {
514     m_loadingXHRSynchronously = true;
515 }
516
517 void InspectorResourceAgent::didLoadXHRSynchronously()
518 {
519     m_loadingXHRSynchronously = false;
520 }
521
522 void 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
537 void InspectorResourceAgent::willRecalculateStyle()
538 {
539     m_isRecalculatingStyle = true;
540 }
541
542 void InspectorResourceAgent::didRecalculateStyle()
543 {
544     m_isRecalculatingStyle = false;
545     m_styleRecalculationInitiator = nullptr;
546 }
547
548 void InspectorResourceAgent::didScheduleStyleRecalculation(Document* document)
549 {
550     if (!m_styleRecalculationInitiator)
551         m_styleRecalculationInitiator = buildInitiatorObject(document);
552 }
553
554 PassRefPtr<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
582 void InspectorResourceAgent::didCreateWebSocket(unsigned long identifier, const URL& requestURL)
583 {
584     m_frontendDispatcher->webSocketCreated(IdentifiersFactory::requestId(identifier), requestURL.string());
585 }
586
587 void 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
594 void 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
603 void InspectorResourceAgent::didCloseWebSocket(unsigned long identifier)
604 {
605     m_frontendDispatcher->webSocketClosed(IdentifiersFactory::requestId(identifier), currentTime());
606 }
607
608 void 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
617 void 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
626 void 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
633 void InspectorResourceAgent::enable(ErrorString*)
634 {
635     enable();
636 }
637
638 void InspectorResourceAgent::enable()
639 {
640     if (!m_frontendDispatcher)
641         return;
642     m_enabled = true;
643     m_instrumentingAgents->setInspectorResourceAgent(this);
644 }
645
646 void InspectorResourceAgent::disable(ErrorString*)
647 {
648     m_enabled = false;
649     m_instrumentingAgents->setInspectorResourceAgent(nullptr);
650     m_resourcesData->clear();
651     m_extraRequestHeaders.clear();
652 }
653
654 void InspectorResourceAgent::setExtraHTTPHeaders(ErrorString*, const RefPtr<InspectorObject>& headers)
655 {
656     m_extraRequestHeaders = headers;
657 }
658
659 void 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
692 void 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
716 void InspectorResourceAgent::canClearBrowserCache(ErrorString*, bool* result)
717 {
718     *result = m_client->canClearBrowserCache();
719 }
720
721 void InspectorResourceAgent::clearBrowserCache(ErrorString*)
722 {
723     m_client->clearBrowserCache();
724 }
725
726 void InspectorResourceAgent::canClearBrowserCookies(ErrorString*, bool* result)
727 {
728     *result = m_client->canClearBrowserCookies();
729 }
730
731 void InspectorResourceAgent::clearBrowserCookies(ErrorString*)
732 {
733     m_client->clearBrowserCookies();
734 }
735
736 void InspectorResourceAgent::setCacheDisabled(ErrorString*, bool cacheDisabled)
737 {
738     m_cacheDisabled = cacheDisabled;
739     if (cacheDisabled)
740         memoryCache()->evictResources();
741 }
742
743 void 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
785 void 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)