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