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