Unreviewed, rolling out r123715.
[WebKit-https.git] / Source / WebCore / 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
33 #if ENABLE(INSPECTOR)
34
35 #include "InspectorResourceAgent.h"
36
37 #include "CachedResource.h"
38 #include "CachedResourceLoader.h"
39 #include "Document.h"
40 #include "DocumentLoader.h"
41 #include "Frame.h"
42 #include "FrameLoader.h"
43 #include "HTTPHeaderMap.h"
44 #include "IdentifiersFactory.h"
45 #include "InspectorClient.h"
46 #include "InspectorFrontend.h"
47 #include "InspectorPageAgent.h"
48 #include "InspectorState.h"
49 #include "InspectorValues.h"
50 #include "InstrumentingAgents.h"
51 #include "KURL.h"
52 #include "MemoryCache.h"
53 #include "NetworkResourcesData.h"
54 #include "Page.h"
55 #include "ProgressTracker.h"
56 #include "ResourceError.h"
57 #include "ResourceRequest.h"
58 #include "ResourceResponse.h"
59 #include "ScriptCallStack.h"
60 #include "ScriptCallStackFactory.h"
61 #include "ScriptableDocumentParser.h"
62 #include "WebSocketFrame.h"
63 #include "WebSocketHandshakeRequest.h"
64 #include "WebSocketHandshakeResponse.h"
65
66 #include <wtf/CurrentTime.h>
67 #include <wtf/HexNumber.h>
68 #include <wtf/ListHashSet.h>
69 #include <wtf/RefPtr.h>
70 #include <wtf/text/StringBuilder.h>
71
72 namespace WebCore {
73
74 namespace ResourceAgentState {
75 static const char resourceAgentEnabled[] = "resourceAgentEnabled";
76 static const char extraRequestHeaders[] = "extraRequestHeaders";
77 static const char cacheDisabled[] = "cacheDisabled";
78 static const char userAgentOverride[] = "userAgentOverride";
79 }
80
81 void InspectorResourceAgent::setFrontend(InspectorFrontend* frontend)
82 {
83     m_frontend = frontend->network();
84 }
85
86 void InspectorResourceAgent::clearFrontend()
87 {
88     m_frontend = 0;
89     ErrorString error;
90     disable(&error);
91 }
92
93 void InspectorResourceAgent::restore()
94 {
95     if (m_state->getBoolean(ResourceAgentState::resourceAgentEnabled))
96         enable();
97 }
98
99 static PassRefPtr<InspectorObject> buildObjectForHeaders(const HTTPHeaderMap& headers)
100 {
101     RefPtr<InspectorObject> headersObject = InspectorObject::create();
102     HTTPHeaderMap::const_iterator end = headers.end();
103     for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it)
104         headersObject->setString(it->first.string(), it->second);
105     return headersObject;
106 }
107
108 static PassRefPtr<TypeBuilder::Network::ResourceTiming> buildObjectForTiming(const ResourceLoadTiming& timing, DocumentLoader* loader)
109 {
110     return TypeBuilder::Network::ResourceTiming::create()
111         .setRequestTime(timing.convertResourceLoadTimeToDocumentTime(loader->timing(), 0))
112         .setProxyStart(timing.proxyStart)
113         .setProxyEnd(timing.proxyEnd)
114         .setDnsStart(timing.dnsStart)
115         .setDnsEnd(timing.dnsEnd)
116         .setConnectStart(timing.connectStart)
117         .setConnectEnd(timing.connectEnd)
118         .setSslStart(timing.sslStart)
119         .setSslEnd(timing.sslEnd)
120         .setSendStart(timing.sendStart)
121         .setSendEnd(timing.sendEnd)
122         .setReceiveHeadersEnd(timing.receiveHeadersEnd)
123         .release();
124 }
125
126 static PassRefPtr<TypeBuilder::Network::Request> buildObjectForResourceRequest(const ResourceRequest& request)
127 {
128     RefPtr<TypeBuilder::Network::Request> requestObject = TypeBuilder::Network::Request::create()
129         .setUrl(request.url().string())
130         .setMethod(request.httpMethod())
131         .setHeaders(buildObjectForHeaders(request.httpHeaderFields()));
132     if (request.httpBody() && !request.httpBody()->isEmpty())
133         requestObject->setPostData(request.httpBody()->flattenToString());
134     return requestObject;
135 }
136
137 static PassRefPtr<TypeBuilder::Network::Response> buildObjectForResourceResponse(const ResourceResponse& response, DocumentLoader* loader)
138 {
139     if (response.isNull())
140         return 0;
141
142
143     double status;
144     String statusText;
145     if (response.resourceLoadInfo() && response.resourceLoadInfo()->httpStatusCode) {
146         status = response.resourceLoadInfo()->httpStatusCode;
147         statusText = response.resourceLoadInfo()->httpStatusText;
148     } else {
149         status = response.httpStatusCode();
150         statusText = response.httpStatusText();
151     }
152     RefPtr<InspectorObject> headers;
153     if (response.resourceLoadInfo())
154         headers = buildObjectForHeaders(response.resourceLoadInfo()->responseHeaders);
155     else
156         headers = buildObjectForHeaders(response.httpHeaderFields());
157
158     RefPtr<TypeBuilder::Network::Response> responseObject = TypeBuilder::Network::Response::create()
159         .setUrl(response.url().string())
160         .setStatus(status)
161         .setStatusText(statusText)
162         .setHeaders(headers)
163         .setMimeType(response.mimeType())
164         .setConnectionReused(response.connectionReused())
165         .setConnectionId(response.connectionID());
166
167     responseObject->setFromDiskCache(response.wasCached());
168     if (response.resourceLoadTiming())
169         responseObject->setTiming(buildObjectForTiming(*response.resourceLoadTiming(), loader));
170
171     if (response.resourceLoadInfo()) {
172         if (!response.resourceLoadInfo()->responseHeadersText.isEmpty())
173             responseObject->setHeadersText(response.resourceLoadInfo()->responseHeadersText);
174
175         responseObject->setRequestHeaders(buildObjectForHeaders(response.resourceLoadInfo()->requestHeaders));
176         if (!response.resourceLoadInfo()->requestHeadersText.isEmpty())
177             responseObject->setRequestHeadersText(response.resourceLoadInfo()->requestHeadersText);
178     }
179
180     return responseObject;
181 }
182
183 static PassRefPtr<TypeBuilder::Network::CachedResource> buildObjectForCachedResource(const CachedResource& cachedResource, DocumentLoader* loader)
184 {
185     RefPtr<TypeBuilder::Network::CachedResource> resourceObject = TypeBuilder::Network::CachedResource::create()
186         .setUrl(cachedResource.url())
187         .setType(InspectorPageAgent::cachedResourceTypeJson(cachedResource))
188         .setBodySize(cachedResource.encodedSize());
189     RefPtr<TypeBuilder::Network::Response> resourceResponse = buildObjectForResourceResponse(cachedResource.response(), loader);
190     if (resourceResponse)
191         resourceObject->setResponse(resourceResponse);
192     return resourceObject;
193 }
194
195 InspectorResourceAgent::~InspectorResourceAgent()
196 {
197     if (m_state->getBoolean(ResourceAgentState::resourceAgentEnabled)) {
198         ErrorString error;
199         disable(&error);
200     }
201     ASSERT(!m_instrumentingAgents->inspectorResourceAgent());
202 }
203
204 void InspectorResourceAgent::willSendRequest(unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse)
205 {
206     String requestId = IdentifiersFactory::requestId(identifier);
207     m_resourcesData->resourceCreated(requestId, m_pageAgent->loaderId(loader));
208
209     RefPtr<InspectorObject> headers = m_state->getObject(ResourceAgentState::extraRequestHeaders);
210
211     if (headers) {
212         InspectorObject::const_iterator end = headers->end();
213         for (InspectorObject::const_iterator it = headers->begin(); it != end; ++it) {
214             String value;
215             if (it->second->asString(&value))
216                 request.setHTTPHeaderField(it->first, value);
217         }
218     }
219
220     request.setReportLoadTiming(true);
221     request.setReportRawHeaders(true);
222
223     if (m_state->getBoolean(ResourceAgentState::cacheDisabled)) {
224         request.setCachePolicy(ReloadIgnoringCacheData);
225         request.setHTTPHeaderField("Pragma", "no-cache");
226         request.setHTTPHeaderField("Cache-Control", "no-cache");
227     }
228
229     RefPtr<TypeBuilder::Network::Initiator> initiatorObject = buildInitiatorObject(loader->frame() ? loader->frame()->document() : 0);
230     m_frontend->requestWillBeSent(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), loader->url().string(), buildObjectForResourceRequest(request), currentTime(), initiatorObject, buildObjectForResourceResponse(redirectResponse, loader));
231 }
232
233 void InspectorResourceAgent::markResourceAsCached(unsigned long identifier)
234 {
235     m_frontend->requestServedFromCache(IdentifiersFactory::requestId(identifier));
236 }
237
238 void InspectorResourceAgent::didReceiveResponse(unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response)
239 {
240     String requestId = IdentifiersFactory::requestId(identifier);
241     RefPtr<TypeBuilder::Network::Response> resourceResponse = buildObjectForResourceResponse(response, loader);
242     InspectorPageAgent::ResourceType type = InspectorPageAgent::OtherResource;
243     long cachedResourceSize = 0;
244
245     if (loader) {
246         CachedResource* cachedResource = InspectorPageAgent::cachedResource(loader->frame(), response.url());
247         if (cachedResource) {
248             type = InspectorPageAgent::cachedResourceType(*cachedResource);
249             cachedResourceSize = cachedResource->encodedSize();
250             // Use mime type from cached resource in case the one in response is empty.
251             if (resourceResponse && response.mimeType().isEmpty())
252                 resourceResponse->setString(TypeBuilder::Network::Response::MimeType, cachedResource->response().mimeType());
253
254             m_resourcesData->addCachedResource(requestId, cachedResource);
255         }
256         if (m_loadingXHRSynchronously || m_resourcesData->resourceType(requestId) == InspectorPageAgent::XHRResource)
257             type = InspectorPageAgent::XHRResource;
258         else if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::ScriptResource)
259             type = InspectorPageAgent::ScriptResource;
260         else if (equalIgnoringFragmentIdentifier(response.url(), loader->frameLoader()->icon()->url()))
261             type = InspectorPageAgent::ImageResource;
262         else if (equalIgnoringFragmentIdentifier(response.url(), loader->url()) && !loader->isCommitted())
263             type = InspectorPageAgent::DocumentResource;
264
265         m_resourcesData->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), response);
266     }
267     m_resourcesData->setResourceType(requestId, type);
268     m_frontend->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), currentTime(), InspectorPageAgent::resourceTypeJson(type), resourceResponse);
269     // If we revalidated the resource and got Not modified, send content length following didReceiveResponse
270     // as there will be no calls to didReceiveData from the network stack.
271     if (cachedResourceSize && response.httpStatusCode() == 304)
272         didReceiveData(identifier, 0, cachedResourceSize, 0);
273 }
274
275 static bool isErrorStatusCode(int statusCode)
276 {
277     return statusCode >= 400;
278 }
279
280 void InspectorResourceAgent::didReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
281 {
282     String requestId = IdentifiersFactory::requestId(identifier);
283
284     if (data) {
285         NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
286         if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::OtherResource || (resourceData && isErrorStatusCode(resourceData->httpStatusCode()) && (resourceData->cachedResource())))
287             m_resourcesData->maybeAddResourceData(requestId, data, dataLength);
288     }
289
290     m_frontend->dataReceived(requestId, currentTime(), dataLength, encodedDataLength);
291 }
292
293 void InspectorResourceAgent::didFinishLoading(unsigned long identifier, DocumentLoader* loader, double finishTime)
294 {
295     String requestId = IdentifiersFactory::requestId(identifier);
296     if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource)
297         m_resourcesData->addResourceSharedBuffer(requestId, loader->frameLoader()->documentLoader()->mainResourceData(), loader->frame()->document()->inputEncoding());
298
299     m_resourcesData->maybeDecodeDataToContent(requestId);
300
301     if (!finishTime)
302         finishTime = currentTime();
303
304     m_frontend->loadingFinished(requestId, finishTime);
305 }
306
307 void InspectorResourceAgent::didFailLoading(unsigned long identifier, DocumentLoader* loader, const ResourceError& error)
308 {
309     String requestId = IdentifiersFactory::requestId(identifier);
310
311     if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource) {
312         Frame* frame = loader ? loader->frame() : 0;
313         if (frame && frame->loader()->documentLoader() && frame->document())
314             m_resourcesData->addResourceSharedBuffer(requestId, frame->loader()->documentLoader()->mainResourceData(), frame->document()->inputEncoding());
315     }
316
317     bool canceled = error.isCancellation();
318     m_frontend->loadingFailed(requestId, currentTime(), error.localizedDescription(), canceled ? &canceled : 0);
319 }
320
321 void InspectorResourceAgent::didLoadResourceFromMemoryCache(DocumentLoader* loader, CachedResource* resource)
322 {
323     String loaderId = m_pageAgent->loaderId(loader);
324     String frameId = m_pageAgent->frameId(loader->frame());
325     unsigned long identifier = loader->frame()->page()->progress()->createUniqueIdentifier();
326     String requestId = IdentifiersFactory::requestId(identifier);
327     m_resourcesData->resourceCreated(requestId, loaderId);
328     m_resourcesData->addCachedResource(requestId, resource);
329     RefPtr<TypeBuilder::Network::Initiator> initiatorObject = buildInitiatorObject(loader->frame() ? loader->frame()->document() : 0);
330
331     m_frontend->requestServedFromMemoryCache(requestId, frameId, loaderId, loader->url().string(), currentTime(), initiatorObject, buildObjectForCachedResource(*resource, loader));
332 }
333
334 void InspectorResourceAgent::setInitialScriptContent(unsigned long identifier, const String& sourceString)
335 {
336     m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
337 }
338
339 void InspectorResourceAgent::didReceiveScriptResponse(unsigned long identifier)
340 {
341     m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::ScriptResource);
342 }
343
344 void InspectorResourceAgent::setInitialXHRContent(unsigned long identifier, const String& sourceString)
345 {
346     // For Asynchronous XHRs, the inspector can grab the data directly off of the CachedResource. For sync XHRs, we need to
347     // provide the data here, since no CachedResource was involved.
348     if (m_loadingXHRSynchronously)
349         m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
350 }
351
352 void InspectorResourceAgent::didReceiveXHRResponse(unsigned long identifier)
353 {
354     m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::XHRResource);
355 }
356
357 void InspectorResourceAgent::willLoadXHRSynchronously()
358 {
359     m_loadingXHRSynchronously = true;
360 }
361
362 void InspectorResourceAgent::didLoadXHRSynchronously()
363 {
364     m_loadingXHRSynchronously = false;
365 }
366
367 void InspectorResourceAgent::applyUserAgentOverride(String* userAgent)
368 {
369     String userAgentOverride = m_state->getString(ResourceAgentState::userAgentOverride);
370     if (!userAgentOverride.isEmpty())
371         *userAgent = userAgentOverride;
372 }
373
374 void InspectorResourceAgent::willRecalculateStyle()
375 {
376     m_isRecalculatingStyle = true;
377 }
378
379 void InspectorResourceAgent::didRecalculateStyle()
380 {
381     m_isRecalculatingStyle = false;
382     m_styleRecalculationInitiator = nullptr;
383 }
384
385 void InspectorResourceAgent::didScheduleStyleRecalculation(Document* document)
386 {
387     if (!m_styleRecalculationInitiator)
388         m_styleRecalculationInitiator = buildInitiatorObject(document);
389 }
390
391 PassRefPtr<TypeBuilder::Network::Initiator> InspectorResourceAgent::buildInitiatorObject(Document* document)
392 {
393     RefPtr<ScriptCallStack> stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
394     if (stackTrace && stackTrace->size() > 0) {
395         RefPtr<TypeBuilder::Network::Initiator> initiatorObject = TypeBuilder::Network::Initiator::create()
396             .setType(TypeBuilder::Network::Initiator::Type::Script);
397         initiatorObject->setStackTrace(stackTrace->buildInspectorArray());
398         return initiatorObject;
399     }
400
401     if (document && document->scriptableDocumentParser()) {
402         RefPtr<TypeBuilder::Network::Initiator> initiatorObject = TypeBuilder::Network::Initiator::create()
403             .setType(TypeBuilder::Network::Initiator::Type::Parser);
404         initiatorObject->setUrl(document->url().string());
405         initiatorObject->setLineNumber(document->scriptableDocumentParser()->lineNumber().oneBasedInt());
406         return initiatorObject;
407     }
408
409     if (m_isRecalculatingStyle && m_styleRecalculationInitiator)
410         return m_styleRecalculationInitiator;
411
412     return TypeBuilder::Network::Initiator::create()
413         .setType(TypeBuilder::Network::Initiator::Type::Other)
414         .release();
415 }
416
417 #if ENABLE(WEB_SOCKETS)
418
419 // FIXME: More this into the front-end?
420 // Create human-readable binary representation, like "01:23:45:67:89:AB:CD:EF".
421 static String createReadableStringFromBinary(const unsigned char* value, size_t length)
422 {
423     ASSERT(length > 0);
424     StringBuilder builder;
425     builder.reserveCapacity(length * 3 - 1);
426     for (size_t i = 0; i < length; ++i) {
427         if (i > 0)
428             builder.append(':');
429         appendByteAsHex(value[i], builder);
430     }
431     return builder.toString();
432 }
433
434 void InspectorResourceAgent::didCreateWebSocket(unsigned long identifier, const KURL& requestURL)
435 {
436     m_frontend->webSocketCreated(IdentifiersFactory::requestId(identifier), requestURL.string());
437 }
438
439 void InspectorResourceAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, const WebSocketHandshakeRequest& request)
440 {
441     RefPtr<TypeBuilder::Network::WebSocketRequest> requestObject = TypeBuilder::Network::WebSocketRequest::create()
442         .setRequestKey3(createReadableStringFromBinary(request.key3().value, sizeof(request.key3().value)))
443         .setHeaders(buildObjectForHeaders(request.headerFields()));
444     m_frontend->webSocketWillSendHandshakeRequest(IdentifiersFactory::requestId(identifier), currentTime(), requestObject);
445 }
446
447 void InspectorResourceAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const WebSocketHandshakeResponse& response)
448 {
449     RefPtr<TypeBuilder::Network::WebSocketResponse> responseObject = TypeBuilder::Network::WebSocketResponse::create()
450         .setStatus(response.statusCode())
451         .setStatusText(response.statusText())
452         .setHeaders(buildObjectForHeaders(response.headerFields()))
453         .setChallengeResponse(createReadableStringFromBinary(response.challengeResponse().value, sizeof(response.challengeResponse().value)));
454     m_frontend->webSocketHandshakeResponseReceived(IdentifiersFactory::requestId(identifier), currentTime(), responseObject);
455 }
456
457 void InspectorResourceAgent::didCloseWebSocket(unsigned long identifier)
458 {
459     m_frontend->webSocketClosed(IdentifiersFactory::requestId(identifier), currentTime());
460 }
461
462 void InspectorResourceAgent::didReceiveWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
463 {
464     RefPtr<TypeBuilder::Network::WebSocketFrame> frameObject = TypeBuilder::Network::WebSocketFrame::create()
465         .setOpcode(frame.opCode)
466         .setMask(frame.masked)
467         .setPayloadData(String(frame.payload, frame.payloadLength));
468     m_frontend->webSocketFrameReceived(IdentifiersFactory::requestId(identifier), currentTime(), frameObject);
469 }
470
471 void InspectorResourceAgent::didSendWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
472 {
473     RefPtr<TypeBuilder::Network::WebSocketFrame> frameObject = TypeBuilder::Network::WebSocketFrame::create()
474         .setOpcode(frame.opCode)
475         .setMask(frame.masked)
476         .setPayloadData(String(frame.payload, frame.payloadLength));
477     m_frontend->webSocketFrameSent(IdentifiersFactory::requestId(identifier), currentTime(), frameObject);
478 }
479
480 void InspectorResourceAgent::didReceiveWebSocketFrameError(unsigned long identifier, const String& errorMessage)
481 {
482     m_frontend->webSocketFrameError(IdentifiersFactory::requestId(identifier), currentTime(), errorMessage);
483 }
484
485 #endif // ENABLE(WEB_SOCKETS)
486
487 // called from Internals for layout test purposes.
488 void InspectorResourceAgent::setResourcesDataSizeLimitsFromInternals(int maximumResourcesContentSize, int maximumSingleResourceContentSize)
489 {
490     m_resourcesData->setResourcesDataSizeLimits(maximumResourcesContentSize, maximumSingleResourceContentSize);
491 }
492
493 void InspectorResourceAgent::enable(ErrorString*)
494 {
495     enable();
496 }
497
498 void InspectorResourceAgent::enable()
499 {
500     if (!m_frontend)
501         return;
502     m_state->setBoolean(ResourceAgentState::resourceAgentEnabled, true);
503     m_instrumentingAgents->setInspectorResourceAgent(this);
504 }
505
506 void InspectorResourceAgent::disable(ErrorString*)
507 {
508     m_state->setBoolean(ResourceAgentState::resourceAgentEnabled, false);
509     m_instrumentingAgents->setInspectorResourceAgent(0);
510     m_resourcesData->clear();
511 }
512
513 void InspectorResourceAgent::setUserAgentOverride(ErrorString*, const String& userAgent)
514 {
515     m_state->setString(ResourceAgentState::userAgentOverride, userAgent);
516 }
517
518 void InspectorResourceAgent::setExtraHTTPHeaders(ErrorString*, const RefPtr<InspectorObject>& headers)
519 {
520     m_state->setObject(ResourceAgentState::extraRequestHeaders, headers);
521 }
522
523 void InspectorResourceAgent::getResponseBody(ErrorString* errorString, const String& requestId, String* content, bool* base64Encoded)
524 {
525     NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
526     if (!resourceData) {
527         *errorString = "No resource with given identifier found";
528         return;
529     }
530
531     if (resourceData->hasContent()) {
532         *base64Encoded = false;
533         *content = resourceData->content();
534         return;
535     }
536
537     if (resourceData->buffer() && !resourceData->textEncodingName().isNull()) {
538         *base64Encoded = false;
539         if (InspectorPageAgent::sharedBufferContent(resourceData->buffer(), resourceData->textEncodingName(), *base64Encoded, content))
540             return;
541     }
542
543     if (resourceData->cachedResource()) {
544         if (InspectorPageAgent::cachedResourceContent(resourceData->cachedResource(), content, base64Encoded))
545             return;
546     }
547
548     *errorString = "No data found for resource with given identifier";
549 }
550
551 void InspectorResourceAgent::canClearBrowserCache(ErrorString*, bool* result)
552 {
553     *result = m_client->canClearBrowserCache();
554 }
555
556 void InspectorResourceAgent::clearBrowserCache(ErrorString*)
557 {
558     m_client->clearBrowserCache();
559 }
560
561 void InspectorResourceAgent::canClearBrowserCookies(ErrorString*, bool* result)
562 {
563     *result = m_client->canClearBrowserCookies();
564 }
565
566 void InspectorResourceAgent::clearBrowserCookies(ErrorString*)
567 {
568     m_client->clearBrowserCookies();
569 }
570
571 void InspectorResourceAgent::setCacheDisabled(ErrorString*, bool cacheDisabled)
572 {
573     m_state->setBoolean(ResourceAgentState::cacheDisabled, cacheDisabled);
574     if (cacheDisabled)
575         memoryCache()->evictResources();
576 }
577
578 void InspectorResourceAgent::mainFrameNavigated(DocumentLoader* loader)
579 {
580     if (m_state->getBoolean(ResourceAgentState::cacheDisabled))
581         memoryCache()->evictResources();
582
583     m_resourcesData->clear(m_pageAgent->loaderId(loader));
584 }
585
586 InspectorResourceAgent::InspectorResourceAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorClient* client, InspectorState* state)
587     : InspectorBaseAgent<InspectorResourceAgent>("Network", instrumentingAgents, state)
588     , m_pageAgent(pageAgent)
589     , m_client(client)
590     , m_frontend(0)
591     , m_resourcesData(adoptPtr(new NetworkResourcesData()))
592     , m_loadingXHRSynchronously(false)
593     , m_isRecalculatingStyle(false)
594 {
595 }
596
597 } // namespace WebCore
598
599 #endif // ENABLE(INSPECTOR)