Home | History | Annotate | Download | only in inspector
      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