• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
buildObjectForHeaders(const HTTPHeaderMap & headers)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:
InspectorThreadableLoaderClient(PassRefPtr<LoadResourceForFrontendCallback> callback)97     InspectorThreadableLoaderClient(PassRefPtr<LoadResourceForFrontendCallback> callback)
98         : m_callback(callback)
99         , m_statusCode(0) { }
100 
~InspectorThreadableLoaderClient()101     virtual ~InspectorThreadableLoaderClient() { }
102 
didReceiveResponse(unsigned long identifier,const ResourceResponse & response)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 
didReceiveData(const char * data,int dataLength)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 
didFinishLoading(unsigned long,double)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 
didFail(const ResourceError &)135     virtual void didFail(const ResourceError&)
136     {
137         m_callback->sendFailure("Loading resource for inspector failed");
138         dispose();
139     }
140 
didFailRedirectCheck()141     virtual void didFailRedirectCheck()
142     {
143         m_callback->sendFailure("Loading resource for inspector failed redirect check");
144         dispose();
145     }
146 
didFailLoaderCreation()147     void didFailLoaderCreation()
148     {
149         m_callback->sendFailure("Couldn't create a loader");
150         dispose();
151     }
152 
setLoader(PassRefPtr<ThreadableLoader> loader)153     void setLoader(PassRefPtr<ThreadableLoader> loader)
154     {
155         m_loader = loader;
156     }
157 
158 private:
dispose()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 
urlWithoutFragment(const KURL & url)173 KURL urlWithoutFragment(const KURL& url)
174 {
175     KURL result = url;
176     result.removeFragmentIdentifier();
177     return result;
178 }
179 
180 } // namespace
181 
setFrontend(InspectorFrontend * frontend)182 void InspectorResourceAgent::setFrontend(InspectorFrontend* frontend)
183 {
184     m_frontend = frontend->network();
185 }
186 
clearFrontend()187 void InspectorResourceAgent::clearFrontend()
188 {
189     m_frontend = 0;
190     ErrorString error;
191     disable(&error);
192 }
193 
restore()194 void InspectorResourceAgent::restore()
195 {
196     if (m_state->getBoolean(ResourceAgentState::resourceAgentEnabled))
197         enable();
198 }
199 
buildObjectForTiming(const ResourceLoadTiming & timing,DocumentLoader * loader)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 
buildObjectForResourceRequest(const ResourceRequest & request)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 
buildObjectForResourceResponse(const ResourceResponse & response,DocumentLoader * loader)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 
~InspectorResourceAgent()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 
willSendRequest(unsigned long identifier,DocumentLoader * loader,ResourceRequest & request,const ResourceResponse & redirectResponse,const FetchInitiatorInfo & initiatorInfo)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 
markResourceAsCached(unsigned long identifier)327 void InspectorResourceAgent::markResourceAsCached(unsigned long identifier)
328 {
329     m_frontend->requestServedFromCache(IdentifiersFactory::requestId(identifier));
330 }
331 
didReceiveResourceResponse(Frame *,unsigned long identifier,DocumentLoader * loader,const ResourceResponse & response,ResourceLoader * resourceLoader)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 
isErrorStatusCode(int statusCode)372 static bool isErrorStatusCode(int statusCode)
373 {
374     return statusCode >= 400;
375 }
376 
didReceiveData(unsigned long identifier,const char * data,int dataLength,int encodedDataLength)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 
didFinishLoading(unsigned long identifier,DocumentLoader * loader,double monotonicFinishTime)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 
didReceiveCORSRedirectResponse(Frame * frame,unsigned long identifier,DocumentLoader * loader,const ResourceResponse & response,ResourceLoader * resourceLoader)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 
didFailLoading(unsigned long identifier,DocumentLoader * loader,const ResourceError & error)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 
scriptImported(unsigned long identifier,const String & sourceString)418 void InspectorResourceAgent::scriptImported(unsigned long identifier, const String& sourceString)
419 {
420     m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
421 }
422 
didReceiveScriptResponse(unsigned long identifier)423 void InspectorResourceAgent::didReceiveScriptResponse(unsigned long identifier)
424 {
425     m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::ScriptResource);
426 }
427 
documentThreadableLoaderStartedLoadingForClient(unsigned long identifier,ThreadableLoaderClient * client)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 
willLoadXHR(XMLHttpRequest *,ThreadableLoaderClient * client,const AtomicString & method,const KURL & url,bool async,PassRefPtr<FormData> formData,const HTTPHeaderMap & headers,bool includeCredentials)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 
didFailXHRLoading(XMLHttpRequest *,ThreadableLoaderClient * client)451 void InspectorResourceAgent::didFailXHRLoading(XMLHttpRequest*, ThreadableLoaderClient* client)
452 {
453     m_pendingXHRReplayData.remove(client);
454 }
455 
didFinishXHRLoading(XMLHttpRequest *,ThreadableLoaderClient * client,unsigned long identifier,ScriptString sourceString,const String &,const String &,unsigned)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 
willDestroyResource(Resource * cachedResource)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 
applyUserAgentOverride(String * userAgent)476 void InspectorResourceAgent::applyUserAgentOverride(String* userAgent)
477 {
478     String userAgentOverride = m_state->getString(ResourceAgentState::userAgentOverride);
479     if (!userAgentOverride.isEmpty())
480         *userAgent = userAgentOverride;
481 }
482 
willRecalculateStyle(Document *)483 void InspectorResourceAgent::willRecalculateStyle(Document*)
484 {
485     m_isRecalculatingStyle = true;
486 }
487 
didRecalculateStyle()488 void InspectorResourceAgent::didRecalculateStyle()
489 {
490     m_isRecalculatingStyle = false;
491     m_styleRecalculationInitiator = nullptr;
492 }
493 
didScheduleStyleRecalculation(Document * document)494 void InspectorResourceAgent::didScheduleStyleRecalculation(Document* document)
495 {
496     if (!m_styleRecalculationInitiator)
497         m_styleRecalculationInitiator = buildInitiatorObject(document, FetchInitiatorInfo());
498 }
499 
buildInitiatorObject(Document * document,const FetchInitiatorInfo & initiatorInfo)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 
didCreateWebSocket(Document *,unsigned long identifier,const KURL & requestURL,const String &)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 
willSendWebSocketHandshakeRequest(Document *,unsigned long identifier,const WebSocketHandshakeRequest & request)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 
didReceiveWebSocketHandshakeResponse(Document *,unsigned long identifier,const WebSocketHandshakeResponse & response)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 
didCloseWebSocket(Document *,unsigned long identifier)550 void InspectorResourceAgent::didCloseWebSocket(Document*, unsigned long identifier)
551 {
552     m_frontend->webSocketClosed(IdentifiersFactory::requestId(identifier), currentTime());
553 }
554 
didReceiveWebSocketFrame(unsigned long identifier,const WebSocketFrame & frame)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 
didSendWebSocketFrame(unsigned long identifier,const WebSocketFrame & frame)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 
didReceiveWebSocketFrameError(unsigned long identifier,const String & errorMessage)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.
setResourcesDataSizeLimitsFromInternals(int maximumResourcesContentSize,int maximumSingleResourceContentSize)579 void InspectorResourceAgent::setResourcesDataSizeLimitsFromInternals(int maximumResourcesContentSize, int maximumSingleResourceContentSize)
580 {
581     m_resourcesData->setResourcesDataSizeLimits(maximumResourcesContentSize, maximumSingleResourceContentSize);
582 }
583 
enable(ErrorString *)584 void InspectorResourceAgent::enable(ErrorString*)
585 {
586     enable();
587 }
588 
enable()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 
disable(ErrorString *)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 
setUserAgentOverride(ErrorString *,const String & userAgent)605 void InspectorResourceAgent::setUserAgentOverride(ErrorString*, const String& userAgent)
606 {
607     m_state->setString(ResourceAgentState::userAgentOverride, userAgent);
608 }
609 
setExtraHTTPHeaders(ErrorString *,const RefPtr<JSONObject> & headers)610 void InspectorResourceAgent::setExtraHTTPHeaders(ErrorString*, const RefPtr<JSONObject>& headers)
611 {
612     m_state->setObject(ResourceAgentState::extraRequestHeaders, headers);
613 }
614 
getResponseBody(ErrorString * errorString,const String & requestId,String * content,bool * base64Encoded)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 
replayXHR(ErrorString *,const String & requestId)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 
canClearBrowserCache(ErrorString *,bool * result)668 void InspectorResourceAgent::canClearBrowserCache(ErrorString*, bool* result)
669 {
670     *result = true;
671 }
672 
clearBrowserCache(ErrorString *)673 void InspectorResourceAgent::clearBrowserCache(ErrorString*)
674 {
675     m_client->clearBrowserCache();
676 }
677 
canClearBrowserCookies(ErrorString *,bool * result)678 void InspectorResourceAgent::canClearBrowserCookies(ErrorString*, bool* result)
679 {
680     *result = true;
681 }
682 
clearBrowserCookies(ErrorString *)683 void InspectorResourceAgent::clearBrowserCookies(ErrorString*)
684 {
685     m_client->clearBrowserCookies();
686 }
687 
setCacheDisabled(ErrorString *,bool cacheDisabled)688 void InspectorResourceAgent::setCacheDisabled(ErrorString*, bool cacheDisabled)
689 {
690     m_state->setBoolean(ResourceAgentState::cacheDisabled, cacheDisabled);
691     if (cacheDisabled)
692         memoryCache()->evictResources();
693 }
694 
loadResourceForFrontend(ErrorString * errorString,const String & frameId,const String & url,const RefPtr<JSONObject> * requestHeaders,PassRefPtr<LoadResourceForFrontendCallback> prpCallback)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 
didCommitLoad(Frame * frame,DocumentLoader * loader)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 
frameScheduledNavigation(Frame * frame,double)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 
frameClearedScheduledNavigation(Frame * frame)757 void InspectorResourceAgent::frameClearedScheduledNavigation(Frame* frame)
758 {
759     m_frameNavigationInitiatorMap.remove(m_pageAgent->frameId(frame));
760 }
761 
fetchResourceContent(Frame * frame,const KURL & url,String * content,bool * base64Encoded)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 
InspectorResourceAgent(InstrumentingAgents * instrumentingAgents,InspectorPageAgent * pageAgent,InspectorClient * client,InspectorCompositeState * state)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