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