loadtimes_extension_bindings.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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/WebFrame.h"
13#include "v8/include/v8.h"
14
15using WebKit::WebDataSource;
16using WebKit::WebFrame;
17using WebKit::WebNavigationType;
18using content::DocumentState;
19
20// Values for CSI "tran" property
21const int kTransitionLink = 0;
22const int kTransitionForwardBack = 6;
23const int kTransitionOther = 15;
24const int kTransitionReload = 16;
25
26namespace extensions_v8 {
27
28static const char* const kLoadTimesExtensionName = "v8/LoadTimes";
29
30class 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> GetNativeFunction(
56      v8::Handle<v8::String> name) OVERRIDE {
57    if (name->Equals(v8::String::New("GetLoadTimes"))) {
58      return v8::FunctionTemplate::New(GetLoadTimes);
59    } else if (name->Equals(v8::String::New("GetCSI"))) {
60      return v8::FunctionTemplate::New(GetCSI);
61    }
62    return v8::Handle<v8::FunctionTemplate>();
63  }
64
65  static const char* GetNavigationType(WebNavigationType nav_type) {
66    switch (nav_type) {
67      case WebKit::WebNavigationTypeLinkClicked:
68        return "LinkClicked";
69      case WebKit::WebNavigationTypeFormSubmitted:
70        return "FormSubmitted";
71      case WebKit::WebNavigationTypeBackForward:
72        return "BackForward";
73      case WebKit::WebNavigationTypeReload:
74        return "Reload";
75      case WebKit::WebNavigationTypeFormResubmitted:
76        return "Resubmitted";
77      case WebKit::WebNavigationTypeOther:
78        return "Other";
79    }
80    return "";
81  }
82
83  static int GetCSITransitionType(WebNavigationType nav_type) {
84    switch (nav_type) {
85      case WebKit::WebNavigationTypeLinkClicked:
86      case WebKit::WebNavigationTypeFormSubmitted:
87      case WebKit::WebNavigationTypeFormResubmitted:
88        return kTransitionLink;
89      case WebKit::WebNavigationTypeBackForward:
90        return kTransitionForwardBack;
91      case WebKit::WebNavigationTypeReload:
92        return kTransitionReload;
93      case WebKit::WebNavigationTypeOther:
94        return kTransitionOther;
95    }
96    return kTransitionOther;
97  }
98
99  static void GetLoadTimes(const v8::FunctionCallbackInfo<v8::Value>& args) {
100    WebFrame* frame = WebFrame::frameForCurrentContext();
101    if (frame) {
102      WebDataSource* data_source = frame->dataSource();
103      if (data_source) {
104        DocumentState* document_state =
105            DocumentState::FromDataSource(data_source);
106        v8::Local<v8::Object> load_times = v8::Object::New();
107        load_times->Set(
108            v8::String::New("requestTime"),
109            v8::Number::New(document_state->request_time().ToDoubleT()));
110        load_times->Set(
111            v8::String::New("startLoadTime"),
112            v8::Number::New(document_state->start_load_time().ToDoubleT()));
113        load_times->Set(
114            v8::String::New("commitLoadTime"),
115            v8::Number::New(document_state->commit_load_time().ToDoubleT()));
116        load_times->Set(
117            v8::String::New("finishDocumentLoadTime"),
118            v8::Number::New(
119                document_state->finish_document_load_time().ToDoubleT()));
120        load_times->Set(
121            v8::String::New("finishLoadTime"),
122            v8::Number::New(document_state->finish_load_time().ToDoubleT()));
123        load_times->Set(
124            v8::String::New("firstPaintTime"),
125            v8::Number::New(document_state->first_paint_time().ToDoubleT()));
126        load_times->Set(
127            v8::String::New("firstPaintAfterLoadTime"),
128            v8::Number::New(
129                document_state->first_paint_after_load_time().ToDoubleT()));
130        load_times->Set(
131            v8::String::New("navigationType"),
132            v8::String::New(GetNavigationType(data_source->navigationType())));
133        load_times->Set(
134            v8::String::New("wasFetchedViaSpdy"),
135            v8::Boolean::New(document_state->was_fetched_via_spdy()));
136        load_times->Set(
137            v8::String::New("wasNpnNegotiated"),
138            v8::Boolean::New(document_state->was_npn_negotiated()));
139        load_times->Set(
140            v8::String::New("npnNegotiatedProtocol"),
141            v8::String::New(document_state->npn_negotiated_protocol().c_str()));
142        load_times->Set(
143            v8::String::New("wasAlternateProtocolAvailable"),
144            v8::Boolean::New(
145                document_state->was_alternate_protocol_available()));
146        load_times->Set(
147            v8::String::New("connectionInfo"),
148            v8::String::New(
149                net::HttpResponseInfo::ConnectionInfoToString(
150                    document_state->connection_info()).c_str()));
151        args.GetReturnValue().Set(load_times);
152        return;
153      }
154    }
155    args.GetReturnValue().SetNull();
156  }
157
158  static void GetCSI(const v8::FunctionCallbackInfo<v8::Value>& args) {
159    WebFrame* frame = WebFrame::frameForCurrentContext();
160    if (frame) {
161      WebDataSource* data_source = frame->dataSource();
162      if (data_source) {
163        DocumentState* document_state =
164            DocumentState::FromDataSource(data_source);
165        v8::Local<v8::Object> csi = v8::Object::New();
166        base::Time now = base::Time::Now();
167        base::Time start = document_state->request_time().is_null() ?
168            document_state->start_load_time() :
169            document_state->request_time();
170        base::Time onload = document_state->finish_document_load_time();
171        base::TimeDelta page = now - start;
172        csi->Set(
173            v8::String::New("startE"),
174            v8::Number::New(floor(start.ToDoubleT() * 1000)));
175        csi->Set(
176            v8::String::New("onloadT"),
177            v8::Number::New(floor(onload.ToDoubleT() * 1000)));
178        csi->Set(
179          v8::String::New("pageT"),
180          v8::Number::New(page.InMillisecondsF()));
181        csi->Set(
182            v8::String::New("tran"),
183            v8::Number::New(
184                GetCSITransitionType(data_source->navigationType())));
185
186        args.GetReturnValue().Set(csi);
187        return;
188      }
189    }
190    args.GetReturnValue().SetNull();
191    return;
192  }
193};
194
195v8::Extension* LoadTimesExtension::Get() {
196  return new LoadTimesExtensionWrapper();
197}
198
199}  // namespace extensions_v8
200