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