Exemple #1
0
void HeapProfileRequestHandler::handleRequest(Transport *transport) {
  const char *url = transport->getCommand().c_str();
  if (!strcmp(url, "hhprof/start")) {
    // if we can place the request, send a 200
    if (handleStartRequest(transport)) {
      transport->sendString("OK\n", 200);
    } else {
      transport->sendString("Resource Unavailable\n", 503);
    }
  } else if (!strcmp(url, "pprof/cmdline")) {
    // the first thing pprof does when you call the script is find out
    // the name of the binary running on the remote server
    transport->sendString(current_executable_path(), 200);
  } else if (!strcmp(url, "pprof/heap")) {
    // the next thing pprof does is hit this endpoint and get a profile
    // dump
    ProfileController::waitForProfile([&](const ProfileDump& dump) {
      transport->sendString(dump.toPProfFormat(), 200);
    });
  } else if (!strcmp(url, "pprof/symbol")) {
    // lastly, pprof hits this endpoint three times. the first time, it
    // hits with a HEAD request, which gives it some knowledge as to the
    // presence of the endpoint. then it hits with a GET request, and
    // expects the number of defined symbols in response. finally, it
    // hits with a POST request, with the POST data being a plus-separated
    // list of addresses for which it wants symbols
    if (transport->getMethod() == Transport::Method::HEAD) {
      transport->sendString("OK\n", 200);
    } else if (transport->getMethod() == Transport::Method::GET) {
      // actual number of sumbols is not really relevant
      // from the pprof documentation, pprof only considers values
      // that are either zero or non-zero
      transport->sendString("num_symbols: 1\n", 200);
    } else if (transport->getMethod() == Transport::Method::POST) {
      // split the post data by '+' character and resolve the symbol
      // for each
      int size;
      auto data = static_cast<const char *>(transport->getPostData(size));
      std::string res;

      std::vector<folly::StringPiece> addrs;
      folly::split('+', folly::StringPiece(data, size), addrs);
      for (const auto &addr : addrs) {
        // for each address we get from pprof, it expects a line formatted
        // like the following
        // <address>\t<symbol name>
        if (!addr.size()) {
          continue;
        }
        std::string val(addr.data(), addr.size());
        SrcKey sk = SrcKey::fromAtomicInt(
          static_cast<uint64_t>(std::stoll(val, 0, 16))
        );
        folly::toAppend(addr, "\t", sk.getSymbol(), "\n", &res);
      }
      transport->sendString(res, 200);

      if (RuntimeOption::ClientExecutionMode() &&
          RuntimeOption::HHProfServerProfileClientMode) {
        std::unique_lock<std::mutex> lock(s_clientMutex);
        s_cond = true;
        s_clientWaitq.notify_all();
      }
    }
  } else if (!strcmp(url, "hhprof/stop")) {
    // user has requested cancellation of the current profile dump
    ProfileController::cancelRequest();
    transport->sendString("OK\n", 200);
  } else {
    // the pprof server doesn't understand any other endpoints so just error
    // out
    Logger::Warning(folly::format(
      "Unknown HHProf endpoint requested, command was: {}", url
    ).str());
    transport->sendString("Not Found\n", 404);
  }
}