RPCRequestHandler::RPCRequestHandler() : m_count(0), m_reset(false) {
  hphp_session_init();
  m_context = hphp_context_init();
  m_created = time(0);

  Logger::ResetRequestCount();
  Logger::Info("creating new RPC request handler");
}
RPCRequestHandler::RPCRequestHandler(bool info /* = true */)
  : m_count(0), m_reset(false),
  m_returnEncodeType(Json) {
  hphp_session_init();
  m_context = hphp_context_init();
  m_created = time(0);

  Logger::ResetRequestCount();
  if (info) {
    Logger::Info("creating new RPC request handler");
  }
}
Beispiel #3
0
void preloadRepo() {
  auto& repo = Repo::get();
  auto units = repo.enumerateUnits(RepoIdLocal, true, false);
  if (units.size() == 0) {
    units = repo.enumerateUnits(RepoIdCentral, true, false);
  }
  if (!units.size()) return;

  std::vector<std::thread> workers;
  auto numWorkers = Process::GetCPUCount();
  // Compute a batch size that causes each thread to process approximately 16
  // batches.  Even if the batches are somewhat imbalanced in what they contain,
  // the straggler workers are very unlikey to take more than 10% longer than
  // the first worker to finish.
  size_t batchSize{std::max(units.size() / numWorkers / 16, size_t(1))};
  std::atomic<size_t> index{0};
  for (auto worker = 0; worker < numWorkers; ++worker) {
    workers.push_back(std::thread([&] {
      hphp_session_init();
      hphp_context_init();

      while (true) {
        auto begin = index.fetch_add(batchSize);
        auto end = std::min(begin + batchSize, units.size());
        if (begin >= end) break;
        auto unitCount = end - begin;
        for (auto i = size_t{0}; i < unitCount; ++i) {
          auto& kv = units[begin + i];
          try {
            lookupUnit(String(RuntimeOption::SourceRoot + kv.first).get(),
                       "", nullptr);
          } catch (...) {
            // swallow errors silently
          }
        }
      }

      hphp_context_exit();
      hphp_session_exit();
      hphp_thread_exit();

    }));
  }
  for (auto& worker : workers) {
    worker.join();
  }
}
RPCRequestHandler::RPCRequestHandler(bool info /* = true */)
  : m_count(0), m_reset(false),
  m_returnEncodeType(Json) {
  hphp_session_init();
  bool isServer = RuntimeOption::serverExecutionMode();
  if (isServer) {
    m_context = hphp_context_init();
  } else {
    // In command line mode, we want the xbox workers to
    // output to STDOUT
    m_context = g_context.getNoCheck();
    m_context->obSetImplicitFlush(true);
  }
  m_created = time(0);

  Logger::ResetRequestCount();
  if (info) {
    Logger::Info("creating new RPC request handler");
  }
}
void RPCRequestHandler::initState() {
  hphp_session_init();
  bool isServer = RuntimeOption::ServerExecutionMode();
  if (isServer) {
    m_context = hphp_context_init();
  } else {
    // In command line mode, we want the xbox workers to
    // output to STDOUT
    m_context = g_context.getNoCheck();
    m_context->obSetImplicitFlush(true);
  }
  m_lastReset = time(0);

  Logger::ResetRequestCount();
  if (m_logResets) {
    Logger::Info("initializing RPC request handler");
  }

  m_reset = false;
  m_requestsSinceReset = 0;
}
bool HttpRequestHandler::executePHPRequest(Transport *transport,
                                           RequestURI &reqURI,
                                           SourceRootInfo &sourceRootInfo,
                                           bool cachableDynamicContent) {
  ExecutionContext *context = hphp_context_init();
  if (RuntimeOption::ImplicitFlush) {
    context->obSetImplicitFlush(true);
  }
  if (RuntimeOption::EnableOutputBuffering) {
    if (RuntimeOption::OutputHandler.empty()) {
      context->obStart();
    } else {
      context->obStart(String(RuntimeOption::OutputHandler));
    }
  }
  context->setTransport(transport);

  string file = reqURI.absolutePath().c_str();
  {
    ServerStatsHelper ssh("input");
    HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo);

    if (RuntimeOption::EnableDebugger) {
      Eval::DSandboxInfo sInfo = sourceRootInfo.getSandboxInfo();
      Eval::Debugger::RegisterSandbox(sInfo);
      context->setSandboxId(sInfo.id());
    }
    reqURI.clear();
    sourceRootInfo.clear();
  }

  int code;
  bool ret = true;

  if (RuntimeOption::EnableDebugger) {
    Eval::Debugger::InterruptRequestStarted(transport->getUrl());
  }

  bool error = false;
  std::string errorMsg = "Internal Server Error";
  ret = hphp_invoke(context, file, false, Array(), uninit_null(),
                    RuntimeOption::RequestInitFunction,
                    RuntimeOption::RequestInitDocument,
                    error, errorMsg);

  if (ret) {
    String content = context->obDetachContents();
    if (cachableDynamicContent && !content.empty()) {
      assert(transport->getUrl());
      string key = file + transport->getUrl();
      DynamicContentCache::TheCache.store(key, content.data(),
                                          content.size());
    }
    transport->sendRaw((void*)content.data(), content.size());
    code = transport->getResponseCode();
  } else if (error) {
    code = 500;

    string errorPage = context->getErrorPage().data();
    if (errorPage.empty()) {
      errorPage = RuntimeOption::ErrorDocument500;
    }
    if (!errorPage.empty()) {
      context->obProtect(false);
      context->obEndAll();
      context->obStart();
      context->obProtect(true);
      ret = hphp_invoke(context, errorPage, false, Array(), uninit_null(),
                        RuntimeOption::RequestInitFunction,
                        RuntimeOption::RequestInitDocument,
                        error, errorMsg);
      if (ret) {
        String content = context->obDetachContents();
        transport->sendRaw((void*)content.data(), content.size());
        code = transport->getResponseCode();
      } else {
        Logger::Error("Unable to invoke error page %s", errorPage.c_str());
        errorPage.clear(); // so we fall back to 500 return
      }
    }
    if (errorPage.empty()) {
      if (RuntimeOption::ServerErrorMessage) {
        transport->sendString(errorMsg, 500, false, false, "hphp_invoke");
      } else {
        transport->sendString(RuntimeOption::FatalErrorMessage,
                              500, false, false, "hphp_invoke");
      }
    }
  } else {
    code = 404;
    transport->sendString("Not Found", 404);
  }

  if (RuntimeOption::EnableDebugger) {
    Eval::Debugger::InterruptRequestEnded(transport->getUrl());
  }

  transport->onSendEnd();
  hphp_context_exit(context, true, true, transport->getUrl());
  ServerStats::LogPage(file, code);
  return ret;
}
Beispiel #7
0
void OptWorker<Pre>::onThreadEnter() {
  hphp_session_init();
  hphp_context_init();
}
bool HttpRequestHandler::executePHPRequest(Transport *transport,
                                           RequestURI &reqURI,
                                           SourceRootInfo &sourceRootInfo,
                                           bool cachableDynamicContent) {
  ExecutionContext *context = hphp_context_init();
  context->setTransport(transport);

  string file = reqURI.absolutePath().c_str();
  {
    ServerStatsHelper ssh("input");
    HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo);
    reqURI.clear();
    sourceRootInfo.clear();
  }

  bool error = false;
  std::string errorMsg = "Internal Server Error";
  bool ret = hphp_invoke(context, file, false, Array(), null,
                         RuntimeOption::WarmupDocument,
                         RuntimeOption::RequestInitFunction,
                         error, errorMsg);

  int code;
  if (ret) {
    std::string content = context->getContents();
    if (cachableDynamicContent && !content.empty()) {
      ASSERT(transport->getUrl());
      string key = file + transport->getUrl();
      DynamicContentCache::TheCache.store(key, content.data(), content.size());
    }
    code = 200;
    transport->sendRaw((void*)content.data(), content.size());
  } else if (error) {
    code = 500;

    string errorPage = context->getErrorPage();
    if (errorPage.empty()) {
      errorPage = RuntimeOption::ErrorDocument500;
    }
    if (!errorPage.empty()) {
      context->obEndAll();
      context->obStart();
      context->obProtect(true);
      ret = hphp_invoke(context, errorPage, false, Array(), null,
                        RuntimeOption::WarmupDocument,
                        RuntimeOption::RequestInitFunction,
                        error, errorMsg);
      if (ret) {
        std::string content = context->getContents();
        transport->sendRaw((void*)content.data(), content.size());
      } else {
        errorPage.clear(); // so we fall back to 500 return
      }
    }
    if (errorPage.empty()) {
      if (RuntimeOption::ServerErrorMessage) {
        transport->sendString(errorMsg, 500);
      } else {
        transport->sendString(RuntimeOption::FatalErrorMessage, 500);
      }
    }
  } else {
    code = 404;
    transport->sendString("Not Found", 404);
  }
  transport->onSendEnd();
  ServerStats::LogPage(file, code);
  hphp_context_exit(context, true);
  return ret;
}
bool HttpRequestHandler::executePHPRequest(Transport *transport,
                                           RequestURI &reqURI,
                                           SourceRootInfo &sourceRootInfo,
                                           bool cachableDynamicContent) {
  ExecutionContext *context = hphp_context_init();
  if (RuntimeOption::ImplicitFlush) {
    context->obSetImplicitFlush(true);
  }
  if (RuntimeOption::EnableOutputBuffering) {
    if (RuntimeOption::OutputHandler.empty()) {
      context->obStart();
    } else {
      context->obStart(String(RuntimeOption::OutputHandler));
    }
  }
  context->setTransport(transport);

  string file = reqURI.absolutePath().c_str();
  {
    ServerStatsHelper ssh("input");
    HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo);
    reqURI.clear();
    sourceRootInfo.clear();
  }

  int code;
  bool ret = true;
  if (!RuntimeOption::ForbiddenFileExtensions.empty()) {
    size_t pos = file.rfind('.');
    if (pos != string::npos) {
      const char *ext = file.c_str() + pos + 1;
      if (RuntimeOption::ForbiddenFileExtensions.find(ext) !=
          RuntimeOption::ForbiddenFileExtensions.end()) {
        code = 403;
        transport->sendString("Forbidden", 403);
        ret = false;
      }
    }
  }

  if (ret) {
    if (RuntimeOption::EnableDebugger) {
      Eval::Debugger::InterruptRequestStarted(transport->getUrl());
    }

    bool error = false;
    std::string errorMsg = "Internal Server Error";
    ret = hphp_invoke(context, file, false, Array(), null,
                      RuntimeOption::WarmupDocument,
                      RuntimeOption::RequestInitFunction,
                      RuntimeOption::RequestInitDocument,
                      error, errorMsg);

    if (ret) {
      String content = context->obDetachContents();
      if (cachableDynamicContent && !content.empty()) {
        ASSERT(transport->getUrl());
        string key = file + transport->getUrl();
        DynamicContentCache::TheCache.store(key, content.data(),
                                            content.size());
      }
      code = 200;
      transport->sendRaw((void*)content.data(), content.size(), code);
    } else if (error) {
      code = 500;

      string errorPage = context->getErrorPage().data();
      if (errorPage.empty()) {
        errorPage = RuntimeOption::ErrorDocument500;
      }
      if (!errorPage.empty()) {
        context->obProtect(false);
        context->obEndAll();
        context->obStart();
        context->obProtect(true);
        ret = hphp_invoke(context, errorPage, false, Array(), null,
                          RuntimeOption::WarmupDocument,
                          RuntimeOption::RequestInitFunction,
                          RuntimeOption::RequestInitDocument,
                          error, errorMsg);
        if (ret) {
          String content = context->obDetachContents();
          transport->sendRaw((void*)content.data(), content.size());
        } else {
          errorPage.clear(); // so we fall back to 500 return
        }
      }
      if (errorPage.empty()) {
        if (RuntimeOption::ServerErrorMessage) {
          transport->sendString(errorMsg, 500, false, false, "hphp_invoke");
        } else {
          transport->sendString(RuntimeOption::FatalErrorMessage,
                                500, false, false, "hphp_invoke");
        }
      }
    } else {
      code = 404;
      transport->sendString("Not Found", 404);
    }

    if (RuntimeOption::EnableDebugger) {
      Eval::Debugger::InterruptRequestEnded(transport->getUrl());
    }
  }

  transport->onSendEnd();
  ServerStats::LogPage(file, code);
  hphp_context_exit(context, true, true, transport->getUrl());
  return ret;
}
bool RPCRequestHandler::executePHPFunction(Transport *transport,
                                           SourceRootInfo &sourceRootInfo) {
  ExecutionContext *context = hphp_context_init();

  // reset timeout counter
  ThreadInfo::s_threadInfo->m_reqInjectionData.started = time(0);

  std::string rpcFunc = transport->getCommand();
  {
    ServerStatsHelper ssh("input");
    RequestURI reqURI(rpcFunc);
    HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo);
    sourceRootInfo.clear();
  }

  bool error = false;

  Array params;
  std::string sparams = transport->getParam("params");
  if (!sparams.empty()) {
    Variant jparams = f_json_decode(String(sparams), true);
    if (jparams.isArray()) {
      params = jparams.toArray();
    } else {
      error = true;
    }
  } else {
    vector<string> sparams;
    transport->getArrayParam("p", sparams);
    if (!sparams.empty()) {
      for (unsigned int i = 0; i < sparams.size(); i++) {
        Variant jparams = f_json_decode(String(sparams[i]), true);
        if (same(jparams, false)) {
          error = true;
          break;
        }
        params.append(jparams);
      }
    } else {
      // single string parameter, used by xbox to avoid any en/decoding
      int size;
      const void *data = transport->getPostData(size);
      if (data && size) {
        params.append(String((char*)data, size, AttachLiteral));
      }
    }
  }

  if (transport->getIntParam("reset") == 1) {
    m_reset = true;
  }
  int output = transport->getIntParam("output");

  int code;
  if (!error) {
    Variant funcRet;
    std::string errorMsg = "Internal Server Error";
    string warmupDoc, reqInitFunc;
    if (m_serverInfo) {
      warmupDoc = m_serverInfo->getWarmupDoc();
      reqInitFunc = m_serverInfo->getReqInitFunc();
    }
    if (warmupDoc.empty()) {
      warmupDoc = RuntimeOption::WarmupDocument;
      reqInitFunc = RuntimeOption::RequestInitFunction;
    }
    warmupDoc = canonicalize_path(warmupDoc, "", 0);
    warmupDoc = get_source_filename(warmupDoc.c_str());
    bool ret = hphp_invoke(context, rpcFunc, true, params, ref(funcRet),
                           warmupDoc, reqInitFunc, error, errorMsg);
    if (ret) {
      String response;
      switch (output) {
      case 0: response = f_json_encode(funcRet);   break;
      case 1: response = context->obGetContents(); break;
      case 2:
        response =
          f_json_encode(CREATE_MAP2("output", context->obGetContents(),
                                    "return", f_json_encode(funcRet)));
        break;
      }
      code = 200;
      transport->sendRaw((void*)response.data(), response.size());
    } else if (error) {
      code = 500;
      transport->sendString(errorMsg, 500);
      m_reset = true;
    } else {
      code = 404;
      transport->sendString("Not Found", 404);
    }
  } else {
    code = 400;
    transport->sendString("Bad Request", 400);
  }
  params.reset();

  transport->onSendEnd();
  ServerStats::LogPage(rpcFunc, code);

  hphp_context_exit(context, true, false);
  return !error;
}
RPCRequestHandler::~RPCRequestHandler() {
  // important to call requestShutdown()
  hphp_context_exit(hphp_context_init(), true);

  hphp_session_exit();
}