Remove all uses of PassRefPtr in WebCore/inspector
[WebKit-https.git] / Source / WebCore / inspector / NetworkResourcesData.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  * 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 "NetworkResourcesData.h"
31
32 #include "CachedResource.h"
33 #include "DOMImplementation.h"
34 #include "ResourceResponse.h"
35 #include "SharedBuffer.h"
36 #include "TextResourceDecoder.h"
37
38 namespace {
39 // 100MB
40 static const size_t maximumResourcesContentSize = 100 * 1000 * 1000;
41
42 // 10MB
43 static const size_t maximumSingleResourceContentSize = 10 * 1000 * 1000;
44 }
45
46 using namespace Inspector;
47
48 namespace WebCore {
49
50 // ResourceData
51 NetworkResourcesData::ResourceData::ResourceData(const String& requestId, const String& loaderId)
52     : m_requestId(requestId)
53     , m_loaderId(loaderId)
54     , m_base64Encoded(false)
55     , m_isContentEvicted(false)
56     , m_type(InspectorPageAgent::OtherResource)
57     , m_cachedResource(nullptr)
58 {
59 }
60
61 void NetworkResourcesData::ResourceData::setContent(const String& content, bool base64Encoded)
62 {
63     ASSERT(!hasData());
64     ASSERT(!hasContent());
65     m_content = content;
66     m_base64Encoded = base64Encoded;
67 }
68
69 static size_t contentSizeInBytes(const String& content)
70 {
71     return content.isNull() ? 0 : content.impl()->sizeInBytes();
72 }
73
74 unsigned NetworkResourcesData::ResourceData::removeContent()
75 {
76     unsigned result = 0;
77     if (hasData()) {
78         ASSERT(!hasContent());
79         result = m_dataBuffer->size();
80         m_dataBuffer = nullptr;
81     }
82
83     if (hasContent()) {
84         ASSERT(!hasData());
85         result = contentSizeInBytes(m_content);
86         m_content = String();
87     }
88     return result;
89 }
90
91 unsigned NetworkResourcesData::ResourceData::evictContent()
92 {
93     m_isContentEvicted = true;
94     return removeContent();
95 }
96
97 size_t NetworkResourcesData::ResourceData::dataLength() const
98 {
99     return m_dataBuffer ? m_dataBuffer->size() : 0;
100 }
101
102 void NetworkResourcesData::ResourceData::appendData(const char* data, size_t dataLength)
103 {
104     ASSERT(!hasContent());
105     if (!m_dataBuffer)
106         m_dataBuffer = SharedBuffer::create(data, dataLength);
107     else
108         m_dataBuffer->append(data, dataLength);
109 }
110
111 size_t NetworkResourcesData::ResourceData::decodeDataToContent()
112 {
113     ASSERT(!hasContent());
114     size_t dataLength = m_dataBuffer->size();
115     m_content = m_decoder->decodeAndFlush(m_dataBuffer->data(), m_dataBuffer->size());
116     m_dataBuffer = nullptr;
117     return contentSizeInBytes(m_content) - dataLength;
118 }
119
120 // NetworkResourcesData
121 NetworkResourcesData::NetworkResourcesData()
122     : m_contentSize(0)
123     , m_maximumResourcesContentSize(maximumResourcesContentSize)
124     , m_maximumSingleResourceContentSize(maximumSingleResourceContentSize)
125 {
126 }
127
128 NetworkResourcesData::~NetworkResourcesData()
129 {
130     clear();
131 }
132
133 void NetworkResourcesData::resourceCreated(const String& requestId, const String& loaderId)
134 {
135     ensureNoDataForRequestId(requestId);
136     m_requestIdToResourceDataMap.set(requestId, new ResourceData(requestId, loaderId));
137 }
138
139 static RefPtr<TextResourceDecoder> createOtherResourceTextDecoder(const String& mimeType, const String& textEncodingName)
140 {
141     RefPtr<TextResourceDecoder> decoder;
142     if (!textEncodingName.isEmpty())
143         decoder = TextResourceDecoder::create("text/plain", textEncodingName);
144     else if (DOMImplementation::isXMLMIMEType(mimeType.lower())) {
145         decoder = TextResourceDecoder::create("application/xml");
146         decoder->useLenientXMLDecoding();
147     } else if (equalIgnoringCase(mimeType, "text/html"))
148         decoder = TextResourceDecoder::create("text/html", "UTF-8");
149     else if (mimeType == "text/plain")
150         decoder = TextResourceDecoder::create("text/plain", "ISO-8859-1");
151     return decoder;
152 }
153
154 void NetworkResourcesData::responseReceived(const String& requestId, const String& frameId, const ResourceResponse& response)
155 {
156     ResourceData* resourceData = resourceDataForRequestId(requestId);
157     if (!resourceData)
158         return;
159     resourceData->setFrameId(frameId);
160     resourceData->setUrl(response.url());
161     resourceData->setDecoder(createOtherResourceTextDecoder(response.mimeType(), response.textEncodingName()));
162     resourceData->setHTTPStatusCode(response.httpStatusCode());
163 }
164
165 void NetworkResourcesData::setResourceType(const String& requestId, InspectorPageAgent::ResourceType type)
166 {
167     ResourceData* resourceData = resourceDataForRequestId(requestId);
168     if (!resourceData)
169         return;
170     resourceData->setType(type);
171 }
172
173 InspectorPageAgent::ResourceType NetworkResourcesData::resourceType(const String& requestId)
174 {
175     ResourceData* resourceData = resourceDataForRequestId(requestId);
176     if (!resourceData)
177         return InspectorPageAgent::OtherResource;
178     return resourceData->type();
179 }
180
181 void NetworkResourcesData::setResourceContent(const String& requestId, const String& content, bool base64Encoded)
182 {
183     ResourceData* resourceData = resourceDataForRequestId(requestId);
184     if (!resourceData)
185         return;
186     size_t dataLength = contentSizeInBytes(content);
187     if (dataLength > m_maximumSingleResourceContentSize)
188         return;
189     if (resourceData->isContentEvicted())
190         return;
191     if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
192         // We can not be sure that we didn't try to save this request data while it was loading, so remove it, if any.
193         if (resourceData->hasContent())
194             m_contentSize -= resourceData->removeContent();
195         m_requestIdsDeque.append(requestId);
196         resourceData->setContent(content, base64Encoded);
197         m_contentSize += dataLength;
198     }
199 }
200
201 void NetworkResourcesData::maybeAddResourceData(const String& requestId, const char* data, size_t dataLength)
202 {
203     ResourceData* resourceData = resourceDataForRequestId(requestId);
204     if (!resourceData)
205         return;
206     if (!resourceData->decoder())
207         return;
208     if (resourceData->dataLength() + dataLength > m_maximumSingleResourceContentSize)
209         m_contentSize -= resourceData->evictContent();
210     if (resourceData->isContentEvicted())
211         return;
212     if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
213         m_requestIdsDeque.append(requestId);
214         resourceData->appendData(data, dataLength);
215         m_contentSize += dataLength;
216     }
217 }
218
219 void NetworkResourcesData::maybeDecodeDataToContent(const String& requestId)
220 {
221     ResourceData* resourceData = resourceDataForRequestId(requestId);
222     if (!resourceData)
223         return;
224     if (!resourceData->hasData())
225         return;
226     m_contentSize += resourceData->decodeDataToContent();
227     size_t dataLength = contentSizeInBytes(resourceData->content());
228     if (dataLength > m_maximumSingleResourceContentSize)
229         m_contentSize -= resourceData->evictContent();
230 }
231
232 void NetworkResourcesData::addCachedResource(const String& requestId, CachedResource* cachedResource)
233 {
234     ResourceData* resourceData = resourceDataForRequestId(requestId);
235     if (!resourceData)
236         return;
237     resourceData->setCachedResource(cachedResource);
238 }
239
240 void NetworkResourcesData::addResourceSharedBuffer(const String& requestId, RefPtr<SharedBuffer>&& buffer, const String& textEncodingName)
241 {
242     ResourceData* resourceData = resourceDataForRequestId(requestId);
243     if (!resourceData)
244         return;
245     resourceData->setBuffer(WTF::move(buffer));
246     resourceData->setTextEncodingName(textEncodingName);
247 }
248
249 NetworkResourcesData::ResourceData const* NetworkResourcesData::data(const String& requestId)
250 {
251     return resourceDataForRequestId(requestId);
252 }
253
254 Vector<String> NetworkResourcesData::removeCachedResource(CachedResource* cachedResource)
255 {
256     Vector<String> result;
257     ResourceDataMap::iterator it;
258     ResourceDataMap::iterator end = m_requestIdToResourceDataMap.end();
259     for (it = m_requestIdToResourceDataMap.begin(); it != end; ++it) {
260         ResourceData* resourceData = it->value;
261         if (resourceData->cachedResource() == cachedResource) {
262             resourceData->setCachedResource(nullptr);
263             result.append(it->key);
264         }
265     }
266
267     return result;
268 }
269
270 void NetworkResourcesData::clear(const String& preservedLoaderId)
271 {
272     m_requestIdsDeque.clear();
273     m_contentSize = 0;
274
275     ResourceDataMap preservedMap;
276
277     ResourceDataMap::iterator it;
278     ResourceDataMap::iterator end = m_requestIdToResourceDataMap.end();
279     for (it = m_requestIdToResourceDataMap.begin(); it != end; ++it) {
280         ResourceData* resourceData = it->value;
281         ASSERT(resourceData);
282         if (!preservedLoaderId.isNull() && resourceData->loaderId() == preservedLoaderId)
283             preservedMap.set(it->key, it->value);
284         else
285             delete resourceData;
286     }
287     m_requestIdToResourceDataMap.swap(preservedMap);
288 }
289
290 NetworkResourcesData::ResourceData* NetworkResourcesData::resourceDataForRequestId(const String& requestId)
291 {
292     if (requestId.isNull())
293         return nullptr;
294     return m_requestIdToResourceDataMap.get(requestId);
295 }
296
297 void NetworkResourcesData::ensureNoDataForRequestId(const String& requestId)
298 {
299     ResourceData* resourceData = resourceDataForRequestId(requestId);
300     if (!resourceData)
301         return;
302     if (resourceData->hasContent() || resourceData->hasData())
303         m_contentSize -= resourceData->evictContent();
304     delete resourceData;
305     m_requestIdToResourceDataMap.remove(requestId);
306 }
307
308 bool NetworkResourcesData::ensureFreeSpace(size_t size)
309 {
310     if (size > m_maximumResourcesContentSize)
311         return false;
312
313     while (size > m_maximumResourcesContentSize - m_contentSize) {
314         String requestId = m_requestIdsDeque.takeFirst();
315         ResourceData* resourceData = resourceDataForRequestId(requestId);
316         if (resourceData)
317             m_contentSize -= resourceData->evictContent();
318     }
319     return true;
320 }
321
322 } // namespace WebCore