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