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 |