Chromium Code Reviews| Index: content/browser/loader/resource_dispatcher_host_impl.cc |
| diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc |
| index 6cc7f6196f95a3832224a5332cb20df0b113cf6c..eb63c60683f30108eeab45ba851d6238672c52d8 100644 |
| --- a/content/browser/loader/resource_dispatcher_host_impl.cc |
| +++ b/content/browser/loader/resource_dispatcher_host_impl.cc |
| @@ -8,6 +8,7 @@ |
| #include <algorithm> |
| #include <set> |
| +#include <utility> |
| #include <vector> |
| #include "base/bind.h" |
| @@ -19,6 +20,7 @@ |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/shared_memory.h" |
| #include "base/message_loop/message_loop.h" |
| +#include "base/metrics/field_trial.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/metrics/sparse_histogram.h" |
| #include "base/profiler/scoped_tracker.h" |
| @@ -91,6 +93,8 @@ |
| #include "net/cookies/cookie_monster.h" |
| #include "net/http/http_response_headers.h" |
| #include "net/http/http_response_info.h" |
| +#include "net/http/http_transaction_factory.h" |
| +#include "net/http/http_util.h" |
| #include "net/ssl/ssl_cert_request_info.h" |
| #include "net/url_request/url_request.h" |
| #include "net/url_request/url_request_context.h" |
| @@ -435,6 +439,23 @@ void LogResourceRequestTimeOnUI( |
| } |
| } |
| +bool QualifiesForAsyncRevalidation(const ResourceHostMsg_Request& request) { |
| + if (request.load_flags & |
| + (net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | |
| + net::LOAD_VALIDATE_CACHE | net::LOAD_PREFERRING_CACHE | |
| + net::LOAD_ONLY_FROM_CACHE)) { |
|
mmenke
2015/10/09 16:02:22
LOAD_IGNORE_LIMITS is also kinda weird. You eithe
Adam Rice
2015/10/13 22:53:17
LOAD_IGNORE_LIMITS is never set by Blink, but I ad
|
| + return false; |
| + } |
| + if (request.method != "GET") |
| + return false; |
| + // A GET request should not have a body, but don't leave it to chance. |
| + if (request.request_body.get()) |
| + return false; |
| + if (!request.url.SchemeIsHTTPOrHTTPS()) |
| + return false; |
| + return true; |
| +} |
| + |
| } // namespace |
| // static |
| @@ -448,14 +469,14 @@ ResourceDispatcherHostImpl::ResourceDispatcherHostImpl() |
| is_shutdown_(false), |
| num_in_flight_requests_(0), |
| max_num_in_flight_requests_(base::SharedMemory::GetHandleLimit()), |
| - max_num_in_flight_requests_per_process_( |
| - static_cast<int>( |
| - max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)), |
| + max_num_in_flight_requests_per_process_(static_cast<int>( |
| + max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)), |
| max_outstanding_requests_cost_per_process_( |
| kMaxOutstandingRequestsCostPerProcess), |
| filter_(NULL), |
| delegate_(NULL), |
| - allow_cross_origin_auth_prompt_(false) { |
| + allow_cross_origin_auth_prompt_(false), |
| + async_revalidation_enabled_(false) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| DCHECK(!g_resource_dispatcher_host); |
| g_resource_dispatcher_host = this; |
| @@ -473,10 +494,19 @@ ResourceDispatcherHostImpl::ResourceDispatcherHostImpl() |
| update_load_states_timer_.reset( |
| new base::RepeatingTimer<ResourceDispatcherHostImpl>()); |
| + |
| + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| + if (base::FieldTrialList::FindFullName("StaleWhileRevalidate") == "Enabled" || |
| + command_line->HasSwitch(switches::kEnableStaleWhileRevalidate)) { |
| + async_revalidation_enabled_ = true; |
| + } |
| } |
| ResourceDispatcherHostImpl::~ResourceDispatcherHostImpl() { |
| DCHECK(outstanding_requests_stats_map_.empty()); |
| + // It's not safe to destroy this object while AsyncRevalidationDriver objects |
| + // have callbacks referencing it. |
| + CHECK(in_progress_async_revalidations_.empty()); |
| DCHECK(g_resource_dispatcher_host); |
| g_resource_dispatcher_host = NULL; |
| } |
| @@ -578,6 +608,10 @@ void ResourceDispatcherHostImpl::CancelRequestsForContext( |
| loaders_to_cancel.clear(); |
| + // Cancelling async revalidations should not result in the creation of new |
| + // requests, but do it before the checks just to be on the safe side. |
| + CancelAsyncRevalidationsForResourceContext(context); |
| + |
| // Validate that no more requests for this context were added. |
| for (LoaderMap::const_iterator i = pending_loaders_.begin(); |
| i != pending_loaders_.end(); ++i) { |
| @@ -776,6 +810,14 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::MaybeInterceptAsStream( |
| return handler.Pass(); |
| } |
| +ResourceDispatcherHostImpl::ExtraRequestParams::ExtraRequestParams() |
| + : blob_context(nullptr), |
| + child_id(0), |
| + is_sync_load(false), |
| + use_embedded_identity(false), |
| + support_async_revalidation(false), |
| + extra_headers(nullptr) {} |
| + |
| ResourceDispatcherHostLoginDelegate* |
| ResourceDispatcherHostImpl::CreateLoginDelegate( |
| ResourceLoader* loader, |
| @@ -824,6 +866,14 @@ void ResourceDispatcherHostImpl::DidReceiveRedirect(ResourceLoader* loader, |
| if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_host)) |
| return; |
| + // Remove the LOAD_SUPPORT_ASYNC_REVALIDATION flag if it is present. |
| + net::URLRequest* request = loader->request(); |
| + if (request->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION) { |
| + int new_load_flags = request->load_flags() & |
| + ~net::LOAD_SUPPORT_ASYNC_REVALIDATION; |
| + request->SetLoadFlags(new_load_flags); |
|
davidben
2015/10/08 21:57:51
This isn't sufficient. The first redirect leg alre
Adam Rice
2015/10/13 22:53:17
I think will just modify net::HttpCache::Transacti
|
| + } |
| + |
| // Notify the observers on the UI thread. |
| scoped_ptr<ResourceRedirectDetails> detail(new ResourceRedirectDetails( |
| loader->request(), |
| @@ -846,6 +896,9 @@ void ResourceDispatcherHostImpl::DidReceiveResponse(ResourceLoader* loader) { |
| info->GetChildID(), info->GetRouteID()); |
| } |
| + if (request->response_info().async_revalidation_required) |
| + BeginAsyncRevalidation(request); |
|
mmenke
2015/10/09 16:02:22
We shouldn't call this on failures, right? Partic
mmenke
2015/10/09 16:29:57
David pointed out to me that we don't reach this p
|
| + |
| int render_process_id, render_frame_host; |
| if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_host)) |
| return; |
| @@ -1210,55 +1263,13 @@ void ResourceDispatcherHostImpl::BeginRequest( |
| return; |
| } |
| - // Construct the request. |
| - scoped_ptr<net::URLRequest> new_request = request_context->CreateRequest( |
| - request_data.url, request_data.priority, NULL); |
| - |
| - new_request->set_method(request_data.method); |
| - new_request->set_first_party_for_cookies( |
| - request_data.first_party_for_cookies); |
| - |
| - // If the request is a MAIN_FRAME request, the first-party URL gets updated on |
| - // redirects. |
| - if (request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME) { |
| - new_request->set_first_party_url_policy( |
| - net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT); |
| - } |
| - |
| - const Referrer referrer(request_data.referrer, request_data.referrer_policy); |
| - SetReferrerForRequest(new_request.get(), referrer); |
| - |
| - new_request->SetExtraRequestHeaders(headers); |
| - |
| - storage::BlobStorageContext* blob_context = |
| - GetBlobStorageContext(filter_->blob_storage_context()); |
| - // Resolve elements from request_body and prepare upload data. |
| - if (request_data.request_body.get()) { |
| - // |blob_context| could be null when the request is from the plugins because |
| - // ResourceMessageFilters created in PluginProcessHost don't have the blob |
| - // context. |
| - if (blob_context) { |
| - // Attaches the BlobDataHandles to request_body not to free the blobs and |
| - // any attached shareable files until upload completion. These data will |
| - // be used in UploadDataStream and ServiceWorkerURLRequestJob. |
| - AttachRequestBodyBlobDataHandles( |
| - request_data.request_body.get(), |
| - blob_context); |
| - } |
| - new_request->set_upload(UploadDataStreamBuilder::Build( |
| - request_data.request_body.get(), |
| - blob_context, |
| - filter_->file_system_context(), |
| - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE) |
| - .get())); |
| - } |
| - |
| - bool allow_download = request_data.allow_download && |
| - IsResourceTypeFrame(request_data.resource_type); |
| + ExtraRequestParams params; |
| + params.blob_context = GetBlobStorageContext(filter_->blob_storage_context()); |
| + params.child_id = child_id; |
| + params.is_sync_load = sync_result != nullptr; |
| + params.use_embedded_identity = true; |
| + params.extra_headers = &headers; |
| bool do_not_prompt_for_login = request_data.do_not_prompt_for_login; |
| - bool is_sync_load = sync_result != NULL; |
| - int load_flags = |
| - BuildLoadFlagsForRequest(request_data, child_id, is_sync_load); |
| if (request_data.resource_type == RESOURCE_TYPE_PREFETCH || |
| request_data.resource_type == RESOURCE_TYPE_FAVICON) { |
| do_not_prompt_for_login = true; |
| @@ -1276,18 +1287,19 @@ void ResourceDispatcherHostImpl::BeginRequest( |
| // filter sources for <script>, <link>, <embed>, <object>, <iframe> tags |
| // would be considered vulnerable in and of itself. |
| do_not_prompt_for_login = true; |
| - load_flags |= net::LOAD_DO_NOT_USE_EMBEDDED_IDENTITY; |
| + params.use_embedded_identity = false; |
| } |
| - // Sync loads should have maximum priority and should be the only |
| - // requets that have the ignore limits flag set. |
| - if (is_sync_load) { |
| - DCHECK_EQ(request_data.priority, net::MAXIMUM_PRIORITY); |
| - DCHECK_NE(load_flags & net::LOAD_IGNORE_LIMITS, 0); |
| - } else { |
| - DCHECK_EQ(load_flags & net::LOAD_IGNORE_LIMITS, 0); |
| - } |
| - new_request->SetLoadFlags(load_flags); |
| + // Check if request is eligible for async revalidation. |
| + params.support_async_revalidation = |
| + (!params.is_sync_load && async_revalidation_enabled_ && |
| + QualifiesForAsyncRevalidation(request_data)); |
|
mmenke
2015/10/08 21:58:26
We shouldn't do async revalidations when "predicti
Adam Rice
2015/10/13 22:53:17
I don't agree that stale-while-revalidate is a pre
mmenke
2015/10/13 23:01:53
You are guessing that it will be used in the futur
mmenke
2015/10/14 00:16:49
Worth noting it also potentially drains battery by
Adam Rice
2015/10/14 15:03:45
The feature is not speculative. We are not making
|
| + |
| + scoped_ptr<net::URLRequest> new_request = |
| + ConstructRequest(request_context, request_data, params); |
| + |
| + bool allow_download = request_data.allow_download && |
| + IsResourceTypeFrame(request_data.resource_type); |
| // Make extra info and read footer (contains request ID). |
| ResourceRequestInfoImpl* extra_info = new ResourceRequestInfoImpl( |
| @@ -1312,7 +1324,8 @@ void ResourceDispatcherHostImpl::BeginRequest( |
| request_data.referrer_policy, |
| request_data.visiblity_state, |
| resource_context, filter_->GetWeakPtr(), |
| - !is_sync_load); |
| + !params.is_sync_load, |
| + params.support_async_revalidation ? &request_data : NULL); |
| // Request takes ownership. |
| extra_info->AssociateWithRequest(new_request.get()); |
| @@ -1328,9 +1341,9 @@ void ResourceDispatcherHostImpl::BeginRequest( |
| // Initialize the service worker handler for the request. We don't use |
| // ServiceWorker for synchronous loads to avoid renderer deadlocks. |
| ServiceWorkerRequestHandler::InitializeHandler( |
| - new_request.get(), filter_->service_worker_context(), blob_context, |
| + new_request.get(), filter_->service_worker_context(), params.blob_context, |
| child_id, request_data.service_worker_provider_id, |
| - request_data.skip_service_worker || is_sync_load, |
| + request_data.skip_service_worker || params.is_sync_load, |
| request_data.fetch_request_mode, request_data.fetch_credentials_mode, |
| request_data.fetch_redirect_mode, request_data.resource_type, |
| request_data.fetch_request_context_type, request_data.fetch_frame_type, |
| @@ -1342,16 +1355,79 @@ void ResourceDispatcherHostImpl::BeginRequest( |
| request_data.appcache_host_id, request_data.resource_type, |
| request_data.should_reset_appcache); |
| - scoped_ptr<ResourceHandler> handler( |
| - CreateResourceHandler( |
| - new_request.get(), |
| - request_data, sync_result, route_id, process_type, child_id, |
| - resource_context)); |
| + scoped_ptr<ResourceHandler> handler(CreateResourceHandler( |
| + new_request.get(), request_data, sync_result, route_id, process_type, |
| + child_id, resource_context)); |
| if (handler) |
| BeginRequestInternal(new_request.Pass(), handler.Pass()); |
| } |
| +scoped_ptr<net::URLRequest> ResourceDispatcherHostImpl::ConstructRequest( |
| + net::URLRequestContext* request_context, |
| + const ResourceHostMsg_Request& request_data, |
| + const ExtraRequestParams& extra_params) { |
| + // Construct the request. |
| + scoped_ptr<net::URLRequest> new_request = request_context->CreateRequest( |
| + request_data.url, request_data.priority, NULL); |
| + |
| + new_request->set_method(request_data.method); |
| + new_request->set_first_party_for_cookies( |
| + request_data.first_party_for_cookies); |
| + |
| + // If the request is a MAIN_FRAME request, the first-party URL gets updated on |
| + // redirects. |
| + if (request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME) { |
| + new_request->set_first_party_url_policy( |
| + net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT); |
| + } |
| + |
| + const Referrer referrer(request_data.referrer, request_data.referrer_policy); |
| + SetReferrerForRequest(new_request.get(), referrer); |
| + |
| + new_request->SetExtraRequestHeaders(*extra_params.extra_headers); |
| + |
| + // Resolve elements from request_body and prepare upload data. |
| + if (request_data.request_body.get()) { |
| + // |blob_context| could be null when the request is from the plugins because |
| + // ResourceMessageFilters created in PluginProcessHost don't have the blob |
| + // context. |
| + if (extra_params.blob_context) { |
| + // Attaches the BlobDataHandles to request_body not to free the blobs and |
| + // any attached shareable files until upload completion. These data will |
| + // be used in UploadDataStream and ServiceWorkerURLRequestJob. |
| + AttachRequestBodyBlobDataHandles(request_data.request_body.get(), |
| + extra_params.blob_context); |
| + } |
| + new_request->set_upload(UploadDataStreamBuilder::Build( |
| + request_data.request_body.get(), extra_params.blob_context, |
| + filter_->file_system_context(), |
| + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE) |
| + .get())); |
| + } |
| + |
| + int load_flags = BuildLoadFlagsForRequest(request_data, extra_params.child_id, |
| + extra_params.is_sync_load); |
| + |
| + if (!extra_params.use_embedded_identity) |
| + load_flags |= net::LOAD_DO_NOT_USE_EMBEDDED_IDENTITY; |
| + |
| + if (extra_params.support_async_revalidation) |
| + load_flags |= net::LOAD_SUPPORT_ASYNC_REVALIDATION; |
| + |
| + // Sync loads should have maximum priority and should be the only |
| + // requests that have the ignore limits flag set. |
| + if (extra_params.is_sync_load) { |
| + DCHECK_EQ(request_data.priority, net::MAXIMUM_PRIORITY); |
| + DCHECK_NE(load_flags & net::LOAD_IGNORE_LIMITS, 0); |
| + } else { |
| + DCHECK_EQ(load_flags & net::LOAD_IGNORE_LIMITS, 0); |
| + } |
| + new_request->SetLoadFlags(load_flags); |
| + |
| + return new_request.Pass(); |
| +} |
| + |
| scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler( |
| net::URLRequest* request, |
| const ResourceHostMsg_Request& request_data, |
| @@ -1583,7 +1659,8 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo( |
| blink::WebPageVisibilityStateVisible, |
| context, |
| base::WeakPtr<ResourceMessageFilter>(), // filter |
| - true); // is_async |
| + true, // is_async |
| + NULL); // original_request |
|
davidben
2015/10/08 21:57:52
nullptr
Adam Rice
2015/10/13 22:53:17
Done.
|
| } |
| void ResourceDispatcherHostImpl::OnRenderViewHostCreated(int child_id, |
| @@ -2026,7 +2103,8 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest( |
| blink::WebPageVisibilityStateVisible, |
| resource_context, |
| base::WeakPtr<ResourceMessageFilter>(), // filter |
| - true); |
| + true, // is_async |
| + NULL); // original_message |
|
davidben
2015/10/08 21:57:51
original_request
davidben
2015/10/08 21:57:52
nullptr
Adam Rice
2015/10/13 22:53:17
Done.
Adam Rice
2015/10/13 22:53:17
Done.
|
| // Request takes ownership. |
| extra_info->AssociateWithRequest(new_request.get()); |
| @@ -2053,8 +2131,8 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest( |
| handler = AddStandardHandlers(new_request.get(), resource_type, |
| resource_context, |
| nullptr, // appcache_service |
| - -1, // child_id |
| - -1, // route_id |
| + -1, // child_id |
| + -1, // route_id |
| handler.Pass()); |
| BeginRequestInternal(new_request.Pass(), handler.Pass()); |
| @@ -2392,4 +2470,104 @@ int ResourceDispatcherHostImpl::BuildLoadFlagsForRequest( |
| return load_flags; |
| } |
| +void ResourceDispatcherHostImpl::BeginAsyncRevalidation( |
| + net::URLRequest* for_request) { |
| + ResourceRequestInfoImpl* info = |
| + ResourceRequestInfoImpl::ForRequest(for_request); |
| + DCHECK(info); |
| + ResourceHostMsg_Request* original_request_data = info->original_request(); |
| + DCHECK(original_request_data); |
| + DCHECK(!original_request_data->request_body); |
| + |
| + ResourceHostMsg_Request new_request_data = *original_request_data; |
| + new_request_data.do_not_prompt_for_login = true; |
| + new_request_data.allow_download = false; |
| + new_request_data.priority = net::MINIMUM_PRIORITY; |
| + |
| + int child_id = info->GetChildID(); |
| + int route_id = info->GetRouteID(); |
| + |
| + ResourceContext* resource_context = NULL; |
| + net::URLRequestContext* request_context = NULL; |
| + // This |request_context| needs to be valid until |
| + // RemoveResourceContext(resource_context) is called. This is currently |
| + // correct, see |
| + // https://groups.google.com/a/chromium.org/d/msg/net-dev/lHh764ZFdr0/phJIWXokt7cJ |
|
davidben
2015/10/08 21:57:51
I must have missed the context when you made the o
Adam Rice
2015/10/13 22:53:17
If the child is already gone at this point, I thin
|
| + info->filter()->GetContexts(new_request_data, &resource_context, |
| + &request_context); |
| + CHECK(ContainsKey(active_resource_contexts_, resource_context)); |
| + if (is_shutdown_) |
| + return; |
|
mmenke
2015/10/09 16:02:22
Can this happen while shutting down? Also, why is
Adam Rice
2015/10/13 22:53:17
1. Based on other uses in this file: probably.
2.
|
| + |
| + AsyncRevalidationKey async_revalidation_key( |
| + resource_context, request_context->http_transaction_factory()->GetCache(), |
| + original_request_data->url); |
| + std::pair<AsyncRevalidationMap::iterator, bool> insert_result = |
| + in_progress_async_revalidations_.insert( |
| + AsyncRevalidationMap::value_type(async_revalidation_key, nullptr)); |
| + if (!insert_result.second) { |
| + // A matching async revalidation is already in progress for this cache; we |
| + // don't need another one. |
| + return; |
| + } |
| + |
| + net::HttpRequestHeaders headers; |
| + headers.AddHeadersFromString(new_request_data.headers); |
|
davidben
2015/10/08 21:57:51
If the request did not change, it really needs to
Adam Rice
2015/10/13 22:53:17
The cache will conditionalize the request if If-Mo
|
| + |
| + ExtraRequestParams params; |
| + params.child_id = child_id; |
|
davidben
2015/10/08 21:57:52
This request cannot be associated with this proces
Adam Rice
2015/10/13 22:53:17
This is only used by BuildLoadFlagsForRequest to d
|
| + params.is_sync_load = false; |
| + params.use_embedded_identity = true; |
| + params.support_async_revalidation = false; |
| + params.extra_headers = &headers; |
| + if (new_request_data.resource_type == RESOURCE_TYPE_IMAGE && |
| + HTTP_AUTH_RELATION_BLOCKED_CROSS == |
| + HttpAuthRelationTypeOf(new_request_data.url, |
| + new_request_data.first_party_for_cookies)) { |
|
davidben
2015/10/08 21:57:52
We should avoid duplicating this code. Ideally by
Adam Rice
2015/10/13 22:53:17
I would rather do the experiment first before worr
|
| + // Prevent <img> tags from using cached credentials to third-party sites |
| + // to perform actions on those sites. |
| + params.use_embedded_identity = false; |
| + } |
| + |
| + scoped_ptr<net::URLRequest> new_request = |
| + ConstructRequest(request_context, new_request_data, params); |
| + |
| + scoped_ptr<ResourceThrottle> throttle = scheduler_->ScheduleRequest( |
| + child_id, route_id, false, new_request.get()); |
|
davidben
2015/10/08 21:57:51
Associating the request with child_id / route_id d
Adam Rice
2015/10/13 22:53:17
The async request has to be scheduled after the ot
|
| + // This use of base::Unretained() is safe because the AsyncRevalidatonDriver |
| + // object will be destroyed before this object is. |
| + insert_result.first->second = new AsyncRevalidationDriver( |
| + new_request.Pass(), throttle.Pass(), |
| + base::Bind(&ResourceDispatcherHostImpl::OnAsyncRevalidationComplete, |
| + base::Unretained(this), async_revalidation_key)); |
|
mmenke
2015/10/09 16:02:22
Not creating a ResourceRequestInfo for the request
Adam Rice
2015/10/13 22:53:17
Sorry, I thought we had agreed that the request sh
mmenke
2015/10/13 23:01:53
I'm not saying we should have the object, but that
|
| + insert_result.first->second->StartRequest(); |
| +} |
| + |
| +void ResourceDispatcherHostImpl::OnAsyncRevalidationComplete( |
| + const AsyncRevalidationKey& key) { |
| + // TODO(ricea): Record histograms? |
| + auto it = in_progress_async_revalidations_.find(key); |
| + // This is CHECK() and not DCHECK() because deferencing an off-the-end |
| + // iterator would cause a security hole. |
| + CHECK(it != in_progress_async_revalidations_.end()); |
|
davidben
2015/10/08 21:57:52
I don't think we do CHECK vs DCHECK this way. Othe
Adam Rice
2015/10/13 22:53:17
My understanding is that the security people would
|
| + delete it->second, it->second = nullptr; |
|
davidben
2015/10/08 21:57:51
Style: Don't use the comma operator.
Adam Rice
2015/10/13 22:53:17
Done.
|
| + in_progress_async_revalidations_.erase(it); |
| +} |
| + |
| +void ResourceDispatcherHostImpl::CancelAsyncRevalidationsForResourceContext( |
| + ResourceContext* resource_context) { |
| + // For this algorithm to work, elements using |resource_context| must be |
| + // contiguous in the map (ie. it must form the first part of the key). |
| + AsyncRevalidationKey partial_key(resource_context); |
| + auto next_it = in_progress_async_revalidations_.lower_bound(partial_key); |
| + while (next_it != in_progress_async_revalidations_.end() && |
| + next_it->first.resource_context == resource_context) { |
| + // Erasing the element invalidates the iterator. Increment it first. |
| + auto current_it = next_it++; |
| + current_it->second->CancelRequest(); |
| + delete current_it->second, current_it->second = nullptr; |
|
davidben
2015/10/08 21:57:52
Style: Don't use the comma operator.
Adam Rice
2015/10/13 22:53:17
Done.
|
| + in_progress_async_revalidations_.erase(current_it); |
| + } |
| +} |
| + |
| } // namespace content |