NetworkResourcesData.cpp 13 KB

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