1 /* 2 * Copyright (C) 2009 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 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "ApplicationCacheHost.h" 33 34 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 35 36 #include "ApplicationCacheHostInternal.h" 37 #include "DocumentLoader.h" 38 #include "DOMApplicationCache.h" 39 #include "Frame.h" 40 #include "InspectorApplicationCacheAgent.h" 41 #include "InspectorInstrumentation.h" 42 #include "Page.h" 43 #include "ProgressEvent.h" 44 #include "Settings.h" 45 #include "WebFrameImpl.h" 46 #include "WebURL.h" 47 #include "WebURLError.h" 48 #include "WebURLResponse.h" 49 #include "WebVector.h" 50 #include "WrappedResourceRequest.h" 51 #include "WrappedResourceResponse.h" 52 53 using namespace WebKit; 54 55 namespace WebCore { 56 57 // We provide a custom implementation of this class that calls out to the 58 // embedding application instead of using WebCore's built in appcache system. 59 // This file replaces webcore/appcache/ApplicationCacheHost.cpp in our build. 60 61 ApplicationCacheHost::ApplicationCacheHost(DocumentLoader* documentLoader) 62 : m_domApplicationCache(0) 63 , m_documentLoader(documentLoader) 64 , m_defersEvents(true) 65 { 66 ASSERT(m_documentLoader); 67 } 68 69 ApplicationCacheHost::~ApplicationCacheHost() 70 { 71 } 72 73 void ApplicationCacheHost::maybeLoadMainResource(ResourceRequest& request, SubstituteData&) 74 { 75 // We defer creating the outer host object to avoid spurious creation/destruction 76 // around creating empty documents. At this point, we're initiating a main resource 77 // load for the document, so its for real. 78 79 if (!isApplicationCacheEnabled()) 80 return; 81 82 m_internal.set(new ApplicationCacheHostInternal(this)); 83 if (m_internal->m_outerHost) { 84 WrappedResourceRequest wrapped(request); 85 m_internal->m_outerHost->willStartMainResourceRequest(wrapped, WebFrameImpl::fromFrame(m_documentLoader->frame())); 86 } else 87 m_internal.clear(); 88 89 // NOTE: The semantics of this method, and others in this interface, are subtly different 90 // than the method names would suggest. For example, in this method never returns an appcached 91 // response in the SubstituteData out argument, instead we return the appcached response thru 92 // the usual resource loading pipeline. 93 } 94 95 void ApplicationCacheHost::selectCacheWithoutManifest() 96 { 97 if (m_internal) 98 m_internal->m_outerHost->selectCacheWithoutManifest(); 99 } 100 101 void ApplicationCacheHost::selectCacheWithManifest(const KURL& manifestURL) 102 { 103 if (m_internal) { 104 if (!m_internal->m_outerHost->selectCacheWithManifest(manifestURL)) { 105 // It's a foreign entry, restart the current navigation from the top 106 // of the navigation algorithm. The navigation will not result in the 107 // same resource being loaded, because "foreign" entries are never picked 108 // during navigation. 109 // see WebCore::ApplicationCacheGroup::selectCache() 110 Frame* frame = m_documentLoader->frame(); 111 frame->navigationScheduler()->scheduleLocationChange(frame->document()->securityOrigin(), 112 frame->document()->url(), frame->loader()->referrer()); 113 } 114 } 115 } 116 117 void ApplicationCacheHost::maybeLoadMainResourceForRedirect(ResourceRequest&, SubstituteData&) 118 { 119 // N/A to the chromium port 120 } 121 122 bool ApplicationCacheHost::maybeLoadFallbackForMainResponse(const ResourceRequest&, const ResourceResponse& response) 123 { 124 if (m_internal) { 125 WrappedResourceResponse wrapped(response); 126 m_internal->m_outerHost->didReceiveResponseForMainResource(wrapped); 127 } 128 return false; 129 } 130 131 bool ApplicationCacheHost::maybeLoadFallbackForMainError(const ResourceRequest&, const ResourceError& error) 132 { 133 // N/A to the chromium port 134 return false; 135 } 136 137 void ApplicationCacheHost::mainResourceDataReceived(const char* data, int length, long long, bool) 138 { 139 if (m_internal) 140 m_internal->m_outerHost->didReceiveDataForMainResource(data, length); 141 } 142 143 void ApplicationCacheHost::failedLoadingMainResource() 144 { 145 if (m_internal) 146 m_internal->m_outerHost->didFinishLoadingMainResource(false); 147 } 148 149 void ApplicationCacheHost::finishedLoadingMainResource() 150 { 151 if (m_internal) 152 m_internal->m_outerHost->didFinishLoadingMainResource(true); 153 } 154 155 bool ApplicationCacheHost::maybeLoadResource(ResourceLoader*, ResourceRequest& request, const KURL&) 156 { 157 // FIXME: look into the purpose of the unused KURL& originalURL parameter 158 if (m_internal) { 159 WrappedResourceRequest wrapped(request); 160 m_internal->m_outerHost->willStartSubResourceRequest(wrapped); 161 } 162 return false; 163 } 164 165 bool ApplicationCacheHost::maybeLoadFallbackForRedirect(ResourceLoader*, ResourceRequest&, const ResourceResponse&) 166 { 167 // N/A to the chromium port 168 return false; 169 } 170 171 bool ApplicationCacheHost::maybeLoadFallbackForResponse(ResourceLoader*, const ResourceResponse&) 172 { 173 // N/A to the chromium port 174 return false; 175 } 176 177 bool ApplicationCacheHost::maybeLoadFallbackForError(ResourceLoader*, const ResourceError&) 178 { 179 // N/A to the chromium port 180 return false; 181 } 182 183 bool ApplicationCacheHost::maybeLoadSynchronously(ResourceRequest& request, ResourceError&, ResourceResponse&, Vector<char>&) 184 { 185 if (m_internal) { 186 WrappedResourceRequest wrapped(request); 187 m_internal->m_outerHost->willStartSubResourceRequest(wrapped); 188 } 189 return false; 190 } 191 192 void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>&) 193 { 194 // N/A to the chromium port 195 } 196 197 bool ApplicationCacheHost::canCacheInPageCache() const 198 { 199 // N/A to the chromium port which doesn't use the page cache. 200 return false; 201 } 202 203 void ApplicationCacheHost::setDOMApplicationCache(DOMApplicationCache* domApplicationCache) 204 { 205 ASSERT(!m_domApplicationCache || !domApplicationCache); 206 m_domApplicationCache = domApplicationCache; 207 } 208 209 void ApplicationCacheHost::notifyDOMApplicationCache(EventID id, int total, int done) 210 { 211 #if ENABLE(INSPECTOR) 212 if (id != PROGRESS_EVENT) 213 InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader->frame()); 214 #endif 215 216 if (m_defersEvents) { 217 // Event dispatching is deferred until document.onload has fired. 218 m_deferredEvents.append(DeferredEvent(id, total, done)); 219 return; 220 } 221 dispatchDOMEvent(id, total, done); 222 } 223 224 #if ENABLE(INSPECTOR) 225 ApplicationCacheHost::CacheInfo ApplicationCacheHost::applicationCacheInfo() 226 { 227 if (!m_internal) 228 return CacheInfo(KURL(), 0, 0, 0); 229 230 WebKit::WebApplicationCacheHost::CacheInfo webInfo; 231 m_internal->m_outerHost->getAssociatedCacheInfo(&webInfo); 232 return CacheInfo(webInfo.manifestURL, webInfo.creationTime, webInfo.updateTime, webInfo.totalSize); 233 } 234 235 void ApplicationCacheHost::fillResourceList(ResourceInfoList* resources) 236 { 237 if (!m_internal) 238 return; 239 240 WebKit::WebVector<WebKit::WebApplicationCacheHost::ResourceInfo> webResources; 241 m_internal->m_outerHost->getResourceList(&webResources); 242 for (size_t i = 0; i < webResources.size(); ++i) { 243 resources->append(ResourceInfo( 244 webResources[i].url, webResources[i].isMaster, webResources[i].isManifest, webResources[i].isFallback, 245 webResources[i].isForeign, webResources[i].isExplicit, webResources[i].size)); 246 } 247 } 248 #endif 249 250 void ApplicationCacheHost::stopDeferringEvents() 251 { 252 RefPtr<DocumentLoader> protect(documentLoader()); 253 for (unsigned i = 0; i < m_deferredEvents.size(); ++i) { 254 const DeferredEvent& deferred = m_deferredEvents[i]; 255 dispatchDOMEvent(deferred.eventID, deferred.progressTotal, deferred.progressDone); 256 } 257 m_deferredEvents.clear(); 258 m_defersEvents = false; 259 } 260 261 void ApplicationCacheHost::stopLoadingInFrame(Frame* frame) 262 { 263 // N/A to the chromium port 264 } 265 266 void ApplicationCacheHost::dispatchDOMEvent(EventID id, int total, int done) 267 { 268 if (m_domApplicationCache) { 269 const AtomicString& eventType = DOMApplicationCache::toEventType(id); 270 ExceptionCode ec = 0; 271 RefPtr<Event> event; 272 if (id == PROGRESS_EVENT) 273 event = ProgressEvent::create(eventType, true, done, total); 274 else 275 event = Event::create(eventType, false, false); 276 m_domApplicationCache->dispatchEvent(event, ec); 277 ASSERT(!ec); 278 } 279 } 280 281 ApplicationCacheHost::Status ApplicationCacheHost::status() const 282 { 283 return m_internal ? static_cast<Status>(m_internal->m_outerHost->status()) : UNCACHED; 284 } 285 286 bool ApplicationCacheHost::update() 287 { 288 return m_internal ? m_internal->m_outerHost->startUpdate() : false; 289 } 290 291 bool ApplicationCacheHost::swapCache() 292 { 293 return m_internal ? m_internal->m_outerHost->swapCache() : false; 294 } 295 296 bool ApplicationCacheHost::isApplicationCacheEnabled() 297 { 298 ASSERT(m_documentLoader->frame()); 299 return m_documentLoader->frame()->settings() 300 && m_documentLoader->frame()->settings()->offlineWebApplicationCacheEnabled(); 301 } 302 303 } // namespace WebCore 304 305 #endif // ENABLE(OFFLINE_WEB_APPLICATIONS) 306