Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/safe_browsing/client_side_model_loader.h" | 5 #include "chrome/browser/safe_browsing/client_side_model_loader.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
| 13 #include "base/single_thread_task_runner.h" | |
| 14 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 15 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 16 #include "base/threading/thread_task_runner_handle.h" | 15 #include "base/threading/sequenced_task_runner_handle.h" |
| 17 #include "base/time/time.h" | 16 #include "base/time/time.h" |
| 18 #include "chrome/browser/safe_browsing/protocol_manager.h" | 17 #include "chrome/browser/safe_browsing/protocol_manager.h" |
| 19 #include "chrome/common/safe_browsing/client_model.pb.h" | 18 #include "chrome/common/safe_browsing/client_model.pb.h" |
| 20 #include "components/data_use_measurement/core/data_use_user_data.h" | 19 #include "components/data_use_measurement/core/data_use_user_data.h" |
| 21 #include "components/safe_browsing/common/safebrowsing_messages.h" | 20 #include "components/safe_browsing/common/safebrowsing_messages.h" |
| 22 #include "components/safe_browsing/common/safebrowsing_switches.h" | 21 #include "components/safe_browsing/common/safebrowsing_switches.h" |
| 23 #include "components/safe_browsing/csd.pb.h" | 22 #include "components/safe_browsing/csd.pb.h" |
| 24 #include "components/variations/variations_associated_data.h" | 23 #include "components/variations/variations_associated_data.h" |
| 25 #include "net/base/load_flags.h" | 24 #include "net/base/load_flags.h" |
| 26 #include "net/http/http_response_headers.h" | 25 #include "net/http/http_response_headers.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 return false; | 80 return false; |
| 82 } | 81 } |
| 83 } | 82 } |
| 84 return true; | 83 return true; |
| 85 } | 84 } |
| 86 | 85 |
| 87 // Model name and URL are a function of is_extended_reporting and Finch. | 86 // Model name and URL are a function of is_extended_reporting and Finch. |
| 88 ModelLoader::ModelLoader(base::Closure update_renderers_callback, | 87 ModelLoader::ModelLoader(base::Closure update_renderers_callback, |
| 89 net::URLRequestContextGetter* request_context_getter, | 88 net::URLRequestContextGetter* request_context_getter, |
| 90 bool is_extended_reporting) | 89 bool is_extended_reporting) |
| 91 : name_(FillInModelName(is_extended_reporting, GetModelNumber())), | 90 : ModelLoader(update_renderers_callback, |
| 91 request_context_getter, | |
| 92 FillInModelName(is_extended_reporting, GetModelNumber())) {} | |
| 93 | |
| 94 // For testing only | |
| 95 ModelLoader::ModelLoader(base::Closure update_renderers_callback, | |
| 96 const std::string& model_name) | |
| 97 : ModelLoader(update_renderers_callback, nullptr, model_name) {} | |
| 98 | |
| 99 ModelLoader::ModelLoader(base::Closure update_renderers_callback, | |
| 100 net::URLRequestContextGetter* request_context_getter, | |
| 101 const std::string& model_name) | |
|
gab
2017/04/25 14:34:08
Can avoid a string copy by taking a std::string by
Joe Mason
2017/04/25 18:05:48
I don't follow. Either we pass it in by reference,
gab
2017/04/25 18:38:27
In the non-test constructor, it's constructed as a
Joe Mason
2017/04/28 13:54:19
But if I take it by value, wouldn't it be copied f
gab
2017/04/28 16:29:53
No because the temporary is an r-value and will be
Joe Mason
2017/04/28 19:43:55
I see. Without the DetachFromSequence call there's
| |
| 102 : name_(model_name), | |
| 92 url_(kClientModelUrlPrefix + name_), | 103 url_(kClientModelUrlPrefix + name_), |
| 93 update_renderers_callback_(update_renderers_callback), | 104 update_renderers_callback_(update_renderers_callback), |
| 94 request_context_getter_(request_context_getter), | 105 request_context_getter_(request_context_getter), |
| 95 weak_factory_(this) { | 106 weak_factory_(this) { |
| 96 DCHECK(url_.is_valid()); | 107 DCHECK(url_.is_valid()); |
| 97 } | |
| 98 | 108 |
| 99 // For testing only | 109 // ScheduleFetch and CancelFetcher must be called on the same sequence, but |
| 100 ModelLoader::ModelLoader(base::Closure update_renderers_callback, | 110 // it doesn't have to be the same one the ModelLoader is constructed on. |
|
gab
2017/04/25 14:34:08
I typically call that the "creation sequence", i.e
Joe Mason
2017/04/28 19:43:55
Removed the Detach call.
| |
| 101 const std::string& model_name) | 111 fetch_sequence_checker_.DetachFromSequence(); |
| 102 : name_(model_name), | |
| 103 url_(kClientModelUrlPrefix + name_), | |
| 104 update_renderers_callback_(update_renderers_callback), | |
| 105 request_context_getter_(NULL), | |
| 106 weak_factory_(this) { | |
| 107 DCHECK(url_.is_valid()); | |
| 108 } | 112 } |
| 109 | 113 |
| 110 ModelLoader::~ModelLoader() { | 114 ModelLoader::~ModelLoader() { |
| 111 } | 115 } |
| 112 | 116 |
| 113 void ModelLoader::StartFetch() { | 117 void ModelLoader::StartFetch() { |
| 114 // Start fetching the model either from the cache or possibly from the | 118 // Start fetching the model either from the cache or possibly from the |
| 115 // network if the model isn't in the cache. | 119 // network if the model isn't in the cache. |
| 116 | 120 |
| 117 // TODO(nparker): If no profile needs this model, we shouldn't fetch it. | 121 // TODO(nparker): If no profile needs this model, we shouldn't fetch it. |
| 118 // Then only re-fetch when a profile setting changes to need it. | 122 // Then only re-fetch when a profile setting changes to need it. |
| 119 // This will save on the order of ~50KB/week/client of bandwidth. | 123 // This will save on the order of ~50KB/week/client of bandwidth. |
| 124 DCHECK(fetch_sequence_checker_.CalledOnValidSequence()); | |
| 120 fetcher_ = net::URLFetcher::Create(0 /* ID used for testing */, url_, | 125 fetcher_ = net::URLFetcher::Create(0 /* ID used for testing */, url_, |
| 121 net::URLFetcher::GET, this); | 126 net::URLFetcher::GET, this); |
| 122 data_use_measurement::DataUseUserData::AttachToFetcher( | 127 data_use_measurement::DataUseUserData::AttachToFetcher( |
| 123 fetcher_.get(), data_use_measurement::DataUseUserData::SAFE_BROWSING); | 128 fetcher_.get(), data_use_measurement::DataUseUserData::SAFE_BROWSING); |
| 124 fetcher_->SetRequestContext(request_context_getter_); | 129 fetcher_->SetRequestContext(request_context_getter_); |
| 125 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | | 130 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | |
| 126 net::LOAD_DO_NOT_SEND_COOKIES); | 131 net::LOAD_DO_NOT_SEND_COOKIES); |
| 127 fetcher_->Start(); | 132 fetcher_->Start(); |
| 128 } | 133 } |
| 129 | 134 |
| 130 void ModelLoader::OnURLFetchComplete(const net::URLFetcher* source) { | 135 void ModelLoader::OnURLFetchComplete(const net::URLFetcher* source) { |
| 136 DCHECK(fetch_sequence_checker_.CalledOnValidSequence()); | |
| 131 DCHECK_EQ(fetcher_.get(), source); | 137 DCHECK_EQ(fetcher_.get(), source); |
| 132 DCHECK_EQ(url_, source->GetURL()); | 138 DCHECK_EQ(url_, source->GetURL()); |
| 133 | 139 |
| 134 std::string data; | 140 std::string data; |
| 135 source->GetResponseAsString(&data); | 141 source->GetResponseAsString(&data); |
| 136 net::URLRequestStatus status = source->GetStatus(); | 142 net::URLRequestStatus status = source->GetStatus(); |
| 137 const bool is_success = status.is_success(); | 143 const bool is_success = status.is_success(); |
| 138 const int response_code = source->GetResponseCode(); | 144 const int response_code = source->GetResponseCode(); |
| 139 SafeBrowsingProtocolManager::RecordHttpResponseOrErrorCode( | 145 SafeBrowsingProtocolManager::RecordHttpResponseOrErrorCode( |
| 140 kUmaModelDownloadResponseMetricName, status, response_code); | 146 kUmaModelDownloadResponseMetricName, status, response_code); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 167 } else { | 173 } else { |
| 168 // The model is valid => replace the existing model with the new one. | 174 // The model is valid => replace the existing model with the new one. |
| 169 model_str_.assign(data); | 175 model_str_.assign(data); |
| 170 model_.swap(model); | 176 model_.swap(model); |
| 171 model_status = MODEL_SUCCESS; | 177 model_status = MODEL_SUCCESS; |
| 172 } | 178 } |
| 173 EndFetch(model_status, max_age); | 179 EndFetch(model_status, max_age); |
| 174 } | 180 } |
| 175 | 181 |
| 176 void ModelLoader::EndFetch(ClientModelStatus status, base::TimeDelta max_age) { | 182 void ModelLoader::EndFetch(ClientModelStatus status, base::TimeDelta max_age) { |
| 183 DCHECK(fetch_sequence_checker_.CalledOnValidSequence()); | |
| 177 // We don't differentiate models in the UMA stats. | 184 // We don't differentiate models in the UMA stats. |
| 178 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.ClientModelStatus", | 185 UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.ClientModelStatus", |
| 179 status, | 186 status, |
| 180 MODEL_STATUS_MAX); | 187 MODEL_STATUS_MAX); |
| 181 if (status == MODEL_SUCCESS) { | 188 if (status == MODEL_SUCCESS) { |
| 182 update_renderers_callback_.Run(); | 189 update_renderers_callback_.Run(); |
| 183 } | 190 } |
| 184 int delay_ms = kClientModelFetchIntervalMs; | 191 int delay_ms = kClientModelFetchIntervalMs; |
| 185 // If the most recently fetched model had a valid max-age and the model was | 192 // If the most recently fetched model had a valid max-age and the model was |
| 186 // valid we're scheduling the next model update for after the max-age expired. | 193 // valid we're scheduling the next model update for after the max-age expired. |
| 187 if (!max_age.is_zero() && | 194 if (!max_age.is_zero() && |
| 188 (status == MODEL_SUCCESS || status == MODEL_NOT_CHANGED)) { | 195 (status == MODEL_SUCCESS || status == MODEL_NOT_CHANGED)) { |
| 189 // We're adding 60s of additional delay to make sure we're past | 196 // We're adding 60s of additional delay to make sure we're past |
| 190 // the model's age. | 197 // the model's age. |
| 191 max_age += base::TimeDelta::FromMinutes(1); | 198 max_age += base::TimeDelta::FromMinutes(1); |
| 192 delay_ms = max_age.InMilliseconds(); | 199 delay_ms = max_age.InMilliseconds(); |
| 193 } | 200 } |
| 194 | 201 |
| 195 // Reset |fetcher_| as it will be re-created on next fetch. | 202 // Reset |fetcher_| as it will be re-created on next fetch. |
| 196 fetcher_.reset(); | 203 fetcher_.reset(); |
| 197 | 204 |
| 198 // Schedule the next model reload. | 205 // Schedule the next model reload. |
| 199 ScheduleFetch(delay_ms); | 206 ScheduleFetch(delay_ms); |
| 200 } | 207 } |
| 201 | 208 |
| 202 void ModelLoader::ScheduleFetch(int64_t delay_ms) { | 209 void ModelLoader::ScheduleFetch(int64_t delay_ms) { |
| 210 // Bind the sequence checker to the current sequence. CancelFetcher must be | |
| 211 // called on the same sequence because it invalidates the WeakPtr. | |
|
gab
2017/04/25 14:34:08
PS: ~ModelLoader() also invalidates WeakPtrs and s
Joe Mason
2017/04/25 18:05:48
Good catch. I'll double check on this before commi
Joe Mason
2017/04/28 13:54:19
I think I'll remove the DetachFromSequence in the
gab
2017/04/28 16:29:52
Yeah let's not detach in constructor if current us
Jialiu Lin
2017/04/28 17:52:47
I'm OK with this. We are no longer actively changi
Joe Mason
2017/04/28 19:43:55
Done.
| |
| 212 DCHECK(fetch_sequence_checker_.CalledOnValidSequence()); | |
| 203 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 213 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 204 safe_browsing::switches::kSbDisableAutoUpdate)) | 214 safe_browsing::switches::kSbDisableAutoUpdate)) |
| 205 return; | 215 return; |
| 206 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 216 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( |
| 207 FROM_HERE, | 217 FROM_HERE, |
| 208 base::BindOnce(&ModelLoader::StartFetch, weak_factory_.GetWeakPtr()), | 218 base::BindOnce(&ModelLoader::StartFetch, weak_factory_.GetWeakPtr()), |
| 209 base::TimeDelta::FromMilliseconds(delay_ms)); | 219 base::TimeDelta::FromMilliseconds(delay_ms)); |
| 210 } | 220 } |
| 211 | 221 |
| 212 void ModelLoader::CancelFetcher() { | 222 void ModelLoader::CancelFetcher() { |
| 223 DCHECK(fetch_sequence_checker_.CalledOnValidSequence()); | |
| 213 // Invalidate any scheduled request. | 224 // Invalidate any scheduled request. |
| 214 weak_factory_.InvalidateWeakPtrs(); | 225 weak_factory_.InvalidateWeakPtrs(); |
| 215 // Cancel any request in progress. | 226 // Cancel any request in progress. |
| 216 fetcher_.reset(); | 227 fetcher_.reset(); |
| 217 } | 228 } |
| 218 | 229 |
| 219 } // namespace safe_browsing | 230 } // namespace safe_browsing |
| OLD | NEW |