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 3 // found in the LICENSE file. 4 5 #include "chrome/renderer/loadtimes_extension_bindings.h" 6 7 #include <math.h> 8 9 #include "base/time/time.h" 10 #include "content/public/renderer/document_state.h" 11 #include "net/http/http_response_info.h" 12 #include "third_party/WebKit/public/web/WebLocalFrame.h" 13 #include "v8/include/v8.h" 14 15 using blink::WebDataSource; 16 using blink::WebLocalFrame; 17 using blink::WebNavigationType; 18 using content::DocumentState; 19 20 // Values for CSI "tran" property 21 const int kTransitionLink = 0; 22 const int kTransitionForwardBack = 6; 23 const int kTransitionOther = 15; 24 const int kTransitionReload = 16; 25 26 namespace extensions_v8 { 27 28 static const char* const kLoadTimesExtensionName = "v8/LoadTimes"; 29 30 class LoadTimesExtensionWrapper : public v8::Extension { 31 public: 32 // Creates an extension which adds a new function, chromium.GetLoadTimes() 33 // This function returns an object containing the following members: 34 // requestTime: The time the request to load the page was received 35 // loadTime: The time the renderer started the load process 36 // finishDocumentLoadTime: The time the document itself was loaded 37 // (this is before the onload() method is fired) 38 // finishLoadTime: The time all loading is done, after the onload() 39 // method and all resources 40 // navigationType: A string describing what user action initiated the load 41 LoadTimesExtensionWrapper() : 42 v8::Extension(kLoadTimesExtensionName, 43 "var chrome;" 44 "if (!chrome)" 45 " chrome = {};" 46 "chrome.loadTimes = function() {" 47 " native function GetLoadTimes();" 48 " return GetLoadTimes();" 49 "};" 50 "chrome.csi = function() {" 51 " native function GetCSI();" 52 " return GetCSI();" 53 "}") {} 54 55 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( 56 v8::Isolate* isolate, 57 v8::Handle<v8::String> name) OVERRIDE { 58 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetLoadTimes"))) { 59 return v8::FunctionTemplate::New(isolate, GetLoadTimes); 60 } else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetCSI"))) { 61 return v8::FunctionTemplate::New(isolate, GetCSI); 62 } 63 return v8::Handle<v8::FunctionTemplate>(); 64 } 65 66 static const char* GetNavigationType(WebNavigationType nav_type) { 67 switch (nav_type) { 68 case blink::WebNavigationTypeLinkClicked: 69 return "LinkClicked"; 70 case blink::WebNavigationTypeFormSubmitted: 71 return "FormSubmitted"; 72 case blink::WebNavigationTypeBackForward: 73 return "BackForward"; 74 case blink::WebNavigationTypeReload: 75 return "Reload"; 76 case blink::WebNavigationTypeFormResubmitted: 77 return "Resubmitted"; 78 case blink::WebNavigationTypeOther: 79 return "Other"; 80 } 81 return ""; 82 } 83 84 static int GetCSITransitionType(WebNavigationType nav_type) { 85 switch (nav_type) { 86 case blink::WebNavigationTypeLinkClicked: 87 case blink::WebNavigationTypeFormSubmitted: 88 case blink::WebNavigationTypeFormResubmitted: 89 return kTransitionLink; 90 case blink::WebNavigationTypeBackForward: 91 return kTransitionForwardBack; 92 case blink::WebNavigationTypeReload: 93 return kTransitionReload; 94 case blink::WebNavigationTypeOther: 95 return kTransitionOther; 96 } 97 return kTransitionOther; 98 } 99 100 static void GetLoadTimes(const v8::FunctionCallbackInfo<v8::Value>& args) { 101 WebLocalFrame* frame = WebLocalFrame::frameForCurrentContext(); 102 if (frame) { 103 WebDataSource* data_source = frame->dataSource(); 104 if (data_source) { 105 DocumentState* document_state = 106 DocumentState::FromDataSource(data_source); 107 v8::Isolate* isolate = args.GetIsolate(); 108 v8::Local<v8::Object> load_times = v8::Object::New(isolate); 109 load_times->Set( 110 v8::String::NewFromUtf8(isolate, "requestTime"), 111 v8::Number::New(isolate, 112 document_state->request_time().ToDoubleT())); 113 load_times->Set( 114 v8::String::NewFromUtf8(isolate, "startLoadTime"), 115 v8::Number::New(isolate, 116 document_state->start_load_time().ToDoubleT())); 117 load_times->Set( 118 v8::String::NewFromUtf8(isolate, "commitLoadTime"), 119 v8::Number::New(isolate, 120 document_state->commit_load_time().ToDoubleT())); 121 load_times->Set( 122 v8::String::NewFromUtf8(isolate, "finishDocumentLoadTime"), 123 v8::Number::New( 124 isolate, 125 document_state->finish_document_load_time().ToDoubleT())); 126 load_times->Set( 127 v8::String::NewFromUtf8(isolate, "finishLoadTime"), 128 v8::Number::New(isolate, 129 document_state->finish_load_time().ToDoubleT())); 130 load_times->Set( 131 v8::String::NewFromUtf8(isolate, "firstPaintTime"), 132 v8::Number::New(isolate, 133 document_state->first_paint_time().ToDoubleT())); 134 load_times->Set( 135 v8::String::NewFromUtf8(isolate, "firstPaintAfterLoadTime"), 136 v8::Number::New( 137 isolate, 138 document_state->first_paint_after_load_time().ToDoubleT())); 139 load_times->Set( 140 v8::String::NewFromUtf8(isolate, "navigationType"), 141 v8::String::NewFromUtf8( 142 isolate, GetNavigationType(data_source->navigationType()))); 143 load_times->Set( 144 v8::String::NewFromUtf8(isolate, "wasFetchedViaSpdy"), 145 v8::Boolean::New(isolate, document_state->was_fetched_via_spdy())); 146 load_times->Set( 147 v8::String::NewFromUtf8(isolate, "wasNpnNegotiated"), 148 v8::Boolean::New(isolate, document_state->was_npn_negotiated())); 149 load_times->Set( 150 v8::String::NewFromUtf8(isolate, "npnNegotiatedProtocol"), 151 v8::String::NewFromUtf8( 152 isolate, document_state->npn_negotiated_protocol().c_str())); 153 load_times->Set( 154 v8::String::NewFromUtf8(isolate, "wasAlternateProtocolAvailable"), 155 v8::Boolean::New( 156 isolate, document_state->was_alternate_protocol_available())); 157 load_times->Set(v8::String::NewFromUtf8(isolate, "connectionInfo"), 158 v8::String::NewFromUtf8( 159 isolate, 160 net::HttpResponseInfo::ConnectionInfoToString( 161 document_state->connection_info()).c_str())); 162 args.GetReturnValue().Set(load_times); 163 return; 164 } 165 } 166 args.GetReturnValue().SetNull(); 167 } 168 169 static void GetCSI(const v8::FunctionCallbackInfo<v8::Value>& args) { 170 WebLocalFrame* frame = WebLocalFrame::frameForCurrentContext(); 171 if (frame) { 172 WebDataSource* data_source = frame->dataSource(); 173 if (data_source) { 174 DocumentState* document_state = 175 DocumentState::FromDataSource(data_source); 176 v8::Isolate* isolate = args.GetIsolate(); 177 v8::Local<v8::Object> csi = v8::Object::New(isolate); 178 base::Time now = base::Time::Now(); 179 base::Time start = document_state->request_time().is_null() ? 180 document_state->start_load_time() : 181 document_state->request_time(); 182 base::Time onload = document_state->finish_document_load_time(); 183 base::TimeDelta page = now - start; 184 csi->Set(v8::String::NewFromUtf8(isolate, "startE"), 185 v8::Number::New(isolate, floor(start.ToDoubleT() * 1000))); 186 csi->Set(v8::String::NewFromUtf8(isolate, "onloadT"), 187 v8::Number::New(isolate, floor(onload.ToDoubleT() * 1000))); 188 csi->Set(v8::String::NewFromUtf8(isolate, "pageT"), 189 v8::Number::New(isolate, page.InMillisecondsF())); 190 csi->Set( 191 v8::String::NewFromUtf8(isolate, "tran"), 192 v8::Number::New( 193 isolate, GetCSITransitionType(data_source->navigationType()))); 194 195 args.GetReturnValue().Set(csi); 196 return; 197 } 198 } 199 args.GetReturnValue().SetNull(); 200 return; 201 } 202 }; 203 204 v8::Extension* LoadTimesExtension::Get() { 205 return new LoadTimesExtensionWrapper(); 206 } 207 208 } // namespace extensions_v8 209