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 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 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); Extension::RequestInitModules(); 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; }
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; }
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, ReturnEncodeType returnEncodeType) { std::string rpcFunc = transport->getCommand(); { ServerStatsHelper ssh("input"); RequestURI reqURI(rpcFunc); HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo); auto env = php_global(s__ENV); env.toArrRef().set(s_HPHP_RPC, 1); php_global_set(s__ENV, std::move(env)); InitFiniNode::GlobalsInit(); } bool isFile = rpcFunc.rfind('.') != std::string::npos; std::string rpcFile; bool error = false; Array params; Transport::Method requestMethod = m_serverInfo->getMethod(); std::string sparams = transport->getParam("params", requestMethod); if (!sparams.empty()) { Variant jparams = Variant::attach( HHVM_FN(json_decode)(String(sparams), true) ); if (jparams.isArray()) { params = jparams.toArray(); } else { error = true; } } else { std::vector<std::string> sparams; transport->getArrayParam("p", sparams, requestMethod); if (!sparams.empty()) { for (unsigned int i = 0; i < sparams.size(); i++) { Variant jparams = Variant::attach( HHVM_FN(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 size_t size; const void *data = transport->getPostData(size); if (data && size) { params.append(String((char*)data, size, CopyString)); } } } if (transport->getIntParam("reset", requestMethod) == 1) { m_reset = true; } int output = transport->getIntParam("output", requestMethod); // We don't debug RPC requests, so we need to detach XDebugHook if xdebug was // enabled. DEBUGGER_ATTACHED_ONLY(DebuggerHook::detach()); int code; if (!error) { Variant funcRet; std::string errorMsg = "Internal Server Error"; std::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", requestMethod); if (rpcFile.empty()) { rpcFile = transport->getParam("include_once", requestMethod); 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, false /* warmupOnly */, false /* richErrorMessage */); } // 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, true /* once */, false /* warmupOnly */, false /* richErrorMessage */); } if (ret) { bool serializeFailed = false; String response; switch (output) { case 0: { assert(returnEncodeType == ReturnEncodeType::Json || returnEncodeType == ReturnEncodeType::Serialize); try { response = (returnEncodeType == ReturnEncodeType::Json) ? Variant::attach(HHVM_FN(json_encode)(funcRet)).toString() : f_serialize(funcRet); } catch (...) { serializeFailed = true; } break; } case 1: response = m_context->obDetachContents(); break; case 2: response = Variant::attach(HHVM_FN(json_encode)( make_map_array( s_output, m_context->obDetachContents(), s_return, Variant::attach(HHVM_FN(json_encode)(funcRet)) ) )).toString(); 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(); // in case postsend/cleanup output something // PHP5 always provides _START. m_context->obClean(k_PHP_OUTPUT_HANDLER_START | k_PHP_OUTPUT_HANDLER_CLEAN | k_PHP_OUTPUT_HANDLER_END); m_context->restoreSession(); return !error; }
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); Extension::RequestInitModules(); 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; // Let the debugger initialize. // FIXME: hphpd can be initialized this way as well DEBUGGER_ATTACHED_ONLY(phpDebuggerRequestInitHook()); 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, true /* once */, false /* warmupOnly */, false /* richErrorMessage */); 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, true /* once */, false /* warmupOnly */, false /* richErrorMessage */); 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()); } // If we have registered post-send shutdown functions, end the request before // executing them. If we don't, be compatible with Zend by allowing usercode // in hphp_context_shutdown to run before we end the request. bool hasPostSend = context->hasShutdownFunctions(ExecutionContext::ShutdownType::PostSend); if (hasPostSend) { transport->onSendEnd(); } context->onShutdownPostSend(); Eval::Debugger::InterruptPSPEnded(transport->getUrl()); hphp_context_shutdown(); if (!hasPostSend) { transport->onSendEnd(); } hphp_context_exit(false); ServerStats::LogPage(file, code); return ret; }