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