void HttpRequestHandler::setupRequest(Transport* transport) { MemoryManager::requestInit(); g_context.getCheck(); GetAccessLog().onNewRequest(); // Set current virtual host. HttpProtocol::GetVirtualHost(transport); }
void AdminRequestHandler::setupRequest(Transport* transport) { auto const cmd = transport->getCommand(); if (strncmp(cmd.c_str(), "dump-apc", 8) == 0) { hphp_session_init(); } else { g_context.getCheck(); } GetAccessLog().onNewRequest(); }
void HttpRequestHandler::logToAccessLog(Transport* transport) { GetAccessLog().onNewRequest(); GetAccessLog().log(transport, VirtualHost::GetCurrent()); }
void AdminRequestHandler::setupRequest(Transport* transport) { g_context.getCheck(); GetAccessLog().onNewRequest(); }
void AdminRequestHandler::logToAccessLog(Transport* transport) { GetAccessLog().onNewRequest(); GetAccessLog().log(transport, nullptr); }
void AdminRequestHandler::handleRequest(Transport *transport) { GetAccessLog().onNewRequest(); string cmd = transport->getCommand(); do { if (cmd == "" || cmd == "help") { string usage = "/stop: stop the web server\n" "/translate: translate hex encoded stacktrace in 'stack' param\n" " stack required, stack trace to translate\n" " build-id optional, if specified, build ID has to match\n" " bare optional, whether to display frame ordinates\n" "/build-id: returns build id that's passed in from command line" "\n" #ifdef COMPILER_ID "/compiler-id: returns the compiler id that built this app\n" #endif "/check-load: how many threads are actively handling requests\n" "/check-queued: how many http requests are queued waiting to be\n" " handled\n" "/check-mem: report memory quick statistics in log file\n" "/check-apc: report APC quick statistics\n" "/check-sql: report SQL table statistics\n" "/status.xml: show server status in XML\n" "/status.json: show server status in JSON\n" "/status.html: show server status in HTML\n" "/stats-on: main switch: enable server stats\n" "/stats-off: main switch: disable server stats\n" "/stats-clear: clear all server stats\n" "/stats-web: turn on/off server page stats (CPU and gen time)\n" "/stats-mem: turn on/off memory statistics\n" "/stats-apc: turn on/off APC statistics\n" "/stats-apc-key: turn on/off APC key statistics\n" "/stats-mcc: turn on/off memcache statistics\n" "/stats-sql: turn on/off SQL statistics\n" "/stats-mutex: turn on/off mutex statistics\n" " sampling optional, default 1000\n" "/stats.keys: list all available keys\n" " from optional, <timestamp>, or <-n> second ago\n" " to optional, <timestamp>, or <-n> second ago\n" "/stats.xml: show server stats in XML\n" " from optional, <timestamp>, or <-n> second ago\n" " to optional, <timestamp>, or <-n> second ago\n" " agg optional, aggragation: *, url, code\n" " keys optional, <key>,<key/hit>,<key/sec>,<:regex:>\n" " url optional, only stats of this page or URL\n" " code optional, only stats of pages returning this code\n" "/stats.json: show server stats in JSON\n" " (same as /stats.xml)\n" "/stats.kvp: show server stats in key-value pairs\n" " (same as /stats.xml)\n" "/stats.html: show server stats in HTML\n" " (same as /stats.xml)\n" "/apc-ss: get apc size stats\n" "/apc-ss-flat: get apc size stats in flat format\n" "/apc-ss-keys: get apc size break-down on keys\n" "/apc-ss-dump: dump the size info on each key to /tmp/APC_details\n" " only valid when EnableAPCSizeDetail is true\n" " keysample optional, only dump keys that belongs to the same\n" " group as <keysample>\n" #ifdef GOOGLE_CPU_PROFILER "/prof-cpu-on: turn on CPU profiler\n" "/prof-cpu-off: turn off CPU profiler\n" #endif #ifdef GOOGLE_HEAP_PROFILER "/prof-heap-on: turn on heap profiler\n" "/prof-heap-dump: take one snapshot of the heap\n" "/prof-heap-off: turn off heap profiler\n" "/stats-malloc: turn on/off malloc statistics\n" "/leak-on: start leak detection\n" " sampling required, frequency\n" "/leak-off: end leak detection and report leaking\n" " cutoff optional, default 20 seconds, ignore newer allocs\n" #endif ; #ifndef NO_TCMALLOC if (MallocExtensionInstance) { usage.append( "/free-mem: ask tcmalloc to release memory to system\n" "/tcmalloc-stats: get internal tcmalloc stats\n" ); } #endif #ifndef NO_JEMALLOC if (mallctl) { usage.append( "/jemalloc-stats: get internal jemalloc stats\n" "/jemalloc-stats-print:\n" " get comprehensive jemalloc stats in\n" " human-readable form\n" "/jemalloc-prof-activate:\n" " activate heap profiling\n" "/jemalloc-prof-deactivate:\n" " deactivate heap profiling\n" "/jemalloc-prof-dump:\n" " dump heap profile\n" " file optional, filesystem path\n" ); } transport->sendString(usage); break; } #endif if (!RuntimeOption::AdminPassword.empty() && RuntimeOption::AdminPassword != transport->getParam("auth")) { transport->sendString("Unauthorized", 401); break; } if (cmd == "stop") { transport->sendString("OK\n"); HttpServer::Server->stop(); break; } if (cmd == "build-id") { transport->sendString(RuntimeOption::BuildId, 200); break; } #ifdef COMPILER_ID if (cmd == "compiler-id") { transport->sendString(COMPILER_ID, 200); break; } #endif if (cmd == "translate") { string buildId = transport->getParam("build-id"); if (!buildId.empty() && buildId != RuntimeOption::BuildId) { transport->sendString("Build ID doesn't match.", 500); break; } string translated = translate_stack(transport->getParam("stack").c_str(), transport->getParam("bare").empty()); transport->sendString(translated); break; } if (strncmp(cmd.c_str(), "check", 5) == 0 && handleCheckRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "status", 6) == 0 && handleStatusRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "stats", 5) == 0 && handleStatsRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "prof", 4) == 0 && handleProfileRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "leak", 4) == 0 && handleLeakRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "apc-ss", 6) == 0 && handleAPCSizeRequest(cmd, transport)) { break; } #ifndef NO_TCMALLOC if (MallocExtensionInstance) { if (cmd == "free-mem") { MallocExtensionInstance()->ReleaseFreeMemory(); transport->sendString("OK\n"); break; } if (cmd == "tcmalloc-stats") { ostringstream stats; size_t user_allocated, heap_size, slack_bytes; MallocExtensionInstance()-> GetNumericProperty("generic.current_allocated_bytes", &user_allocated); MallocExtensionInstance()-> GetNumericProperty("generic.heap_size", &heap_size); MallocExtensionInstance()-> GetNumericProperty("tcmalloc.slack_bytes", &slack_bytes); stats << "<tcmalloc-stats>" << endl; stats << " <user_allocated>" << user_allocated << "</user_allocated>" << endl; stats << " <heap_size>" << heap_size << "</heap_size>" << endl; stats << " <slack_bytes>" << slack_bytes << "</slack_bytes>" << endl; stats << "</tcmalloc-stats>" << endl; transport->sendString(stats.str()); break; } } #endif #ifndef NO_JEMALLOC if (mallctl) { if (cmd == "jemalloc-stats") { // Force jemalloc to update stats cached for use by mallctl(). uint64_t epoch = 1; mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)); size_t allocated = 0; // Initialize in case stats aren't enabled. size_t sz = sizeof(size_t); mallctl("stats.allocated", &allocated, &sz, NULL, 0); size_t active = 0; mallctl("stats.active", &active, &sz, NULL, 0); size_t mapped = 0; mallctl("stats.mapped", &mapped, &sz, NULL, 0); ostringstream stats; stats << "<jemalloc-stats>" << endl; stats << " <allocated>" << allocated << "</allocated>" << endl; stats << " <active>" << active << "</active>" << endl; stats << " <mapped>" << mapped << "</mapped>" << endl; stats << "</jemalloc-stats>" << endl; transport->sendString(stats.str()); break; } if (cmd == "jemalloc-stats-print") { char *buf = (char *)malloc(MALLOC_WRITE_CB_BUFLEN); if (buf == NULL) { transport->sendString("OOM\n"); break; } buf[0] = '\0'; malloc_stats_print(malloc_write_cb, (void *)buf, ""); transport->sendString(buf); free(buf); break; } if (cmd == "jemalloc-prof-activate") { bool active = true; int err = mallctl("prof.active", NULL, NULL, &active, sizeof(bool)); if (err) { ostringstream estr; estr << "Error " << err << " in mallctl(\"prof.active\", ...)" << endl; transport->sendString(estr.str()); } else { transport->sendString("OK\n"); } break; } if (cmd == "jemalloc-prof-deactivate") { bool active = false; int err = mallctl("prof.active", NULL, NULL, &active, sizeof(bool)); if (err) { ostringstream estr; estr << "Error " << err << " in mallctl(\"prof.active\", ...)" << endl; transport->sendString(estr.str()); } else { transport->sendString("OK\n"); } break; } if (cmd == "jemalloc-prof-dump") { string f = transport->getParam("file"); if (f != "") { const char *s = f.c_str(); int err = mallctl("prof.dump", NULL, NULL, (void *)&s, sizeof(char *)); if (err) { ostringstream estr; estr << "Error " << err << " in mallctl(\"prof.dump\", ..., \"" << f << "\", ...)" << endl; transport->sendString(estr.str()); break; } } else { int err = mallctl("prof.dump", NULL, NULL, NULL, 0); if (err) { ostringstream estr; estr << "Error " << err << " in mallctl(\"prof.dump\", ...)" << endl; transport->sendString(estr.str()); break; } } transport->sendString("OK\n"); break; } #endif } transport->sendString("Unknown command: " + cmd + "\n", 404); } while (0); GetAccessLog().log(transport); }
void HttpRequestHandler::handleRequest(Transport *transport) { ExecutionProfiler ep(ThreadInfo::RuntimeFunctions); Logger::OnNewRequest(); GetAccessLog().onNewRequest(); transport->enableCompression(); ServerStatsHelper ssh("all", ServerStatsHelper::TRACK_MEMORY); Logger::Verbose("receiving %s", transport->getCommand().c_str()); // will clear all extra logging when this function goes out of scope StackTraceNoHeap::ExtraLoggingClearer clearer; StackTraceNoHeap::AddExtraLogging("URL", transport->getUrl()); // resolve virtual host const VirtualHost *vhost = HttpProtocol::GetVirtualHost(transport); assert(vhost); if (vhost->disabled() || vhost->isBlocking(transport->getCommand(), transport->getRemoteHost())) { transport->sendString("Not Found", 404); return; } // don't serve the request if it's been sitting in queue for longer than our // allowed request timeout. int requestTimeoutSeconds = vhost->getRequestTimeoutSeconds(getDefaultTimeout()); if (requestTimeoutSeconds > 0) { timespec now; Timer::GetMonotonicTime(now); const timespec& queueTime = transport->getQueueTime(); if (gettime_diff_us(queueTime, now) > requestTimeoutSeconds * 1000000) { transport->sendString("Service Unavailable", 503); m_requestTimedOutOnQueue->addValue(1); return; } } ServerStats::StartRequest(transport->getCommand().c_str(), transport->getRemoteHost(), vhost->getName().c_str()); // resolve source root string host = transport->getHeader("Host"); SourceRootInfo sourceRootInfo(host.c_str()); if (sourceRootInfo.error()) { sourceRootInfo.handleError(transport); return; } // request URI string pathTranslation = m_pathTranslation ? vhost->getPathTranslation().c_str() : ""; RequestURI reqURI(vhost, transport, sourceRootInfo.path(), pathTranslation); if (reqURI.done()) { return; // already handled with redirection or 404 } string path = reqURI.path().data(); string absPath = reqURI.absolutePath().data(); // determine whether we should compress response bool compressed = transport->decideCompression(); const char *data; int len; const char *ext = reqURI.ext(); if (reqURI.forbidden()) { transport->sendString("Forbidden", 403); return; } bool cachableDynamicContent = (!RuntimeOption::StaticFileGenerators.empty() && RuntimeOption::StaticFileGenerators.find(path) != RuntimeOption::StaticFileGenerators.end()); // If this is not a php file, check the static and dynamic content caches if (ext && strcasecmp(ext, "php") != 0) { if (RuntimeOption::EnableStaticContentCache) { bool original = compressed; // check against static content cache if (StaticContentCache::TheCache.find(path, data, len, compressed)) { Util::ScopedMem decompressed_data; // (qigao) not calling stat at this point because the timestamp of // local cache file is not valuable, maybe misleading. This way // the Last-Modified header will not show in response. // stat(RuntimeOption::FileCache.c_str(), &st); if (!original && compressed) { data = gzdecode(data, len); if (data == nullptr) { throw FatalErrorException("cannot unzip compressed data"); } decompressed_data = const_cast<char*>(data); compressed = false; } sendStaticContent(transport, data, len, 0, compressed, path, ext); StaticContentCache::TheFileCache->adviseOutMemory(); ServerStats::LogPage(path, 200); GetAccessLog().log(transport, vhost); return; } } if (RuntimeOption::EnableStaticContentFromDisk) { String translated = File::TranslatePath(String(absPath)); if (!translated.empty()) { CstrBuffer sb(translated.data()); if (sb.valid()) { struct stat st; st.st_mtime = 0; stat(translated.data(), &st); sendStaticContent(transport, sb.data(), sb.size(), st.st_mtime, false, path, ext); ServerStats::LogPage(path, 200); GetAccessLog().log(transport, vhost); return; } } } // check static contents that were generated by dynamic pages if (cachableDynamicContent) { // check against dynamic content cache assert(transport->getUrl()); string key = path + transport->getUrl(); if (DynamicContentCache::TheCache.find(key, data, len, compressed)) { sendStaticContent(transport, data, len, 0, compressed, path, ext); ServerStats::LogPage(path, 200); GetAccessLog().log(transport, vhost); return; } } } // proxy any URLs that not specified in ServeURLs if (!RuntimeOption::ProxyOrigin.empty() && ((RuntimeOption::UseServeURLs && RuntimeOption::ServeURLs.find(path) == RuntimeOption::ServeURLs.end()) || (RuntimeOption::UseProxyURLs && (RuntimeOption::ProxyURLs.find(path) != RuntimeOption::ProxyURLs.end() || MatchAnyPattern(path, RuntimeOption::ProxyPatterns) || (abs(rand()) % 100) < RuntimeOption::ProxyPercentage)))) { for (int i = 0; i < RuntimeOption::ProxyRetry; i++) { bool force = (i == RuntimeOption::ProxyRetry - 1); // last one if (handleProxyRequest(transport, force)) break; } return; } // record request for debugging purpose std::string tmpfile = HttpProtocol::RecordRequest(transport); // main body hphp_session_init(); ThreadInfo::s_threadInfo->m_reqInjectionData. setTimeout(requestTimeoutSeconds); bool ret = false; try { ret = executePHPRequest(transport, reqURI, sourceRootInfo, cachableDynamicContent); } catch (const Eval::DebuggerException &e) { transport->sendString(e.what(), 200); transport->onSendEnd(); hphp_context_exit(g_context.getNoCheck(), true, true, transport->getUrl()); } catch (...) { Logger::Error("Unhandled exception in HPHP server engine."); } GetAccessLog().log(transport, vhost); /* * HPHP logs may need to access data in ServerStats, so we have to * clear the hashtable after writing the log entry. */ ServerStats::Reset(); hphp_session_exit(); HttpProtocol::ClearRecord(ret, tmpfile); }
void HttpRequestHandler::handleRequest(Transport *transport) { Logger::OnNewRequest(); GetAccessLog().onNewRequest(); transport->enableCompression(); Logger::Verbose("receiving %s", transport->getCommand().c_str()); ServerStatsHelper ssh("all", true); // resolve virtual host const VirtualHost *vhost = HttpProtocol::GetVirtualHost(transport); ASSERT(vhost); if (vhost->disabled() || vhost->isBlocking(transport->getCommand(), transport->getRemoteHost())) { transport->sendString("Not Found", 404); return; } ServerStats::StartRequest(transport->getCommand().c_str(), transport->getRemoteHost(), vhost->getName().c_str()); // resolve source root string host = transport->getHeader("Host"); SourceRootInfo sourceRootInfo(host.c_str()); if (sourceRootInfo.error()) { sourceRootInfo.handleError(transport); return; } // request URI string pathTranslation = m_pathTranslation ? vhost->getPathTranslation().c_str() : ""; RequestURI reqURI(vhost, transport, sourceRootInfo.path(), pathTranslation); if (reqURI.done()) { return; // already handled with redirection or 404 } string path = reqURI.path().data(); string absPath = reqURI.absolutePath().data(); bool compressed = transport->acceptEncoding("gzip"); const char *data; int len; size_t pos = path.rfind('.'); const char *ext = (pos != string::npos) ? (path.c_str() + pos + 1) : NULL; bool cachableDynamicContent = (!RuntimeOption::StaticFileGenerators.empty() && RuntimeOption::StaticFileGenerators.find(path) != RuntimeOption::StaticFileGenerators.end()); // If this is not a php file, check the static and dynamic content caches if (ext && strcasecmp(ext, "php") != 0) { if (RuntimeOption::EnableStaticContentCache) { // check against static content cache if (StaticContentCache::TheCache.find(path, data, len, compressed)) { struct stat st; st.st_mtime = 0; // (qigao) not calling stat at this point because the timestamp of // local cache file is not valuable, maybe misleading. This way // the Last-Modified header will not show in response. // stat(RuntimeOption::FileCache.c_str(), &st); sendStaticContent(transport, data, len, st.st_mtime, compressed, path); ServerStats::LogPage(path, 200); return; } } if (RuntimeOption::EnableStaticContentFromDisk && RuntimeOption::StaticFileExtensions.find(ext) != RuntimeOption::StaticFileExtensions.end()) { String translated = File::TranslatePath(String(absPath)); if (!translated.empty()) { StringBuffer sb(translated.data()); if (sb.valid()) { struct stat st; st.st_mtime = 0; stat(translated.data(), &st); sendStaticContent(transport, sb.data(), sb.size(), st.st_mtime, false, path); ServerStats::LogPage(path, 200); return; } } } // check static contents that were generated by dynamic pages if (cachableDynamicContent) { // check against dynamic content cache ASSERT(transport->getUrl()); string key = path + transport->getUrl(); if (DynamicContentCache::TheCache.find(key, data, len, compressed)) { sendStaticContent(transport, data, len, 0, compressed, path); ServerStats::LogPage(path, 200); return; } } } // proxy any URLs that not specified in ServeURLs if (!RuntimeOption::ProxyOrigin.empty() && ((RuntimeOption::UseServeURLs && RuntimeOption::ServeURLs.find(path) == RuntimeOption::ServeURLs.end()) || (RuntimeOption::UseProxyURLs && (RuntimeOption::ProxyURLs.find(path) != RuntimeOption::ProxyURLs.end() || MatchAnyPattern(path, RuntimeOption::ProxyPatterns) || (abs(rand()) % 100) < RuntimeOption::ProxyPercentage)))) { for (int i = 0; i < RuntimeOption::ProxyRetry; i++) { bool force = (i == RuntimeOption::ProxyRetry - 1); // last one if (handleProxyRequest(transport, force)) break; } return; } // record request for debugging purpose std::string tmpfile = HttpProtocol::RecordRequest(transport); // main body hphp_session_init(); bool ret = false; try { ret = executePHPRequest(transport, reqURI, sourceRootInfo, cachableDynamicContent); } catch (...) { Logger::Error("Unhandled exception in HPHP server engine."); } GetAccessLog().log(transport); hphp_session_exit(); HttpProtocol::ClearRecord(ret, tmpfile); }
void HttpRequestHandler::handleRequest(Transport *transport) { ExecutionProfiler ep(ThreadInfo::RuntimeFunctions); Logger::OnNewRequest(); GetAccessLog().onNewRequest(); transport->enableCompression(); ServerStatsHelper ssh("all", true); Logger::Verbose("receiving %s", transport->getCommand().c_str()); // will clear all extra logging when this function goes out of scope StackTraceNoHeap::ExtraLoggingClearer clearer; StackTraceNoHeap::AddExtraLogging("URL", transport->getUrl()); // resolve virtual host const VirtualHost *vhost = HttpProtocol::GetVirtualHost(transport); ASSERT(vhost); if (vhost->disabled() || vhost->isBlocking(transport->getCommand(), transport->getRemoteHost())) { transport->sendString("Not Found", 404); return; } ServerStats::StartRequest(transport->getCommand().c_str(), transport->getRemoteHost(), vhost->getName().c_str()); // resolve source root string host = transport->getHeader("Host"); SourceRootInfo sourceRootInfo(host.c_str()); if (sourceRootInfo.error()) { sourceRootInfo.handleError(transport); return; } // request URI string pathTranslation = m_pathTranslation ? vhost->getPathTranslation().c_str() : ""; RequestURI reqURI(vhost, transport, sourceRootInfo.path(), pathTranslation); if (reqURI.done()) { return; // already handled with redirection or 404 } string path = reqURI.path().data(); string absPath = reqURI.absolutePath().data(); // determine whether we should compress response bool compressed = transport->decideCompression(); const char *data; int len; size_t pos = path.rfind('.'); const char *ext = (pos != string::npos) && path.find('/', pos) == string::npos // no extention in ./foo or ../bar ? (path.c_str() + pos + 1) : NULL; bool cachableDynamicContent = (!RuntimeOption::StaticFileGenerators.empty() && RuntimeOption::StaticFileGenerators.find(path) != RuntimeOption::StaticFileGenerators.end()); // If this is not a php file, check the static and dynamic content caches if (ext && strcasecmp(ext, "php") != 0) { if (RuntimeOption::EnableStaticContentCache) { bool original = compressed; // check against static content cache if (StaticContentCache::TheCache.find(path, data, len, compressed)) { struct stat st; st.st_mtime = 0; String str; // (qigao) not calling stat at this point because the timestamp of // local cache file is not valuable, maybe misleading. This way // the Last-Modified header will not show in response. // stat(RuntimeOption::FileCache.c_str(), &st); if (!original && compressed) { data = gzdecode(data, len); if (data == NULL) { throw FatalErrorException("cannot unzip compressed data"); } compressed = false; str = NEW(StringData)(data, len, AttachString); } sendStaticContent(transport, data, len, st.st_mtime, compressed, path); StaticContentCache::TheFileCache->adviseOutMemory(); ServerStats::LogPage(path, 200); return; } } if (RuntimeOption::EnableStaticContentFromDisk) { String translated = File::TranslatePath(String(absPath)); if (!translated.empty()) { StringBuffer sb(translated.data()); if (sb.valid()) { struct stat st; st.st_mtime = 0; stat(translated.data(), &st); sendStaticContent(transport, sb.data(), sb.size(), st.st_mtime, false, path); ServerStats::LogPage(path, 200); return; } } } // check static contents that were generated by dynamic pages if (cachableDynamicContent) { // check against dynamic content cache ASSERT(transport->getUrl()); string key = path + transport->getUrl(); if (DynamicContentCache::TheCache.find(key, data, len, compressed)) { sendStaticContent(transport, data, len, 0, compressed, path); ServerStats::LogPage(path, 200); return; } } } // proxy any URLs that not specified in ServeURLs if (!RuntimeOption::ProxyOrigin.empty() && ((RuntimeOption::UseServeURLs && RuntimeOption::ServeURLs.find(path) == RuntimeOption::ServeURLs.end()) || (RuntimeOption::UseProxyURLs && (RuntimeOption::ProxyURLs.find(path) != RuntimeOption::ProxyURLs.end() || MatchAnyPattern(path, RuntimeOption::ProxyPatterns) || (abs(rand()) % 100) < RuntimeOption::ProxyPercentage)))) { for (int i = 0; i < RuntimeOption::ProxyRetry; i++) { bool force = (i == RuntimeOption::ProxyRetry - 1); // last one if (handleProxyRequest(transport, force)) break; } return; } // record request for debugging purpose std::string tmpfile = HttpProtocol::RecordRequest(transport); // main body hphp_session_init(); vhost->setRequestTimeoutSeconds(); bool ret = false; try { ret = executePHPRequest(transport, reqURI, sourceRootInfo, cachableDynamicContent); } catch (const Eval::DebuggerException &e) { transport->sendString(e.what(), 200); transport->onSendEnd(); hphp_context_exit(g_context.getNoCheck(), true, true, transport->getUrl()); } catch (...) { Logger::Error("Unhandled exception in HPHP server engine."); } GetAccessLog().log(transport, vhost); hphp_session_exit(); HttpProtocol::ClearRecord(ret, tmpfile); }
void AdminRequestHandler::handleRequest(Transport *transport) { GetAccessLog().onNewRequest(); transport->addHeader("Content-Type", "text/plain"); string cmd = transport->getCommand(); do { if (cmd == "" || cmd == "help") { string usage = "/stop: stop the web server\n" "/translate: translate hex encoded stacktrace in 'stack' param\n" " stack required, stack trace to translate\n" " build-id optional, if specified, build ID has to match\n" " bare optional, whether to display frame ordinates\n" "/build-id: returns build id that's passed in from command line" "\n" "/compiler-id: returns the compiler id that built this app\n" "/repo-schema: return the repo schema id used by this app\n" "/check-load: how many threads are actively handling requests\n" "/check-queued: how many http requests are queued waiting to be\n" " handled\n" "/check-health: return json containing basic load/usage stats\n" "/check-ev: how many http requests are active by libevent\n" "/check-pl-load: how many pagelet threads are actively handling\n" " requests\n" "/check-pl-queued: how many pagelet requests are queued waiting to\n" " be handled\n" "/check-mem: report memory quick statistics in log file\n" "/check-sql: report SQL table statistics\n" "/status.xml: show server status in XML\n" "/status.json: show server status in JSON\n" "/status.html: show server status in HTML\n" "/stats-on: main switch: enable server stats\n" "/stats-off: main switch: disable server stats\n" "/stats-clear: clear all server stats\n" "/stats-web: turn on/off server page stats (CPU and gen time)\n" "/stats-mem: turn on/off memory statistics\n" "/stats-apc: turn on/off APC statistics\n" "/stats-apc-key: turn on/off APC key statistics\n" "/stats-mcc: turn on/off memcache statistics\n" "/stats-sql: turn on/off SQL statistics\n" "/stats-mutex: turn on/off mutex statistics\n" " sampling optional, default 1000\n" "/stats.keys: list all available keys\n" " from optional, <timestamp>, or <-n> second ago\n" " to optional, <timestamp>, or <-n> second ago\n" "/stats.xml: show server stats in XML\n" " from optional, <timestamp>, or <-n> second ago\n" " to optional, <timestamp>, or <-n> second ago\n" " agg optional, aggragation: *, url, code\n" " keys optional, <key>,<key/hit>,<key/sec>,<:regex:>\n" " url optional, only stats of this page or URL\n" " code optional, only stats of pages returning this code\n" "/stats.json: show server stats in JSON\n" " (same as /stats.xml)\n" "/stats.kvp: show server stats in key-value pairs\n" " (same as /stats.xml)\n" "/stats.html: show server stats in HTML\n" " (same as /stats.xml)\n" "/apc-ss: get apc size stats\n" "/apc-ss-flat: get apc size stats in flat format\n" "/apc-ss-keys: get apc size break-down on keys\n" "/apc-ss-dump: dump the size info on each key to /tmp/APC_details\n" " only valid when EnableAPCSizeDetail is true\n" " keysample optional, only dump keys that belongs to the same\n" " group as <keysample>\n" "/const-ss: get const_map_size\n" "/static-strings: get number of static strings\n" "/dump-apc: dump all current value in APC to /tmp/apc_dump\n" "/dump-const: dump all constant value in constant map to\n" " /tmp/const_map_dump\n" "/dump-file-repo: dump file repository to /tmp/file_repo_dump\n" "/pcre-cache-size: get pcre cache map size\n" #ifdef GOOGLE_CPU_PROFILER "/prof-cpu-on: turn on CPU profiler\n" "/prof-cpu-off: turn off CPU profiler\n" #endif #ifdef GOOGLE_HEAP_PROFILER "/prof-heap-on: turn on heap profiler\n" "/prof-heap-dump: take one snapshot of the heap\n" "/prof-heap-off: turn off heap profiler\n" "/stats-malloc: turn on/off malloc statistics\n" "/leak-on: start leak detection\n" " sampling required, frequency\n" "/leak-off: end leak detection and report leaking\n" " cutoff optional, default 20 seconds, ignore newer allocs\n" #endif #ifdef EXECUTION_PROFILER "/prof-exe: returns sampled execution profile\n" #endif "/vm-tcspace: show space used by translator caches\n" "/vm-dump-tc: dump translation cache to /tmp/tc_dump_a and\n" " /tmp/tc_dump_astub\n" "/vm-tcreset: throw away translations and start over\n" "/vm-namedentities:show size of the NamedEntityTable\n" ; #ifdef USE_TCMALLOC if (MallocExtensionInstance) { usage.append( "/free-mem: ask tcmalloc to release memory to system\n" "/tcmalloc-stats: get internal tcmalloc stats\n" "/tcmalloc-set-tc: set max mem tcmalloc thread-cache can use\n" ); } #endif #ifdef USE_JEMALLOC if (mallctl) { usage.append( "/jemalloc-stats: get internal jemalloc stats\n" "/jemalloc-stats-print:\n" " get comprehensive jemalloc stats in\n" " human-readable form\n" "/jemalloc-prof-activate:\n" " activate heap profiling\n" "/jemalloc-prof-deactivate:\n" " deactivate heap profiling\n" "/jemalloc-prof-dump:\n" " dump heap profile\n" " file optional, filesystem path\n" ); } #endif transport->sendString(usage); break; } if (!RuntimeOption::AdminPasswords.empty()) { std::set<std::string>::const_iterator iter = RuntimeOption::AdminPasswords.find(transport->getParam("auth")); if (iter == RuntimeOption::AdminPasswords.end()) { transport->sendString("Unauthorized", 401); break; } } else { if (!RuntimeOption::AdminPassword.empty() && RuntimeOption::AdminPassword != transport->getParam("auth")) { transport->sendString("Unauthorized", 401); break; } } if (cmd == "stop") { transport->sendString("OK\n"); Logger::Info("Got admin port stop request from %s", transport->getRemoteHost()); HttpServer::Server->stop(); break; } if (cmd == "build-id") { transport->sendString(RuntimeOption::BuildId, 200); break; } if (cmd == "compiler-id") { transport->sendString(kCompilerId, 200); break; } if (cmd == "repo-schema") { transport->sendString(kRepoSchemaId, 200); break; } if (cmd == "translate") { string buildId = transport->getParam("build-id"); if (!buildId.empty() && buildId != RuntimeOption::BuildId) { transport->sendString("Build ID doesn't match.", 500); break; } string translated = translate_stack(transport->getParam("stack").c_str(), transport->getParam("bare").empty()); transport->sendString(translated); break; } if (strncmp(cmd.c_str(), "check", 5) == 0 && handleCheckRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "status", 6) == 0 && handleStatusRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "stats", 5) == 0 && handleStatsRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "prof", 4) == 0 && handleProfileRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "leak", 4) == 0 && handleLeakRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "apc-ss", 6) == 0 && handleAPCSizeRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "dump", 4) == 0 && handleDumpCacheRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "const-ss", 8) == 0 && handleConstSizeRequest(cmd, transport)) { break; } if (strcmp(cmd.c_str(), "static-strings") == 0 && handleStaticStringsRequest(cmd, transport)) { break; } if (strncmp(cmd.c_str(), "vm-", 3) == 0 && handleVMRequest(cmd, transport)) { break; } if (cmd == "pcre-cache-size") { std::ostringstream size; size << preg_pcre_cache_size() << endl; transport->sendString(size.str()); break; } #ifdef USE_TCMALLOC if (MallocExtensionInstance) { if (cmd == "free-mem") { MallocExtensionInstance()->ReleaseFreeMemory(); transport->sendString("OK\n"); break; } if (cmd == "tcmalloc-stats") { std::ostringstream stats; size_t user_allocated, heap_size, slack_bytes; size_t pageheap_free, pageheap_unmapped; size_t tc_max, tc_allocated; MallocExtensionInstance()-> GetNumericProperty("generic.current_allocated_bytes", &user_allocated); MallocExtensionInstance()-> GetNumericProperty("generic.heap_size", &heap_size); MallocExtensionInstance()-> GetNumericProperty("tcmalloc.slack_bytes", &slack_bytes); MallocExtensionInstance()-> GetNumericProperty("tcmalloc.pageheap_free_bytes", &pageheap_free); MallocExtensionInstance()-> GetNumericProperty("tcmalloc.pageheap_unmapped_bytes", &pageheap_unmapped); MallocExtensionInstance()-> GetNumericProperty("tcmalloc.max_total_thread_cache_bytes", &tc_max); MallocExtensionInstance()-> GetNumericProperty("tcmalloc.current_total_thread_cache_bytes", &tc_allocated); stats << "<tcmalloc-stats>" << endl; stats << " <user_allocated>" << user_allocated << "</user_allocated>" << endl; stats << " <heap_size>" << heap_size << "</heap_size>" << endl; stats << " <slack_bytes>" << slack_bytes << "</slack_bytes>" << endl; stats << " <pageheap_free>" << pageheap_free << "</pageheap_free>" << endl; stats << " <pageheap_unmapped>" << pageheap_unmapped << "</pageheap_unmapped>" << endl; stats << " <thread_cache_max>" << tc_max << "</thread_cache_max>" << endl; stats << " <thread_cache_allocated>" << tc_allocated << "</thread_cache_allocated>" << endl; stats << "</tcmalloc-stats>" << endl; transport->sendString(stats.str()); break; } if (cmd == "tcmalloc-set-tc") { size_t tc_max; MallocExtensionInstance()-> GetNumericProperty("tcmalloc.max_total_thread_cache_bytes", &tc_max); size_t tcache = transport->getInt64Param("s"); bool retval = MallocExtensionInstance()-> SetNumericProperty("tcmalloc.max_total_thread_cache_bytes", tcache); transport->sendString(retval == true ? "OK\n" : "FAILED\n"); break; } } #endif #ifdef USE_JEMALLOC if (mallctl) { if (cmd == "free-mem") { // Purge all dirty unused pages. int err = mallctl("arenas.purge", nullptr, nullptr, nullptr, 0); if (err) { std::ostringstream estr; estr << "Error " << err << " in mallctl(\"arenas.purge\", ...)" << endl; transport->sendString(estr.str()); } else { transport->sendString("OK\n"); } break; } if (cmd == "jemalloc-stats") { // Force jemalloc to update stats cached for use by mallctl(). uint64_t epoch = 1; mallctl("epoch", nullptr, nullptr, &epoch, sizeof(epoch)); size_t allocated = 0; // Initialize in case stats aren't enabled. size_t sz = sizeof(size_t); mallctl("stats.allocated", &allocated, &sz, nullptr, 0); size_t active = 0; mallctl("stats.active", &active, &sz, nullptr, 0); size_t mapped = 0; mallctl("stats.mapped", &mapped, &sz, nullptr, 0); std::ostringstream stats; stats << "<jemalloc-stats>" << endl; stats << " <allocated>" << allocated << "</allocated>" << endl; stats << " <active>" << active << "</active>" << endl; stats << " <mapped>" << mapped << "</mapped>" << endl; stats << "</jemalloc-stats>" << endl; transport->sendString(stats.str()); break; } if (cmd == "jemalloc-stats-print") { malloc_write mwo; malloc_write_init(&mwo); malloc_stats_print(malloc_write_cb, (void *)&mwo, ""); if (mwo.oom) { malloc_write_fini(&mwo); transport->sendString("OOM\n"); break; } transport->sendString(mwo.s); malloc_write_fini(&mwo); break; } if (cmd == "jemalloc-prof-activate") { bool active = true; int err = mallctl("prof.active", nullptr, nullptr, &active, sizeof(bool)); if (err) { std::ostringstream estr; estr << "Error " << err << " in mallctl(\"prof.active\", ...)" << endl; transport->sendString(estr.str()); } else { transport->sendString("OK\n"); } break; } if (cmd == "jemalloc-prof-deactivate") { bool active = false; int err = mallctl("prof.active", nullptr, nullptr, &active, sizeof(bool)); if (err) { std::ostringstream estr; estr << "Error " << err << " in mallctl(\"prof.active\", ...)" << endl; transport->sendString(estr.str()); } else { transport->sendString("OK\n"); } break; } if (cmd == "jemalloc-prof-dump") { string f = transport->getParam("file"); if (f != "") { const char *s = f.c_str(); int err = mallctl("prof.dump", nullptr, nullptr, (void *)&s, sizeof(char *)); if (err) { std::ostringstream estr; estr << "Error " << err << " in mallctl(\"prof.dump\", ..., \"" << f << "\", ...)" << endl; transport->sendString(estr.str()); break; } } else { int err = mallctl("prof.dump", nullptr, nullptr, nullptr, 0); if (err) { std::ostringstream estr; estr << "Error " << err << " in mallctl(\"prof.dump\", ...)" << endl; transport->sendString(estr.str()); break; } } transport->sendString("OK\n"); break; } } #endif transport->sendString("Unknown command: " + cmd + "\n", 404); } while (0); GetAccessLog().log(transport, nullptr); }