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