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