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