Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1096)

Unified Diff: components/network_time/network_time_tracker.cc

Issue 1835823002: network_time_tracker: add temporary time protocol. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: estark review 1 Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/network_time/network_time_tracker.cc
diff --git a/components/network_time/network_time_tracker.cc b/components/network_time/network_time_tracker.cc
index e3dc58ecd754f6ab26550ecb56db4d9a9425a092..9ec2b1897b90cba10c55a7d2d1196d8e3856ac8e 100644
--- a/components/network_time/network_time_tracker.cc
+++ b/components/network_time/network_time_tracker.cc
@@ -8,13 +8,19 @@
#include <utility>
#include "base/i18n/time_formatting.h"
+#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/tick_clock.h"
#include "build/build_config.h"
+#include "components/client_update_protocol/ecdsa.h"
#include "components/network_time/network_time_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_fetcher.h"
+#include "url/gurl.h"
namespace network_time {
@@ -41,6 +47,34 @@ const char kPrefUncertainty[] = "uncertainty";
// Name of a pref that stores the network time via |ToJsTime|.
const char kPrefNetworkTime[] = "network";
+// DO NOT SUBMIT
+const char kTimeServiceURL[] = "http://localhost:6125/time/1/current";
+
+// This is an ECDSA prime256v1 named-curve key.
+// DO NOT SUBMIT.
+const int kKeyVersion = 2;
+const uint8_t kKeyPubBytes[] = {
+ 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+ 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
+ 0x42, 0x00, 0x04, 0xe0, 0x6b, 0x0d, 0x76, 0x75, 0xa3, 0x99, 0x7d, 0x7c,
+ 0x1b, 0xd6, 0x3c, 0x73, 0xbb, 0x4b, 0xfe, 0x0a, 0xe7, 0x2f, 0x61, 0x3d,
+ 0x77, 0x0a, 0xaa, 0x14, 0xd8, 0x5a, 0xbf, 0x14, 0x60, 0xec, 0xf6, 0x32,
+ 0x77, 0xb5, 0xa7, 0xe6, 0x35, 0xa5, 0x61, 0xaf, 0xdc, 0xdf, 0x91, 0xce,
+ 0x45, 0x34, 0x5f, 0x36, 0x85, 0x2f, 0xb9, 0x53, 0x00, 0x5d, 0x86, 0xe7,
+ 0x04, 0x16, 0xe2, 0x3d, 0x21, 0x76, 0x2b};
+
+static std::string GetServerETag(const net::URLFetcher* source) {
+ const net::HttpResponseHeaders* response_headers =
+ source->GetResponseHeaders();
+ if (response_headers == nullptr) {
+ return std::string();
+ }
+ std::string etag;
+ return response_headers->EnumerateHeader(nullptr, "ETag", &etag)
+ ? etag
+ : std::string();
+}
+
} // namespace
// static
@@ -51,8 +85,10 @@ void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) {
NetworkTimeTracker::NetworkTimeTracker(scoped_ptr<base::Clock> clock,
scoped_ptr<base::TickClock> tick_clock,
- PrefService* pref_service)
- : clock_(std::move(clock)),
+ PrefService* pref_service,
+ net::URLRequestContextGetter* getter)
+ : getter_(getter),
+ clock_(std::move(clock)),
tick_clock_(std::move(tick_clock)),
pref_service_(pref_service) {
estark 2016/03/28 23:18:59 Initialize |query_signer_| and |time_fetcher_| to
mab 2016/03/29 03:13:03 Whoa. Surprised that's necessary for scoped_ptr.
const base::DictionaryValue* time_mapping =
@@ -82,12 +118,102 @@ NetworkTimeTracker::NetworkTimeTracker(scoped_ptr<base::Clock> clock,
pref_service_->ClearPref(prefs::kNetworkTimeMapping);
network_time_at_last_measurement_ = base::Time(); // Reset.
}
+ if (getter != nullptr) {
+ query_signer_ = client_update_protocol::Ecdsa::Create(
+ kKeyVersion,
+ {reinterpret_cast<const char*>(kKeyPubBytes), sizeof(kKeyPubBytes)});
+ base::TimeDelta period = base::TimeDelta::FromMinutes(60);
+ query_timer_.Start(FROM_HERE, period, this,
+ &NetworkTimeTracker::QueryTimeService);
+ }
}
NetworkTimeTracker::~NetworkTimeTracker() {
DCHECK(thread_checker_.CalledOnValidThread());
}
+void NetworkTimeTracker::QueryTimeService() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // If GetNetworkTime() returns true, the NetworkTimeTracker thinks
+ // it is in sync, so there is no need to query.
+ base::Time network_time;
+ if (GetNetworkTime(&network_time, nullptr)) {
+ return;
+ }
+
+ std::string query_string;
+ query_signer_->SignRequest({"", 0}, &query_string);
+ GURL url(kTimeServiceURL);
+ GURL::Replacements replacements;
+ replacements.SetQueryStr(query_string);
+ url = url.ReplaceComponents(replacements);
+
+ // This cancels any outstanding fetch.
+ time_fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
+ if (time_fetcher_ == nullptr) {
+ VLOG(1) << "tried to make fetch happen; failed";
+ return;
+ }
+ time_fetcher_->SetRequestContext(getter_);
+ // Not expecting any cookies, but just in case.
+ time_fetcher_->SetLoadFlags(
+ net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_BYPASS_CACHE |
+ net::LOAD_DO_NOT_SEND_AUTH_DATA);
+ time_fetcher_->Start();
+ fetch_started_ = tick_clock_->NowTicks();
+}
+
+void NetworkTimeTracker::OnURLFetchComplete(const net::URLFetcher* source) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(source);
+ if (source->GetStatus().status() != net::URLRequestStatus::SUCCESS &&
+ source->GetResponseCode() != 200) {
+ VLOG(1) << "fetch failed, status=" << source->GetStatus().status()
+ << ",code=" << source->GetResponseCode();
+ return;
+ }
+
+ std::string response_body;
+ if (!source->GetResponseAsString(&response_body)) {
+ VLOG(1) << "failed to get response";
+ return;
+ }
+ DCHECK(query_signer_.get());
+ if (!query_signer_->ValidateResponse(response_body, GetServerETag(source))) {
+ VLOG(1) << "invalid signature";
+ return;
+ }
+ response_body = response_body.substr(5); // Skips leading )]}'\n
+ base::JSONReader reader;
+ scoped_ptr<base::Value> value = reader.Read(response_body);
+ if (value == nullptr) {
+ VLOG(1) << "bad JSON";
+ return;
+ }
+ const base::DictionaryValue* dict;
+ if (!value->GetAsDictionary(&dict)) {
+ VLOG(1) << "not a dictionary";
+ return;
+ }
+ double current_time_millis;
+ if (!dict->GetDouble("current_time_millis", &current_time_millis)) {
+ VLOG(1) << "no current_time_millis";
+ return;
+ }
+ // There's also a "server_nonce" key, which we can ignore.
+ base::Time current_time = base::Time::FromJsTime(current_time_millis);
+ // The extra 10 seconds comes from a property of the time server that we
+ // happen to know, which its maximum allowable clock skew. It's unlikely that
+ // it would ever be that badly wrong, but all the same it's included here to
+ // document the very rough nature of the time service provided by this class.
+ base::TimeDelta resolution =
+ base::TimeDelta::FromMilliseconds(1) + base::TimeDelta::FromSeconds(10);
+ base::TimeDelta latency = tick_clock_->NowTicks() - fetch_started_;
+ UpdateNetworkTime(current_time, resolution, latency, tick_clock_->NowTicks());
+}
+
void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time,
base::TimeDelta resolution,
base::TimeDelta latency,
@@ -131,6 +257,8 @@ void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time,
time_mapping.SetDouble(kPrefNetworkTime,
network_time_at_last_measurement_.ToJsTime());
pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping);
+
+ query_timer_.Reset();
}
bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time,

Powered by Google App Engine
This is Rietveld 408576698