service_worker_request_handler.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/browser/service_worker/service_worker_request_handler.h" 6 7#include "content/browser/service_worker/service_worker_context_core.h" 8#include "content/browser/service_worker/service_worker_context_wrapper.h" 9#include "content/browser/service_worker/service_worker_provider_host.h" 10#include "content/browser/service_worker/service_worker_registration.h" 11#include "content/browser/service_worker/service_worker_url_request_job.h" 12#include "content/browser/service_worker/service_worker_utils.h" 13#include "content/common/service_worker/service_worker_types.h" 14#include "net/url_request/url_request.h" 15 16namespace content { 17 18namespace { 19 20int kUserDataKey; // Key value is not important. 21 22class ServiceWorkerRequestInterceptor 23 : public net::URLRequestJobFactory::ProtocolHandler { 24 public: 25 ServiceWorkerRequestInterceptor() {} 26 virtual ~ServiceWorkerRequestInterceptor() {} 27 virtual net::URLRequestJob* MaybeCreateJob( 28 net::URLRequest* request, 29 net::NetworkDelegate* network_delegate) const OVERRIDE { 30 ServiceWorkerRequestHandler* handler = 31 ServiceWorkerRequestHandler::GetHandler(request); 32 if (!handler) 33 return NULL; 34 return handler->MaybeCreateJob(request, network_delegate); 35 } 36 37 private: 38 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRequestInterceptor); 39}; 40 41} // namespace 42 43void ServiceWorkerRequestHandler::InitializeHandler( 44 net::URLRequest* request, 45 ServiceWorkerContextWrapper* context_wrapper, 46 int process_id, 47 int provider_id, 48 ResourceType::Type resource_type) { 49 if (!ServiceWorkerUtils::IsFeatureEnabled()) 50 return; 51 52 if (!context_wrapper || !context_wrapper->context() || 53 provider_id == kInvalidServiceWorkerProviderId) { 54 return; 55 } 56 57 ServiceWorkerProviderHost* provider_host = 58 context_wrapper->context()->GetProviderHost(process_id, provider_id); 59 if (!provider_host) 60 return; 61 62 if (!provider_host->ShouldHandleRequest(resource_type)) 63 return; 64 65 scoped_ptr<ServiceWorkerRequestHandler> handler( 66 new ServiceWorkerRequestHandler(context_wrapper->context()->AsWeakPtr(), 67 provider_host->AsWeakPtr(), 68 resource_type)); 69 request->SetUserData(&kUserDataKey, handler.release()); 70} 71 72ServiceWorkerRequestHandler* ServiceWorkerRequestHandler::GetHandler( 73 net::URLRequest* request) { 74 return reinterpret_cast<ServiceWorkerRequestHandler*>( 75 request->GetUserData(&kUserDataKey)); 76} 77 78scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> 79ServiceWorkerRequestHandler::CreateInterceptor() { 80 return make_scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>( 81 new ServiceWorkerRequestInterceptor); 82} 83 84ServiceWorkerRequestHandler::~ServiceWorkerRequestHandler() { 85} 86 87net::URLRequestJob* ServiceWorkerRequestHandler::MaybeCreateJob( 88 net::URLRequest* request, 89 net::NetworkDelegate* network_delegate) { 90 if (!context_ || !provider_host_) { 91 // We can't do anything other than to fall back to network. 92 job_ = NULL; 93 return NULL; 94 } 95 96 // This may get called multiple times for original and redirect requests: 97 // A. original request case: job_ is null, no previous location info. 98 // B. redirect or restarted request case: 99 // a) job_ is non-null if the previous location was forwarded to SW. 100 // b) job_ is null if the previous location was fallback. 101 // c) job_ is non-null if additional restart was required to fall back. 102 103 // We've come here by restart, we already have original request and it 104 // tells we should fallback to network. (Case B-c) 105 if (job_.get() && job_->ShouldFallbackToNetwork()) { 106 job_ = NULL; 107 return NULL; 108 } 109 110 // It's for original request (A) or redirect case (B-a or B-b). 111 DCHECK(!job_.get() || job_->ShouldForwardToServiceWorker()); 112 113 job_ = new ServiceWorkerURLRequestJob(request, network_delegate, 114 provider_host_); 115 if (ServiceWorkerUtils::IsMainResourceType(resource_type_)) 116 PrepareForMainResource(request->url()); 117 else 118 PrepareForSubResource(); 119 120 if (job_->ShouldFallbackToNetwork()) { 121 // If we know we can fallback to network at this point (in case 122 // the storage lookup returned immediately), just return NULL here to 123 // fallback to network. 124 job_ = NULL; 125 return NULL; 126 } 127 128 return job_.get(); 129} 130 131ServiceWorkerRequestHandler::ServiceWorkerRequestHandler( 132 base::WeakPtr<ServiceWorkerContextCore> context, 133 base::WeakPtr<ServiceWorkerProviderHost> provider_host, 134 ResourceType::Type resource_type) 135 : context_(context), 136 provider_host_(provider_host), 137 resource_type_(resource_type), 138 weak_factory_(this) { 139} 140 141void ServiceWorkerRequestHandler::PrepareForMainResource(const GURL& url) { 142 DCHECK(job_.get()); 143 DCHECK(context_); 144 // The corresponding provider_host may already have associate version in 145 // redirect case, unassociate it now. 146 provider_host_->AssociateVersion(NULL); 147 context_->storage()->FindRegistrationForDocument( 148 url, 149 base::Bind(&self::DidLookupRegistrationForMainResource, 150 weak_factory_.GetWeakPtr())); 151} 152 153void ServiceWorkerRequestHandler::DidLookupRegistrationForMainResource( 154 ServiceWorkerStatusCode status, 155 const scoped_refptr<ServiceWorkerRegistration>& registration) { 156 DCHECK(job_.get()); 157 if (status != SERVICE_WORKER_OK || !registration->active_version()) { 158 // No registration, or no active version for the registration is available. 159 job_->FallbackToNetwork(); 160 return; 161 } 162 DCHECK(registration); 163 provider_host_->AssociateVersion(registration->active_version()); 164 job_->ForwardToServiceWorker(); 165} 166 167void ServiceWorkerRequestHandler::PrepareForSubResource() { 168 DCHECK(job_.get()); 169 DCHECK(context_); 170 DCHECK(provider_host_->associated_version()); 171 job_->ForwardToServiceWorker(); 172} 173 174} // namespace content 175