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 "content/renderer/dom_automation_controller.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/json/json_string_value_serializer.h"
     10 #include "base/metrics/histogram.h"
     11 #include "base/metrics/statistics_recorder.h"
     12 #include "base/strings/string_util.h"
     13 #include "content/common/child_process_messages.h"
     14 #include "content/common/view_messages.h"
     15 
     16 using webkit_glue::CppArgumentList;
     17 using webkit_glue::CppVariant;
     18 
     19 namespace content {
     20 
     21 DomAutomationController::DomAutomationController()
     22     : sender_(NULL),
     23       routing_id_(MSG_ROUTING_NONE),
     24       automation_id_(MSG_ROUTING_NONE) {
     25   BindCallback("send", base::Bind(&DomAutomationController::Send,
     26                                   base::Unretained(this)));
     27   BindCallback("setAutomationId",
     28                base::Bind(&DomAutomationController::SetAutomationId,
     29                           base::Unretained(this)));
     30   BindCallback("sendJSON", base::Bind(&DomAutomationController::SendJSON,
     31                                       base::Unretained(this)));
     32   BindCallback("sendWithId", base::Bind(&DomAutomationController::SendWithId,
     33                                         base::Unretained(this)));
     34 }
     35 
     36 void DomAutomationController::Send(const CppArgumentList& args,
     37                                    CppVariant* result) {
     38   if (args.size() != 1) {
     39     result->SetNull();
     40     return;
     41   }
     42 
     43   if (automation_id_ == MSG_ROUTING_NONE) {
     44     result->SetNull();
     45     return;
     46   }
     47 
     48   if (!sender_) {
     49     NOTREACHED();
     50     result->SetNull();
     51     return;
     52   }
     53 
     54   std::string json;
     55   JSONStringValueSerializer serializer(&json);
     56   scoped_ptr<base::Value> value;
     57 
     58   // Warning: note that JSON officially requires the root-level object to be
     59   // an object (e.g. {foo:3}) or an array, while here we're serializing
     60   // strings, bools, etc. to "JSON".  This only works because (a) the JSON
     61   // writer is lenient, and (b) on the receiving side we wrap the JSON string
     62   // in square brackets, converting it to an array, then parsing it and
     63   // grabbing the 0th element to get the value out.
     64   switch (args[0].type) {
     65     case NPVariantType_String: {
     66       value.reset(new base::StringValue(args[0].ToString()));
     67       break;
     68     }
     69     case NPVariantType_Bool: {
     70       value.reset(new base::FundamentalValue(args[0].ToBoolean()));
     71       break;
     72     }
     73     case NPVariantType_Int32: {
     74       value.reset(new base::FundamentalValue(args[0].ToInt32()));
     75       break;
     76     }
     77     case NPVariantType_Double: {
     78       // The value that is sent back is an integer while it is treated
     79       // as a double in this binding. The reason being that KJS treats
     80       // any number value as a double. Refer for more details,
     81       // chrome/third_party/webkit/src/JavaScriptCore/bindings/c/c_utility.cpp
     82       value.reset(new base::FundamentalValue(args[0].ToInt32()));
     83       break;
     84     }
     85     default: {
     86       result->SetNull();
     87       return;
     88     }
     89   }
     90 
     91   if (!serializer.Serialize(*value)) {
     92     result->SetNull();
     93     return;
     94   }
     95 
     96   bool succeeded = sender_->Send(
     97       new ViewHostMsg_DomOperationResponse(routing_id_, json, automation_id_));
     98   result->Set(succeeded);
     99 
    100   automation_id_ = MSG_ROUTING_NONE;
    101 }
    102 
    103 void DomAutomationController::SendJSON(const CppArgumentList& args,
    104                                        CppVariant* result) {
    105   if (args.size() != 1) {
    106     result->SetNull();
    107     return;
    108   }
    109 
    110   if (automation_id_ == MSG_ROUTING_NONE) {
    111     result->SetNull();
    112     return;
    113   }
    114 
    115   if (!sender_) {
    116     NOTREACHED();
    117     result->SetNull();
    118     return;
    119   }
    120 
    121   if (args[0].type != NPVariantType_String) {
    122     result->SetNull();
    123     return;
    124   }
    125 
    126   std::string json = args[0].ToString();
    127   result->Set(sender_->Send(
    128       new ViewHostMsg_DomOperationResponse(routing_id_, json, automation_id_)));
    129 
    130   automation_id_ = MSG_ROUTING_NONE;
    131 }
    132 
    133 void DomAutomationController::SendWithId(const CppArgumentList& args,
    134                                          CppVariant* result) {
    135   if (args.size() != 2) {
    136     result->SetNull();
    137     return;
    138   }
    139 
    140   if (!sender_) {
    141     NOTREACHED();
    142     result->SetNull();
    143     return;
    144   }
    145 
    146   if (!args[0].isNumber() || args[1].type != NPVariantType_String) {
    147     result->SetNull();
    148     return;
    149   }
    150 
    151   result->Set(sender_->Send(
    152       new ViewHostMsg_DomOperationResponse(routing_id_, args[1].ToString(),
    153                                            args[0].ToInt32())));
    154 }
    155 
    156 void DomAutomationController::SetAutomationId(
    157     const CppArgumentList& args, CppVariant* result) {
    158   if (args.size() != 1) {
    159     result->SetNull();
    160     return;
    161   }
    162 
    163   // The check here is for NumberType and not Int32 as
    164   // KJS::JSType only defines a NumberType (no Int32)
    165   if (!args[0].isNumber()) {
    166     result->SetNull();
    167     return;
    168   }
    169 
    170   automation_id_ = args[0].ToInt32();
    171   result->Set(true);
    172 }
    173 
    174 }  // namespace content
    175