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