Skip to content

Commit

Permalink
Fix 'Unexpected EOF' in old bridge
Browse files Browse the repository at this point in the history
Summary: This is caused by receiving \u2028/2029 in callbacks/function calls. The correct solution is to not evaluate these strings as scripts but instead parse them as json and pass them through the JSC API.

Reviewed By: lexs

Differential Revision: D3543098

fbshipit-source-id: 4d8acce1d510bb17361d32103d4738fc0208b0a8
  • Loading branch information
astreet authored and Facebook Github Bot 7 committed Jul 11, 2016
1 parent 7b718b0 commit 6d3c7b8
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 30 deletions.
57 changes: 27 additions & 30 deletions ReactAndroid/src/main/jni/react/JSCExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,6 @@ static JSValueRef nativeInjectHMRUpdate(
const JSValueRef arguments[],
JSValueRef *exception);

static std::string executeJSCallWithJSC(
JSGlobalContextRef ctx,
const std::string& methodName,
const std::vector<folly::dynamic>& arguments) {
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(
TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.executeJSCall",
"method", methodName);
#endif

// Evaluate script with JSC
folly::dynamic jsonArgs(arguments.begin(), arguments.end());
auto js = folly::to<std::string>(
"__fbBatchedBridge.", methodName, ".apply(null, ",
folly::toJson(jsonArgs), ")");
auto result = evaluateScript(ctx, String(js.c_str()), nullptr);
return Value(ctx, result).toJSONString();
}

std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(Bridge *bridge) {
return std::unique_ptr<JSExecutor>(new JSCExecutor(bridge, cacheDir_, m_jscConfig));
}
Expand Down Expand Up @@ -202,6 +183,8 @@ void JSCExecutor::terminateOnJSVMThread() {

m_batchedBridge.reset();
m_flushedQueueObj.reset();
m_callFunctionObj.reset();
m_invokeCallbackObj.reset();

s_globalContextRefToJSCExecutor.erase(m_context);
JSGlobalContextRelease(m_context);
Expand Down Expand Up @@ -266,6 +249,8 @@ bool JSCExecutor::ensureBatchedBridgeObject() {
}
m_batchedBridge = folly::make_unique<Object>(batchedBridgeValue.asObject());
m_flushedQueueObj = folly::make_unique<Object>(m_batchedBridge->getProperty("flushedQueue").asObject());
m_callFunctionObj = folly::make_unique<Object>(m_batchedBridge->getProperty("callFunctionReturnFlushedQueue").asObject());
m_invokeCallbackObj = folly::make_unique<Object>(m_batchedBridge->getProperty("invokeCallbackAndReturnFlushedQueue").asObject());
return true;
}

Expand All @@ -290,6 +275,10 @@ void JSCExecutor::flush() {
}

void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.callFunction");
#endif

if (!ensureBatchedBridgeObject()) {
throwJSExecutionException(
"Couldn't call JS module %s, method %s: bridge configuration isn't available. This "
Expand All @@ -298,27 +287,35 @@ void JSCExecutor::callFunction(const std::string& moduleId, const std::string& m
methodId.c_str());
}

std::vector<folly::dynamic> call {
moduleId,
methodId,
std::move(arguments),
String argsString = String(folly::toJson(std::move(arguments)).c_str());
String moduleIdStr(moduleId.c_str());
String methodIdStr(methodId.c_str());
JSValueRef args[] = {
JSValueMakeString(m_context, moduleIdStr),
JSValueMakeString(m_context, methodIdStr),
Value::fromJSON(m_context, argsString)
};
std::string calls = executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
m_bridge->callNativeModules(*this, calls, true);
auto result = m_callFunctionObj->callAsFunction(3, args);
m_bridge->callNativeModules(*this, result.toJSONString(), true);
}

void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.invokeCallback");
#endif

if (!ensureBatchedBridgeObject()) {
throwJSExecutionException(
"Couldn't invoke JS callback %d: bridge configuration isn't available. This shouldn't be possible. Congratulations.", (int) callbackId);
}

std::vector<folly::dynamic> call {
(double) callbackId,
std::move(arguments)
String argsString = String(folly::toJson(std::move(arguments)).c_str());
JSValueRef args[] = {
JSValueMakeNumber(m_context, callbackId),
Value::fromJSON(m_context, argsString)
};
std::string calls = executeJSCallWithJSC(m_context, "invokeCallbackAndReturnFlushedQueue", std::move(call));
m_bridge->callNativeModules(*this, calls, true);
auto result = m_invokeCallbackObj->callAsFunction(2, args);
m_bridge->callNativeModules(*this, result.toJSONString(), true);
}

void JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
Expand Down
2 changes: 2 additions & 0 deletions ReactAndroid/src/main/jni/react/JSCExecutor.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class JSCExecutor : public JSExecutor {
folly::dynamic m_jscConfig;
std::unique_ptr<Object> m_batchedBridge;
std::unique_ptr<Object> m_flushedQueueObj;
std::unique_ptr<Object> m_callFunctionObj;
std::unique_ptr<Object> m_invokeCallbackObj;

/**
* WebWorker constructor. Must be invoked from thread this Executor will run on.
Expand Down

0 comments on commit 6d3c7b8

Please sign in to comment.