2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2015 Apple Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "InspectorResourceAgent.h"
35 #include "CachedRawResource.h"
36 #include "CachedResource.h"
37 #include "CachedResourceLoader.h"
39 #include "DocumentLoader.h"
40 #include "DocumentThreadableLoader.h"
41 #include "ExceptionCodePlaceholder.h"
43 #include "FrameLoader.h"
44 #include "HTTPHeaderMap.h"
45 #include "HTTPHeaderNames.h"
46 #include "IconController.h"
47 #include "InspectorClient.h"
48 #include "InspectorPageAgent.h"
49 #include "InspectorTimelineAgent.h"
50 #include "InstrumentingAgents.h"
51 #include "JSMainThreadExecState.h"
52 #include "MemoryCache.h"
53 #include "NetworkResourcesData.h"
55 #include "ProgressTracker.h"
56 #include "ResourceError.h"
57 #include "ResourceLoader.h"
58 #include "ResourceRequest.h"
59 #include "ResourceResponse.h"
60 #include "ScriptableDocumentParser.h"
61 #include "SubresourceLoader.h"
62 #include "ThreadableLoaderClient.h"
64 #include "WebSocketFrame.h"
65 #include <inspector/IdentifiersFactory.h>
66 #include <inspector/InspectorFrontendRouter.h>
67 #include <inspector/InspectorValues.h>
68 #include <inspector/ScriptCallStack.h>
69 #include <inspector/ScriptCallStackFactory.h>
70 #include <wtf/RefPtr.h>
71 #include <wtf/text/StringBuilder.h>
73 using namespace Inspector;
75 typedef Inspector::NetworkBackendDispatcherHandler::LoadResourceCallback LoadResourceCallback;
81 class InspectorThreadableLoaderClient final : public ThreadableLoaderClient {
82 WTF_MAKE_NONCOPYABLE(InspectorThreadableLoaderClient);
84 InspectorThreadableLoaderClient(PassRefPtr<LoadResourceCallback> callback)
85 : m_callback(callback) { }
87 virtual ~InspectorThreadableLoaderClient() { }
89 virtual void didReceiveResponse(unsigned long, const ResourceResponse& response) override
91 m_mimeType = response.mimeType();
92 m_statusCode = response.httpStatusCode();
94 // FIXME: This assumes text only responses. We should support non-text responses as well.
95 TextEncoding textEncoding(response.textEncodingName());
96 bool useDetector = false;
97 if (!textEncoding.isValid()) {
98 textEncoding = UTF8Encoding();
102 m_decoder = TextResourceDecoder::create(ASCIILiteral("text/plain"), textEncoding, useDetector);
105 virtual void didReceiveData(const char* data, int dataLength) override
110 if (dataLength == -1)
111 dataLength = strlen(data);
113 m_responseText.append(m_decoder->decode(data, dataLength));
116 virtual void didFinishLoading(unsigned long, double) override
119 m_responseText.append(m_decoder->flush());
121 m_callback->sendSuccess(m_responseText.toString(), m_mimeType, m_statusCode);
125 virtual void didFail(const ResourceError&) override
127 m_callback->sendFailure(ASCIILiteral("Loading resource for inspector failed"));
131 virtual void didFailRedirectCheck() override
133 m_callback->sendFailure(ASCIILiteral("Loading resource for inspector failed redirect check"));
137 void didFailLoaderCreation()
139 m_callback->sendFailure(ASCIILiteral("Could not create a loader"));
143 void setLoader(PassRefPtr<ThreadableLoader> loader)
155 RefPtr<LoadResourceCallback> m_callback;
156 RefPtr<ThreadableLoader> m_loader;
157 RefPtr<TextResourceDecoder> m_decoder;
159 StringBuilder m_responseText;
165 InspectorResourceAgent::InspectorResourceAgent(WebAgentContext& context, InspectorPageAgent* pageAgent, InspectorClient* client)
166 : InspectorAgentBase(ASCIILiteral("Network"), context)
167 , m_frontendDispatcher(std::make_unique<Inspector::NetworkFrontendDispatcher>(context.frontendRouter))
168 , m_backendDispatcher(Inspector::NetworkBackendDispatcher::create(context.backendDispatcher, this))
169 , m_pageAgent(pageAgent)
171 , m_resourcesData(std::make_unique<NetworkResourcesData>())
175 void InspectorResourceAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
179 void InspectorResourceAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
185 static Ref<InspectorObject> buildObjectForHeaders(const HTTPHeaderMap& headers)
187 Ref<InspectorObject> headersObject = InspectorObject::create();
189 for (const auto& header : headers)
190 headersObject->setString(header.key, header.value);
191 return WTF::move(headersObject);
194 static Ref<Inspector::Protocol::Network::ResourceTiming> buildObjectForTiming(const ResourceLoadTiming& timing, DocumentLoader* loader)
196 return Inspector::Protocol::Network::ResourceTiming::create()
197 .setNavigationStart(loader->timing().navigationStart())
198 .setDomainLookupStart(timing.domainLookupStart)
199 .setDomainLookupEnd(timing.domainLookupEnd)
200 .setConnectStart(timing.connectStart)
201 .setConnectEnd(timing.connectEnd)
202 .setSecureConnectionStart(timing.secureConnectionStart)
203 .setRequestStart(timing.requestStart)
204 .setResponseStart(timing.responseStart)
208 static Ref<Inspector::Protocol::Network::Request> buildObjectForResourceRequest(const ResourceRequest& request)
210 auto requestObject = Inspector::Protocol::Network::Request::create()
211 .setUrl(request.url().string())
212 .setMethod(request.httpMethod())
213 .setHeaders(buildObjectForHeaders(request.httpHeaderFields()))
215 if (request.httpBody() && !request.httpBody()->isEmpty())
216 requestObject->setPostData(request.httpBody()->flattenToString());
217 return WTF::move(requestObject);
220 static RefPtr<Inspector::Protocol::Network::Response> buildObjectForResourceResponse(const ResourceResponse& response, DocumentLoader* loader)
222 if (response.isNull())
225 double status = response.httpStatusCode();
226 Ref<InspectorObject> headers = buildObjectForHeaders(response.httpHeaderFields());
228 auto responseObject = Inspector::Protocol::Network::Response::create()
229 .setUrl(response.url().string())
231 .setStatusText(response.httpStatusText())
232 .setHeaders(WTF::move(headers))
233 .setMimeType(response.mimeType())
236 responseObject->setFromDiskCache(response.source() == ResourceResponse::Source::DiskCache || response.source() == ResourceResponse::Source::DiskCacheAfterValidation);
237 responseObject->setTiming(buildObjectForTiming(response.resourceLoadTiming(), loader));
239 return WTF::move(responseObject);
242 static Ref<Inspector::Protocol::Network::CachedResource> buildObjectForCachedResource(CachedResource* cachedResource, DocumentLoader* loader)
244 auto resourceObject = Inspector::Protocol::Network::CachedResource::create()
245 .setUrl(cachedResource->url())
246 .setType(InspectorPageAgent::cachedResourceTypeJson(*cachedResource))
247 .setBodySize(cachedResource->encodedSize())
250 auto resourceResponse = buildObjectForResourceResponse(cachedResource->response(), loader);
251 resourceObject->setResponse(WTF::move(resourceResponse));
253 String sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(cachedResource);
254 if (!sourceMappingURL.isEmpty())
255 resourceObject->setSourceMapURL(sourceMappingURL);
257 return WTF::move(resourceObject);
260 InspectorResourceAgent::~InspectorResourceAgent()
266 ASSERT(!m_instrumentingAgents.inspectorResourceAgent());
269 double InspectorResourceAgent::timestamp()
271 return m_instrumentingAgents.inspectorEnvironment().executionStopwatch()->elapsedTime();
274 void InspectorResourceAgent::willSendRequest(unsigned long identifier, DocumentLoader& loader, ResourceRequest& request, const ResourceResponse& redirectResponse)
276 if (request.hiddenFromInspector()) {
277 m_hiddenRequestIdentifiers.add(identifier);
281 String requestId = IdentifiersFactory::requestId(identifier);
282 m_resourcesData->resourceCreated(requestId, m_pageAgent->loaderId(&loader));
284 CachedResource* cachedResource = InspectorPageAgent::cachedResource(loader.frame(), request.url());
285 InspectorPageAgent::ResourceType type = cachedResource ? InspectorPageAgent::cachedResourceType(*cachedResource) : m_resourcesData->resourceType(requestId);
286 if (type == InspectorPageAgent::OtherResource) {
287 if (m_loadingXHRSynchronously)
288 type = InspectorPageAgent::XHRResource;
289 else if (equalIgnoringFragmentIdentifier(request.url(), loader.frameLoader()->icon().url()))
290 type = InspectorPageAgent::ImageResource;
291 else if (equalIgnoringFragmentIdentifier(request.url(), loader.url()) && !loader.isCommitted())
292 type = InspectorPageAgent::DocumentResource;
295 m_resourcesData->setResourceType(requestId, type);
297 for (auto& entry : m_extraRequestHeaders)
298 request.setHTTPHeaderField(entry.key, entry.value);
300 request.setReportLoadTiming(true);
301 request.setReportRawHeaders(true);
303 if (m_cacheDisabled) {
304 request.setHTTPHeaderField(HTTPHeaderName::Pragma, "no-cache");
305 request.setCachePolicy(ReloadIgnoringCacheData);
306 request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache");
309 Inspector::Protocol::Page::ResourceType resourceType = InspectorPageAgent::resourceTypeJson(type);
311 RefPtr<Inspector::Protocol::Network::Initiator> initiatorObject = buildInitiatorObject(loader.frame() ? loader.frame()->document() : nullptr);
312 m_frontendDispatcher->requestWillBeSent(requestId, m_pageAgent->frameId(loader.frame()), m_pageAgent->loaderId(&loader), loader.url().string(), buildObjectForResourceRequest(request), timestamp(), initiatorObject, buildObjectForResourceResponse(redirectResponse, &loader), type != InspectorPageAgent::OtherResource ? &resourceType : nullptr);
315 void InspectorResourceAgent::markResourceAsCached(unsigned long identifier)
317 if (m_hiddenRequestIdentifiers.contains(identifier))
320 m_frontendDispatcher->requestServedFromCache(IdentifiersFactory::requestId(identifier));
323 void InspectorResourceAgent::didReceiveResponse(unsigned long identifier, DocumentLoader& loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
325 if (m_hiddenRequestIdentifiers.contains(identifier))
328 String requestId = IdentifiersFactory::requestId(identifier);
329 RefPtr<Inspector::Protocol::Network::Response> resourceResponse = buildObjectForResourceResponse(response, &loader);
331 bool isNotModified = response.httpStatusCode() == 304;
333 CachedResource* cachedResource = nullptr;
334 if (resourceLoader && resourceLoader->isSubresourceLoader() && !isNotModified)
335 cachedResource = static_cast<SubresourceLoader*>(resourceLoader)->cachedResource();
337 cachedResource = InspectorPageAgent::cachedResource(loader.frame(), response.url());
339 if (cachedResource) {
340 // Use mime type from cached resource in case the one in response is empty.
341 if (resourceResponse && response.mimeType().isEmpty())
342 resourceResponse->setString(Inspector::Protocol::Network::Response::MimeType, cachedResource->response().mimeType());
343 m_resourcesData->addCachedResource(requestId, cachedResource);
346 InspectorPageAgent::ResourceType type = m_resourcesData->resourceType(requestId);
347 InspectorPageAgent::ResourceType newType = cachedResource ? InspectorPageAgent::cachedResourceType(*cachedResource) : type;
349 // FIXME: XHRResource is returned for CachedResource::RawResource, it should be OtherResource unless it truly is an XHR.
350 // RawResource is used for loading worker scripts, and those should stay as ScriptResource and not change to XHRResource.
351 if (type != newType && newType != InspectorPageAgent::XHRResource && newType != InspectorPageAgent::OtherResource)
354 m_resourcesData->responseReceived(requestId, m_pageAgent->frameId(loader.frame()), response);
355 m_resourcesData->setResourceType(requestId, type);
357 m_frontendDispatcher->responseReceived(requestId, m_pageAgent->frameId(loader.frame()), m_pageAgent->loaderId(&loader), timestamp(), InspectorPageAgent::resourceTypeJson(type), resourceResponse);
359 // If we revalidated the resource and got Not modified, send content length following didReceiveResponse
360 // as there will be no calls to didReceiveData from the network stack.
361 if (isNotModified && cachedResource && cachedResource->encodedSize())
362 didReceiveData(identifier, nullptr, cachedResource->encodedSize(), 0);
365 static bool isErrorStatusCode(int statusCode)
367 return statusCode >= 400;
370 void InspectorResourceAgent::didReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
372 if (m_hiddenRequestIdentifiers.contains(identifier))
375 String requestId = IdentifiersFactory::requestId(identifier);
378 NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
379 if (resourceData && !m_loadingXHRSynchronously && (!resourceData->cachedResource() || resourceData->cachedResource()->dataBufferingPolicy() == DoNotBufferData || isErrorStatusCode(resourceData->httpStatusCode())))
380 m_resourcesData->maybeAddResourceData(requestId, data, dataLength);
383 m_frontendDispatcher->dataReceived(requestId, timestamp(), dataLength, encodedDataLength);
386 void InspectorResourceAgent::didFinishLoading(unsigned long identifier, DocumentLoader& loader, double finishTime)
388 if (m_hiddenRequestIdentifiers.remove(identifier))
391 String requestId = IdentifiersFactory::requestId(identifier);
392 if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource)
393 m_resourcesData->addResourceSharedBuffer(requestId, loader.frameLoader()->documentLoader()->mainResourceData(), loader.frame()->document()->encoding());
395 m_resourcesData->maybeDecodeDataToContent(requestId);
397 // FIXME: The finishTime that is passed in is from the NetworkProcess and is more accurate.
398 // However, all other times passed to the Inspector are generated from the web process. Mixing
399 // times from different processes can cause the finish time to be earlier than the response
400 // received time due to inter-process communication lag.
401 finishTime = timestamp();
403 String sourceMappingURL;
404 NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
405 if (resourceData && resourceData->cachedResource())
406 sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(resourceData->cachedResource());
408 m_frontendDispatcher->loadingFinished(requestId, finishTime, !sourceMappingURL.isEmpty() ? &sourceMappingURL : nullptr);
411 void InspectorResourceAgent::didFailLoading(unsigned long identifier, DocumentLoader& loader, const ResourceError& error)
413 if (m_hiddenRequestIdentifiers.remove(identifier))
416 String requestId = IdentifiersFactory::requestId(identifier);
418 if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource) {
419 Frame* frame = loader.frame();
420 if (frame && frame->loader().documentLoader() && frame->document()) {
421 m_resourcesData->addResourceSharedBuffer(requestId,
422 frame->loader().documentLoader()->mainResourceData(),
423 frame->document()->encoding());
427 bool canceled = error.isCancellation();
428 m_frontendDispatcher->loadingFailed(requestId, timestamp(), error.localizedDescription(), canceled ? &canceled : nullptr);
431 void InspectorResourceAgent::didLoadResourceFromMemoryCache(DocumentLoader& loader, CachedResource& resource)
433 String loaderId = m_pageAgent->loaderId(&loader);
434 String frameId = m_pageAgent->frameId(loader.frame());
435 unsigned long identifier = loader.frame()->page()->progress().createUniqueIdentifier();
436 String requestId = IdentifiersFactory::requestId(identifier);
437 m_resourcesData->resourceCreated(requestId, loaderId);
438 m_resourcesData->addCachedResource(requestId, &resource);
440 RefPtr<Inspector::Protocol::Network::Initiator> initiatorObject = buildInitiatorObject(loader.frame() ? loader.frame()->document() : nullptr);
442 m_frontendDispatcher->requestServedFromMemoryCache(requestId, frameId, loaderId, loader.url().string(), timestamp(), initiatorObject, buildObjectForCachedResource(&resource, &loader));
445 void InspectorResourceAgent::setInitialScriptContent(unsigned long identifier, const String& sourceString)
447 m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
450 void InspectorResourceAgent::didReceiveScriptResponse(unsigned long identifier)
452 m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::ScriptResource);
455 void InspectorResourceAgent::didFinishXHRLoading(ThreadableLoaderClient*, unsigned long identifier, const String& sourceString)
457 // For Asynchronous XHRs, the inspector can grab the data directly off of the CachedResource. For sync XHRs, we need to
458 // provide the data here, since no CachedResource was involved.
459 if (m_loadingXHRSynchronously)
460 m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
463 void InspectorResourceAgent::didReceiveXHRResponse(unsigned long identifier)
465 m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::XHRResource);
468 void InspectorResourceAgent::willLoadXHRSynchronously()
470 m_loadingXHRSynchronously = true;
473 void InspectorResourceAgent::didLoadXHRSynchronously()
475 m_loadingXHRSynchronously = false;
478 void InspectorResourceAgent::willDestroyCachedResource(CachedResource& cachedResource)
480 Vector<String> requestIds = m_resourcesData->removeCachedResource(&cachedResource);
481 if (!requestIds.size())
486 if (!InspectorPageAgent::cachedResourceContent(&cachedResource, &content, &base64Encoded))
488 Vector<String>::iterator end = requestIds.end();
489 for (Vector<String>::iterator it = requestIds.begin(); it != end; ++it)
490 m_resourcesData->setResourceContent(*it, content, base64Encoded);
493 void InspectorResourceAgent::willRecalculateStyle()
495 m_isRecalculatingStyle = true;
498 void InspectorResourceAgent::didRecalculateStyle()
500 m_isRecalculatingStyle = false;
501 m_styleRecalculationInitiator = nullptr;
504 void InspectorResourceAgent::didScheduleStyleRecalculation(Document& document)
506 if (!m_styleRecalculationInitiator)
507 m_styleRecalculationInitiator = buildInitiatorObject(&document);
510 RefPtr<Inspector::Protocol::Network::Initiator> InspectorResourceAgent::buildInitiatorObject(Document* document)
512 RefPtr<ScriptCallStack> stackTrace = createScriptCallStack(JSMainThreadExecState::currentState(), ScriptCallStack::maxCallStackSizeToCapture);
513 if (stackTrace && stackTrace->size() > 0) {
514 auto initiatorObject = Inspector::Protocol::Network::Initiator::create()
515 .setType(Inspector::Protocol::Network::Initiator::Type::Script)
517 initiatorObject->setStackTrace(stackTrace->buildInspectorArray());
518 return WTF::move(initiatorObject);
521 if (document && document->scriptableDocumentParser()) {
522 auto initiatorObject = Inspector::Protocol::Network::Initiator::create()
523 .setType(Inspector::Protocol::Network::Initiator::Type::Parser)
525 initiatorObject->setUrl(document->url().string());
526 initiatorObject->setLineNumber(document->scriptableDocumentParser()->textPosition().m_line.oneBasedInt());
527 return WTF::move(initiatorObject);
530 if (m_isRecalculatingStyle && m_styleRecalculationInitiator)
531 return m_styleRecalculationInitiator;
533 return Inspector::Protocol::Network::Initiator::create()
534 .setType(Inspector::Protocol::Network::Initiator::Type::Other)
538 #if ENABLE(WEB_SOCKETS)
540 void InspectorResourceAgent::didCreateWebSocket(unsigned long identifier, const URL& requestURL)
542 m_frontendDispatcher->webSocketCreated(IdentifiersFactory::requestId(identifier), requestURL.string());
545 void InspectorResourceAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, const ResourceRequest& request)
547 auto requestObject = Inspector::Protocol::Network::WebSocketRequest::create()
548 .setHeaders(buildObjectForHeaders(request.httpHeaderFields()))
550 m_frontendDispatcher->webSocketWillSendHandshakeRequest(IdentifiersFactory::requestId(identifier), timestamp(), WTF::move(requestObject));
553 void InspectorResourceAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const ResourceResponse& response)
555 auto responseObject = Inspector::Protocol::Network::WebSocketResponse::create()
556 .setStatus(response.httpStatusCode())
557 .setStatusText(response.httpStatusText())
558 .setHeaders(buildObjectForHeaders(response.httpHeaderFields()))
560 m_frontendDispatcher->webSocketHandshakeResponseReceived(IdentifiersFactory::requestId(identifier), timestamp(), WTF::move(responseObject));
563 void InspectorResourceAgent::didCloseWebSocket(unsigned long identifier)
565 m_frontendDispatcher->webSocketClosed(IdentifiersFactory::requestId(identifier), timestamp());
568 void InspectorResourceAgent::didReceiveWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
570 auto frameObject = Inspector::Protocol::Network::WebSocketFrame::create()
571 .setOpcode(frame.opCode)
572 .setMask(frame.masked)
573 .setPayloadData(String(frame.payload, frame.payloadLength))
575 m_frontendDispatcher->webSocketFrameReceived(IdentifiersFactory::requestId(identifier), timestamp(), WTF::move(frameObject));
578 void InspectorResourceAgent::didSendWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
580 auto frameObject = Inspector::Protocol::Network::WebSocketFrame::create()
581 .setOpcode(frame.opCode)
582 .setMask(frame.masked)
583 .setPayloadData(String(frame.payload, frame.payloadLength))
585 m_frontendDispatcher->webSocketFrameSent(IdentifiersFactory::requestId(identifier), timestamp(), WTF::move(frameObject));
588 void InspectorResourceAgent::didReceiveWebSocketFrameError(unsigned long identifier, const String& errorMessage)
590 m_frontendDispatcher->webSocketFrameError(IdentifiersFactory::requestId(identifier), timestamp(), errorMessage);
593 #endif // ENABLE(WEB_SOCKETS)
595 void InspectorResourceAgent::enable(ErrorString&)
600 void InspectorResourceAgent::enable()
603 m_instrumentingAgents.setInspectorResourceAgent(this);
606 void InspectorResourceAgent::disable(ErrorString&)
609 m_instrumentingAgents.setInspectorResourceAgent(nullptr);
610 m_resourcesData->clear();
611 m_extraRequestHeaders.clear();
614 void InspectorResourceAgent::setExtraHTTPHeaders(ErrorString&, const InspectorObject& headers)
616 for (auto& entry : headers) {
618 if (entry.value->asString(stringValue))
619 m_extraRequestHeaders.set(entry.key, stringValue);
623 void InspectorResourceAgent::getResponseBody(ErrorString& errorString, const String& requestId, String* content, bool* base64Encoded)
625 NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
627 errorString = ASCIILiteral("No resource with given identifier found");
631 if (resourceData->hasContent()) {
632 *base64Encoded = resourceData->base64Encoded();
633 *content = resourceData->content();
637 if (resourceData->isContentEvicted()) {
638 errorString = ASCIILiteral("Request content was evicted from inspector cache");
642 if (resourceData->buffer() && !resourceData->textEncodingName().isNull()) {
643 *base64Encoded = false;
644 if (InspectorPageAgent::sharedBufferContent(resourceData->buffer(), resourceData->textEncodingName(), *base64Encoded, content))
648 if (resourceData->cachedResource()) {
649 if (InspectorPageAgent::cachedResourceContent(resourceData->cachedResource(), content, base64Encoded))
653 errorString = ASCIILiteral("No data found for resource with given identifier");
656 void InspectorResourceAgent::canClearBrowserCache(ErrorString&, bool* result)
658 *result = m_client->canClearBrowserCache();
661 void InspectorResourceAgent::clearBrowserCache(ErrorString&)
663 m_client->clearBrowserCache();
666 void InspectorResourceAgent::canClearBrowserCookies(ErrorString&, bool* result)
668 *result = m_client->canClearBrowserCookies();
671 void InspectorResourceAgent::clearBrowserCookies(ErrorString&)
673 m_client->clearBrowserCookies();
676 void InspectorResourceAgent::setCacheDisabled(ErrorString&, bool cacheDisabled)
678 m_cacheDisabled = cacheDisabled;
680 MemoryCache::singleton().evictResources();
683 void InspectorResourceAgent::loadResource(ErrorString& errorString, const String& frameId, const String& urlString, Ref<LoadResourceCallback>&& callback)
685 Frame* frame = m_pageAgent->assertFrame(errorString, frameId);
689 Document* document = frame->document();
691 errorString = ASCIILiteral("No Document instance for the specified frame");
695 URL url = document->completeURL(urlString);
696 ResourceRequest request(url);
697 request.setHTTPMethod(ASCIILiteral("GET"));
698 request.setHiddenFromInspector(true);
700 ThreadableLoaderOptions options;
701 options.setSendLoadCallbacks(SendCallbacks); // So we remove this from m_hiddenRequestIdentifiers on completion.
702 options.setAllowCredentials(AllowStoredCredentials);
703 options.setDefersLoadingPolicy(DefersLoadingPolicy::DisallowDefersLoading); // So the request is never deferred.
704 options.crossOriginRequestPolicy = AllowCrossOriginRequests;
706 // InspectorThreadableLoaderClient deletes itself when the load completes.
707 InspectorThreadableLoaderClient* inspectorThreadableLoaderClient = new InspectorThreadableLoaderClient(callback.copyRef());
709 RefPtr<DocumentThreadableLoader> loader = DocumentThreadableLoader::create(*document, *inspectorThreadableLoaderClient, request, options);
711 inspectorThreadableLoaderClient->didFailLoaderCreation();
715 // If the load already completed, inspectorThreadableLoaderClient will have been deleted and we will have already called the callback.
716 if (!callback->isActive())
719 inspectorThreadableLoaderClient->setLoader(loader.release());
722 void InspectorResourceAgent::mainFrameNavigated(DocumentLoader& loader)
725 MemoryCache::singleton().evictResources();
727 m_resourcesData->clear(m_pageAgent->loaderId(&loader));
730 } // namespace WebCore