/* * Copyright (C) 2008 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "ApplicationCache.h" #include "ApplicationCacheGroup.h" #include "ApplicationCacheResource.h" #include "ApplicationCacheStorage.h" #include "ResourceRequest.h" #include "SecurityOrigin.h" #include #include #include namespace WebCore { static inline bool fallbackURLLongerThan(const std::pair& lhs, const std::pair& rhs) { return lhs.first.string().length() > rhs.first.string().length(); } ApplicationCache::ApplicationCache() : m_group(nullptr) , m_manifest(nullptr) , m_estimatedSizeInStorage(0) , m_storageID(0) { } ApplicationCache::~ApplicationCache() { if (m_group) m_group->cacheDestroyed(this); } void ApplicationCache::setGroup(ApplicationCacheGroup* group) { ASSERT(!m_group || group == m_group); m_group = group; } bool ApplicationCache::isComplete() { return m_group && m_group->cacheIsComplete(this); } void ApplicationCache::setManifestResource(PassRefPtr manifest) { ASSERT(manifest); ASSERT(!m_manifest); ASSERT(manifest->type() & ApplicationCacheResource::Manifest); m_manifest = manifest.get(); addResource(manifest); } void ApplicationCache::addResource(PassRefPtr resource) { ASSERT(resource); const String& url = resource->url(); ASSERT(!m_resources.contains(url)); if (m_storageID) { ASSERT(!resource->storageID()); ASSERT(resource->type() & ApplicationCacheResource::Master); // Add the resource to the storage. ApplicationCacheStorage::singleton().store(resource.get(), this); } m_estimatedSizeInStorage += resource->estimatedSizeInStorage(); m_resources.set(url, resource); } unsigned ApplicationCache::removeResource(const String& url) { HashMap>::iterator it = m_resources.find(url); if (it == m_resources.end()) return 0; // The resource exists, get its type so we can return it. unsigned type = it->value->type(); m_estimatedSizeInStorage -= it->value->estimatedSizeInStorage(); m_resources.remove(it); return type; } ApplicationCacheResource* ApplicationCache::resourceForURL(const String& url) { ASSERT(!URL(ParsedURLString, url).hasFragmentIdentifier()); return m_resources.get(url); } bool ApplicationCache::requestIsHTTPOrHTTPSGet(const ResourceRequest& request) { return request.url().protocolIsInHTTPFamily() && equalLettersIgnoringASCIICase(request.httpMethod(), "get"); } ApplicationCacheResource* ApplicationCache::resourceForRequest(const ResourceRequest& request) { // We only care about HTTP/HTTPS GET requests. if (!requestIsHTTPOrHTTPSGet(request)) return nullptr; URL url(request.url()); if (url.hasFragmentIdentifier()) url.removeFragmentIdentifier(); return resourceForURL(url); } void ApplicationCache::setOnlineWhitelist(const Vector& onlineWhitelist) { ASSERT(m_onlineWhitelist.isEmpty()); m_onlineWhitelist = onlineWhitelist; } bool ApplicationCache::isURLInOnlineWhitelist(const URL& url) { for (auto& whitelistURL : m_onlineWhitelist) { if (protocolHostAndPortAreEqual(url, whitelistURL) && url.string().startsWith(whitelistURL.string())) return true; } return false; } void ApplicationCache::setFallbackURLs(const FallbackURLVector& fallbackURLs) { ASSERT(m_fallbackURLs.isEmpty()); m_fallbackURLs = fallbackURLs; // FIXME: What's the right behavior if we have 2 or more identical namespace URLs? std::stable_sort(m_fallbackURLs.begin(), m_fallbackURLs.end(), fallbackURLLongerThan); } bool ApplicationCache::urlMatchesFallbackNamespace(const URL& url, URL* fallbackURL) { for (auto& fallback : m_fallbackURLs) { if (protocolHostAndPortAreEqual(url, fallback.first) && url.string().startsWith(fallback.first.string())) { if (fallbackURL) *fallbackURL = fallback.second; return true; } } return false; } void ApplicationCache::clearStorageID() { m_storageID = 0; for (const auto& resource : m_resources.values()) resource->clearStorageID(); } #ifndef NDEBUG void ApplicationCache::dump() { for (const auto& urlAndResource : m_resources) { printf("%s ", urlAndResource.key.utf8().data()); ApplicationCacheResource::dumpType(urlAndResource.value->type()); } } #endif }