Variant f_call_user_func_rpc(int _argc, CStrRef host, int port, CStrRef auth, int timeout, CVarRef function, CArrRef _argv /* = null_array */) { string shost = host.data(); if (!RuntimeOption::DebuggerRpcHostDomain.empty()) { unsigned int pos = shost.find(RuntimeOption::DebuggerRpcHostDomain); if (pos == string::npos || pos != shost.length() - RuntimeOption::DebuggerRpcHostDomain.size()) { shost += RuntimeOption::DebuggerRpcHostDomain; } } string url = "http://"; url += shost; url += ":"; url += lexical_cast<string>(port); url += "/call_user_func_serialized?auth="; url += auth.data(); Array blob = CREATE_MAP2("func", function, "args", _argv); String message = f_serialize(blob); vector<string> headers; LibEventHttpClientPtr http = LibEventHttpClient::Get(shost, port); if (!http->send(url, headers, timeout < 0 ? 0 : timeout, false, message.data(), message.size())) { raise_error("Unable to send RPC request"); return false; } int code = http->getCode(); if (code <= 0) { raise_error("Server timed out or unable to find specified URL: %s", url.c_str()); return false; } int len = 0; char *response = http->recv(len); String sresponse(response, len, AttachString); if (code != 200) { raise_error("Internal server error: %d %s", code, HttpProtocol::GetReasonString(code)); return false; } // This double decoding can be avoided by modifying RPC server to directly // take PHP serialization format. Variant res = f_unserialize(f_json_decode(sresponse)); if (!res.isArray()) { raise_error("Internal protocol error"); return false; } if (res.toArray().exists("exception")) { throw res["exception"]; } return res["ret"]; }
Array f_hphp_get_status() { std::string out; ServerStats::ReportStatus(out, ServerStats::Format::JSON); return f_json_decode(String(out)).toArray(); }
bool RPCRequestHandler::executePHPFunction(Transport *transport, SourceRootInfo &sourceRootInfo) { // reset timeout counter ThreadInfo::s_threadInfo->m_reqInjectionData.started = time(0); string rpcFunc = transport->getCommand(); { ServerStatsHelper ssh("input"); RequestURI reqURI(rpcFunc); HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo); } bool isFile = rpcFunc.rfind('.') != string::npos; string rpcFile; bool error = false; Array params; string sparams = transport->getParam("params"); if (!sparams.empty()) { Variant jparams = f_json_decode(String(sparams), true); if (jparams.isArray()) { params = jparams.toArray(); } else { error = true; } } else { vector<string> sparams; transport->getArrayParam("p", sparams); if (!sparams.empty()) { for (unsigned int i = 0; i < sparams.size(); i++) { Variant jparams = f_json_decode(String(sparams[i]), true); if (same(jparams, false)) { error = true; break; } params.append(jparams); } } else { // single string parameter, used by xbox to avoid any en/decoding int size; const void *data = transport->getPostData(size); if (data && size) { params.append(String((char*)data, size, AttachLiteral)); } } } if (transport->getIntParam("reset") == 1) { m_reset = true; } int output = transport->getIntParam("output"); int code; if (!error) { Variant funcRet; string errorMsg = "Internal Server Error"; string warmupDoc, reqInitFunc, reqInitDoc; if (m_serverInfo) { warmupDoc = m_serverInfo->getWarmupDoc(); reqInitFunc = m_serverInfo->getReqInitFunc(); reqInitDoc = m_serverInfo->getReqInitDoc(); } if (!warmupDoc.empty()) warmupDoc = canonicalize_path(warmupDoc, "", 0); if (!warmupDoc.empty()) { warmupDoc = getSourceFilename(warmupDoc, sourceRootInfo); } if (!reqInitDoc.empty()) reqInitDoc = canonicalize_path(reqInitDoc, "", 0); if (!reqInitDoc.empty()) { reqInitDoc = getSourceFilename(reqInitDoc, sourceRootInfo); } bool runOnce = false; bool ret = true; if (isFile) { rpcFile = rpcFunc; rpcFunc.clear(); } else { rpcFile = transport->getParam("include"); if (rpcFile.empty()) { rpcFile = transport->getParam("include_once"); runOnce = true; } } if (!rpcFile.empty()) { // invoking a file through rpc bool forbidden = false; if (!RuntimeOption::ForbiddenFileExtensions.empty()) { const char *ext = rpcFile.c_str() + rpcFile.rfind('.') + 1; if (RuntimeOption::ForbiddenFileExtensions.find(ext) != RuntimeOption::ForbiddenFileExtensions.end()) { forbidden = true; } } if (!forbidden) { rpcFile = canonicalize_path(rpcFile, "", 0); rpcFile = getSourceFilename(rpcFile, sourceRootInfo); ret = hphp_invoke(m_context, rpcFile, false, Array(), null, warmupDoc, reqInitFunc, reqInitDoc, error, errorMsg, runOnce); } // no need to do the initialization for a second time warmupDoc.clear(); reqInitFunc.clear(); reqInitDoc.clear(); } if (ret && !rpcFunc.empty()) { ret = hphp_invoke(m_context, rpcFunc, true, params, ref(funcRet), warmupDoc, reqInitFunc, reqInitDoc, error, errorMsg); } if (ret) { String response; switch (output) { case 0: response = f_json_encode(funcRet); break; case 1: response = m_context->obDetachContents(); break; case 2: response = f_json_encode(CREATE_MAP2("output", m_context->obDetachContents(), "return", f_json_encode(funcRet))); break; } code = 200; transport->sendRaw((void*)response.data(), response.size()); } else if (error) { code = 500; transport->sendString(errorMsg, 500); m_reset = true; } else { code = 404; transport->sendString("Not Found", 404); } } else { code = 400; transport->sendString("Bad Request", 400); } params.reset(); sourceRootInfo.clear(); transport->onSendEnd(); ServerStats::LogPage(isFile ? rpcFile : rpcFunc, code); m_context->onShutdownPostSend(); m_context->obClean(); // in case postsend/cleanup output something m_context->restoreSession(); return !error; }
bool TestExtJson::test_json_decode() { Array arr = CREATE_MAP1("fbid", 101501853510151001LL); VS(f_json_decode(f_json_encode(arr), true), arr); VS(f_json_decode("{\"0\":{\"00\":0}}", true), CREATE_MAP1("0", CREATE_MAP1("00", 0))); VS(f_json_decode("{\"a\":1,\"b\":2.3,\"3\":\"test\"}", true), CREATE_MAP3("a", 1, "b", 2.3, 3, "test")); VS(f_json_decode("[\"a\",1,true,false,null]", true), CREATE_VECTOR5("a", 1, true, false, uninit_null())); Object obj = f_json_decode("{\"a\":1,\"b\":2.3,\"3\":\"test\"}"); Object obj2(SystemLib::AllocStdClassObject()); obj2->o_set("a", 1); obj2->o_set("b", 2.3); obj2->o_set("3", "test"); VS(obj.toArray(), obj2.toArray()); obj = f_json_decode("[\"a\",1,true,false,null]"); VS(obj.toArray(), CREATE_VECTOR5("a", 1, true, false, uninit_null())); VS(f_json_decode("{z:1}", true), uninit_null()); VS(f_json_decode("{z:1}", true, k_JSON_FB_LOOSE), CREATE_MAP1("z", 1)); VS(f_json_decode("{z:\"z\"}", true), uninit_null()); VS(f_json_decode("{z:\"z\"}", true, k_JSON_FB_LOOSE), CREATE_MAP1("z", "z")); VS(f_json_decode("{'x':1}", true), uninit_null()); VS(f_json_decode("{'x':1}", true, k_JSON_FB_LOOSE), CREATE_MAP1("x", 1)); VS(f_json_decode("{y:1,}", true), uninit_null()); VS(f_json_decode("{y:1,}", true, k_JSON_FB_LOOSE), CREATE_MAP1("y", 1)); VS(f_json_decode("{,}", true), uninit_null()); VS(f_json_decode("{,}", true, k_JSON_FB_LOOSE), uninit_null()); VS(f_json_decode("[1,2,3,]", true), uninit_null()); VS(f_json_decode("[1,2,3,]", true, k_JSON_FB_LOOSE), CREATE_VECTOR3(1,2,3)); VS(f_json_decode("[,]", true), uninit_null()); VS(f_json_decode("[,]", true, k_JSON_FB_LOOSE), uninit_null()); VS(f_json_decode("[]", true), Array::Create()); VS(f_json_decode("[]", true, k_JSON_FB_LOOSE), Array::Create()); VS(f_json_decode("{}", true), Array::Create()); VS(f_json_decode("{}", true, k_JSON_FB_LOOSE), Array::Create()); VS(f_json_decode("[{\"a\":\"apple\"},{\"b\":\"banana\"}]", true), CREATE_VECTOR2(CREATE_MAP1("a", "apple"), CREATE_MAP1("b", "banana"))); Variant a = "[{\"a\":[{\"n\":\"1st\"}]},{\"b\":[{\"n\":\"2nd\"}]}]"; VS(f_json_decode(a, true), CREATE_VECTOR2 (CREATE_MAP1("a", CREATE_VECTOR1(CREATE_MAP1("n", "1st"))), CREATE_MAP1("b", CREATE_VECTOR1(CREATE_MAP1("n", "2nd"))))); return Count(true); }
bool RPCRequestHandler::executePHPFunction(Transport *transport, SourceRootInfo &sourceRootInfo, ReturnEncodeType returnEncodeType) { string rpcFunc = transport->getCommand(); { ServerStatsHelper ssh("input"); RequestURI reqURI(rpcFunc); HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo); GlobalVariables *g = get_global_variables(); g->getRef(s__ENV).set(s_HPHP_RPC, 1); } bool isFile = rpcFunc.rfind('.') != string::npos; string rpcFile; bool error = false; Array params; string sparams = transport->getParam("params"); if (!sparams.empty()) { Variant jparams = f_json_decode(String(sparams), true); if (jparams.isArray()) { params = jparams.toArray(); } else { error = true; } } else { vector<string> sparams; transport->getArrayParam("p", sparams); if (!sparams.empty()) { for (unsigned int i = 0; i < sparams.size(); i++) { Variant jparams = f_json_decode(String(sparams[i]), true); if (same(jparams, false)) { error = true; break; } params.append(jparams); } } else { // single string parameter, used by xbox to avoid any en/decoding int size; const void *data = transport->getPostData(size); if (data && size) { params.append(String((char*)data, size, CopyString)); } } } if (transport->getIntParam("reset") == 1) { m_reset = true; } int output = transport->getIntParam("output"); int code; if (!error) { Variant funcRet; string errorMsg = "Internal Server Error"; string reqInitFunc, reqInitDoc; reqInitDoc = transport->getHeader("ReqInitDoc"); if (reqInitDoc.empty() && m_serverInfo) { reqInitFunc = m_serverInfo->getReqInitFunc(); reqInitDoc = m_serverInfo->getReqInitDoc(); } if (!reqInitDoc.empty()) { reqInitDoc = (std::string)canonicalize_path(reqInitDoc, "", 0); } if (!reqInitDoc.empty()) { reqInitDoc = getSourceFilename(reqInitDoc, sourceRootInfo); } bool runOnce = false; bool ret = true; if (isFile) { rpcFile = rpcFunc; rpcFunc.clear(); } else { rpcFile = transport->getParam("include"); if (rpcFile.empty()) { rpcFile = transport->getParam("include_once"); runOnce = true; } } if (!rpcFile.empty()) { // invoking a file through rpc bool forbidden = false; if (!RuntimeOption::ForbiddenFileExtensions.empty()) { const char *ext = rpcFile.c_str() + rpcFile.rfind('.') + 1; if (RuntimeOption::ForbiddenFileExtensions.find(ext) != RuntimeOption::ForbiddenFileExtensions.end()) { forbidden = true; } } if (!forbidden) { rpcFile = (std::string) canonicalize_path(rpcFile, "", 0); rpcFile = getSourceFilename(rpcFile, sourceRootInfo); ret = hphp_invoke(m_context, rpcFile, false, Array(), uninit_null(), reqInitFunc, reqInitDoc, error, errorMsg, runOnce); } // no need to do the initialization for a second time reqInitFunc.clear(); reqInitDoc.clear(); } if (ret && !rpcFunc.empty()) { ret = hphp_invoke(m_context, rpcFunc, true, params, ref(funcRet), reqInitFunc, reqInitDoc, error, errorMsg); } if (ret) { bool serializeFailed = false; String response; switch (output) { case 0: { assert(returnEncodeType == ReturnEncodeType::Json || returnEncodeType == ReturnEncodeType::Serialize); try { response = (returnEncodeType == ReturnEncodeType::Json) ? f_json_encode(funcRet) : f_serialize(funcRet); } catch (...) { serializeFailed = true; } break; } case 1: response = m_context->obDetachContents(); break; case 2: response = f_json_encode( make_map_array(s_output, m_context->obDetachContents(), s_return, f_json_encode(funcRet))); break; case 3: response = f_serialize(funcRet); break; } if (serializeFailed) { code = 500; transport->sendString( "Serialization of the return value failed", 500); m_reset = true; } else { transport->sendRaw((void*)response.data(), response.size()); code = transport->getResponseCode(); } } else if (error) { code = 500; transport->sendString(errorMsg, 500); m_reset = true; } else { code = 404; transport->sendString("Not Found", 404); } } else { code = 400; transport->sendString("Bad Request", 400); } params.reset(); sourceRootInfo.clear(); transport->onSendEnd(); ServerStats::LogPage(isFile ? rpcFile : rpcFunc, code); m_context->onShutdownPostSend(); m_context->obClean(); // in case postsend/cleanup output something m_context->restoreSession(); return !error; }
bool RPCRequestHandler::executePHPFunction(Transport *transport, SourceRootInfo &sourceRootInfo) { // reset timeout counter ThreadInfo::s_threadInfo->m_reqInjectionData.started = time(0); std::string rpcFunc = transport->getCommand(); { ServerStatsHelper ssh("input"); RequestURI reqURI(rpcFunc); HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo); sourceRootInfo.clear(); } bool error = false; Array params; std::string sparams = transport->getParam("params"); if (!sparams.empty()) { Variant jparams = f_json_decode(String(sparams), true); if (jparams.isArray()) { params = jparams.toArray(); } else { error = true; } } else { vector<string> sparams; transport->getArrayParam("p", sparams); if (!sparams.empty()) { for (unsigned int i = 0; i < sparams.size(); i++) { Variant jparams = f_json_decode(String(sparams[i]), true); if (same(jparams, false)) { error = true; break; } params.append(jparams); } } else { // single string parameter, used by xbox to avoid any en/decoding int size; const void *data = transport->getPostData(size); if (data && size) { params.append(String((char*)data, size, AttachLiteral)); } } } if (transport->getIntParam("reset") == 1) { m_reset = true; } int output = transport->getIntParam("output"); int code; if (!error) { Variant funcRet; std::string errorMsg = "Internal Server Error"; string warmupDoc, reqInitFunc, reqInitDoc; if (m_serverInfo) { warmupDoc = m_serverInfo->getWarmupDoc(); reqInitFunc = m_serverInfo->getReqInitFunc(); reqInitDoc = m_serverInfo->getReqInitDoc(); } if (!warmupDoc.empty()) warmupDoc = canonicalize_path(warmupDoc, "", 0); if (!warmupDoc.empty()) warmupDoc = get_source_filename(warmupDoc.c_str()); bool ret = hphp_invoke(m_context, rpcFunc, true, params, ref(funcRet), warmupDoc, reqInitFunc, reqInitDoc, error, errorMsg); if (ret) { String response; switch (output) { case 0: response = f_json_encode(funcRet); break; case 1: response = m_context->obDetachContents(); break; case 2: response = f_json_encode(CREATE_MAP2("output", m_context->obDetachContents(), "return", f_json_encode(funcRet))); break; } code = 200; transport->sendRaw((void*)response.data(), response.size()); } else if (error) { code = 500; transport->sendString(errorMsg, 500); m_reset = true; } else { code = 404; transport->sendString("Not Found", 404); } } else { code = 400; transport->sendString("Bad Request", 400); } params.reset(); transport->onSendEnd(); ServerStats::LogPage(rpcFunc, code); m_context->onShutdownPostSend(); m_context->restoreSession(); return !error; }