| 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 // This is a small utility that snarfs the server time from the | 5 // This is a small utility that snarfs the server time from the |
| 6 // response headers of an http/https HEAD request and compares it to | 6 // response headers of an http/https HEAD request and compares it to |
| 7 // the local time. | 7 // the local time. |
| 8 // | 8 // |
| 9 // TODO(akalin): Also snarf the server time from the TLS handshake, if | 9 // TODO(akalin): Also snarf the server time from the TLS handshake, if |
| 10 // any (http://crbug.com/146090). | 10 // any (http://crbug.com/146090). |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 public: | 72 public: |
| 73 QuitDelegate() {} | 73 QuitDelegate() {} |
| 74 | 74 |
| 75 virtual ~QuitDelegate() {} | 75 virtual ~QuitDelegate() {} |
| 76 | 76 |
| 77 // net::URLFetcherDelegate implementation. | 77 // net::URLFetcherDelegate implementation. |
| 78 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE { | 78 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE { |
| 79 base::MessageLoop::current()->Quit(); | 79 base::MessageLoop::current()->Quit(); |
| 80 } | 80 } |
| 81 | 81 |
| 82 virtual void OnURLFetchDownloadProgress( | 82 virtual void OnURLFetchDownloadProgress(const net::URLFetcher* source, |
| 83 const net::URLFetcher* source, | 83 int64 current, |
| 84 int64 current, int64 total) OVERRIDE { | 84 int64 total) OVERRIDE { |
| 85 NOTREACHED(); | 85 NOTREACHED(); |
| 86 } | 86 } |
| 87 | 87 |
| 88 virtual void OnURLFetchUploadProgress(const net::URLFetcher* source, | 88 virtual void OnURLFetchUploadProgress(const net::URLFetcher* source, |
| 89 int64 current, int64 total) OVERRIDE { | 89 int64 current, |
| 90 int64 total) OVERRIDE { |
| 90 NOTREACHED(); | 91 NOTREACHED(); |
| 91 } | 92 } |
| 92 | 93 |
| 93 private: | 94 private: |
| 94 DISALLOW_COPY_AND_ASSIGN(QuitDelegate); | 95 DISALLOW_COPY_AND_ASSIGN(QuitDelegate); |
| 95 }; | 96 }; |
| 96 | 97 |
| 97 // NetLog::ThreadSafeObserver implementation that simply prints events | 98 // NetLog::ThreadSafeObserver implementation that simply prints events |
| 98 // to the logs. | 99 // to the logs. |
| 99 class PrintingLogObserver : public net::NetLog::ThreadSafeObserver { | 100 class PrintingLogObserver : public net::NetLog::ThreadSafeObserver { |
| 100 public: | 101 public: |
| 101 PrintingLogObserver() {} | 102 PrintingLogObserver() {} |
| 102 | 103 |
| 103 virtual ~PrintingLogObserver() { | 104 virtual ~PrintingLogObserver() { |
| 104 // This is guaranteed to be safe as this program is single threaded. | 105 // This is guaranteed to be safe as this program is single threaded. |
| 105 net_log()->RemoveThreadSafeObserver(this); | 106 net_log()->RemoveThreadSafeObserver(this); |
| 106 } | 107 } |
| 107 | 108 |
| 108 // NetLog::ThreadSafeObserver implementation: | 109 // NetLog::ThreadSafeObserver implementation: |
| 109 virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE { | 110 virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE { |
| 110 // The log level of the entry is unknown, so just assume it maps | 111 // The log level of the entry is unknown, so just assume it maps |
| 111 // to VLOG(1). | 112 // to VLOG(1). |
| 112 if (!VLOG_IS_ON(1)) | 113 if (!VLOG_IS_ON(1)) |
| 113 return; | 114 return; |
| 114 | 115 |
| 115 const char* const source_type = | 116 const char* const source_type = |
| 116 net::NetLog::SourceTypeToString(entry.source().type); | 117 net::NetLog::SourceTypeToString(entry.source().type); |
| 117 const char* const event_type = | 118 const char* const event_type = net::NetLog::EventTypeToString(entry.type()); |
| 118 net::NetLog::EventTypeToString(entry.type()); | |
| 119 const char* const event_phase = | 119 const char* const event_phase = |
| 120 net::NetLog::EventPhaseToString(entry.phase()); | 120 net::NetLog::EventPhaseToString(entry.phase()); |
| 121 scoped_ptr<base::Value> params(entry.ParametersToValue()); | 121 scoped_ptr<base::Value> params(entry.ParametersToValue()); |
| 122 std::string params_str; | 122 std::string params_str; |
| 123 if (params.get()) { | 123 if (params.get()) { |
| 124 base::JSONWriter::Write(params.get(), ¶ms_str); | 124 base::JSONWriter::Write(params.get(), ¶ms_str); |
| 125 params_str.insert(0, ": "); | 125 params_str.insert(0, ": "); |
| 126 } | 126 } |
| 127 | 127 |
| 128 VLOG(1) << source_type << "(" << entry.source().id << "): " | 128 VLOG(1) << source_type << "(" << entry.source().id << "): " << event_type |
| 129 << event_type << ": " << event_phase << params_str; | 129 << ": " << event_phase << params_str; |
| 130 } | 130 } |
| 131 | 131 |
| 132 private: | 132 private: |
| 133 DISALLOW_COPY_AND_ASSIGN(PrintingLogObserver); | 133 DISALLOW_COPY_AND_ASSIGN(PrintingLogObserver); |
| 134 }; | 134 }; |
| 135 | 135 |
| 136 // Builds a URLRequestContext assuming there's only a single loop. | 136 // Builds a URLRequestContext assuming there's only a single loop. |
| 137 scoped_ptr<net::URLRequestContext> | 137 scoped_ptr<net::URLRequestContext> BuildURLRequestContext( |
| 138 BuildURLRequestContext(net::NetLog* net_log) { | 138 net::NetLog* net_log) { |
| 139 net::URLRequestContextBuilder builder; | 139 net::URLRequestContextBuilder builder; |
| 140 #if defined(OS_LINUX) | 140 #if defined(OS_LINUX) |
| 141 // On Linux, use a fixed ProxyConfigService, since the default one | 141 // On Linux, use a fixed ProxyConfigService, since the default one |
| 142 // depends on glib. | 142 // depends on glib. |
| 143 // | 143 // |
| 144 // TODO(akalin): Remove this once http://crbug.com/146421 is fixed. | 144 // TODO(akalin): Remove this once http://crbug.com/146421 is fixed. |
| 145 builder.set_proxy_config_service( | 145 builder.set_proxy_config_service( |
| 146 new net::ProxyConfigServiceFixed(net::ProxyConfig())); | 146 new net::ProxyConfigServiceFixed(net::ProxyConfig())); |
| 147 #endif | 147 #endif |
| 148 scoped_ptr<net::URLRequestContext> context(builder.Build()); | 148 scoped_ptr<net::URLRequestContext> context(builder.Build()); |
| 149 context->set_net_log(net_log); | 149 context->set_net_log(net_log); |
| 150 return context.Pass(); | 150 return context.Pass(); |
| 151 } | 151 } |
| 152 | 152 |
| 153 class SingleThreadRequestContextGetter : public net::URLRequestContextGetter { | 153 class SingleThreadRequestContextGetter : public net::URLRequestContextGetter { |
| 154 public: | 154 public: |
| 155 // Since there's only a single thread, there's no need to worry | 155 // Since there's only a single thread, there's no need to worry |
| 156 // about when |context_| gets created. | 156 // about when |context_| gets created. |
| 157 SingleThreadRequestContextGetter( | 157 SingleThreadRequestContextGetter( |
| 158 net::NetLog* net_log, | 158 net::NetLog* net_log, |
| 159 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) | 159 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) |
| 160 : context_(BuildURLRequestContext(net_log)), | 160 : context_(BuildURLRequestContext(net_log)), |
| 161 main_task_runner_(main_task_runner) {} | 161 main_task_runner_(main_task_runner) {} |
| 162 | 162 |
| 163 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE { | 163 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE { |
| 164 return context_.get(); | 164 return context_.get(); |
| 165 } | 165 } |
| 166 | 166 |
| 167 virtual scoped_refptr<base::SingleThreadTaskRunner> | 167 virtual scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() |
| 168 GetNetworkTaskRunner() const OVERRIDE { | 168 const OVERRIDE { |
| 169 return main_task_runner_; | 169 return main_task_runner_; |
| 170 } | 170 } |
| 171 | 171 |
| 172 private: | 172 private: |
| 173 virtual ~SingleThreadRequestContextGetter() {} | 173 virtual ~SingleThreadRequestContextGetter() {} |
| 174 | 174 |
| 175 const scoped_ptr<net::URLRequestContext> context_; | 175 const scoped_ptr<net::URLRequestContext> context_; |
| 176 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | 176 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
| 177 }; | 177 }; |
| 178 | 178 |
| 179 // Assuming that the time |server_time| was received from a server, | 179 // Assuming that the time |server_time| was received from a server, |
| 180 // that the request for the server was started on |start_ticks|, and | 180 // that the request for the server was started on |start_ticks|, and |
| 181 // that it ended on |end_ticks|, fills |server_now| with an estimate | 181 // that it ended on |end_ticks|, fills |server_now| with an estimate |
| 182 // of the current time and |server_now_uncertainty| with a | 182 // of the current time and |server_now_uncertainty| with a |
| 183 // conservative estimate of the uncertainty. | 183 // conservative estimate of the uncertainty. |
| 184 void EstimateServerTimeNow(base::Time server_time, | 184 void EstimateServerTimeNow(base::Time server_time, |
| 185 base::TimeTicks start_ticks, | 185 base::TimeTicks start_ticks, |
| 186 base::TimeTicks end_ticks, | 186 base::TimeTicks end_ticks, |
| 187 base::Time* server_now, | 187 base::Time* server_now, |
| 188 base::TimeDelta* server_now_uncertainty) { | 188 base::TimeDelta* server_now_uncertainty) { |
| 189 const base::TimeDelta delta_ticks = end_ticks - start_ticks; | 189 const base::TimeDelta delta_ticks = end_ticks - start_ticks; |
| 190 const base::TimeTicks mid_ticks = start_ticks + delta_ticks / 2; | 190 const base::TimeTicks mid_ticks = start_ticks + delta_ticks / 2; |
| 191 const base::TimeDelta estimated_elapsed = base::TimeTicks::Now() - mid_ticks; | 191 const base::TimeDelta estimated_elapsed = base::TimeTicks::Now() - mid_ticks; |
| 192 | 192 |
| 193 *server_now = server_time + estimated_elapsed; | 193 *server_now = server_time + estimated_elapsed; |
| 194 | 194 |
| 195 *server_now_uncertainty = | 195 *server_now_uncertainty = |
| 196 base::TimeDelta::FromMilliseconds(kServerTimeResolutionMs) + | 196 base::TimeDelta::FromMilliseconds(kServerTimeResolutionMs) + delta_ticks + |
| 197 delta_ticks + 3 * base::TimeDelta::FromMilliseconds(kTicksResolutionMs); | 197 3 * base::TimeDelta::FromMilliseconds(kTicksResolutionMs); |
| 198 } | 198 } |
| 199 | 199 |
| 200 // Assuming that the time of the server is |server_now| with | 200 // Assuming that the time of the server is |server_now| with |
| 201 // uncertainty |server_now_uncertainty| and that the local time is | 201 // uncertainty |server_now_uncertainty| and that the local time is |
| 202 // |now|, fills |skew| with the skew of the local clock (i.e., add | 202 // |now|, fills |skew| with the skew of the local clock (i.e., add |
| 203 // |*skew| to a client time to get a server time) and | 203 // |*skew| to a client time to get a server time) and |
| 204 // |skew_uncertainty| with a conservative estimate of the uncertainty. | 204 // |skew_uncertainty| with a conservative estimate of the uncertainty. |
| 205 void EstimateSkew(base::Time server_now, | 205 void EstimateSkew(base::Time server_now, |
| 206 base::TimeDelta server_now_uncertainty, | 206 base::TimeDelta server_now_uncertainty, |
| 207 base::Time now, | 207 base::Time now, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 220 #endif | 220 #endif |
| 221 | 221 |
| 222 base::AtExitManager exit_manager; | 222 base::AtExitManager exit_manager; |
| 223 CommandLine::Init(argc, argv); | 223 CommandLine::Init(argc, argv); |
| 224 logging::LoggingSettings settings; | 224 logging::LoggingSettings settings; |
| 225 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; | 225 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; |
| 226 logging::InitLogging(settings); | 226 logging::InitLogging(settings); |
| 227 | 227 |
| 228 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | 228 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| 229 GURL url(parsed_command_line.GetSwitchValueASCII("url")); | 229 GURL url(parsed_command_line.GetSwitchValueASCII("url")); |
| 230 if (!url.is_valid() || | 230 if (!url.is_valid() || (url.scheme() != "http" && url.scheme() != "https")) { |
| 231 (url.scheme() != "http" && url.scheme() != "https")) { | 231 std::fprintf(stderr, |
| 232 std::fprintf( | 232 "Usage: %s --url=[http|https]://www.example.com [--v=[1|2]]\n", |
| 233 stderr, | 233 argv[0]); |
| 234 "Usage: %s --url=[http|https]://www.example.com [--v=[1|2]]\n", | |
| 235 argv[0]); | |
| 236 return EXIT_FAILURE; | 234 return EXIT_FAILURE; |
| 237 } | 235 } |
| 238 | 236 |
| 239 base::MessageLoopForIO main_loop; | 237 base::MessageLoopForIO main_loop; |
| 240 | 238 |
| 241 // NOTE: A NetworkChangeNotifier could be instantiated here, but | 239 // NOTE: A NetworkChangeNotifier could be instantiated here, but |
| 242 // that interferes with the request that will be sent; some | 240 // that interferes with the request that will be sent; some |
| 243 // implementations always send out an OnIPAddressChanged() message, | 241 // implementations always send out an OnIPAddressChanged() message, |
| 244 // which causes the DNS resolution to abort. It's simpler to just | 242 // which causes the DNS resolution to abort. It's simpler to just |
| 245 // not instantiate one, since only a single request is sent anyway. | 243 // not instantiate one, since only a single request is sent anyway. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 | 275 |
| 278 std::printf( | 276 std::printf( |
| 279 "Request ended at %s (ticks = %" PRId64 ")\n", | 277 "Request ended at %s (ticks = %" PRId64 ")\n", |
| 280 UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(end_time)).c_str(), | 278 UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(end_time)).c_str(), |
| 281 end_ticks.ToInternalValue()); | 279 end_ticks.ToInternalValue()); |
| 282 | 280 |
| 283 const int64 delta_ticks_internal = | 281 const int64 delta_ticks_internal = |
| 284 end_ticks.ToInternalValue() - start_ticks.ToInternalValue(); | 282 end_ticks.ToInternalValue() - start_ticks.ToInternalValue(); |
| 285 const base::TimeDelta delta_ticks = end_ticks - start_ticks; | 283 const base::TimeDelta delta_ticks = end_ticks - start_ticks; |
| 286 | 284 |
| 287 std::printf( | 285 std::printf("Request took %" PRId64 " ticks (%.2f ms)\n", |
| 288 "Request took %" PRId64 " ticks (%.2f ms)\n", | 286 delta_ticks_internal, |
| 289 delta_ticks_internal, delta_ticks.InMillisecondsF()); | 287 delta_ticks.InMillisecondsF()); |
| 290 | 288 |
| 291 const net::URLRequestStatus status = fetcher->GetStatus(); | 289 const net::URLRequestStatus status = fetcher->GetStatus(); |
| 292 if (status.status() != net::URLRequestStatus::SUCCESS) { | 290 if (status.status() != net::URLRequestStatus::SUCCESS) { |
| 293 LOG(ERROR) << "Request failed with error code: " | 291 LOG(ERROR) << "Request failed with error code: " |
| 294 << net::ErrorToString(status.error()); | 292 << net::ErrorToString(status.error()); |
| 295 return EXIT_FAILURE; | 293 return EXIT_FAILURE; |
| 296 } | 294 } |
| 297 | 295 |
| 298 const net::HttpResponseHeaders* const headers = | 296 const net::HttpResponseHeaders* const headers = fetcher->GetResponseHeaders(); |
| 299 fetcher->GetResponseHeaders(); | |
| 300 if (!headers) { | 297 if (!headers) { |
| 301 LOG(ERROR) << "Response does not have any headers"; | 298 LOG(ERROR) << "Response does not have any headers"; |
| 302 return EXIT_FAILURE; | 299 return EXIT_FAILURE; |
| 303 } | 300 } |
| 304 | 301 |
| 305 void* iter = NULL; | 302 void* iter = NULL; |
| 306 std::string date_header; | 303 std::string date_header; |
| 307 while (headers->EnumerateHeader(&iter, "Date", &date_header)) { | 304 while (headers->EnumerateHeader(&iter, "Date", &date_header)) { |
| 308 std::printf("Got date header: %s\n", date_header.c_str()); | 305 std::printf("Got date header: %s\n", date_header.c_str()); |
| 309 } | 306 } |
| 310 | 307 |
| 311 base::Time server_time; | 308 base::Time server_time; |
| 312 if (!headers->GetDateValue(&server_time)) { | 309 if (!headers->GetDateValue(&server_time)) { |
| 313 LOG(ERROR) << "Could not parse time from server response headers"; | 310 LOG(ERROR) << "Could not parse time from server response headers"; |
| 314 return EXIT_FAILURE; | 311 return EXIT_FAILURE; |
| 315 } | 312 } |
| 316 | 313 |
| 317 std::printf( | 314 std::printf( |
| 318 "Got time %s from server\n", | 315 "Got time %s from server\n", |
| 319 UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(server_time)).c_str()); | 316 UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(server_time)).c_str()); |
| 320 | 317 |
| 321 base::Time server_now; | 318 base::Time server_now; |
| 322 base::TimeDelta server_now_uncertainty; | 319 base::TimeDelta server_now_uncertainty; |
| 323 EstimateServerTimeNow(server_time, start_ticks, end_ticks, | 320 EstimateServerTimeNow(server_time, |
| 324 &server_now, &server_now_uncertainty); | 321 start_ticks, |
| 322 end_ticks, |
| 323 &server_now, |
| 324 &server_now_uncertainty); |
| 325 base::Time now = base::Time::Now(); | 325 base::Time now = base::Time::Now(); |
| 326 | 326 |
| 327 std::printf( | 327 std::printf( |
| 328 "According to the server, it is now %s with uncertainty %.2f ms\n", | 328 "According to the server, it is now %s with uncertainty %.2f ms\n", |
| 329 UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(server_now)).c_str(), | 329 UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(server_now)).c_str(), |
| 330 server_now_uncertainty.InMillisecondsF()); | 330 server_now_uncertainty.InMillisecondsF()); |
| 331 | 331 |
| 332 base::TimeDelta skew; | 332 base::TimeDelta skew; |
| 333 base::TimeDelta skew_uncertainty; | 333 base::TimeDelta skew_uncertainty; |
| 334 EstimateSkew(server_now, server_now_uncertainty, now, | 334 EstimateSkew(server_now, |
| 335 server_now_uncertainty, |
| 336 now, |
| 335 base::TimeDelta::FromMilliseconds(kTimeResolutionMs), | 337 base::TimeDelta::FromMilliseconds(kTimeResolutionMs), |
| 336 &skew, &skew_uncertainty); | 338 &skew, |
| 339 &skew_uncertainty); |
| 337 | 340 |
| 338 std::printf( | 341 std::printf( |
| 339 "An estimate for the local clock skew is %.2f ms with " | 342 "An estimate for the local clock skew is %.2f ms with " |
| 340 "uncertainty %.2f ms\n", | 343 "uncertainty %.2f ms\n", |
| 341 skew.InMillisecondsF(), | 344 skew.InMillisecondsF(), |
| 342 skew_uncertainty.InMillisecondsF()); | 345 skew_uncertainty.InMillisecondsF()); |
| 343 | 346 |
| 344 return EXIT_SUCCESS; | 347 return EXIT_SUCCESS; |
| 345 } | 348 } |
| OLD | NEW |