Home | History | Annotate | Download | only in renderer
      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 
     15 using WebKit::WebDataSource;
     16 using WebKit::WebFrame;
     17 using WebKit::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> 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 
    195 v8::Extension* LoadTimesExtension::Get() {
    196   return new LoadTimesExtensionWrapper();
    197 }
    198 
    199 }  // namespace extensions_v8
    200