• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "WebCache.h"
28 
29 #include "JNIUtility.h"
30 #include "WebCoreJni.h"
31 #include "WebRequestContext.h"
32 #include "WebUrlLoaderClient.h"
33 #include "net/http/http_network_session.h"
34 #include <wtf/text/CString.h>
35 
36 using namespace WTF;
37 using namespace disk_cache;
38 using namespace net;
39 using namespace std;
40 
41 namespace android {
42 
43 static WTF::Mutex instanceMutex;
44 
storageDirectory()45 static string storageDirectory()
46 {
47     static const char* const kDirectory = "/webviewCacheChromium";
48 
49     JNIEnv* env = JSC::Bindings::getJNIEnv();
50     jclass bridgeClass = env->FindClass("android/webkit/JniUtil");
51     jmethodID method = env->GetStaticMethodID(bridgeClass, "getCacheDirectory", "()Ljava/lang/String;");
52     string storageDirectory = jstringToStdString(env, static_cast<jstring>(env->CallStaticObjectMethod(bridgeClass, method)));
53     env->DeleteLocalRef(bridgeClass);
54 
55     // Return empty string if storageDirectory is an empty string
56     if (storageDirectory.empty())
57         return storageDirectory;
58 
59     storageDirectory.append(kDirectory);
60     return storageDirectory;
61 }
62 
instance(bool isPrivateBrowsing)63 static scoped_refptr<WebCache>* instance(bool isPrivateBrowsing)
64 {
65     static scoped_refptr<WebCache> regularInstance;
66     static scoped_refptr<WebCache> privateInstance;
67     return isPrivateBrowsing ? &privateInstance : &regularInstance;
68 }
69 
get(bool isPrivateBrowsing)70 WebCache* WebCache::get(bool isPrivateBrowsing)
71 {
72     MutexLocker lock(instanceMutex);
73     scoped_refptr<WebCache>* instancePtr = instance(isPrivateBrowsing);
74     if (!instancePtr->get())
75         *instancePtr = new WebCache(isPrivateBrowsing);
76     return instancePtr->get();
77 }
78 
cleanup(bool isPrivateBrowsing)79 void WebCache::cleanup(bool isPrivateBrowsing)
80 {
81     MutexLocker lock(instanceMutex);
82     scoped_refptr<WebCache>* instancePtr = instance(isPrivateBrowsing);
83     *instancePtr = 0;
84 }
85 
WebCache(bool isPrivateBrowsing)86 WebCache::WebCache(bool isPrivateBrowsing)
87     : m_doomAllEntriesCallback(this, &WebCache::doomAllEntries)
88     , m_onClearDoneCallback(this, &WebCache::onClearDone)
89     , m_isClearInProgress(false)
90     , m_openEntryCallback(this, &WebCache::openEntry)
91     , m_onGetEntryDoneCallback(this, &WebCache::onGetEntryDone)
92     , m_isGetEntryInProgress(false)
93     , m_cacheBackend(0)
94 {
95     base::Thread* ioThread = WebUrlLoaderClient::ioThread();
96     scoped_refptr<base::MessageLoopProxy> cacheMessageLoopProxy = ioThread->message_loop_proxy();
97 
98     static const int kMaximumCacheSizeBytes = 20 * 1024 * 1024;
99     m_hostResolver = net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism, 0, 0);
100 
101     m_proxyConfigService = new ProxyConfigServiceAndroid();
102     net::HttpCache::BackendFactory* backendFactory;
103     if (isPrivateBrowsing)
104         backendFactory = net::HttpCache::DefaultBackend::InMemory(kMaximumCacheSizeBytes / 2);
105     else {
106         string storage(storageDirectory());
107         if (storage.empty()) // Can't get a storage directory from the OS
108             backendFactory = net::HttpCache::DefaultBackend::InMemory(kMaximumCacheSizeBytes / 2);
109         else {
110             FilePath directoryPath(storage.c_str());
111             backendFactory = new net::HttpCache::DefaultBackend(net::DISK_CACHE, directoryPath, kMaximumCacheSizeBytes, cacheMessageLoopProxy);
112         }
113     }
114 
115     m_cache = new net::HttpCache(m_hostResolver.get(),
116                                  new CertVerifier(),
117                                  0, // dnsrr_resolver
118                                  0, // dns_cert_checker
119                                  net::ProxyService::CreateWithoutProxyResolver(m_proxyConfigService, 0 /* net_log */),
120                                  net::SSLConfigService::CreateSystemSSLConfigService(),
121                                  net::HttpAuthHandlerFactory::CreateDefault(m_hostResolver.get()),
122                                  0, // network_delegate
123                                  0, // net_log
124                                  backendFactory);
125 }
126 
clear()127 void WebCache::clear()
128 {
129     base::Thread* thread = WebUrlLoaderClient::ioThread();
130     if (thread)
131         thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::clearImpl));
132 }
133 
certTrustChanged()134 void WebCache::certTrustChanged()
135 {
136     base::Thread* thread = WebUrlLoaderClient::ioThread();
137     if (thread)
138         thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::certTrustChangedImpl));
139 }
140 
certTrustChangedImpl()141 void WebCache::certTrustChangedImpl()
142 {
143     net::HttpNetworkSession* session = m_cache->GetSession();
144     if (session)
145         session->cert_verifier()->ClearCache();
146     m_cache->CloseAllConnections();
147 }
148 
closeIdleConnections()149 void WebCache::closeIdleConnections()
150 {
151     base::Thread* thread = WebUrlLoaderClient::ioThread();
152     if (thread)
153         thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::closeIdleImpl));
154 }
155 
closeIdleImpl()156 void WebCache::closeIdleImpl()
157 {
158     m_cache->CloseIdleConnections();
159 }
160 
clearImpl()161 void WebCache::clearImpl()
162 {
163     if (m_isClearInProgress)
164         return;
165     m_isClearInProgress = true;
166 
167     if (!m_cacheBackend) {
168         int code = m_cache->GetBackend(&m_cacheBackend, &m_doomAllEntriesCallback);
169         // Code ERR_IO_PENDING indicates that the operation is still in progress and
170         // the supplied callback will be invoked when it completes.
171         if (code == ERR_IO_PENDING)
172             return;
173         else if (code != OK) {
174             onClearDone(0 /*unused*/);
175             return;
176         }
177     }
178     doomAllEntries(0 /*unused*/);
179 }
180 
doomAllEntries(int)181 void WebCache::doomAllEntries(int)
182 {
183     if (!m_cacheBackend) {
184         onClearDone(0 /*unused*/);
185         return;
186     }
187 
188     // Code ERR_IO_PENDING indicates that the operation is still in progress and
189     // the supplied callback will be invoked when it completes.
190     if (m_cacheBackend->DoomAllEntries(&m_onClearDoneCallback) == ERR_IO_PENDING)
191         return;
192     onClearDone(0 /*unused*/);
193 }
194 
onClearDone(int)195 void WebCache::onClearDone(int)
196 {
197     m_isClearInProgress = false;
198 }
199 
getCacheResult(String url)200 scoped_refptr<CacheResult> WebCache::getCacheResult(String url)
201 {
202     // This is called on the UI thread.
203     MutexLocker lock(m_getEntryMutex);
204     if (m_isGetEntryInProgress)
205         return 0; // TODO: OK? Or can we queue 'em up?
206 
207     // The Chromium methods are asynchronous, but we need this method to be
208     // synchronous. Do the work on the Chromium thread but block this thread
209     // here waiting for the work to complete.
210     base::Thread* thread = WebUrlLoaderClient::ioThread();
211     if (!thread)
212         return 0;
213 
214     m_entry = 0;
215     m_isGetEntryInProgress = true;
216     m_entryUrl = url.threadsafeCopy();
217     thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::getEntryImpl));
218 
219     while (m_isGetEntryInProgress)
220         m_getEntryCondition.wait(m_getEntryMutex);
221 
222     if (!m_entry)
223         return 0;
224 
225     return new CacheResult(m_entry, url);
226 }
227 
getEntryImpl()228 void WebCache::getEntryImpl()
229 {
230     if (!m_cacheBackend) {
231         int code = m_cache->GetBackend(&m_cacheBackend, &m_openEntryCallback);
232         if (code == ERR_IO_PENDING)
233             return;
234         else if (code != OK) {
235             onGetEntryDone(0 /*unused*/);
236             return;
237         }
238     }
239     openEntry(0 /*unused*/);
240 }
241 
openEntry(int)242 void WebCache::openEntry(int)
243 {
244     if (!m_cacheBackend) {
245         onGetEntryDone(0 /*unused*/);
246         return;
247     }
248 
249     if (m_cacheBackend->OpenEntry(string(m_entryUrl.utf8().data()), &m_entry, &m_onGetEntryDoneCallback) == ERR_IO_PENDING)
250         return;
251     onGetEntryDone(0 /*unused*/);
252 }
253 
onGetEntryDone(int)254 void WebCache::onGetEntryDone(int)
255 {
256     // Unblock the UI thread in getEntry();
257     MutexLocker lock(m_getEntryMutex);
258     m_isGetEntryInProgress = false;
259     m_getEntryCondition.signal();
260 }
261 
262 } // namespace android
263