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