• 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 
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 
rootDirectory()45 static const string& rootDirectory()
46 {
47     // This method may be called on any thread, as the Java method is
48     // synchronized.
49     static WTF::Mutex mutex;
50     MutexLocker lock(mutex);
51     static string cacheDirectory;
52     if (cacheDirectory.empty()) {
53         JNIEnv* env = JSC::Bindings::getJNIEnv();
54         jclass bridgeClass = env->FindClass("android/webkit/JniUtil");
55         jmethodID method = env->GetStaticMethodID(bridgeClass, "getCacheDirectory", "()Ljava/lang/String;");
56         cacheDirectory = jstringToStdString(env, static_cast<jstring>(env->CallStaticObjectMethod(bridgeClass, method)));
57         env->DeleteLocalRef(bridgeClass);
58     }
59     return cacheDirectory;
60 }
61 
storageDirectory()62 static string storageDirectory()
63 {
64     // Private cache is currently in memory only
65     static const char* const kDirectory = "/webviewCacheChromium";
66     string storageDirectory = rootDirectory();
67     storageDirectory.append(kDirectory);
68     return storageDirectory;
69 }
70 
instance(bool isPrivateBrowsing)71 static scoped_refptr<WebCache>* instance(bool isPrivateBrowsing)
72 {
73     static scoped_refptr<WebCache> regularInstance;
74     static scoped_refptr<WebCache> privateInstance;
75     return isPrivateBrowsing ? &privateInstance : &regularInstance;
76 }
77 
get(bool isPrivateBrowsing)78 WebCache* WebCache::get(bool isPrivateBrowsing)
79 {
80     MutexLocker lock(instanceMutex);
81     scoped_refptr<WebCache>* instancePtr = instance(isPrivateBrowsing);
82     if (!instancePtr->get())
83         *instancePtr = new WebCache(isPrivateBrowsing);
84     return instancePtr->get();
85 }
86 
cleanup(bool isPrivateBrowsing)87 void WebCache::cleanup(bool isPrivateBrowsing)
88 {
89     MutexLocker lock(instanceMutex);
90     scoped_refptr<WebCache>* instancePtr = instance(isPrivateBrowsing);
91     *instancePtr = 0;
92 }
93 
WebCache(bool isPrivateBrowsing)94 WebCache::WebCache(bool isPrivateBrowsing)
95     : m_doomAllEntriesCallback(this, &WebCache::doomAllEntries)
96     , m_onClearDoneCallback(this, &WebCache::onClearDone)
97     , m_isClearInProgress(false)
98     , m_openEntryCallback(this, &WebCache::openEntry)
99     , m_onGetEntryDoneCallback(this, &WebCache::onGetEntryDone)
100     , m_isGetEntryInProgress(false)
101     , m_cacheBackend(0)
102 {
103     base::Thread* ioThread = WebUrlLoaderClient::ioThread();
104     scoped_refptr<base::MessageLoopProxy> cacheMessageLoopProxy = ioThread->message_loop_proxy();
105 
106     static const int kMaximumCacheSizeBytes = 20 * 1024 * 1024;
107     m_hostResolver = net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism, 0, 0);
108 
109     m_proxyConfigService = new ProxyConfigServiceAndroid();
110     net::HttpCache::BackendFactory* backendFactory;
111     if (isPrivateBrowsing)
112         backendFactory = net::HttpCache::DefaultBackend::InMemory(kMaximumCacheSizeBytes / 2);
113     else {
114         FilePath directoryPath(storageDirectory().c_str());
115         backendFactory = new net::HttpCache::DefaultBackend(net::DISK_CACHE, directoryPath, kMaximumCacheSizeBytes, cacheMessageLoopProxy);
116     }
117 
118     m_cache = new net::HttpCache(m_hostResolver.get(),
119                                  new CertVerifier(),
120                                  0, // dnsrr_resolver
121                                  0, // dns_cert_checker
122                                  net::ProxyService::CreateWithoutProxyResolver(m_proxyConfigService, 0 /* net_log */),
123                                  net::SSLConfigService::CreateSystemSSLConfigService(),
124                                  net::HttpAuthHandlerFactory::CreateDefault(m_hostResolver.get()),
125                                  0, // network_delegate
126                                  0, // net_log
127                                  backendFactory);
128 }
129 
clear()130 void WebCache::clear()
131 {
132     base::Thread* thread = WebUrlLoaderClient::ioThread();
133     if (thread)
134         thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::clearImpl));
135 }
136 
closeIdleConnections()137 void WebCache::closeIdleConnections()
138 {
139     base::Thread* thread = WebUrlLoaderClient::ioThread();
140     if (thread)
141         thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::closeIdleImpl));
142 }
143 
closeIdleImpl()144 void WebCache::closeIdleImpl()
145 {
146     m_cache->CloseIdleConnections();
147 }
148 
clearImpl()149 void WebCache::clearImpl()
150 {
151     if (m_isClearInProgress)
152         return;
153     m_isClearInProgress = true;
154 
155     if (!m_cacheBackend) {
156         int code = m_cache->GetBackend(&m_cacheBackend, &m_doomAllEntriesCallback);
157         // Code ERR_IO_PENDING indicates that the operation is still in progress and
158         // the supplied callback will be invoked when it completes.
159         if (code == ERR_IO_PENDING)
160             return;
161         else if (code != OK) {
162             onClearDone(0 /*unused*/);
163             return;
164         }
165     }
166     doomAllEntries(0 /*unused*/);
167 }
168 
doomAllEntries(int)169 void WebCache::doomAllEntries(int)
170 {
171     if (!m_cacheBackend) {
172         onClearDone(0 /*unused*/);
173         return;
174     }
175 
176     // Code ERR_IO_PENDING indicates that the operation is still in progress and
177     // the supplied callback will be invoked when it completes.
178     if (m_cacheBackend->DoomAllEntries(&m_onClearDoneCallback) == ERR_IO_PENDING)
179         return;
180     onClearDone(0 /*unused*/);
181 }
182 
onClearDone(int)183 void WebCache::onClearDone(int)
184 {
185     m_isClearInProgress = false;
186 }
187 
getCacheResult(String url)188 scoped_refptr<CacheResult> WebCache::getCacheResult(String url)
189 {
190     // This is called on the UI thread.
191     MutexLocker lock(m_getEntryMutex);
192     if (m_isGetEntryInProgress)
193         return 0; // TODO: OK? Or can we queue 'em up?
194 
195     // The Chromium methods are asynchronous, but we need this method to be
196     // synchronous. Do the work on the Chromium thread but block this thread
197     // here waiting for the work to complete.
198     base::Thread* thread = WebUrlLoaderClient::ioThread();
199     if (!thread)
200         return 0;
201 
202     m_entry = 0;
203     m_isGetEntryInProgress = true;
204     m_entryUrl = url.threadsafeCopy();
205     thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::getEntryImpl));
206 
207     while (m_isGetEntryInProgress)
208         m_getEntryCondition.wait(m_getEntryMutex);
209 
210     if (!m_entry)
211         return 0;
212 
213     return new CacheResult(m_entry, url);
214 }
215 
getEntryImpl()216 void WebCache::getEntryImpl()
217 {
218     if (!m_cacheBackend) {
219         int code = m_cache->GetBackend(&m_cacheBackend, &m_openEntryCallback);
220         if (code == ERR_IO_PENDING)
221             return;
222         else if (code != OK) {
223             onGetEntryDone(0 /*unused*/);
224             return;
225         }
226     }
227     openEntry(0 /*unused*/);
228 }
229 
openEntry(int)230 void WebCache::openEntry(int)
231 {
232     if (!m_cacheBackend) {
233         onGetEntryDone(0 /*unused*/);
234         return;
235     }
236 
237     if (m_cacheBackend->OpenEntry(string(m_entryUrl.utf8().data()), &m_entry, &m_onGetEntryDoneCallback) == ERR_IO_PENDING)
238         return;
239     onGetEntryDone(0 /*unused*/);
240 }
241 
onGetEntryDone(int)242 void WebCache::onGetEntryDone(int)
243 {
244     // Unblock the UI thread in getEntry();
245     MutexLocker lock(m_getEntryMutex);
246     m_isGetEntryInProgress = false;
247     m_getEntryCondition.signal();
248 }
249 
250 } // namespace android
251