RPCRequestHandler::RPCRequestHandler() : m_count(0), m_reset(false) { hphp_session_init(); m_context = hphp_context_init(); m_created = time(0); Logger::ResetRequestCount(); Logger::Info("creating new RPC request handler"); }
RPCRequestHandler::RPCRequestHandler(bool info /* = true */) : m_count(0), m_reset(false), m_returnEncodeType(Json) { hphp_session_init(); m_context = hphp_context_init(); m_created = time(0); Logger::ResetRequestCount(); if (info) { Logger::Info("creating new RPC request handler"); } }
void preloadRepo() { auto& repo = Repo::get(); auto units = repo.enumerateUnits(RepoIdLocal, true, false); if (units.size() == 0) { units = repo.enumerateUnits(RepoIdCentral, true, false); } if (!units.size()) return; std::vector<std::thread> workers; auto numWorkers = Process::GetCPUCount(); // Compute a batch size that causes each thread to process approximately 16 // batches. Even if the batches are somewhat imbalanced in what they contain, // the straggler workers are very unlikey to take more than 10% longer than // the first worker to finish. size_t batchSize{std::max(units.size() / numWorkers / 16, size_t(1))}; std::atomic<size_t> index{0}; for (auto worker = 0; worker < numWorkers; ++worker) { workers.push_back(std::thread([&] { hphp_session_init(); hphp_context_init(); while (true) { auto begin = index.fetch_add(batchSize); auto end = std::min(begin + batchSize, units.size()); if (begin >= end) break; auto unitCount = end - begin; for (auto i = size_t{0}; i < unitCount; ++i) { auto& kv = units[begin + i]; try { lookupUnit(String(RuntimeOption::SourceRoot + kv.first).get(), "", nullptr); } catch (...) { // swallow errors silently } } } hphp_context_exit(); hphp_session_exit(); hphp_thread_exit(); })); } for (auto& worker : workers) { worker.join(); } }
RPCRequestHandler::RPCRequestHandler(bool info /* = true */) : m_count(0), m_reset(false), m_returnEncodeType(Json) { hphp_session_init(); bool isServer = RuntimeOption::serverExecutionMode(); if (isServer) { m_context = hphp_context_init(); } else { // In command line mode, we want the xbox workers to // output to STDOUT m_context = g_context.getNoCheck(); m_context->obSetImplicitFlush(true); } m_created = time(0); Logger::ResetRequestCount(); if (info) { Logger::Info("creating new RPC request handler"); } }
void RPCRequestHandler::initState() { hphp_session_init(); bool isServer = RuntimeOption::ServerExecutionMode(); if (isServer) { m_context = hphp_context_init(); } else { // In command line mode, we want the xbox workers to // output to STDOUT m_context = g_context.getNoCheck(); m_context->obSetImplicitFlush(true); } m_lastReset = time(0); Logger::ResetRequestCount(); if (m_logResets) { Logger::Info("initializing RPC request handler"); } m_reset = false; m_requestsSinceReset = 0; }
bool HttpRequestHandler::executePHPRequest(Transport *transport, RequestURI &reqURI, SourceRootInfo &sourceRootInfo, bool cachableDynamicContent) { ExecutionContext *context = hphp_context_init(); if (RuntimeOption::ImplicitFlush) { context->obSetImplicitFlush(true); } if (RuntimeOption::EnableOutputBuffering) { if (RuntimeOption::OutputHandler.empty()) { context->obStart(); } else { context->obStart(String(RuntimeOption::OutputHandler)); } } context->setTransport(transport); string file = reqURI.absolutePath().c_str(); { ServerStatsHelper ssh("input"); HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo); if (RuntimeOption::EnableDebugger) { Eval::DSandboxInfo sInfo = sourceRootInfo.getSandboxInfo(); Eval::Debugger::RegisterSandbox(sInfo); context->setSandboxId(sInfo.id()); } reqURI.clear(); sourceRootInfo.clear(); } int code; bool ret = true; if (RuntimeOption::EnableDebugger) { Eval::Debugger::InterruptRequestStarted(transport->getUrl()); } bool error = false; std::string errorMsg = "Internal Server Error"; ret = hphp_invoke(context, file, false, Array(), uninit_null(), RuntimeOption::RequestInitFunction, RuntimeOption::RequestInitDocument, error, errorMsg); if (ret) { String content = context->obDetachContents(); if (cachableDynamicContent && !content.empty()) { assert(transport->getUrl()); string key = file + transport->getUrl(); DynamicContentCache::TheCache.store(key, content.data(), content.size()); } transport->sendRaw((void*)content.data(), content.size()); code = transport->getResponseCode(); } else if (error) { code = 500; string errorPage = context->getErrorPage().data(); if (errorPage.empty()) { errorPage = RuntimeOption::ErrorDocument500; } if (!errorPage.empty()) { context->obProtect(false); context->obEndAll(); context->obStart(); context->obProtect(true); ret = hphp_invoke(context, errorPage, false, Array(), uninit_null(), RuntimeOption::RequestInitFunction, RuntimeOption::RequestInitDocument, error, errorMsg); if (ret) { String content = context->obDetachContents(); transport->sendRaw((void*)content.data(), content.size()); code = transport->getResponseCode(); } else { Logger::Error("Unable to invoke error page %s", errorPage.c_str()); errorPage.clear(); // so we fall back to 500 return } } if (errorPage.empty()) { if (RuntimeOption::ServerErrorMessage) { transport->sendString(errorMsg, 500, false, false, "hphp_invoke"); } else { transport->sendString(RuntimeOption::FatalErrorMessage, 500, false, false, "hphp_invoke"); } } } else { code = 404; transport->sendString("Not Found", 404); } if (RuntimeOption::EnableDebugger) { Eval::Debugger::InterruptRequestEnded(transport->getUrl()); } transport->onSendEnd(); hphp_context_exit(context, true, true, transport->getUrl()); ServerStats::LogPage(file, code); return ret; }
void OptWorker<Pre>::onThreadEnter() { hphp_session_init(); hphp_context_init(); }
bool HttpRequestHandler::executePHPRequest(Transport *transport, RequestURI &reqURI, SourceRootInfo &sourceRootInfo, bool cachableDynamicContent) { ExecutionContext *context = hphp_context_init(); context->setTransport(transport); string file = reqURI.absolutePath().c_str(); { ServerStatsHelper ssh("input"); HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo); reqURI.clear(); sourceRootInfo.clear(); } bool error = false; std::string errorMsg = "Internal Server Error"; bool ret = hphp_invoke(context, file, false, Array(), null, RuntimeOption::WarmupDocument, RuntimeOption::RequestInitFunction, error, errorMsg); int code; if (ret) { std::string content = context->getContents(); if (cachableDynamicContent && !content.empty()) { ASSERT(transport->getUrl()); string key = file + transport->getUrl(); DynamicContentCache::TheCache.store(key, content.data(), content.size()); } code = 200; transport->sendRaw((void*)content.data(), content.size()); } else if (error) { code = 500; string errorPage = context->getErrorPage(); if (errorPage.empty()) { errorPage = RuntimeOption::ErrorDocument500; } if (!errorPage.empty()) { context->obEndAll(); context->obStart(); context->obProtect(true); ret = hphp_invoke(context, errorPage, false, Array(), null, RuntimeOption::WarmupDocument, RuntimeOption::RequestInitFunction, error, errorMsg); if (ret) { std::string content = context->getContents(); transport->sendRaw((void*)content.data(), content.size()); } else { errorPage.clear(); // so we fall back to 500 return } } if (errorPage.empty()) { if (RuntimeOption::ServerErrorMessage) { transport->sendString(errorMsg, 500); } else { transport->sendString(RuntimeOption::FatalErrorMessage, 500); } } } else { code = 404; transport->sendString("Not Found", 404); } transport->onSendEnd(); ServerStats::LogPage(file, code); hphp_context_exit(context, true); return ret; }
bool HttpRequestHandler::executePHPRequest(Transport *transport, RequestURI &reqURI, SourceRootInfo &sourceRootInfo, bool cachableDynamicContent) { ExecutionContext *context = hphp_context_init(); if (RuntimeOption::ImplicitFlush) { context->obSetImplicitFlush(true); } if (RuntimeOption::EnableOutputBuffering) { if (RuntimeOption::OutputHandler.empty()) { context->obStart(); } else { context->obStart(String(RuntimeOption::OutputHandler)); } } context->setTransport(transport); string file = reqURI.absolutePath().c_str(); { ServerStatsHelper ssh("input"); HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo); reqURI.clear(); sourceRootInfo.clear(); } int code; bool ret = true; if (!RuntimeOption::ForbiddenFileExtensions.empty()) { size_t pos = file.rfind('.'); if (pos != string::npos) { const char *ext = file.c_str() + pos + 1; if (RuntimeOption::ForbiddenFileExtensions.find(ext) != RuntimeOption::ForbiddenFileExtensions.end()) { code = 403; transport->sendString("Forbidden", 403); ret = false; } } } if (ret) { if (RuntimeOption::EnableDebugger) { Eval::Debugger::InterruptRequestStarted(transport->getUrl()); } bool error = false; std::string errorMsg = "Internal Server Error"; ret = hphp_invoke(context, file, false, Array(), null, RuntimeOption::WarmupDocument, RuntimeOption::RequestInitFunction, RuntimeOption::RequestInitDocument, error, errorMsg); if (ret) { String content = context->obDetachContents(); if (cachableDynamicContent && !content.empty()) { ASSERT(transport->getUrl()); string key = file + transport->getUrl(); DynamicContentCache::TheCache.store(key, content.data(), content.size()); } code = 200; transport->sendRaw((void*)content.data(), content.size(), code); } else if (error) { code = 500; string errorPage = context->getErrorPage().data(); if (errorPage.empty()) { errorPage = RuntimeOption::ErrorDocument500; } if (!errorPage.empty()) { context->obProtect(false); context->obEndAll(); context->obStart(); context->obProtect(true); ret = hphp_invoke(context, errorPage, false, Array(), null, RuntimeOption::WarmupDocument, RuntimeOption::RequestInitFunction, RuntimeOption::RequestInitDocument, error, errorMsg); if (ret) { String content = context->obDetachContents(); transport->sendRaw((void*)content.data(), content.size()); } else { errorPage.clear(); // so we fall back to 500 return } } if (errorPage.empty()) { if (RuntimeOption::ServerErrorMessage) { transport->sendString(errorMsg, 500, false, false, "hphp_invoke"); } else { transport->sendString(RuntimeOption::FatalErrorMessage, 500, false, false, "hphp_invoke"); } } } else { code = 404; transport->sendString("Not Found", 404); } if (RuntimeOption::EnableDebugger) { Eval::Debugger::InterruptRequestEnded(transport->getUrl()); } } transport->onSendEnd(); ServerStats::LogPage(file, code); hphp_context_exit(context, true, true, transport->getUrl()); return ret; }
bool RPCRequestHandler::executePHPFunction(Transport *transport, SourceRootInfo &sourceRootInfo) { ExecutionContext *context = hphp_context_init(); // 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; if (m_serverInfo) { warmupDoc = m_serverInfo->getWarmupDoc(); reqInitFunc = m_serverInfo->getReqInitFunc(); } if (warmupDoc.empty()) { warmupDoc = RuntimeOption::WarmupDocument; reqInitFunc = RuntimeOption::RequestInitFunction; } warmupDoc = canonicalize_path(warmupDoc, "", 0); warmupDoc = get_source_filename(warmupDoc.c_str()); bool ret = hphp_invoke(context, rpcFunc, true, params, ref(funcRet), warmupDoc, reqInitFunc, error, errorMsg); if (ret) { String response; switch (output) { case 0: response = f_json_encode(funcRet); break; case 1: response = context->obGetContents(); break; case 2: response = f_json_encode(CREATE_MAP2("output", context->obGetContents(), "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); hphp_context_exit(context, true, false); return !error; }
RPCRequestHandler::~RPCRequestHandler() { // important to call requestShutdown() hphp_context_exit(hphp_context_init(), true); hphp_session_exit(); }