gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2008 Google Inc. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| 5 | * use this file except in compliance with the License. You may obtain a copy of |
| 6 | * the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 13 | * License for the specific language governing permissions and limitations under |
| 14 | * the License. |
| 15 | */ |
| 16 | |
| 17 | #include <cstring> |
| 18 | |
| 19 | #include "ScriptableInstance.h" |
| 20 | #include "InvokeMessage.h" |
| 21 | #include "ReturnMessage.h" |
| 22 | #include "ServerMethods.h" |
| 23 | #include "AllowedConnections.h" |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 24 | |
| 25 | #include "mozincludes.h" |
| 26 | #include "scoped_ptr/scoped_ptr.h" |
| 27 | #include "NPVariantWrapper.h" |
| 28 | |
| 29 | using std::string; |
| 30 | using std::endl; |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 31 | const static string BACKGROUND_PAGE_STR = "chrome-extension://jpjpnpmbddbjkfaccnmhnkdgjideieim/background.html"; |
| 32 | const static string UNKNOWN_STR = "unknown"; |
| 33 | const static string INCLUDE_STR = "include"; |
| 34 | const static string EXCLUDE_STR = "exclude"; |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 35 | |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 36 | bool ScriptableInstance::jsIdentitySafe = false; |
| 37 | |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 38 | static inline string convertToString(const NPString& str) { |
| 39 | return string(GetNPStringUTF8Characters(str), GetNPStringUTF8Length(str)); |
| 40 | } |
| 41 | |
| 42 | string ScriptableInstance::computeTabIdentity() { |
| 43 | return ""; |
| 44 | } |
| 45 | |
| 46 | void ScriptableInstance::dumpObjectBytes(NPObject* obj) { |
| 47 | char buf[20]; |
| 48 | Debug::log(Debug::Debugging) << " object bytes:\n"; |
| 49 | const unsigned char* ptr = reinterpret_cast<const unsigned char*>(obj); |
| 50 | for (int i = 0; i < 24; ++i) { |
| 51 | snprintf(buf, sizeof(buf), " %02x", ptr[i]); |
| 52 | Debug::log(Debug::Debugging) << buf; |
| 53 | } |
| 54 | NPVariant objVar; |
| 55 | OBJECT_TO_NPVARIANT(obj, objVar); |
| 56 | Debug::log(Debug::Debugging) << " obj.toString()=" |
| 57 | << NPVariantProxy::toString(objVar) << Debug::flush; |
| 58 | } |
| 59 | |
| 60 | ScriptableInstance::ScriptableInstance(NPP npp) : NPObjectWrapper<ScriptableInstance>(npp), |
| 61 | plugin(*reinterpret_cast<Plugin*>(npp->pdata)), |
| 62 | _channel(new HostChannel()), |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 63 | localObjects(npp,ScriptableInstance::jsIdentitySafe), |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 64 | _connectId(NPN_GetStringIdentifier("connect")), |
| 65 | initID(NPN_GetStringIdentifier("init")), |
| 66 | toStringID(NPN_GetStringIdentifier("toString")), |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 67 | loadHostEntriesID(NPN_GetStringIdentifier("loadHostEntries")), |
| 68 | locationID(NPN_GetStringIdentifier("location")), |
| 69 | hrefID(NPN_GetStringIdentifier("href")), |
| 70 | urlID(NPN_GetStringIdentifier("url")), |
| 71 | includeID(NPN_GetStringIdentifier("include")), |
| 72 | getHostPermissionID(NPN_GetStringIdentifier("getHostPermission")), |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 73 | testJsIdentityID(NPN_GetStringIdentifier("testJsIdentity")), |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 74 | connectedID(NPN_GetStringIdentifier("connected")), |
| 75 | statsID(NPN_GetStringIdentifier("stats")), |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 76 | jsDisconnectedID(NPN_GetStringIdentifier("__gwt_disconnected")), |
| 77 | jsInvokeID(NPN_GetStringIdentifier("__gwt_jsInvoke")), |
| 78 | jsResultID(NPN_GetStringIdentifier("__gwt_makeResult")), |
| 79 | jsTearOffID(NPN_GetStringIdentifier("__gwt_makeTearOff")), |
| 80 | jsValueOfID(NPN_GetStringIdentifier("valueOf")), |
| 81 | idx0(NPN_GetIntIdentifier(0)), |
| 82 | idx1(NPN_GetIntIdentifier(1)) { |
| 83 | savedValueIdx = -1; |
| 84 | if (NPN_GetValue(npp, NPNVWindowNPObject, &window) != NPERR_NO_ERROR) { |
| 85 | Debug::log(Debug::Error) << "Error getting window object" << Debug::flush; |
| 86 | } |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 87 | |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | ScriptableInstance::~ScriptableInstance() { |
| 91 | // TODO(jat): free any remaining Java objects held by JS, then make |
| 92 | // the JS wrapper handle that situation gracefully |
| 93 | if (window) { |
| 94 | NPN_ReleaseObject(window); |
| 95 | } |
| 96 | for (hash_map<int, JavaObject*>::iterator it = javaObjects.begin(); it != javaObjects.end(); |
| 97 | ++it) { |
| 98 | Debug::log(Debug::Spam) << " disconnecting Java wrapper " << it->first << Debug::flush; |
| 99 | it->second->disconnectPlugin(); |
| 100 | } |
| 101 | if (_channel) { |
| 102 | _channel->disconnectFromHost(); |
| 103 | delete _channel; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | void ScriptableInstance::dumpJSresult(const char* js) { |
| 108 | NPString npScript; |
| 109 | dupString(js, npScript); |
| 110 | NPVariantWrapper wrappedRetVal(*this); |
| 111 | if (!NPN_Evaluate(getNPP(), window, &npScript, wrappedRetVal.addressForReturn())) { |
| 112 | Debug::log(Debug::Error) << " *** dumpJSresult failed" << Debug::flush; |
| 113 | return; |
| 114 | } |
| 115 | Debug::log(Debug::Info) << "dumpWindow=" << wrappedRetVal.toString() << Debug::flush; |
| 116 | } |
| 117 | |
| 118 | bool ScriptableInstance::tryGetStringPrimitive(NPObject* obj, NPVariant& result) { |
| 119 | if (NPN_HasMethod(getNPP(), obj, jsValueOfID)) { |
| 120 | if (NPN_Invoke(getNPP(), obj, jsValueOfID, 0, 0, &result) |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 121 | && NPVariantUtil::isString(result)) { |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 122 | return true; |
| 123 | } |
| 124 | NPVariantProxy::release(result); |
| 125 | } |
| 126 | return false; |
| 127 | } |
| 128 | |
| 129 | bool ScriptableInstance::makeResult(bool isException, const Value& value, NPVariant* result) { |
| 130 | Debug::log(Debug::Debugging) << "makeResult(" << isException << ", " << value << ")" |
| 131 | << Debug::flush; |
| 132 | Value temp; |
| 133 | if (value.getType() == Value::JAVA_OBJECT) { |
| 134 | int javaId = value.getJavaObjectId(); |
| 135 | // We may have previously released the proxy for the same object id, |
| 136 | // but have not yet sent a free message back to the server. |
| 137 | javaObjectsToFree.erase(javaId); |
| 138 | } |
| 139 | NPVariantArray varArgs(*this, 3); |
| 140 | varArgs[0] = isException ? 1 : 0; |
| 141 | varArgs[1] = value; |
| 142 | NPVariantWrapper retVal(*this); |
| 143 | return NPN_Invoke(getNPP(), window, jsResultID, varArgs.getArray(), varArgs.getSize(), result); |
| 144 | } |
| 145 | |
| 146 | //============================================================================= |
| 147 | // NPObject methods |
| 148 | //============================================================================= |
| 149 | |
| 150 | bool ScriptableInstance::hasProperty(NPIdentifier name) { |
| 151 | if (!NPN_IdentifierIsString(name)) { |
| 152 | // all numeric properties are ok, as we assume only JSNI code is making |
| 153 | // the field access via dispatchID |
| 154 | return true; |
| 155 | } |
| 156 | // TODO: special-case toString tear-offs |
| 157 | return name == statsID || name == connectedID; |
| 158 | } |
| 159 | |
| 160 | bool ScriptableInstance::getProperty(NPIdentifier name, NPVariant* variant) { |
| 161 | Debug::log(Debug::Debugging) << "ScriptableInstance::getProperty(name=" |
| 162 | << NPN_UTF8FromIdentifier(name) << ")" << Debug::flush; |
| 163 | bool retVal = false; |
| 164 | VOID_TO_NPVARIANT(*variant); |
| 165 | if (name == connectedID) { |
| 166 | BOOLEAN_TO_NPVARIANT(_channel->isConnected(), *variant); |
| 167 | retVal = true; |
| 168 | } else if (name == statsID) { |
| 169 | NPVariantProxy::assignFrom(*variant, "<stats data>"); |
| 170 | retVal = true; |
| 171 | } |
| 172 | if (retVal) { |
| 173 | // TODO: testing |
| 174 | Debug::log(Debug::Debugging) << " return value " << *variant |
| 175 | << Debug::flush; |
| 176 | } |
| 177 | return retVal; |
| 178 | } |
| 179 | |
| 180 | bool ScriptableInstance::setProperty(NPIdentifier name, const NPVariant* variant) { |
| 181 | Debug::log(Debug::Debugging) << "ScriptableInstance::setProperty(name=" |
| 182 | << NPN_UTF8FromIdentifier(name) << ", value=" << *variant << ")" |
| 183 | << Debug::flush; |
| 184 | return false; |
| 185 | } |
| 186 | |
| 187 | bool ScriptableInstance::hasMethod(NPIdentifier name) { |
| 188 | Debug::log(Debug::Debugging) << "ScriptableInstance::hasMethod(name=" << NPN_UTF8FromIdentifier(name) << ")" |
| 189 | << Debug::flush; |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 190 | if (name == _connectId || |
| 191 | name == initID || |
| 192 | name == toStringID || |
| 193 | name == loadHostEntriesID || |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 194 | name == getHostPermissionID || |
| 195 | name == testJsIdentityID ) { |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 196 | return true; |
| 197 | } |
| 198 | return false; |
| 199 | } |
| 200 | |
| 201 | bool ScriptableInstance::invoke(NPIdentifier name, const NPVariant* args, unsigned argCount, |
| 202 | NPVariant* result) { |
| 203 | NPUTF8* uname = NPN_UTF8FromIdentifier(name); |
| 204 | Debug::log(Debug::Debugging) << "ScriptableInstance::invoke(name=" << uname << ",#args=" << argCount << ")" |
| 205 | << Debug::flush; |
| 206 | VOID_TO_NPVARIANT(*result); |
| 207 | if (name == _connectId) { |
| 208 | connect(args, argCount, result); |
| 209 | } else if (name == initID) { |
| 210 | init(args, argCount, result); |
| 211 | } else if (name == toStringID) { |
| 212 | // TODO(jat): figure out why this doesn't show in Firebug |
| 213 | string val("[GWT OOPHM Plugin: connected="); |
| 214 | val += _channel->isConnected() ? 'Y' : 'N'; |
| 215 | val += ']'; |
| 216 | NPVariantProxy::assignFrom(*result, val); |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 217 | } else if (name == loadHostEntriesID) { |
| 218 | loadHostEntries(args, argCount, result); |
| 219 | } else if (name == getHostPermissionID) { |
| 220 | getHostPermission(args, argCount, result); |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 221 | } else if (name == testJsIdentityID) { |
| 222 | testJsIdentity(args, argCount, result); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 223 | } |
| 224 | return true; |
| 225 | } |
| 226 | |
| 227 | bool ScriptableInstance::invokeDefault(const NPVariant* args, unsigned argCount, |
| 228 | NPVariant* result) { |
| 229 | Debug::log(Debug::Debugging) << "ScriptableInstance::invokeDefault(#args=" << argCount << ")" |
| 230 | << Debug::flush; |
| 231 | VOID_TO_NPVARIANT(*result); |
| 232 | return true; |
| 233 | } |
| 234 | |
| 235 | bool ScriptableInstance::enumeration(NPIdentifier** propReturn, uint32_t* count) { |
| 236 | Debug::log(Debug::Debugging) << "ScriptableInstance::enumeration()" << Debug::flush; |
| 237 | int n = 2; |
| 238 | NPIdentifier* props = static_cast<NPIdentifier*>(NPN_MemAlloc(sizeof(NPIdentifier) * n)); |
| 239 | props[0] = connectedID; |
| 240 | props[1] = statsID; |
| 241 | *propReturn = props; |
| 242 | *count = n; |
| 243 | return true; |
| 244 | } |
| 245 | |
| 246 | //============================================================================= |
| 247 | // internal methods |
| 248 | //============================================================================= |
| 249 | |
| 250 | void ScriptableInstance::init(const NPVariant* args, unsigned argCount, NPVariant* result) { |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 251 | if (argCount != 1 || !NPVariantUtil::isObject(args[0])) { |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 252 | // TODO: better failure? |
| 253 | Debug::log(Debug::Error) << "ScriptableInstance::init called with incorrect arguments:\n"; |
| 254 | for (unsigned i = 0; i < argCount; ++i) { |
| 255 | Debug::log(Debug::Error) << " " << i << " " << NPVariantProxy::toString(args[i]) << "\n"; |
| 256 | } |
| 257 | Debug::log(Debug::Error) << Debug::flush; |
| 258 | result->type = NPVariantType_Void; |
| 259 | return; |
| 260 | } |
| 261 | if (window) { |
| 262 | NPN_ReleaseObject(window); |
| 263 | } |
| 264 | // replace our window object with that passed by the caller |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 265 | window = NPVariantUtil::getAsObject(args[0]); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 266 | NPN_RetainObject(window); |
| 267 | BOOLEAN_TO_NPVARIANT(true, *result); |
| 268 | result->type = NPVariantType_Bool; |
| 269 | } |
| 270 | |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 271 | string ScriptableInstance::getLocationHref() { |
| 272 | NPVariantWrapper locationVariant(*this); |
| 273 | NPVariantWrapper hrefVariant(*this); |
| 274 | |
| 275 | // window.location |
| 276 | NPN_GetProperty(getNPP(), window, locationID, locationVariant.addressForReturn()); |
| 277 | //window.location.href |
| 278 | NPN_GetProperty(getNPP(), locationVariant.getAsObject(), hrefID, hrefVariant.addressForReturn()); |
| 279 | |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 280 | const NPString* locationHref = NPVariantUtil::getAsNPString(hrefVariant); |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 281 | return convertToString(*locationHref); |
| 282 | } |
| 283 | |
| 284 | |
| 285 | void ScriptableInstance::loadHostEntries(const NPVariant* args, unsigned argCount, NPVariant* result) { |
| 286 | string locationHref = getLocationHref(); |
| 287 | if (locationHref.compare(BACKGROUND_PAGE_STR) == 0) { |
| 288 | AllowedConnections::clearRules(); |
| 289 | for (unsigned i = 0; i < argCount; ++i) { |
| 290 | //Get the host entry object {url: "somehost.net", include: true/false} |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 291 | NPObject* hostEntry = NPVariantUtil::getAsObject(args[i]); |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 292 | if (!hostEntry) { |
| 293 | Debug::log(Debug::Error) << "Got a host entry that is not an object.\n"; |
| 294 | break; |
| 295 | } |
| 296 | |
| 297 | //Get the url |
| 298 | NPVariantWrapper urlVariant(*this); |
| 299 | if (!NPN_GetProperty(getNPP(), hostEntry, urlID, urlVariant.addressForReturn()) || |
| 300 | !urlVariant.isString()) { |
| 301 | Debug::log(Debug::Error) << "Got a host.url entry that is not a string.\n"; |
| 302 | break; |
| 303 | } |
| 304 | const NPString* urlNPString = urlVariant.getAsNPString(); |
| 305 | string urlString = convertToString(*urlNPString); |
| 306 | |
| 307 | //Include/Exclude? |
| 308 | NPVariantWrapper includeVariant(*this); |
| 309 | if (!NPN_GetProperty(getNPP(), hostEntry, includeID, includeVariant.addressForReturn()) || |
| 310 | !includeVariant.isBoolean()) { |
| 311 | Debug::log(Debug::Error) << "Got a host.include entry that is not a boolean.\n"; |
| 312 | break; |
| 313 | } |
| 314 | bool include = includeVariant.getAsBoolean(); |
| 315 | Debug::log(Debug::Info) << "Adding " << urlString << "(" << (include ? "include" : "exclude") << ")\n"; |
codefu@google.com | 977045b | 2011-05-31 17:15:12 +0000 | [diff] [blame] | 316 | |
| 317 | int slash = urlString.find( '/' ); |
| 318 | if( slash == std::string::npos ) { |
| 319 | AllowedConnections::addRule(urlString, "localhost", !include); |
| 320 | } else { |
| 321 | AllowedConnections::addRule(urlString.substr( 0, slash), urlString.substr(slash+1), !include); |
| 322 | } |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 323 | } |
| 324 | } else { |
| 325 | Debug::log(Debug::Error) << "ScriptableInstance::loadHostEntries called from outside the background page: " << |
| 326 | locationHref << "\n"; |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | void ScriptableInstance::getHostPermission(const NPVariant* args, unsigned argCount, NPVariant* result) { |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 331 | if (argCount != 1 || !NPVariantUtil::isString(args[0])) { |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 332 | Debug::log(Debug::Error) << "ScriptableInstance::getHostPermission called with incorrect arguments.\n"; |
| 333 | } |
| 334 | |
| 335 | const NPString url = args[0].value.stringValue; |
| 336 | const string urlStr = convertToString(url); |
| 337 | bool allowed = false; |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 338 | |
codefu@google.com | 977045b | 2011-05-31 17:15:12 +0000 | [diff] [blame] | 339 | Debug::log(Debug::Info) << "getHostPermission() url " << urlStr << Debug::flush; |
| 340 | bool matches = AllowedConnections::matchesRule( |
| 341 | AllowedConnections::getHostFromUrl(urlStr), |
| 342 | AllowedConnections::getCodeServerFromUrl(urlStr), |
| 343 | &allowed); |
| 344 | string retStr; |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 345 | if (!matches) { |
| 346 | retStr = UNKNOWN_STR; |
| 347 | } else if (allowed) { |
| 348 | retStr = INCLUDE_STR; |
| 349 | } else { |
| 350 | retStr = EXCLUDE_STR; |
| 351 | } |
| 352 | |
| 353 | NPVariantProxy(*this, *result) = retStr; |
| 354 | } |
| 355 | |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 356 | void ScriptableInstance::testJsIdentity(const NPVariant* args, unsigned argCount, NPVariant* result) { |
| 357 | if (argCount != 2 || !NPVariantUtil::isObject(args[0]) || |
| 358 | !NPVariantUtil::isObject(args[1]) ) { |
| 359 | Debug::log(Debug::Error) << "ScriptableInstance::testJsIdentity called" |
| 360 | << " with incorrect arguments.\n"; |
| 361 | } |
| 362 | NPObject* obj1 = NPVariantUtil::getAsObject(args[0]); |
| 363 | NPObject* obj2 = NPVariantUtil::getAsObject(args[1]); |
| 364 | Debug::log(Debug::Info) << "obj1:" << obj1 << " obj2:" << obj2 |
| 365 | << Debug::flush; |
| 366 | if( obj1 == obj2 ) { |
| 367 | Debug::log(Debug::Info) << "Idenity check passed; not using expando!" |
| 368 | << Debug::flush; |
| 369 | ScriptableInstance::jsIdentitySafe = true; |
| 370 | } else { |
| 371 | Debug::log(Debug::Info) << "Idenity check failed; using expando" |
| 372 | << Debug::flush; |
| 373 | ScriptableInstance::jsIdentitySafe = false; |
| 374 | } |
| 375 | } |
| 376 | |
| 377 | |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 378 | void ScriptableInstance::connect(const NPVariant* args, unsigned argCount, NPVariant* result) { |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 379 | if (argCount != 5 || !NPVariantUtil::isString(args[0]) |
| 380 | || !NPVariantUtil::isString(args[1]) |
| 381 | || !NPVariantUtil::isString(args[2]) |
| 382 | || !NPVariantUtil::isString(args[3]) |
| 383 | || !NPVariantUtil::isString(args[4])) { |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 384 | // TODO: better failure? |
| 385 | Debug::log(Debug::Error) << "ScriptableInstance::connect called with incorrect arguments:\n"; |
| 386 | for (unsigned i = 0; i < argCount; ++i) { |
| 387 | Debug::log(Debug::Error) << " " << i << " " << NPVariantProxy::toString(args[i]) << "\n"; |
| 388 | } |
| 389 | Debug::log(Debug::Error) << Debug::flush; |
| 390 | result->type = NPVariantType_Void; |
| 391 | return; |
| 392 | } |
conroy@google.com | 20638f6 | 2011-01-25 20:47:44 +0000 | [diff] [blame] | 393 | |
| 394 | // application provided URL string used for user facing things like the |
| 395 | // devmode tab title |
| 396 | const NPString appUrl = args[0].value.stringValue; |
| 397 | const string appUrlStr = convertToString(appUrl); |
| 398 | |
| 399 | // window.location.href provided URL. (used for security) |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 400 | const string urlStr = getLocationHref(); |
conroy@google.com | 20638f6 | 2011-01-25 20:47:44 +0000 | [diff] [blame] | 401 | |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 402 | const NPString sessionKey = args[1].value.stringValue; |
| 403 | const NPString hostAddr = args[2].value.stringValue; |
| 404 | const NPString moduleName = args[3].value.stringValue; |
| 405 | const NPString hostedHtmlVersion = args[4].value.stringValue; |
| 406 | Debug::log(Debug::Info) << "ScriptableInstance::connect(url=" << NPVariantProxy::toString(args[0]) |
| 407 | << ",sessionKey=" << NPVariantProxy::toString(args[1]) << ",host=" << NPVariantProxy::toString(args[2]) |
| 408 | << ",module=" << NPVariantProxy::toString(args[3]) << ",hostedHtmlVers=" << NPVariantProxy::toString(args[4]) |
| 409 | << ")" << Debug::flush; |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 410 | |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 411 | bool allowed = false; |
codefu@google.com | 977045b | 2011-05-31 17:15:12 +0000 | [diff] [blame] | 412 | AllowedConnections::matchesRule( |
| 413 | AllowedConnections::getHostFromUrl(urlStr), |
| 414 | AllowedConnections::getCodeServerFromUrl(appUrlStr), |
| 415 | &allowed); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 416 | if (!allowed) { |
| 417 | BOOLEAN_TO_NPVARIANT(false, *result); |
| 418 | result->type = NPVariantType_Bool; |
| 419 | return; |
| 420 | } |
| 421 | |
| 422 | bool connected = false; |
| 423 | unsigned port = 9997; // TODO(jat): should there be a default? |
| 424 | int n = GetNPStringUTF8Length(hostAddr); |
| 425 | scoped_ptr<char> host(new char[n + 1]); |
| 426 | const char* s = GetNPStringUTF8Characters(hostAddr); |
| 427 | char* d = host.get(); |
| 428 | while (n > 0 && *s != ':') { |
| 429 | n--; |
| 430 | *d++ = *s++; |
| 431 | } |
| 432 | *d = 0; |
| 433 | if (n > 0) { |
| 434 | port = atoi(s + 1); |
| 435 | } |
| 436 | Debug::log(Debug::Info) << " host=" << host.get() << ",port=" << port << Debug::flush; |
| 437 | |
| 438 | |
| 439 | if (!_channel->connectToHost(host.get(), port)) { |
| 440 | BOOLEAN_TO_NPVARIANT(false, *result); |
| 441 | result->type = NPVariantType_Bool; |
| 442 | } |
| 443 | |
| 444 | string hostedHtmlVersionStr = convertToString(hostedHtmlVersion); |
| 445 | if (!_channel->init(this, BROWSERCHANNEL_PROTOCOL_VERSION, |
| 446 | BROWSERCHANNEL_PROTOCOL_VERSION, hostedHtmlVersionStr)) { |
| 447 | BOOLEAN_TO_NPVARIANT(false, *result); |
| 448 | result->type = NPVariantType_Bool; |
| 449 | } |
| 450 | |
| 451 | string moduleNameStr = convertToString(moduleName); |
| 452 | string userAgent(NPN_UserAgent(getNPP())); |
| 453 | string tabKeyStr = computeTabIdentity(); |
| 454 | string sessionKeyStr = convertToString(sessionKey); |
| 455 | Debug::log(Debug::Debugging) << " connected, sending loadModule" << Debug::flush; |
conroy@google.com | 20638f6 | 2011-01-25 20:47:44 +0000 | [diff] [blame] | 456 | connected = LoadModuleMessage::send(*_channel, appUrlStr, tabKeyStr, sessionKeyStr, |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 457 | moduleNameStr, userAgent, this); |
| 458 | BOOLEAN_TO_NPVARIANT(connected, *result); |
| 459 | result->type = NPVariantType_Bool; |
| 460 | } |
| 461 | |
| 462 | int ScriptableInstance::getLocalObjectRef(NPObject* obj) { |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 463 | int id = localObjects.getObjectId(obj); |
| 464 | if(id == -1) { |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 465 | id = localObjects.add(obj); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 466 | } |
| 467 | return id; |
| 468 | } |
| 469 | |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 470 | void ScriptableInstance::fatalError(HostChannel& channel, const string& message) { |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 471 | // TODO(jat): better error handling |
| 472 | Debug::log(Debug::Error) << "Fatal error: " << message << Debug::flush; |
| 473 | } |
| 474 | |
| 475 | void ScriptableInstance::dupString(const char* str, NPString& npString) { |
| 476 | npString.UTF8Length = static_cast<uint32_t>(strlen(str)); |
| 477 | NPUTF8* chars = static_cast<NPUTF8*>(NPN_MemAlloc(npString.UTF8Length)); |
| 478 | memcpy(chars, str, npString.UTF8Length); |
| 479 | npString.UTF8Characters = chars; |
| 480 | } |
| 481 | |
| 482 | // SessionHandler methods |
| 483 | void ScriptableInstance::freeValue(HostChannel& channel, int idCount, const int* const ids) { |
| 484 | Debug::log(Debug::Debugging) << "freeValue(#ids=" << idCount << ")" << Debug::flush; |
| 485 | for (int i = 0; i < idCount; ++i) { |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 486 | Debug::log(Debug::Spam) << " id=" << ids[i] << Debug::flush; |
| 487 | localObjects.free(ids[i]); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 488 | } |
| 489 | } |
| 490 | |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 491 | void ScriptableInstance::loadJsni(HostChannel& channel, const string& js) { |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 492 | NPString npScript; |
| 493 | dupString(js.c_str(), npScript); |
| 494 | NPVariantWrapper npResult(*this); |
| 495 | Debug::log(Debug::Spam) << "loadJsni - \n" << js << Debug::flush; |
| 496 | if (!NPN_Evaluate(getNPP(), window, &npScript, npResult.addressForReturn())) { |
| 497 | Debug::log(Debug::Error) << "loadJsni failed\n" << js << Debug::flush; |
| 498 | } |
| 499 | } |
| 500 | |
| 501 | Value ScriptableInstance::clientMethod_getProperty(HostChannel& channel, int numArgs, const Value* const args) { |
| 502 | if (numArgs != 2 || !args[0].isInt() || (!args[1].isString() && !args[1].isInt())) { |
| 503 | Debug::log(Debug::Error) << "Incorrect invocation of getProperty: #args=" << numArgs << ":"; |
| 504 | for (int i = 0; i < numArgs; ++i) { |
| 505 | Debug::log(Debug::Error) << " " << i << "=" << args[i].toString(); |
| 506 | } |
| 507 | Debug::log(Debug::Error) << Debug::flush; |
| 508 | return Value(); |
| 509 | } |
| 510 | int id = args[0].getInt(); |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 511 | NPObject* obj = localObjects.getById(id); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 512 | NPIdentifier propID; |
| 513 | if (args[1].isString()) { |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 514 | string propName = args[1].getString(); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 515 | propID = NPN_GetStringIdentifier(propName.c_str()); |
| 516 | } else { |
| 517 | int propNum = args[1].getInt(); |
| 518 | propID = NPN_GetIntIdentifier(propNum); |
| 519 | } |
| 520 | NPVariantWrapper npResult(*this); |
| 521 | if (!NPN_GetProperty(getNPP(), obj, propID, npResult.addressForReturn())) { |
| 522 | Debug::log(Debug::Warning) << "getProperty(id=" << id << ", prop=" |
| 523 | << NPN_UTF8FromIdentifier(propID) << ") failed" << Debug::flush; |
| 524 | return Value(); |
| 525 | } |
| 526 | return npResult.getAsValue(*this); |
| 527 | } |
| 528 | |
| 529 | Value ScriptableInstance::clientMethod_setProperty(HostChannel& channel, int numArgs, const Value* const args) { |
| 530 | if (numArgs != 2 || !args[0].isInt() || (!args[1].isString() && !args[1].isInt())) { |
| 531 | Debug::log(Debug::Error) << "Incorrect invocation of setProperty: #args=" |
| 532 | << numArgs << ":"; |
| 533 | for (int i = 0; i < numArgs; ++i) { |
| 534 | Debug::log(Debug::Error) << " " << i << "=" << args[i].toString(); |
| 535 | } |
| 536 | Debug::log(Debug::Error) << Debug::flush; |
| 537 | return Value(); |
| 538 | } |
| 539 | int id = args[0].getInt(); |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 540 | NPObject* obj = localObjects.getById(id); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 541 | NPIdentifier propID; |
| 542 | if (args[1].isString()) { |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 543 | string propName = args[1].getString(); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 544 | propID = NPN_GetStringIdentifier(propName.c_str()); |
| 545 | } else { |
| 546 | int propNum = args[1].getInt(); |
| 547 | propID = NPN_GetIntIdentifier(propNum); |
| 548 | } |
| 549 | NPVariantWrapper npValue(*this); |
| 550 | npValue.operator=(args[2]); |
| 551 | if (!NPN_SetProperty(getNPP(), obj, propID, npValue.address())) { |
| 552 | Debug::log(Debug::Warning) << "setProperty(id=" << id << ", prop=" |
| 553 | << NPN_UTF8FromIdentifier(propID) << ", val=" << args[2].toString() |
| 554 | << ") failed" << Debug::flush; |
| 555 | return Value(); |
| 556 | } |
| 557 | return Value(); |
| 558 | } |
| 559 | |
| 560 | /** |
| 561 | * SessionHandler.invoke - used by LoadModule and reactToMessages* to process server-side |
| 562 | * requests to invoke methods in Javascript or the plugin. |
| 563 | */ |
| 564 | bool ScriptableInstance::invokeSpecial(HostChannel& channel, SpecialMethodId dispatchId, |
| 565 | int numArgs, const Value* const args, Value* returnValue) { |
| 566 | switch (dispatchId) { |
| 567 | case SessionHandler::HasMethod: |
| 568 | case SessionHandler::HasProperty: |
| 569 | break; |
| 570 | case SessionHandler::SetProperty: |
| 571 | *returnValue = clientMethod_setProperty(channel, numArgs, args); |
| 572 | return false; |
| 573 | case SessionHandler::GetProperty: |
| 574 | *returnValue = clientMethod_getProperty(channel, numArgs, args); |
| 575 | return false; |
| 576 | default: |
| 577 | break; |
| 578 | } |
| 579 | Debug::log(Debug::Error) << "Unexpected special method " << dispatchId |
| 580 | << " called on plugin; #args=" << numArgs << ":"; |
| 581 | for (int i = 0; i < numArgs; ++i) { |
| 582 | Debug::log(Debug::Error) << " " << i << "=" << args[i].toString(); |
| 583 | } |
| 584 | Debug::log(Debug::Error) << Debug::flush; |
| 585 | // TODO(jat): should we create a real exception object? |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 586 | string buf("unexpected invokeSpecial("); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 587 | buf += static_cast<int>(dispatchId); |
| 588 | buf += ")"; |
| 589 | returnValue->setString(buf); |
| 590 | return true; |
| 591 | } |
| 592 | |
| 593 | bool ScriptableInstance::invoke(HostChannel& channel, const Value& thisRef, |
conroy@google.com | 8806978 | 2010-11-23 13:51:12 +0000 | [diff] [blame] | 594 | const string& methodName, int numArgs, const Value* const args, |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 595 | Value* returnValue) { |
| 596 | Debug::log(Debug::Debugging) << "invokeJS(" << methodName << ", this=" |
| 597 | << thisRef.toString() << ", numArgs=" << numArgs << ")" << Debug::flush; |
| 598 | NPVariantArray varArgs(*this, numArgs + 2); |
| 599 | varArgs[0] = thisRef; |
| 600 | varArgs[1] = methodName; |
| 601 | for (int i = 0; i < numArgs; ++i) { |
| 602 | varArgs[i + 2] = args[i]; |
| 603 | } |
| 604 | const NPVariant* argArray = varArgs.getArray(); |
| 605 | if (Debug::level(Debug::Spam)) { |
| 606 | for (int i = 0; i < varArgs.getSize(); ++i) { |
| 607 | Debug::log(Debug::Spam) << " arg " << i << " is " |
| 608 | << NPVariantProxy::toString(argArray[i]) << Debug::flush; |
| 609 | } |
| 610 | } |
| 611 | NPVariantWrapper wrappedRetVal(*this); |
| 612 | if (!NPN_Invoke(getNPP(), window, jsInvokeID, argArray, varArgs.getSize(), |
| 613 | wrappedRetVal.addressForReturn())) { |
| 614 | Debug::log(Debug::Error) << "*** invokeJS(" << methodName << ", this=" |
| 615 | << thisRef.toString() << ", numArgs=" << numArgs << ") failed" |
| 616 | << Debug::flush; |
| 617 | // TODO(jat): should we create a real exception object? |
| 618 | returnValue->setString("invoke of " + methodName + " failed"); |
| 619 | return true; |
| 620 | } |
| 621 | Debug::log(Debug::Spam) << " wrapped return is " << wrappedRetVal.toString() << Debug::flush; |
| 622 | NPVariantWrapper exceptFlag(*this); |
| 623 | NPVariantWrapper retval(*this); |
| 624 | NPObject* wrappedArray = wrappedRetVal.getAsObject(); |
| 625 | if (!NPN_GetProperty(getNPP(), wrappedArray, idx0, exceptFlag.addressForReturn())) { |
| 626 | Debug::log(Debug::Error) << " Error getting element 0 of wrapped return value (" |
| 627 | << wrappedRetVal << ") on call to " << methodName << Debug::flush; |
| 628 | } |
| 629 | if (!NPN_GetProperty(getNPP(), wrappedArray, idx1, retval.addressForReturn())) { |
| 630 | Debug::log(Debug::Error) << " Error getting element 1 of wrapped return value (" |
| 631 | << wrappedRetVal << ") on call to " << methodName << Debug::flush; |
| 632 | } |
| 633 | Debug::log(Debug::Debugging) << " return value " << retval.toString() << Debug::flush; |
| 634 | *returnValue = retval.getAsValue(*this); |
| 635 | if (exceptFlag.isInt() && exceptFlag.getAsInt() != 0) { |
| 636 | Debug::log(Debug::Debugging) << " exception: " << retval << Debug::flush; |
| 637 | return true; |
| 638 | } |
| 639 | return false; |
| 640 | } |
| 641 | |
| 642 | bool ScriptableInstance::JavaObject_invoke(int objectId, int dispId, |
| 643 | const NPVariant* args, uint32_t numArgs, NPVariant* result) { |
| 644 | Debug::log(Debug::Debugging) << "JavaObject_invoke(dispId= " << dispId << ", numArgs=" << numArgs << ")" << Debug::flush; |
| 645 | if (Debug::level(Debug::Spam)) { |
| 646 | for (uint32_t i = 0; i < numArgs; ++i) { |
| 647 | Debug::log(Debug::Spam) << " " << i << " = " << args[i] << Debug::flush; |
| 648 | } |
| 649 | } |
| 650 | |
| 651 | bool isRawToString = false; |
| 652 | if (dispId == -1) { |
| 653 | dispId = 0; |
| 654 | isRawToString = true; |
| 655 | } |
| 656 | |
| 657 | Value javaThis; |
| 658 | javaThis.setJavaObject(objectId); |
| 659 | scoped_array<Value> vargs(new Value[numArgs]); |
| 660 | for (unsigned i = 0; i < numArgs; ++i) { |
| 661 | vargs[i] = NPVariantProxy::getAsValue(args[i], *this); |
| 662 | } |
| 663 | bool isException = false; |
| 664 | Value returnValue; |
| 665 | if (!InvokeMessage::send(*_channel, javaThis, dispId, numArgs, vargs.get())) { |
| 666 | Debug::log(Debug::Error) << "JavaObject_invoke: failed to send invoke message" << Debug::flush; |
| 667 | } else { |
| 668 | Debug::log(Debug::Debugging) << " return from invoke" << Debug::flush; |
| 669 | scoped_ptr<ReturnMessage> retMsg(_channel->reactToMessagesWhileWaitingForReturn(this)); |
| 670 | if (!retMsg.get()) { |
| 671 | Debug::log(Debug::Error) << "JavaObject_invoke: failed to get return value" << Debug::flush; |
| 672 | } else { |
| 673 | if (isRawToString) { |
| 674 | // toString() needs the raw value |
| 675 | NPVariantProxy::assignFrom(*this, *result, retMsg->getReturnValue()); |
| 676 | return !retMsg->isException(); |
| 677 | } |
| 678 | isException = retMsg->isException(); |
| 679 | returnValue = retMsg->getReturnValue(); |
| 680 | } |
| 681 | } |
| 682 | // Wrap the result |
| 683 | return makeResult(isException, returnValue, result); |
| 684 | } |
| 685 | |
| 686 | bool ScriptableInstance::JavaObject_getProperty(int objectId, int dispId, |
| 687 | NPVariant* result) { |
| 688 | Debug::log(Debug::Debugging) << "JavaObject_getProperty(objectid=" |
| 689 | << objectId << ", dispId=" << dispId << ")" << Debug::flush; |
| 690 | VOID_TO_NPVARIANT(*result); |
| 691 | Value propertyValue = ServerMethods::getProperty(*_channel, this, objectId, dispId); |
| 692 | if (propertyValue.isJsObject()) { |
| 693 | // TODO(jat): special-case for testing |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 694 | NPObject* npObj = localObjects.getById(propertyValue.getJsObjectId()); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 695 | OBJECT_TO_NPVARIANT(npObj, *result); |
| 696 | NPN_RetainObject(npObj); |
| 697 | } else { |
| 698 | NPVariantProxy::assignFrom(*this, *result, propertyValue); |
| 699 | } |
| 700 | Debug::log(Debug::Debugging) << " return val=" << propertyValue |
| 701 | << ", NPVariant=" << *result << Debug::flush; |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 702 | if (NPVariantUtil::isObject(*result)) { |
| 703 | dumpObjectBytes(NPVariantUtil::getAsObject(*result)); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 704 | } |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 705 | if (NPVariantUtil::isObject(*result)) { |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 706 | Debug::log(Debug::Debugging) << " final return refcount = " |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 707 | << NPVariantUtil::getAsObject(*result)->referenceCount << Debug::flush; |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 708 | } |
| 709 | return true; |
| 710 | } |
| 711 | |
| 712 | bool ScriptableInstance::JavaObject_setProperty(int objectId, int dispId, |
| 713 | const NPVariant* npValue) { |
| 714 | Debug::log(Debug::Debugging) << "JavaObject_setProperty(objectid=" |
| 715 | << objectId << ", dispId=" << dispId << ", value=" << *npValue << ")" << Debug::flush; |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 716 | if (NPVariantUtil::isObject(*npValue)) { |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 717 | Debug::log(Debug::Debugging) << " before localObj: refcount = " |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 718 | << NPVariantUtil::getAsObject(*npValue)->referenceCount << Debug::flush; |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 719 | } |
| 720 | Value value = NPVariantProxy::getAsValue(*npValue, *this, true); |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 721 | if (NPVariantUtil::isObject(*npValue)) { |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 722 | Debug::log(Debug::Debugging) << " after localObj: refcount = " |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 723 | << NPVariantUtil::getAsObject(*npValue)->referenceCount << Debug::flush; |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 724 | } |
codefu@google.com | f722fe2 | 2011-07-11 13:15:51 +0000 | [diff] [blame] | 725 | if (NPVariantUtil::isObject(*npValue)) { |
| 726 | dumpObjectBytes(NPVariantUtil::getAsObject(*npValue)); |
gwt.mirrorbot@gmail.com | d54a4bd | 2010-06-07 19:20:31 +0000 | [diff] [blame] | 727 | } |
| 728 | Debug::log(Debug::Debugging) << " as value: " << value << Debug::flush; |
| 729 | // TODO: no way to set an actual exception object! (Could ClassCastException on server.) |
| 730 | return ServerMethods::setProperty(*_channel, this, objectId, dispId, value); |
| 731 | } |
| 732 | |
| 733 | bool ScriptableInstance::JavaObject_getToStringTearOff(NPVariant* result) { |
| 734 | Debug::log(Debug::Debugging) << "JavaObject_getToStringTearOff()" << Debug::flush; |
| 735 | VOID_TO_NPVARIANT(*result); |
| 736 | |
| 737 | Value temp; |
| 738 | NPVariantArray varArgs(*this, 3); |
| 739 | temp.setNull(); varArgs[0] = temp; // proxy: no proxy needed |
| 740 | temp.setInt(0); varArgs[1] = temp; // dispId: always 0 for toString() |
| 741 | temp.setInt(0); varArgs[2] = temp; // argCount: always 0 for toString() |
| 742 | |
| 743 | if (!NPN_Invoke(getNPP(), window, jsTearOffID, varArgs.getArray(), 3, result)) { |
| 744 | Debug::log(Debug::Error) << "*** JavaObject_getToStringTearOff() failed" |
| 745 | << Debug::flush; |
| 746 | return true; |
| 747 | } |
| 748 | return true; |
| 749 | } |
| 750 | |
| 751 | JavaObject* ScriptableInstance::createJavaWrapper(int objectId) { |
| 752 | Debug::log(Debug::Debugging) << "createJavaWrapper(objectId=" << objectId << ")" << Debug::flush; |
| 753 | JavaObject* jObj; |
| 754 | hash_map<int, JavaObject*>::iterator it = javaObjects.find(objectId); |
| 755 | if (it != javaObjects.end()) { |
| 756 | jObj = it->second; |
| 757 | NPN_RetainObject(jObj); |
| 758 | return jObj; |
| 759 | } |
| 760 | jObj = JavaObject::create(this, objectId); |
| 761 | javaObjects[objectId] = jObj; |
| 762 | return jObj; |
| 763 | } |
| 764 | |
| 765 | void ScriptableInstance::destroyJavaWrapper(JavaObject* jObj) { |
| 766 | int objectId = jObj->getObjectId(); |
| 767 | if (!javaObjects.erase(objectId)) { |
| 768 | Debug::log(Debug::Error) << "destroyJavaWrapper(id=" << objectId |
| 769 | << "): trying to free unknown JavaObject" << Debug::flush; |
| 770 | } |
| 771 | Debug::log(Debug::Debugging) << "destroyJavaWrapper(id=" << objectId << ")" << Debug::flush; |
| 772 | javaObjectsToFree.insert(objectId); |
| 773 | } |
| 774 | |
| 775 | void ScriptableInstance::disconnectDetectedImpl() { |
| 776 | NPVariantWrapper result(*this); |
| 777 | NPN_Invoke(getNPP(), window, jsDisconnectedID, 0, 0, result.addressForReturn()); |
| 778 | } |
| 779 | |
| 780 | void ScriptableInstance::sendFreeValues(HostChannel& channel) { |
| 781 | unsigned n = javaObjectsToFree.size(); |
| 782 | if (n) { |
| 783 | scoped_array<int> ids(new int[n]); |
| 784 | int i = 0; |
| 785 | for (std::set<int>::iterator it = javaObjectsToFree.begin(); |
| 786 | it != javaObjectsToFree.end(); ++it) { |
| 787 | ids[i++] = *it; |
| 788 | } |
| 789 | if (ServerMethods::freeJava(channel, this, n, ids.get())) { |
| 790 | javaObjectsToFree.clear(); |
| 791 | } |
| 792 | } |
| 793 | } |