Bluetooth: fix header sentry comment style
[chromium-blink-merge.git] / webkit / appcache / appcache_request_handler.cc
blobb400b14011f4b9186e4799e0ffb5a5b2dfc552b0
1 // Copyright (c) 2011 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.
5 #include "webkit/appcache/appcache_request_handler.h"
7 #include "net/url_request/url_request.h"
8 #include "net/url_request/url_request_job.h"
9 #include "webkit/appcache/appcache.h"
10 #include "webkit/appcache/appcache_policy.h"
11 #include "webkit/appcache/appcache_url_request_job.h"
13 namespace appcache {
15 AppCacheRequestHandler::AppCacheRequestHandler(
16 AppCacheHost* host, ResourceType::Type resource_type)
17 : host_(host), resource_type_(resource_type),
18 is_waiting_for_cache_selection_(false), found_group_id_(0),
19 found_cache_id_(0), found_network_namespace_(false),
20 cache_entry_not_found_(false), maybe_load_resource_executed_(false) {
21 DCHECK(host_);
22 host_->AddObserver(this);
25 AppCacheRequestHandler::~AppCacheRequestHandler() {
26 if (host_) {
27 storage()->CancelDelegateCallbacks(this);
28 host_->RemoveObserver(this);
32 AppCacheStorage* AppCacheRequestHandler::storage() const {
33 DCHECK(host_);
34 return host_->service()->storage();
37 void AppCacheRequestHandler::GetExtraResponseInfo(
38 int64* cache_id, GURL* manifest_url) {
39 if (job_ && job_->is_delivering_appcache_response()) {
40 *cache_id = job_->cache_id();
41 *manifest_url = job_->manifest_url();
45 AppCacheURLRequestJob* AppCacheRequestHandler::MaybeLoadResource(
46 net::URLRequest* request, net::NetworkDelegate* network_delegate) {
47 maybe_load_resource_executed_ = true;
48 if (!host_ || !IsSchemeAndMethodSupported(request) || cache_entry_not_found_)
49 return NULL;
51 // This method can get called multiple times over the life
52 // of a request. The case we detect here is having scheduled
53 // delivery of a "network response" using a job setup on an
54 // earlier call thru this method. To send the request thru
55 // to the network involves restarting the request altogether,
56 // which will call thru to our interception layer again.
57 // This time thru, we return NULL so the request hits the wire.
58 if (job_) {
59 DCHECK(job_->is_delivering_network_response() ||
60 job_->cache_entry_not_found());
61 if (job_->cache_entry_not_found())
62 cache_entry_not_found_ = true;
63 job_ = NULL;
64 storage()->CancelDelegateCallbacks(this);
65 return NULL;
68 // Clear out our 'found' fields since we're starting a request for a
69 // new resource, any values in those fields are no longer valid.
70 found_entry_ = AppCacheEntry();
71 found_fallback_entry_ = AppCacheEntry();
72 found_cache_id_ = kNoCacheId;
73 found_manifest_url_ = GURL();
74 found_network_namespace_ = false;
76 if (is_main_resource())
77 MaybeLoadMainResource(request, network_delegate);
78 else
79 MaybeLoadSubResource(request, network_delegate);
81 // If its been setup to deliver a network response, we can just delete
82 // it now and return NULL instead to achieve that since it couldn't
83 // have been started yet.
84 if (job_ && job_->is_delivering_network_response()) {
85 DCHECK(!job_->has_been_started());
86 job_ = NULL;
89 return job_;
92 AppCacheURLRequestJob* AppCacheRequestHandler::MaybeLoadFallbackForRedirect(
93 net::URLRequest* request,
94 net::NetworkDelegate* network_delegate,
95 const GURL& location) {
96 if (!host_ || !IsSchemeAndMethodSupported(request) || cache_entry_not_found_)
97 return NULL;
98 if (is_main_resource())
99 return NULL;
100 // TODO(vabr) This is a temporary fix (see crbug/141114). We should get rid of
101 // it once a more general solution to crbug/121325 is in place.
102 if (!maybe_load_resource_executed_)
103 return NULL;
104 if (request->url().GetOrigin() == location.GetOrigin())
105 return NULL;
107 DCHECK(!job_); // our jobs never generate redirects
109 if (found_fallback_entry_.has_response_id()) {
110 // 6.9.6, step 4: If this results in a redirect to another origin,
111 // get the resource of the fallback entry.
112 job_ = new AppCacheURLRequestJob(request, network_delegate, storage());
113 DeliverAppCachedResponse(
114 found_fallback_entry_, found_cache_id_, found_group_id_,
115 found_manifest_url_, true, found_namespace_entry_url_);
116 } else if (!found_network_namespace_) {
117 // 6.9.6, step 6: Fail the resource load.
118 job_ = new AppCacheURLRequestJob(request, network_delegate, storage());
119 DeliverErrorResponse();
120 } else {
121 // 6.9.6 step 3 and 5: Fetch the resource normally.
124 return job_;
127 AppCacheURLRequestJob* AppCacheRequestHandler::MaybeLoadFallbackForResponse(
128 net::URLRequest* request, net::NetworkDelegate* network_delegate) {
129 if (!host_ || !IsSchemeAndMethodSupported(request) || cache_entry_not_found_)
130 return NULL;
131 if (!found_fallback_entry_.has_response_id())
132 return NULL;
134 if (request->status().status() == net::URLRequestStatus::CANCELED) {
135 // 6.9.6, step 4: But not if the user canceled the download.
136 return NULL;
139 // We don't fallback for responses that we delivered.
140 if (job_) {
141 DCHECK(!job_->is_delivering_network_response());
142 return NULL;
145 if (request->status().is_success()) {
146 int code_major = request->GetResponseCode() / 100;
147 if (code_major !=4 && code_major != 5)
148 return NULL;
150 // Servers can override the fallback behavior with a response header.
151 const std::string kFallbackOverrideHeader(
152 "x-chromium-appcache-fallback-override");
153 const std::string kFallbackOverrideValue(
154 "disallow-fallback");
155 std::string header_value;
156 request->GetResponseHeaderByName(kFallbackOverrideHeader, &header_value);
157 if (header_value == kFallbackOverrideValue)
158 return NULL;
161 // 6.9.6, step 4: If this results in a 4xx or 5xx status code
162 // or there were network errors, get the resource of the fallback entry.
163 job_ = new AppCacheURLRequestJob(request, network_delegate, storage());
164 DeliverAppCachedResponse(
165 found_fallback_entry_, found_cache_id_, found_group_id_,
166 found_manifest_url_, true, found_namespace_entry_url_);
167 return job_;
170 void AppCacheRequestHandler::OnDestructionImminent(AppCacheHost* host) {
171 storage()->CancelDelegateCallbacks(this);
172 host_ = NULL; // no need to RemoveObserver, the host is being deleted
174 // Since the host is being deleted, we don't have to complete any job
175 // that is current running. It's destined for the bit bucket anyway.
176 if (job_) {
177 job_->Kill();
178 job_ = NULL;
182 void AppCacheRequestHandler::DeliverAppCachedResponse(
183 const AppCacheEntry& entry, int64 cache_id, int64 group_id,
184 const GURL& manifest_url, bool is_fallback,
185 const GURL& namespace_entry_url) {
186 DCHECK(host_ && job_ && job_->is_waiting());
187 DCHECK(entry.has_response_id());
189 if (ResourceType::IsFrame(resource_type_) && !namespace_entry_url.is_empty())
190 host_->NotifyMainResourceIsNamespaceEntry(namespace_entry_url);
192 job_->DeliverAppCachedResponse(manifest_url, group_id, cache_id,
193 entry, is_fallback);
196 void AppCacheRequestHandler::DeliverErrorResponse() {
197 DCHECK(job_ && job_->is_waiting());
198 job_->DeliverErrorResponse();
201 void AppCacheRequestHandler::DeliverNetworkResponse() {
202 DCHECK(job_ && job_->is_waiting());
203 job_->DeliverNetworkResponse();
206 // Main-resource handling ----------------------------------------------
208 void AppCacheRequestHandler::MaybeLoadMainResource(
209 net::URLRequest* request, net::NetworkDelegate* network_delegate) {
210 DCHECK(!job_);
211 DCHECK(host_);
213 const AppCacheHost* spawning_host =
214 ResourceType::IsSharedWorker(resource_type_) ?
215 host_ : host_->GetSpawningHost();
216 GURL preferred_manifest_url = spawning_host ?
217 spawning_host->preferred_manifest_url() : GURL();
219 // We may have to wait for our storage query to complete, but
220 // this query can also complete syncrhonously.
221 job_ = new AppCacheURLRequestJob(request, network_delegate, storage());
222 storage()->FindResponseForMainRequest(
223 request->url(), preferred_manifest_url, this);
226 void AppCacheRequestHandler::OnMainResponseFound(
227 const GURL& url, const AppCacheEntry& entry,
228 const GURL& namespace_entry_url, const AppCacheEntry& fallback_entry,
229 int64 cache_id, int64 group_id, const GURL& manifest_url) {
230 DCHECK(job_);
231 DCHECK(host_);
232 DCHECK(is_main_resource());
233 DCHECK(!entry.IsForeign());
234 DCHECK(!fallback_entry.IsForeign());
235 DCHECK(!(entry.has_response_id() && fallback_entry.has_response_id()));
237 if (!job_)
238 return;
240 AppCachePolicy* policy = host_->service()->appcache_policy();
241 bool was_blocked_by_policy = !manifest_url.is_empty() && policy &&
242 !policy->CanLoadAppCache(manifest_url, host_->first_party_url());
244 if (was_blocked_by_policy) {
245 if (ResourceType::IsFrame(resource_type_)) {
246 host_->NotifyMainResourceBlocked(manifest_url);
247 } else {
248 DCHECK(ResourceType::IsSharedWorker(resource_type_));
249 host_->frontend()->OnContentBlocked(host_->host_id(), manifest_url);
251 DeliverNetworkResponse();
252 return;
255 if (ResourceType::IsFrame(resource_type_) && cache_id != kNoCacheId) {
256 // AppCacheHost loads and holds a reference to the main resource cache
257 // for two reasons, firstly to preload the cache into the working set
258 // in advance of subresource loads happening, secondly to prevent the
259 // AppCache from falling out of the working set on frame navigations.
260 host_->LoadMainResourceCache(cache_id);
261 host_->set_preferred_manifest_url(manifest_url);
264 // 6.11.1 Navigating across documents, steps 10 and 14.
266 found_entry_ = entry;
267 found_namespace_entry_url_ = namespace_entry_url;
268 found_fallback_entry_ = fallback_entry;
269 found_cache_id_ = cache_id;
270 found_group_id_ = group_id;
271 found_manifest_url_ = manifest_url;
272 found_network_namespace_ = false; // not applicable to main requests
274 if (found_entry_.has_response_id()) {
275 DCHECK(!found_fallback_entry_.has_response_id());
276 DeliverAppCachedResponse(
277 found_entry_, found_cache_id_, found_group_id_, found_manifest_url_,
278 false, found_namespace_entry_url_);
279 } else {
280 DeliverNetworkResponse();
284 // Sub-resource handling ----------------------------------------------
286 void AppCacheRequestHandler::MaybeLoadSubResource(
287 net::URLRequest* request, net::NetworkDelegate* network_delegate) {
288 DCHECK(!job_);
290 if (host_->is_selection_pending()) {
291 // We have to wait until cache selection is complete and the
292 // selected cache is loaded.
293 is_waiting_for_cache_selection_ = true;
294 job_ = new AppCacheURLRequestJob(request, network_delegate, storage());
295 return;
298 if (!host_->associated_cache() ||
299 !host_->associated_cache()->is_complete()) {
300 return;
303 job_ = new AppCacheURLRequestJob(request, network_delegate, storage());
304 ContinueMaybeLoadSubResource();
307 void AppCacheRequestHandler::ContinueMaybeLoadSubResource() {
308 // 6.9.6 Changes to the networking model
309 // If the resource is not to be fetched using the HTTP GET mechanism or
310 // equivalent ... then fetch the resource normally.
311 DCHECK(job_);
312 DCHECK(host_->associated_cache() &&
313 host_->associated_cache()->is_complete());
315 const GURL& url = job_->request()->url();
316 AppCache* cache = host_->associated_cache();
317 storage()->FindResponseForSubRequest(
318 host_->associated_cache(), url,
319 &found_entry_, &found_fallback_entry_, &found_network_namespace_);
321 if (found_entry_.has_response_id()) {
322 // Step 2: If there's an entry, get it instead.
323 DCHECK(!found_network_namespace_ &&
324 !found_fallback_entry_.has_response_id());
325 found_cache_id_ = cache->cache_id();
326 found_group_id_ = cache->owning_group()->group_id();
327 found_manifest_url_ = cache->owning_group()->manifest_url();
328 DeliverAppCachedResponse(
329 found_entry_, found_cache_id_, found_group_id_, found_manifest_url_,
330 false, GURL());
331 return;
334 if (found_fallback_entry_.has_response_id()) {
335 // Step 4: Fetch the resource normally, if this results
336 // in certain conditions, then use the fallback.
337 DCHECK(!found_network_namespace_ &&
338 !found_entry_.has_response_id());
339 found_cache_id_ = cache->cache_id();
340 found_manifest_url_ = cache->owning_group()->manifest_url();
341 DeliverNetworkResponse();
342 return;
345 if (found_network_namespace_) {
346 // Step 3 and 5: Fetch the resource normally.
347 DCHECK(!found_entry_.has_response_id() &&
348 !found_fallback_entry_.has_response_id());
349 DeliverNetworkResponse();
350 return;
353 // Step 6: Fail the resource load.
354 DeliverErrorResponse();
357 void AppCacheRequestHandler::OnCacheSelectionComplete(AppCacheHost* host) {
358 DCHECK(host == host_);
359 if (is_main_resource())
360 return;
361 if (!is_waiting_for_cache_selection_)
362 return;
364 is_waiting_for_cache_selection_ = false;
366 if (!host_->associated_cache() ||
367 !host_->associated_cache()->is_complete()) {
368 DeliverNetworkResponse();
369 return;
372 ContinueMaybeLoadSubResource();
375 } // namespace appcache