コード例 #1
0
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);
}
コード例 #2
0
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);
}