| 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/renderer/loadtimes_extension_bindings.h" | 5 #include "chrome/renderer/loadtimes_extension_bindings.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include "base/time/time.h" | 9 #include "base/time/time.h" |
| 10 #include "content/public/renderer/document_state.h" | 10 #include "content/public/renderer/document_state.h" |
| 11 #include "extensions/renderer/v8_helpers.h" | 11 #include "extensions/renderer/v8_helpers.h" |
| 12 #include "net/http/http_response_info.h" | 12 #include "net/http/http_response_info.h" |
| 13 #include "third_party/WebKit/public/web/WebLocalFrame.h" | 13 #include "third_party/WebKit/public/web/WebLocalFrame.h" |
| 14 #include "third_party/WebKit/public/web/WebPerformance.h" | 14 #include "third_party/WebKit/public/web/WebPerformance.h" |
| 15 #include "v8/include/v8.h" | 15 #include "v8/include/v8.h" |
| 16 | 16 |
| 17 using blink::WebDataSource; | 17 using blink::WebDataSource; |
| 18 using blink::WebLocalFrame; | 18 using blink::WebLocalFrame; |
| 19 using blink::WebNavigationType; | |
| 20 using blink::WebPerformance; | 19 using blink::WebPerformance; |
| 21 using content::DocumentState; | 20 using content::DocumentState; |
| 22 | 21 |
| 23 // Values for CSI "tran" property | 22 // Values for CSI "tran" property |
| 24 const int kTransitionLink = 0; | |
| 25 const int kTransitionForwardBack = 6; | |
| 26 const int kTransitionOther = 15; | 23 const int kTransitionOther = 15; |
| 27 const int kTransitionReload = 16; | |
| 28 | 24 |
| 29 namespace extensions_v8 { | 25 namespace extensions_v8 { |
| 30 | 26 |
| 31 static const char* const kLoadTimesExtensionName = "v8/LoadTimes"; | 27 static const char* const kLoadTimesExtensionName = "v8/LoadTimes"; |
| 32 | 28 |
| 33 class LoadTimesExtensionWrapper : public v8::Extension { | 29 class LoadTimesExtensionWrapper : public v8::Extension { |
| 34 public: | 30 public: |
| 35 // Creates an extension which adds a new function, chrome.loadTimes() | 31 // Creates an extension which adds a new function, chrome.loadTimes() |
| 36 // This function returns an object containing the following members: | 32 // This function returns an object containing the following members: |
| 37 // requestTime: The time the request to load the page was received | 33 // requestTime: The time the request to load the page was received |
| 38 // loadTime: The time the renderer started the load process | 34 // loadTime: The time the renderer started the load process |
| 39 // finishDocumentLoadTime: The time the document itself was loaded | 35 // finishDocumentLoadTime: The time the document itself was loaded |
| 40 // (this is before the onload() method is fired) | 36 // (this is before the onload() method is fired) |
| 41 // finishLoadTime: The time all loading is done, after the onload() | 37 // finishLoadTime: The time all loading is done, after the onload() |
| 42 // method and all resources | 38 // method and all resources |
| 43 // navigationType: A string describing what user action initiated the load | 39 // navigationType: A string describing what user action initiated the load, |
| 40 // now hard-coded to "Other" |
| 44 // | 41 // |
| 45 // Note that chrome.loadTimes() is deprecated in favor of performance.timing. | 42 // Note that chrome.loadTimes() is deprecated in favor of performance.timing. |
| 46 // Many of the timings reported via chrome.loadTimes() match timings available | 43 // Many of the timings reported via chrome.loadTimes() match timings available |
| 47 // in performance.timing. Timing data will be removed from chrome.loadTimes() | 44 // in performance.timing. Timing data will be removed from chrome.loadTimes() |
| 48 // in a future release. No new timings or other information should be exposed | 45 // in a future release. No new timings or other information should be exposed |
| 49 // via these APIs. | 46 // via these APIs. |
| 50 LoadTimesExtensionWrapper() : | 47 LoadTimesExtensionWrapper() : |
| 51 v8::Extension(kLoadTimesExtensionName, | 48 v8::Extension(kLoadTimesExtensionName, |
| 52 "var chrome;" | 49 "var chrome;" |
| 53 "if (!chrome)" | 50 "if (!chrome)" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 65 v8::Isolate* isolate, | 62 v8::Isolate* isolate, |
| 66 v8::Local<v8::String> name) override { | 63 v8::Local<v8::String> name) override { |
| 67 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetLoadTimes"))) { | 64 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetLoadTimes"))) { |
| 68 return v8::FunctionTemplate::New(isolate, GetLoadTimes); | 65 return v8::FunctionTemplate::New(isolate, GetLoadTimes); |
| 69 } else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetCSI"))) { | 66 } else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetCSI"))) { |
| 70 return v8::FunctionTemplate::New(isolate, GetCSI); | 67 return v8::FunctionTemplate::New(isolate, GetCSI); |
| 71 } | 68 } |
| 72 return v8::Local<v8::FunctionTemplate>(); | 69 return v8::Local<v8::FunctionTemplate>(); |
| 73 } | 70 } |
| 74 | 71 |
| 75 static const char* GetNavigationType(WebNavigationType nav_type) { | |
| 76 switch (nav_type) { | |
| 77 case blink::WebNavigationTypeLinkClicked: | |
| 78 return "LinkClicked"; | |
| 79 case blink::WebNavigationTypeFormSubmitted: | |
| 80 return "FormSubmitted"; | |
| 81 case blink::WebNavigationTypeBackForward: | |
| 82 return "BackForward"; | |
| 83 case blink::WebNavigationTypeReload: | |
| 84 return "Reload"; | |
| 85 case blink::WebNavigationTypeFormResubmitted: | |
| 86 return "Resubmitted"; | |
| 87 case blink::WebNavigationTypeOther: | |
| 88 return "Other"; | |
| 89 } | |
| 90 return ""; | |
| 91 } | |
| 92 | |
| 93 static int GetCSITransitionType(WebNavigationType nav_type) { | |
| 94 switch (nav_type) { | |
| 95 case blink::WebNavigationTypeLinkClicked: | |
| 96 case blink::WebNavigationTypeFormSubmitted: | |
| 97 case blink::WebNavigationTypeFormResubmitted: | |
| 98 return kTransitionLink; | |
| 99 case blink::WebNavigationTypeBackForward: | |
| 100 return kTransitionForwardBack; | |
| 101 case blink::WebNavigationTypeReload: | |
| 102 return kTransitionReload; | |
| 103 case blink::WebNavigationTypeOther: | |
| 104 return kTransitionOther; | |
| 105 } | |
| 106 return kTransitionOther; | |
| 107 } | |
| 108 | |
| 109 static void LoadtimesGetter( | 72 static void LoadtimesGetter( |
| 110 v8::Local<v8::Name> name, | 73 v8::Local<v8::Name> name, |
| 111 const v8::PropertyCallbackInfo<v8::Value>& info) { | 74 const v8::PropertyCallbackInfo<v8::Value>& info) { |
| 112 if (WebLocalFrame* frame = WebLocalFrame::frameForCurrentContext()) { | 75 if (WebLocalFrame* frame = WebLocalFrame::frameForCurrentContext()) { |
| 113 frame->usageCountChromeLoadTimes(blink::WebString::fromUTF8( | 76 frame->usageCountChromeLoadTimes(blink::WebString::fromUTF8( |
| 114 *v8::String::Utf8Value(name))); | 77 *v8::String::Utf8Value(name))); |
| 115 } | 78 } |
| 116 info.GetReturnValue().Set(info.Data()); | 79 info.GetReturnValue().Set(info.Data()); |
| 117 } | 80 } |
| 118 | 81 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 double commit_load_time = web_performance.responseStart(); | 121 double commit_load_time = web_performance.responseStart(); |
| 159 double finish_document_load_time = | 122 double finish_document_load_time = |
| 160 web_performance.domContentLoadedEventEnd(); | 123 web_performance.domContentLoadedEventEnd(); |
| 161 double finish_load_time = web_performance.loadEventEnd(); | 124 double finish_load_time = web_performance.loadEventEnd(); |
| 162 double first_paint_time = web_performance.firstPaint(); | 125 double first_paint_time = web_performance.firstPaint(); |
| 163 // TODO(bmcquade): remove this. It's misleading to track the first paint | 126 // TODO(bmcquade): remove this. It's misleading to track the first paint |
| 164 // after the load event, since many pages perform their meaningful paints | 127 // after the load event, since many pages perform their meaningful paints |
| 165 // long before the load event fires. We report a time of zero for the | 128 // long before the load event fires. We report a time of zero for the |
| 166 // time being. | 129 // time being. |
| 167 double first_paint_after_load_time = 0.0; | 130 double first_paint_after_load_time = 0.0; |
| 168 std::string navigation_type = | |
| 169 GetNavigationType(data_source->navigationType()); | |
| 170 bool was_fetched_via_spdy = document_state->was_fetched_via_spdy(); | 131 bool was_fetched_via_spdy = document_state->was_fetched_via_spdy(); |
| 171 bool was_alpn_negotiated = document_state->was_alpn_negotiated(); | 132 bool was_alpn_negotiated = document_state->was_alpn_negotiated(); |
| 172 std::string alpn_negotiated_protocol = | 133 std::string alpn_negotiated_protocol = |
| 173 document_state->alpn_negotiated_protocol(); | 134 document_state->alpn_negotiated_protocol(); |
| 174 bool was_alternate_protocol_available = | 135 bool was_alternate_protocol_available = |
| 175 document_state->was_alternate_protocol_available(); | 136 document_state->was_alternate_protocol_available(); |
| 176 std::string connection_info = net::HttpResponseInfo::ConnectionInfoToString( | 137 std::string connection_info = net::HttpResponseInfo::ConnectionInfoToString( |
| 177 document_state->connection_info()); | 138 document_state->connection_info()); |
| 178 | 139 |
| 179 // Important: |frame|, |data_source| and |document_state| should not be | 140 // Important: |frame|, |data_source| and |document_state| should not be |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 ctx, | 214 ctx, |
| 254 v8::String::NewFromUtf8( | 215 v8::String::NewFromUtf8( |
| 255 isolate, "firstPaintAfterLoadTime", v8::NewStringType::kNormal) | 216 isolate, "firstPaintAfterLoadTime", v8::NewStringType::kNormal) |
| 256 .ToLocalChecked(), | 217 .ToLocalChecked(), |
| 257 LoadtimesGetter, | 218 LoadtimesGetter, |
| 258 nullptr, | 219 nullptr, |
| 259 v8::Number::New(isolate,first_paint_after_load_time)) | 220 v8::Number::New(isolate,first_paint_after_load_time)) |
| 260 .FromMaybe(false)) { | 221 .FromMaybe(false)) { |
| 261 return; | 222 return; |
| 262 } | 223 } |
| 263 if (!load_times->SetAccessor( | 224 if (!load_times |
| 264 ctx, | 225 ->SetAccessor(ctx, |
| 265 v8::String::NewFromUtf8( | 226 v8::String::NewFromUtf8(isolate, "navigationType", |
| 266 isolate, "navigationType", v8::NewStringType::kNormal) | 227 v8::NewStringType::kNormal) |
| 267 .ToLocalChecked(), | 228 .ToLocalChecked(), |
| 268 LoadtimesGetter, | 229 LoadtimesGetter, nullptr, |
| 269 nullptr, | 230 v8::String::NewFromUtf8(isolate, "Other", |
| 270 v8::String::NewFromUtf8(isolate, navigation_type.c_str(), | 231 v8::NewStringType::kNormal) |
| 271 v8::NewStringType::kNormal) | 232 .ToLocalChecked()) |
| 272 .ToLocalChecked()) | 233 .FromMaybe(false)) { |
| 273 .FromMaybe(false)) { | |
| 274 return; | 234 return; |
| 275 } | 235 } |
| 276 if (!load_times->SetAccessor( | 236 if (!load_times->SetAccessor( |
| 277 ctx, | 237 ctx, |
| 278 v8::String::NewFromUtf8( | 238 v8::String::NewFromUtf8( |
| 279 isolate, "wasFetchedViaSpdy", v8::NewStringType::kNormal) | 239 isolate, "wasFetchedViaSpdy", v8::NewStringType::kNormal) |
| 280 .ToLocalChecked(), | 240 .ToLocalChecked(), |
| 281 LoadtimesGetter, | 241 LoadtimesGetter, |
| 282 nullptr, | 242 nullptr, |
| 283 v8::Boolean::New(isolate, was_fetched_via_spdy)) | 243 v8::Boolean::New(isolate, was_fetched_via_spdy)) |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 return; | 307 return; |
| 348 } | 308 } |
| 349 WebPerformance web_performance = frame->performance(); | 309 WebPerformance web_performance = frame->performance(); |
| 350 base::Time now = base::Time::Now(); | 310 base::Time now = base::Time::Now(); |
| 351 base::Time start = | 311 base::Time start = |
| 352 base::Time::FromDoubleT(web_performance.navigationStart()); | 312 base::Time::FromDoubleT(web_performance.navigationStart()); |
| 353 | 313 |
| 354 base::Time dom_content_loaded_end = | 314 base::Time dom_content_loaded_end = |
| 355 base::Time::FromDoubleT(web_performance.domContentLoadedEventEnd()); | 315 base::Time::FromDoubleT(web_performance.domContentLoadedEventEnd()); |
| 356 base::TimeDelta page = now - start; | 316 base::TimeDelta page = now - start; |
| 357 int navigation_type = GetCSITransitionType(data_source->navigationType()); | |
| 358 // Important: |frame| and |data_source| should not be referred to below this | 317 // Important: |frame| and |data_source| should not be referred to below this |
| 359 // line, as JS setters below can invalidate these pointers. | 318 // line, as JS setters below can invalidate these pointers. |
| 360 v8::Isolate* isolate = args.GetIsolate(); | 319 v8::Isolate* isolate = args.GetIsolate(); |
| 361 v8::Local<v8::Context> ctx = isolate->GetCurrentContext(); | 320 v8::Local<v8::Context> ctx = isolate->GetCurrentContext(); |
| 362 v8::Local<v8::Object> csi = v8::Object::New(isolate); | 321 v8::Local<v8::Object> csi = v8::Object::New(isolate); |
| 363 if (!csi->Set(ctx, v8::String::NewFromUtf8(isolate, "startE", | 322 if (!csi->Set(ctx, v8::String::NewFromUtf8(isolate, "startE", |
| 364 v8::NewStringType::kNormal) | 323 v8::NewStringType::kNormal) |
| 365 .ToLocalChecked(), | 324 .ToLocalChecked(), |
| 366 v8::Number::New(isolate, floor(start.ToDoubleT() * 1000))) | 325 v8::Number::New(isolate, floor(start.ToDoubleT() * 1000))) |
| 367 .FromMaybe(false)) { | 326 .FromMaybe(false)) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 381 if (!csi->Set(ctx, v8::String::NewFromUtf8(isolate, "pageT", | 340 if (!csi->Set(ctx, v8::String::NewFromUtf8(isolate, "pageT", |
| 382 v8::NewStringType::kNormal) | 341 v8::NewStringType::kNormal) |
| 383 .ToLocalChecked(), | 342 .ToLocalChecked(), |
| 384 v8::Number::New(isolate, page.InMillisecondsF())) | 343 v8::Number::New(isolate, page.InMillisecondsF())) |
| 385 .FromMaybe(false)) { | 344 .FromMaybe(false)) { |
| 386 return; | 345 return; |
| 387 } | 346 } |
| 388 if (!csi->Set(ctx, v8::String::NewFromUtf8(isolate, "tran", | 347 if (!csi->Set(ctx, v8::String::NewFromUtf8(isolate, "tran", |
| 389 v8::NewStringType::kNormal) | 348 v8::NewStringType::kNormal) |
| 390 .ToLocalChecked(), | 349 .ToLocalChecked(), |
| 391 v8::Number::New(isolate, navigation_type)) | 350 v8::Number::New(isolate, kTransitionOther)) |
| 392 .FromMaybe(false)) { | 351 .FromMaybe(false)) { |
| 393 return; | 352 return; |
| 394 } | 353 } |
| 395 args.GetReturnValue().Set(csi); | 354 args.GetReturnValue().Set(csi); |
| 396 } | 355 } |
| 397 }; | 356 }; |
| 398 | 357 |
| 399 v8::Extension* LoadTimesExtension::Get() { | 358 v8::Extension* LoadTimesExtension::Get() { |
| 400 return new LoadTimesExtensionWrapper(); | 359 return new LoadTimesExtensionWrapper(); |
| 401 } | 360 } |
| 402 | 361 |
| 403 } // namespace extensions_v8 | 362 } // namespace extensions_v8 |
| OLD | NEW |