2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
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
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.
30 #include "NetworkResourcesData.h"
32 #include "CachedResource.h"
33 #include "DOMImplementation.h"
34 #include "ResourceResponse.h"
35 #include "SharedBuffer.h"
36 #include "TextResourceDecoder.h"
40 static const size_t maximumResourcesContentSize = 100 * 1000 * 1000;
43 static const size_t maximumSingleResourceContentSize = 10 * 1000 * 1000;
46 using namespace Inspector;
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)
61 void NetworkResourcesData::ResourceData::setContent(const String& content, bool base64Encoded)
64 ASSERT(!hasContent());
66 m_base64Encoded = base64Encoded;
69 static size_t contentSizeInBytes(const String& content)
71 return content.isNull() ? 0 : content.impl()->sizeInBytes();
74 unsigned NetworkResourcesData::ResourceData::removeContent()
78 ASSERT(!hasContent());
79 result = m_dataBuffer->size();
80 m_dataBuffer = nullptr;
85 result = contentSizeInBytes(m_content);
91 unsigned NetworkResourcesData::ResourceData::evictContent()
93 m_isContentEvicted = true;
94 return removeContent();
97 size_t NetworkResourcesData::ResourceData::dataLength() const
99 return m_dataBuffer ? m_dataBuffer->size() : 0;
102 void NetworkResourcesData::ResourceData::appendData(const char* data, size_t dataLength)
104 ASSERT(!hasContent());
106 m_dataBuffer = SharedBuffer::create(data, dataLength);
108 m_dataBuffer->append(data, dataLength);
111 size_t NetworkResourcesData::ResourceData::decodeDataToContent()
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;
120 // NetworkResourcesData
121 NetworkResourcesData::NetworkResourcesData()
123 , m_maximumResourcesContentSize(maximumResourcesContentSize)
124 , m_maximumSingleResourceContentSize(maximumSingleResourceContentSize)
128 NetworkResourcesData::~NetworkResourcesData()
133 void NetworkResourcesData::resourceCreated(const String& requestId, const String& loaderId)
135 ensureNoDataForRequestId(requestId);
136 m_requestIdToResourceDataMap.set(requestId, new ResourceData(requestId, loaderId));
139 static PassRefPtr<TextResourceDecoder> createOtherResourceTextDecoder(const String& mimeType, const String& textEncodingName)
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");
154 void NetworkResourcesData::responseReceived(const String& requestId, const String& frameId, const ResourceResponse& response)
156 ResourceData* resourceData = resourceDataForRequestId(requestId);
159 resourceData->setFrameId(frameId);
160 resourceData->setUrl(response.url());
161 resourceData->setDecoder(createOtherResourceTextDecoder(response.mimeType(), response.textEncodingName()));
162 resourceData->setHTTPStatusCode(response.httpStatusCode());
165 void NetworkResourcesData::setResourceType(const String& requestId, InspectorPageAgent::ResourceType type)
167 ResourceData* resourceData = resourceDataForRequestId(requestId);
170 resourceData->setType(type);
173 InspectorPageAgent::ResourceType NetworkResourcesData::resourceType(const String& requestId)
175 ResourceData* resourceData = resourceDataForRequestId(requestId);
177 return InspectorPageAgent::OtherResource;
178 return resourceData->type();
181 void NetworkResourcesData::setResourceContent(const String& requestId, const String& content, bool base64Encoded)
183 ResourceData* resourceData = resourceDataForRequestId(requestId);
186 size_t dataLength = contentSizeInBytes(content);
187 if (dataLength > m_maximumSingleResourceContentSize)
189 if (resourceData->isContentEvicted())
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;
201 void NetworkResourcesData::maybeAddResourceData(const String& requestId, const char* data, size_t dataLength)
203 ResourceData* resourceData = resourceDataForRequestId(requestId);
206 if (!resourceData->decoder())
208 if (resourceData->dataLength() + dataLength > m_maximumSingleResourceContentSize)
209 m_contentSize -= resourceData->evictContent();
210 if (resourceData->isContentEvicted())
212 if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
213 m_requestIdsDeque.append(requestId);
214 resourceData->appendData(data, dataLength);
215 m_contentSize += dataLength;
219 void NetworkResourcesData::maybeDecodeDataToContent(const String& requestId)
221 ResourceData* resourceData = resourceDataForRequestId(requestId);
224 if (!resourceData->hasData())
226 m_contentSize += resourceData->decodeDataToContent();
227 size_t dataLength = contentSizeInBytes(resourceData->content());
228 if (dataLength > m_maximumSingleResourceContentSize)
229 m_contentSize -= resourceData->evictContent();
232 void NetworkResourcesData::addCachedResource(const String& requestId, CachedResource* cachedResource)
234 ResourceData* resourceData = resourceDataForRequestId(requestId);
237 resourceData->setCachedResource(cachedResource);
240 void NetworkResourcesData::addResourceSharedBuffer(const String& requestId, PassRefPtr<SharedBuffer> buffer, const String& textEncodingName)
242 ResourceData* resourceData = resourceDataForRequestId(requestId);
245 resourceData->setBuffer(buffer);
246 resourceData->setTextEncodingName(textEncodingName);
249 NetworkResourcesData::ResourceData const* NetworkResourcesData::data(const String& requestId)
251 return resourceDataForRequestId(requestId);
254 Vector<String> NetworkResourcesData::removeCachedResource(CachedResource* cachedResource)
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);
270 void NetworkResourcesData::clear(const String& preservedLoaderId)
272 m_requestIdsDeque.clear();
275 ResourceDataMap preservedMap;
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);
287 m_requestIdToResourceDataMap.swap(preservedMap);
290 NetworkResourcesData::ResourceData* NetworkResourcesData::resourceDataForRequestId(const String& requestId)
292 if (requestId.isNull())
294 return m_requestIdToResourceDataMap.get(requestId);
297 void NetworkResourcesData::ensureNoDataForRequestId(const String& requestId)
299 ResourceData* resourceData = resourceDataForRequestId(requestId);
302 if (resourceData->hasContent() || resourceData->hasData())
303 m_contentSize -= resourceData->evictContent();
305 m_requestIdToResourceDataMap.remove(requestId);
308 bool NetworkResourcesData::ensureFreeSpace(size_t size)
310 if (size > m_maximumResourcesContentSize)
313 while (size > m_maximumResourcesContentSize - m_contentSize) {
314 String requestId = m_requestIdsDeque.takeFirst();
315 ResourceData* resourceData = resourceDataForRequestId(requestId);
317 m_contentSize -= resourceData->evictContent();
322 } // namespace WebCore