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 "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 
     71 typedef WebCore::InspectorBackendDispatcher::NetworkCommandHandler::LoadResourceForFrontendCallback LoadResourceForFrontendCallback;
     72 
     73 namespace WebCore {
     74 
     75 namespace ResourceAgentState {
     76 static const char resourceAgentEnabled[] = "resourceAgentEnabled";
     77 static const char extraRequestHeaders[] = "extraRequestHeaders";
     78 static const char cacheDisabled[] = "cacheDisabled";
     79 static const char userAgentOverride[] = "userAgentOverride";
     80 }
     81 
     82 namespace {
     83 
     84 static 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 
     93 class InspectorThreadableLoaderClient : public ThreadableLoaderClient {
     94     WTF_MAKE_NONCOPYABLE(InspectorThreadableLoaderClient);
     95 public:
     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 
    157 private:
    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 
    172 KURL urlWithoutFragment(const KURL& url)
    173 {
    174     KURL result = url;
    175     result.removeFragmentIdentifier();
    176     return result;
    177 }
    178 
    179 } // namespace
    180 
    181 void InspectorResourceAgent::setFrontend(InspectorFrontend* frontend)
    182 {
    183     m_frontend = frontend->network();
    184 }
    185 
    186 void InspectorResourceAgent::clearFrontend()
    187 {
    188     m_frontend = 0;
    189     ErrorString error;
    190     disable(&error);
    191 }
    192 
    193 void InspectorResourceAgent::restore()
    194 {
    195     if (m_state->getBoolean(ResourceAgentState::resourceAgentEnabled))
    196         enable();
    197 }
    198 
    199 static 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 
    217 static 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 
    231 static 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 
    277 InspectorResourceAgent::~InspectorResourceAgent()
    278 {
    279     if (m_state->getBoolean(ResourceAgentState::resourceAgentEnabled)) {
    280         ErrorString error;
    281         disable(&error);
    282     }
    283     ASSERT(!m_instrumentingAgents->inspectorResourceAgent());
    284 }
    285 
    286 void 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 
    315 void InspectorResourceAgent::markResourceAsCached(unsigned long identifier)
    316 {
    317     m_frontend->requestServedFromCache(IdentifiersFactory::requestId(identifier));
    318 }
    319 
    320 void 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 
    360 static bool isErrorStatusCode(int statusCode)
    361 {
    362     return statusCode >= 400;
    363 }
    364 
    365 void 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 
    378 void 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 
    392 void 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 
    399 void InspectorResourceAgent::scriptImported(unsigned long identifier, const String& sourceString)
    400 {
    401     m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
    402 }
    403 
    404 void InspectorResourceAgent::didReceiveScriptResponse(unsigned long identifier)
    405 {
    406     m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::ScriptResource);
    407 }
    408 
    409 void 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 
    423 void 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 
    432 void InspectorResourceAgent::didFailXHRLoading(ThreadableLoaderClient* client)
    433 {
    434     m_pendingXHRReplayData.remove(client);
    435 }
    436 
    437 void 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 
    446 void InspectorResourceAgent::didReceiveXHRResponse(unsigned long identifier)
    447 {
    448     m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::XHRResource);
    449 }
    450 
    451 void InspectorResourceAgent::willLoadXHRSynchronously()
    452 {
    453     m_loadingXHRSynchronously = true;
    454 }
    455 
    456 void InspectorResourceAgent::didLoadXHRSynchronously()
    457 {
    458     m_loadingXHRSynchronously = false;
    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     m_overlay->setOverride(InspectorOverlay::UserAgentOverride, !userAgent.isEmpty());
    609 }
    610 
    611 void InspectorResourceAgent::setExtraHTTPHeaders(ErrorString*, const RefPtr<JSONObject>& headers)
    612 {
    613     m_state->setObject(ResourceAgentState::extraRequestHeaders, headers);
    614 }
    615 
    616 void 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 
    649 void 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 
    669 void InspectorResourceAgent::canClearBrowserCache(ErrorString*, bool* result)
    670 {
    671     *result = true;
    672 }
    673 
    674 void InspectorResourceAgent::clearBrowserCache(ErrorString*)
    675 {
    676     m_client->clearBrowserCache();
    677 }
    678 
    679 void InspectorResourceAgent::canClearBrowserCookies(ErrorString*, bool* result)
    680 {
    681     *result = true;
    682 }
    683 
    684 void InspectorResourceAgent::clearBrowserCookies(ErrorString*)
    685 {
    686     m_client->clearBrowserCookies();
    687 }
    688 
    689 void InspectorResourceAgent::setCacheDisabled(ErrorString*, bool cacheDisabled)
    690 {
    691     m_state->setBoolean(ResourceAgentState::cacheDisabled, cacheDisabled);
    692     if (cacheDisabled)
    693         memoryCache()->evictResources();
    694 }
    695 
    696 void 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 
    741 void 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 
    752 InspectorResourceAgent::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