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