• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
20  * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 #include "core/inspector/NetworkResourcesData.h"
31 
32 #include "core/dom/DOMImplementation.h"
33 #include "core/fetch/Resource.h"
34 #include "platform/SharedBuffer.h"
35 #include "platform/network/ResourceResponse.h"
36 
37 namespace {
38 // 100MB
39 static size_t maximumResourcesContentSize = 100 * 1000 * 1000;
40 
41 // 10MB
42 static size_t maximumSingleResourceContentSize = 10 * 1000 * 1000;
43 }
44 
45 namespace WebCore {
46 
47 
create(const AtomicString & method,const KURL & url,bool async,PassRefPtr<FormData> formData,bool includeCredentials)48 PassRefPtr<XHRReplayData> XHRReplayData::create(const AtomicString& method, const KURL& url, bool async, PassRefPtr<FormData> formData, bool includeCredentials)
49 {
50     return adoptRef(new XHRReplayData(method, url, async, formData, includeCredentials));
51 }
52 
addHeader(const AtomicString & key,const AtomicString & value)53 void XHRReplayData::addHeader(const AtomicString& key, const AtomicString& value)
54 {
55     m_headers.set(key, value);
56 }
57 
XHRReplayData(const AtomicString & method,const KURL & url,bool async,PassRefPtr<FormData> formData,bool includeCredentials)58 XHRReplayData::XHRReplayData(const AtomicString& method, const KURL& url, bool async, PassRefPtr<FormData> formData, bool includeCredentials)
59     : m_method(method)
60     , m_url(url)
61     , m_async(async)
62     , m_formData(formData)
63     , m_includeCredentials(includeCredentials)
64 {
65 }
66 
67 // ResourceData
ResourceData(const String & requestId,const String & loaderId)68 NetworkResourcesData::ResourceData::ResourceData(const String& requestId, const String& loaderId)
69     : m_requestId(requestId)
70     , m_loaderId(loaderId)
71     , m_base64Encoded(false)
72     , m_isContentEvicted(false)
73     , m_type(InspectorPageAgent::OtherResource)
74     , m_cachedResource(0)
75 {
76 }
77 
setContent(const String & content,bool base64Encoded)78 void NetworkResourcesData::ResourceData::setContent(const String& content, bool base64Encoded)
79 {
80     ASSERT(!hasData());
81     ASSERT(!hasContent());
82     m_content = content;
83     m_base64Encoded = base64Encoded;
84 }
85 
contentSizeInBytes(const String & content)86 static size_t contentSizeInBytes(const String& content)
87 {
88     return content.isNull() ? 0 : content.impl()->sizeInBytes();
89 }
90 
removeContent()91 unsigned NetworkResourcesData::ResourceData::removeContent()
92 {
93     unsigned result = 0;
94     if (hasData()) {
95         ASSERT(!hasContent());
96         result = m_dataBuffer->size();
97         m_dataBuffer = nullptr;
98     }
99 
100     if (hasContent()) {
101         ASSERT(!hasData());
102         result = contentSizeInBytes(m_content);
103         m_content = String();
104     }
105     return result;
106 }
107 
evictContent()108 unsigned NetworkResourcesData::ResourceData::evictContent()
109 {
110     m_isContentEvicted = true;
111     return removeContent();
112 }
113 
dataLength() const114 size_t NetworkResourcesData::ResourceData::dataLength() const
115 {
116     return m_dataBuffer ? m_dataBuffer->size() : 0;
117 }
118 
appendData(const char * data,size_t dataLength)119 void NetworkResourcesData::ResourceData::appendData(const char* data, size_t dataLength)
120 {
121     ASSERT(!hasContent());
122     if (!m_dataBuffer)
123         m_dataBuffer = SharedBuffer::create(data, dataLength);
124     else
125         m_dataBuffer->append(data, dataLength);
126 }
127 
decodeDataToContent()128 size_t NetworkResourcesData::ResourceData::decodeDataToContent()
129 {
130     ASSERT(!hasContent());
131     size_t dataLength = m_dataBuffer->size();
132     m_content = m_decoder->decode(m_dataBuffer->data(), m_dataBuffer->size());
133     m_content.append(m_decoder->flush());
134     m_dataBuffer = nullptr;
135     return contentSizeInBytes(m_content) - dataLength;
136 }
137 
138 // NetworkResourcesData
NetworkResourcesData()139 NetworkResourcesData::NetworkResourcesData()
140     : m_contentSize(0)
141     , m_maximumResourcesContentSize(maximumResourcesContentSize)
142     , m_maximumSingleResourceContentSize(maximumSingleResourceContentSize)
143 {
144 }
145 
~NetworkResourcesData()146 NetworkResourcesData::~NetworkResourcesData()
147 {
148     clear();
149 }
150 
resourceCreated(const String & requestId,const String & loaderId)151 void NetworkResourcesData::resourceCreated(const String& requestId, const String& loaderId)
152 {
153     ensureNoDataForRequestId(requestId);
154     m_requestIdToResourceDataMap.set(requestId, new ResourceData(requestId, loaderId));
155 }
156 
createOtherResourceTextDecoder(const String & mimeType,const String & textEncodingName)157 static PassOwnPtr<TextResourceDecoder> createOtherResourceTextDecoder(const String& mimeType, const String& textEncodingName)
158 {
159     OwnPtr<TextResourceDecoder> decoder;
160     if (!textEncodingName.isEmpty())
161         decoder = TextResourceDecoder::create("text/plain", textEncodingName);
162     else if (DOMImplementation::isXMLMIMEType(mimeType.lower())) {
163         decoder = TextResourceDecoder::create("application/xml");
164         decoder->useLenientXMLDecoding();
165     } else if (equalIgnoringCase(mimeType, "text/html"))
166         decoder = TextResourceDecoder::create("text/html", "UTF-8");
167     else if (mimeType == "text/plain")
168         decoder = TextResourceDecoder::create("text/plain", "ISO-8859-1");
169     return decoder.release();
170 }
171 
responseReceived(const String & requestId,const String & frameId,const ResourceResponse & response)172 void NetworkResourcesData::responseReceived(const String& requestId, const String& frameId, const ResourceResponse& response)
173 {
174     ResourceData* resourceData = resourceDataForRequestId(requestId);
175     if (!resourceData)
176         return;
177     resourceData->setFrameId(frameId);
178     resourceData->setUrl(response.url());
179     resourceData->setDecoder(createOtherResourceTextDecoder(response.mimeType(), response.textEncodingName()));
180     resourceData->setHTTPStatusCode(response.httpStatusCode());
181 }
182 
setResourceType(const String & requestId,InspectorPageAgent::ResourceType type)183 void NetworkResourcesData::setResourceType(const String& requestId, InspectorPageAgent::ResourceType type)
184 {
185     ResourceData* resourceData = resourceDataForRequestId(requestId);
186     if (!resourceData)
187         return;
188     resourceData->setType(type);
189 }
190 
resourceType(const String & requestId)191 InspectorPageAgent::ResourceType NetworkResourcesData::resourceType(const String& requestId)
192 {
193     ResourceData* resourceData = resourceDataForRequestId(requestId);
194     if (!resourceData)
195         return InspectorPageAgent::OtherResource;
196     return resourceData->type();
197 }
198 
setResourceContent(const String & requestId,const String & content,bool base64Encoded)199 void NetworkResourcesData::setResourceContent(const String& requestId, const String& content, bool base64Encoded)
200 {
201     ResourceData* resourceData = resourceDataForRequestId(requestId);
202     if (!resourceData)
203         return;
204     size_t dataLength = contentSizeInBytes(content);
205     if (dataLength > m_maximumSingleResourceContentSize)
206         return;
207     if (resourceData->isContentEvicted())
208         return;
209     if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
210         // We can not be sure that we didn't try to save this request data while it was loading, so remove it, if any.
211         if (resourceData->hasContent())
212             m_contentSize -= resourceData->removeContent();
213         m_requestIdsDeque.append(requestId);
214         resourceData->setContent(content, base64Encoded);
215         m_contentSize += dataLength;
216     }
217 }
218 
maybeAddResourceData(const String & requestId,const char * data,size_t dataLength)219 void NetworkResourcesData::maybeAddResourceData(const String& requestId, const char* data, size_t dataLength)
220 {
221     ResourceData* resourceData = resourceDataForRequestId(requestId);
222     if (!resourceData)
223         return;
224     if (!resourceData->decoder())
225         return;
226     if (resourceData->dataLength() + dataLength > m_maximumSingleResourceContentSize)
227         m_contentSize -= resourceData->evictContent();
228     if (resourceData->isContentEvicted())
229         return;
230     if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
231         m_requestIdsDeque.append(requestId);
232         resourceData->appendData(data, dataLength);
233         m_contentSize += dataLength;
234     }
235 }
236 
maybeDecodeDataToContent(const String & requestId)237 void NetworkResourcesData::maybeDecodeDataToContent(const String& requestId)
238 {
239     ResourceData* resourceData = resourceDataForRequestId(requestId);
240     if (!resourceData)
241         return;
242     if (!resourceData->hasData())
243         return;
244     m_contentSize += resourceData->decodeDataToContent();
245     size_t dataLength = contentSizeInBytes(resourceData->content());
246     if (dataLength > m_maximumSingleResourceContentSize)
247         m_contentSize -= resourceData->evictContent();
248 }
249 
addResource(const String & requestId,Resource * cachedResource)250 void NetworkResourcesData::addResource(const String& requestId, Resource* cachedResource)
251 {
252     ResourceData* resourceData = resourceDataForRequestId(requestId);
253     if (!resourceData)
254         return;
255     resourceData->setResource(cachedResource);
256 }
257 
addResourceSharedBuffer(const String & requestId,PassRefPtr<SharedBuffer> buffer,const String & textEncodingName)258 void NetworkResourcesData::addResourceSharedBuffer(const String& requestId, PassRefPtr<SharedBuffer> buffer, const String& textEncodingName)
259 {
260     ResourceData* resourceData = resourceDataForRequestId(requestId);
261     if (!resourceData)
262         return;
263     resourceData->setBuffer(buffer);
264     resourceData->setTextEncodingName(textEncodingName);
265 }
266 
data(const String & requestId)267 NetworkResourcesData::ResourceData const* NetworkResourcesData::data(const String& requestId)
268 {
269     return resourceDataForRequestId(requestId);
270 }
271 
xhrReplayData(const String & requestId)272 XHRReplayData* NetworkResourcesData::xhrReplayData(const String& requestId)
273 {
274     if (m_reusedXHRReplayDataRequestIds.contains(requestId))
275         return xhrReplayData(m_reusedXHRReplayDataRequestIds.get(requestId));
276 
277     ResourceData* resourceData = resourceDataForRequestId(requestId);
278     if (!resourceData)
279         return 0;
280     return resourceData->xhrReplayData();
281 }
282 
setXHRReplayData(const String & requestId,XHRReplayData * xhrReplayData)283 void NetworkResourcesData::setXHRReplayData(const String& requestId, XHRReplayData* xhrReplayData)
284 {
285     ResourceData* resourceData = resourceDataForRequestId(requestId);
286     if (!resourceData) {
287         Vector<String> result;
288         ReusedRequestIds::iterator it;
289         ReusedRequestIds::iterator end = m_reusedXHRReplayDataRequestIds.end();
290         for (it = m_reusedXHRReplayDataRequestIds.begin(); it != end; ++it) {
291             if (it->value == requestId)
292                 setXHRReplayData(it->key, xhrReplayData);
293         }
294         return;
295     }
296 
297     resourceData->setXHRReplayData(xhrReplayData);
298 }
299 
reuseXHRReplayData(const String & requestId,const String & reusedRequestId)300 void NetworkResourcesData::reuseXHRReplayData(const String& requestId, const String& reusedRequestId)
301 {
302     ResourceData* reusedResourceData = resourceDataForRequestId(reusedRequestId);
303     ResourceData* resourceData = resourceDataForRequestId(requestId);
304     if (!reusedResourceData || !resourceData) {
305         m_reusedXHRReplayDataRequestIds.set(requestId, reusedRequestId);
306         return;
307     }
308 
309     resourceData->setXHRReplayData(reusedResourceData->xhrReplayData());
310 }
311 
resources()312 Vector<NetworkResourcesData::ResourceData*> NetworkResourcesData::resources()
313 {
314     Vector<ResourceData*> result;
315     for (ResourceDataMap::iterator it = m_requestIdToResourceDataMap.begin(); it != m_requestIdToResourceDataMap.end(); ++it)
316         result.append(it->value);
317     return result;
318 }
319 
removeResource(Resource * cachedResource)320 Vector<String> NetworkResourcesData::removeResource(Resource* cachedResource)
321 {
322     Vector<String> result;
323     ResourceDataMap::iterator it;
324     ResourceDataMap::iterator end = m_requestIdToResourceDataMap.end();
325     for (it = m_requestIdToResourceDataMap.begin(); it != end; ++it) {
326         ResourceData* resourceData = it->value;
327         if (resourceData->cachedResource() == cachedResource) {
328             resourceData->setResource(0);
329             result.append(it->key);
330         }
331     }
332 
333     return result;
334 }
335 
clear(const String & preservedLoaderId)336 void NetworkResourcesData::clear(const String& preservedLoaderId)
337 {
338     m_requestIdsDeque.clear();
339     m_contentSize = 0;
340 
341     ResourceDataMap preservedMap;
342 
343     ResourceDataMap::iterator it;
344     ResourceDataMap::iterator end = m_requestIdToResourceDataMap.end();
345     for (it = m_requestIdToResourceDataMap.begin(); it != end; ++it) {
346         ResourceData* resourceData = it->value;
347         if (!preservedLoaderId.isNull() && resourceData->loaderId() == preservedLoaderId)
348             preservedMap.set(it->key, it->value);
349         else
350             delete resourceData;
351     }
352     m_requestIdToResourceDataMap.swap(preservedMap);
353 
354     m_reusedXHRReplayDataRequestIds.clear();
355 }
356 
setResourcesDataSizeLimits(size_t maximumResourcesContentSize,size_t maximumSingleResourceContentSize)357 void NetworkResourcesData::setResourcesDataSizeLimits(size_t maximumResourcesContentSize, size_t maximumSingleResourceContentSize)
358 {
359     clear();
360     m_maximumResourcesContentSize = maximumResourcesContentSize;
361     m_maximumSingleResourceContentSize = maximumSingleResourceContentSize;
362 }
363 
resourceDataForRequestId(const String & requestId)364 NetworkResourcesData::ResourceData* NetworkResourcesData::resourceDataForRequestId(const String& requestId)
365 {
366     if (requestId.isNull())
367         return 0;
368     return m_requestIdToResourceDataMap.get(requestId);
369 }
370 
ensureNoDataForRequestId(const String & requestId)371 void NetworkResourcesData::ensureNoDataForRequestId(const String& requestId)
372 {
373     ResourceData* resourceData = resourceDataForRequestId(requestId);
374     if (!resourceData)
375         return;
376     if (resourceData->hasContent() || resourceData->hasData())
377         m_contentSize -= resourceData->evictContent();
378     delete resourceData;
379     m_requestIdToResourceDataMap.remove(requestId);
380 }
381 
ensureFreeSpace(size_t size)382 bool NetworkResourcesData::ensureFreeSpace(size_t size)
383 {
384     if (size > m_maximumResourcesContentSize)
385         return false;
386 
387     while (size > m_maximumResourcesContentSize - m_contentSize) {
388         String requestId = m_requestIdsDeque.takeFirst();
389         ResourceData* resourceData = resourceDataForRequestId(requestId);
390         if (resourceData)
391             m_contentSize -= resourceData->evictContent();
392     }
393     return true;
394 }
395 
396 } // namespace WebCore
397 
398