• 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/MIMETypeRegistry.h"
35 #include "platform/SharedBuffer.h"
36 #include "platform/network/ResourceResponse.h"
37 
38 namespace {
39 // 100MB
40 static size_t maximumResourcesContentSize = 100 * 1000 * 1000;
41 
42 // 10MB
43 static size_t maximumSingleResourceContentSize = 10 * 1000 * 1000;
44 }
45 
46 namespace blink {
47 
48 
create(ExecutionContext * executionContext,const AtomicString & method,const KURL & url,bool async,PassRefPtr<FormData> formData,bool includeCredentials)49 PassRefPtrWillBeRawPtr<XHRReplayData> XHRReplayData::create(ExecutionContext* executionContext, const AtomicString& method, const KURL& url, bool async, PassRefPtr<FormData> formData, bool includeCredentials)
50 {
51     return adoptRefWillBeNoop(new XHRReplayData(executionContext, method, url, async, formData, includeCredentials));
52 }
53 
addHeader(const AtomicString & key,const AtomicString & value)54 void XHRReplayData::addHeader(const AtomicString& key, const AtomicString& value)
55 {
56     m_headers.set(key, value);
57 }
58 
XHRReplayData(ExecutionContext * executionContext,const AtomicString & method,const KURL & url,bool async,PassRefPtr<FormData> formData,bool includeCredentials)59 XHRReplayData::XHRReplayData(ExecutionContext* executionContext, const AtomicString& method, const KURL& url, bool async, PassRefPtr<FormData> formData, bool includeCredentials)
60     : ContextLifecycleObserver(executionContext)
61     , m_method(method)
62     , m_url(url)
63     , m_async(async)
64     , m_formData(formData)
65     , m_includeCredentials(includeCredentials)
66 {
67 }
68 
69 // ResourceData
ResourceData(const String & requestId,const String & loaderId)70 NetworkResourcesData::ResourceData::ResourceData(const String& requestId, const String& loaderId)
71     : m_requestId(requestId)
72     , m_loaderId(loaderId)
73     , m_base64Encoded(false)
74     , m_isContentEvicted(false)
75     , m_type(InspectorPageAgent::OtherResource)
76     , m_cachedResource(0)
77 {
78 }
79 
setContent(const String & content,bool base64Encoded)80 void NetworkResourcesData::ResourceData::setContent(const String& content, bool base64Encoded)
81 {
82     ASSERT(!hasData());
83     ASSERT(!hasContent());
84     m_content = content;
85     m_base64Encoded = base64Encoded;
86 }
87 
contentSizeInBytes(const String & content)88 static size_t contentSizeInBytes(const String& content)
89 {
90     return content.isNull() ? 0 : content.impl()->sizeInBytes();
91 }
92 
removeContent()93 unsigned NetworkResourcesData::ResourceData::removeContent()
94 {
95     unsigned result = 0;
96     if (hasData()) {
97         ASSERT(!hasContent());
98         result = m_dataBuffer->size();
99         m_dataBuffer = nullptr;
100     }
101 
102     if (hasContent()) {
103         ASSERT(!hasData());
104         result = contentSizeInBytes(m_content);
105         m_content = String();
106     }
107     return result;
108 }
109 
evictContent()110 unsigned NetworkResourcesData::ResourceData::evictContent()
111 {
112     m_isContentEvicted = true;
113     return removeContent();
114 }
115 
dataLength() const116 size_t NetworkResourcesData::ResourceData::dataLength() const
117 {
118     return m_dataBuffer ? m_dataBuffer->size() : 0;
119 }
120 
appendData(const char * data,size_t dataLength)121 void NetworkResourcesData::ResourceData::appendData(const char* data, size_t dataLength)
122 {
123     ASSERT(!hasContent());
124     if (!m_dataBuffer)
125         m_dataBuffer = SharedBuffer::create(data, dataLength);
126     else
127         m_dataBuffer->append(data, dataLength);
128 }
129 
decodeDataToContent()130 size_t NetworkResourcesData::ResourceData::decodeDataToContent()
131 {
132     ASSERT(!hasContent());
133     size_t dataLength = m_dataBuffer->size();
134     m_content = m_decoder->decode(m_dataBuffer->data(), m_dataBuffer->size());
135     m_content = m_content + m_decoder->flush();
136     m_dataBuffer = nullptr;
137     return contentSizeInBytes(m_content) - dataLength;
138 }
139 
140 // NetworkResourcesData
NetworkResourcesData()141 NetworkResourcesData::NetworkResourcesData()
142     : m_contentSize(0)
143     , m_maximumResourcesContentSize(maximumResourcesContentSize)
144     , m_maximumSingleResourceContentSize(maximumSingleResourceContentSize)
145 {
146 }
147 
~NetworkResourcesData()148 NetworkResourcesData::~NetworkResourcesData()
149 {
150     clear();
151 }
152 
resourceCreated(const String & requestId,const String & loaderId)153 void NetworkResourcesData::resourceCreated(const String& requestId, const String& loaderId)
154 {
155     ensureNoDataForRequestId(requestId);
156     m_requestIdToResourceDataMap.set(requestId, new ResourceData(requestId, loaderId));
157 }
158 
createOtherResourceTextDecoder(const String & mimeType,const String & textEncodingName)159 static PassOwnPtr<TextResourceDecoder> createOtherResourceTextDecoder(const String& mimeType, const String& textEncodingName)
160 {
161     OwnPtr<TextResourceDecoder> decoder;
162     if (!textEncodingName.isEmpty()) {
163         decoder = TextResourceDecoder::create("text/plain", textEncodingName);
164     } else if (DOMImplementation::isXMLMIMEType(mimeType)) {
165         decoder = TextResourceDecoder::create("application/xml");
166         decoder->useLenientXMLDecoding();
167     } else if (equalIgnoringCase(mimeType, "text/html")) {
168         decoder = TextResourceDecoder::create("text/html", "UTF-8");
169     } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) || DOMImplementation::isJSONMIMEType(mimeType)) {
170         decoder = TextResourceDecoder::create("text/plain", "UTF-8");
171     } else if (DOMImplementation::isTextMIMEType(mimeType)) {
172         decoder = TextResourceDecoder::create("text/plain", "ISO-8859-1");
173     }
174     return decoder.release();
175 }
176 
responseReceived(const String & requestId,const String & frameId,const ResourceResponse & response)177 void NetworkResourcesData::responseReceived(const String& requestId, const String& frameId, const ResourceResponse& response)
178 {
179     ResourceData* resourceData = resourceDataForRequestId(requestId);
180     if (!resourceData)
181         return;
182     resourceData->setFrameId(frameId);
183     resourceData->setUrl(response.url());
184     resourceData->setDecoder(createOtherResourceTextDecoder(response.mimeType(), response.textEncodingName()));
185     resourceData->setHTTPStatusCode(response.httpStatusCode());
186 }
187 
setResourceType(const String & requestId,InspectorPageAgent::ResourceType type)188 void NetworkResourcesData::setResourceType(const String& requestId, InspectorPageAgent::ResourceType type)
189 {
190     ResourceData* resourceData = resourceDataForRequestId(requestId);
191     if (!resourceData)
192         return;
193     resourceData->setType(type);
194 }
195 
resourceType(const String & requestId)196 InspectorPageAgent::ResourceType NetworkResourcesData::resourceType(const String& requestId)
197 {
198     ResourceData* resourceData = resourceDataForRequestId(requestId);
199     if (!resourceData)
200         return InspectorPageAgent::OtherResource;
201     return resourceData->type();
202 }
203 
setResourceContent(const String & requestId,const String & content,bool base64Encoded)204 void NetworkResourcesData::setResourceContent(const String& requestId, const String& content, bool base64Encoded)
205 {
206     ResourceData* resourceData = resourceDataForRequestId(requestId);
207     if (!resourceData)
208         return;
209     size_t dataLength = contentSizeInBytes(content);
210     if (dataLength > m_maximumSingleResourceContentSize)
211         return;
212     if (resourceData->isContentEvicted())
213         return;
214     if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
215         // We can not be sure that we didn't try to save this request data while it was loading, so remove it, if any.
216         if (resourceData->hasContent())
217             m_contentSize -= resourceData->removeContent();
218         m_requestIdsDeque.append(requestId);
219         resourceData->setContent(content, base64Encoded);
220         m_contentSize += dataLength;
221     }
222 }
223 
maybeAddResourceData(const String & requestId,const char * data,size_t dataLength)224 void NetworkResourcesData::maybeAddResourceData(const String& requestId, const char* data, size_t dataLength)
225 {
226     ResourceData* resourceData = resourceDataForRequestId(requestId);
227     if (!resourceData)
228         return;
229     if (!resourceData->decoder())
230         return;
231     if (resourceData->dataLength() + dataLength > m_maximumSingleResourceContentSize)
232         m_contentSize -= resourceData->evictContent();
233     if (resourceData->isContentEvicted())
234         return;
235     if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
236         m_requestIdsDeque.append(requestId);
237         resourceData->appendData(data, dataLength);
238         m_contentSize += dataLength;
239     }
240 }
241 
maybeDecodeDataToContent(const String & requestId)242 void NetworkResourcesData::maybeDecodeDataToContent(const String& requestId)
243 {
244     ResourceData* resourceData = resourceDataForRequestId(requestId);
245     if (!resourceData)
246         return;
247     if (!resourceData->hasData())
248         return;
249     m_contentSize += resourceData->decodeDataToContent();
250     size_t dataLength = contentSizeInBytes(resourceData->content());
251     if (dataLength > m_maximumSingleResourceContentSize)
252         m_contentSize -= resourceData->evictContent();
253 }
254 
addResource(const String & requestId,Resource * cachedResource)255 void NetworkResourcesData::addResource(const String& requestId, Resource* cachedResource)
256 {
257     ResourceData* resourceData = resourceDataForRequestId(requestId);
258     if (!resourceData)
259         return;
260     resourceData->setResource(cachedResource);
261 }
262 
data(const String & requestId)263 NetworkResourcesData::ResourceData const* NetworkResourcesData::data(const String& requestId)
264 {
265     return resourceDataForRequestId(requestId);
266 }
267 
xhrReplayData(const String & requestId)268 XHRReplayData* NetworkResourcesData::xhrReplayData(const String& requestId)
269 {
270     if (m_reusedXHRReplayDataRequestIds.contains(requestId))
271         return xhrReplayData(m_reusedXHRReplayDataRequestIds.get(requestId));
272 
273     ResourceData* resourceData = resourceDataForRequestId(requestId);
274     if (!resourceData)
275         return 0;
276     return resourceData->xhrReplayData();
277 }
278 
setXHRReplayData(const String & requestId,XHRReplayData * xhrReplayData)279 void NetworkResourcesData::setXHRReplayData(const String& requestId, XHRReplayData* xhrReplayData)
280 {
281     ResourceData* resourceData = resourceDataForRequestId(requestId);
282     if (!resourceData) {
283         Vector<String> result;
284         ReusedRequestIds::iterator it;
285         ReusedRequestIds::iterator end = m_reusedXHRReplayDataRequestIds.end();
286         for (it = m_reusedXHRReplayDataRequestIds.begin(); it != end; ++it) {
287             if (it->value == requestId)
288                 setXHRReplayData(it->key, xhrReplayData);
289         }
290         return;
291     }
292 
293     resourceData->setXHRReplayData(xhrReplayData);
294 }
295 
resources()296 Vector<NetworkResourcesData::ResourceData*> NetworkResourcesData::resources()
297 {
298     Vector<ResourceData*> result;
299     for (ResourceDataMap::iterator it = m_requestIdToResourceDataMap.begin(); it != m_requestIdToResourceDataMap.end(); ++it)
300         result.append(it->value);
301     return result;
302 }
303 
removeResource(Resource * cachedResource)304 Vector<String> NetworkResourcesData::removeResource(Resource* cachedResource)
305 {
306     Vector<String> result;
307     ResourceDataMap::iterator it;
308     ResourceDataMap::iterator end = m_requestIdToResourceDataMap.end();
309     for (it = m_requestIdToResourceDataMap.begin(); it != end; ++it) {
310         ResourceData* resourceData = it->value;
311         if (resourceData->cachedResource() == cachedResource) {
312             resourceData->setResource(0);
313             result.append(it->key);
314         }
315     }
316 
317     return result;
318 }
319 
clear(const String & preservedLoaderId)320 void NetworkResourcesData::clear(const String& preservedLoaderId)
321 {
322     m_requestIdsDeque.clear();
323     m_contentSize = 0;
324 
325     ResourceDataMap preservedMap;
326 
327     ResourceDataMap::iterator it;
328     ResourceDataMap::iterator end = m_requestIdToResourceDataMap.end();
329     for (it = m_requestIdToResourceDataMap.begin(); it != end; ++it) {
330         ResourceData* resourceData = it->value;
331         if (!preservedLoaderId.isNull() && resourceData->loaderId() == preservedLoaderId)
332             preservedMap.set(it->key, it->value);
333         else
334             delete resourceData;
335     }
336     m_requestIdToResourceDataMap.swap(preservedMap);
337 
338     m_reusedXHRReplayDataRequestIds.clear();
339 }
340 
setResourcesDataSizeLimits(size_t maximumResourcesContentSize,size_t maximumSingleResourceContentSize)341 void NetworkResourcesData::setResourcesDataSizeLimits(size_t maximumResourcesContentSize, size_t maximumSingleResourceContentSize)
342 {
343     clear();
344     m_maximumResourcesContentSize = maximumResourcesContentSize;
345     m_maximumSingleResourceContentSize = maximumSingleResourceContentSize;
346 }
347 
resourceDataForRequestId(const String & requestId)348 NetworkResourcesData::ResourceData* NetworkResourcesData::resourceDataForRequestId(const String& requestId)
349 {
350     if (requestId.isNull())
351         return 0;
352     return m_requestIdToResourceDataMap.get(requestId);
353 }
354 
ensureNoDataForRequestId(const String & requestId)355 void NetworkResourcesData::ensureNoDataForRequestId(const String& requestId)
356 {
357     ResourceData* resourceData = resourceDataForRequestId(requestId);
358     if (!resourceData)
359         return;
360     if (resourceData->hasContent() || resourceData->hasData())
361         m_contentSize -= resourceData->evictContent();
362     delete resourceData;
363     m_requestIdToResourceDataMap.remove(requestId);
364 }
365 
ensureFreeSpace(size_t size)366 bool NetworkResourcesData::ensureFreeSpace(size_t size)
367 {
368     if (size > m_maximumResourcesContentSize)
369         return false;
370 
371     while (size > m_maximumResourcesContentSize - m_contentSize) {
372         String requestId = m_requestIdsDeque.takeFirst();
373         ResourceData* resourceData = resourceDataForRequestId(requestId);
374         if (resourceData)
375             m_contentSize -= resourceData->evictContent();
376     }
377     return true;
378 }
379 
380 } // namespace blink
381 
382