void ListenHTTP::onSchedule()

in extensions/civetweb/processors/ListenHTTP.cpp [41:171]


void ListenHTTP::onSchedule(core::ProcessContext *context, core::ProcessSessionFactory* /*sessionFactory*/) {
  std::string basePath;

  if (!context->getProperty(BasePath, basePath)) {
    static_assert(BasePath.default_value);
    logger_->log_info("%s attribute is missing, so default value of %s will be used", std::string(BasePath.name), std::string(*BasePath.default_value));
    basePath = *BasePath.default_value;
  }

  basePath.insert(0, "/");

  if (!context->getProperty(Port, listeningPort)) {
    logger_->log_error("%s attribute is missing or invalid", std::string(Port.name));
    return;
  }

  bool randomPort = listeningPort == "0";

  std::string authDNPattern;
  if (context->getProperty(AuthorizedDNPattern, authDNPattern) && !authDNPattern.empty()) {
    logger_->log_debug("ListenHTTP using %s: %s", std::string(AuthorizedDNPattern.name), authDNPattern);
  } else {
    authDNPattern = ".*";
    logger_->log_debug("Authorized DN Pattern not set or invalid, using default '%s' pattern", authDNPattern);
  }

  std::string sslCertFile;

  if (context->getProperty(SSLCertificate, sslCertFile) && !sslCertFile.empty()) {
    logger_->log_debug("ListenHTTP using %s: %s", std::string(SSLCertificate.name), sslCertFile);
  }

  // Read further TLS/SSL options only if TLS/SSL usage is implied by virtue of certificate value being set
  std::string sslCertAuthorityFile;
  std::string sslVerifyPeer;
  std::string sslMinVer;

  if (!sslCertFile.empty()) {
    if (context->getProperty(SSLCertificateAuthority, sslCertAuthorityFile) && !sslCertAuthorityFile.empty()) {
      logger_->log_debug("ListenHTTP using %s: %s", std::string(SSLCertificateAuthority.name), sslCertAuthorityFile);
    }

    if (context->getProperty(SSLVerifyPeer, sslVerifyPeer)) {
      if (sslVerifyPeer.empty() || sslVerifyPeer == "no") {
        logger_->log_debug("ListenHTTP will not verify peers");
      } else {
        logger_->log_debug("ListenHTTP will verify peers");
      }
    } else {
      logger_->log_debug("ListenHTTP will not verify peers");
    }

    if (context->getProperty(SSLMinimumVersion, sslMinVer)) {
      logger_->log_debug("ListenHTTP using %s: %s", std::string(SSLMinimumVersion.name), sslMinVer);
    }
  }

  std::string headersAsAttributesPattern;

  if (context->getProperty(HeadersAsAttributesRegex, headersAsAttributesPattern) && !headersAsAttributesPattern.empty()) {
    logger_->log_debug("ListenHTTP using %s: %s", std::string(HeadersAsAttributesRegex.name), headersAsAttributesPattern);
  }

  auto numThreads = getMaxConcurrentTasks();

  logger_->log_info("ListenHTTP starting HTTP server on port %s and path %s with %d threads", randomPort ? "random" : listeningPort, basePath, numThreads);

  // Initialize web server
  std::vector<std::string> options;
  options.emplace_back("enable_keep_alive");
  options.emplace_back("yes");
  options.emplace_back("keep_alive_timeout_ms");
  options.emplace_back("15000");
  options.emplace_back("num_threads");
  options.emplace_back(std::to_string(numThreads));

  if (sslCertFile.empty()) {
    options.emplace_back("listening_ports");
    options.emplace_back(listeningPort);
  } else {
    listeningPort += "s";
    options.emplace_back("listening_ports");
    options.emplace_back(listeningPort);

    options.emplace_back("ssl_certificate");
    options.emplace_back(sslCertFile);

    if (!sslCertAuthorityFile.empty()) {
      options.emplace_back("ssl_ca_file");
      options.emplace_back(sslCertAuthorityFile);
    }

    if (sslVerifyPeer.empty() || sslVerifyPeer == "no") {
      options.emplace_back("ssl_verify_peer");
      options.emplace_back("no");
    } else {
      options.emplace_back("ssl_verify_peer");
      options.emplace_back("yes");
    }

    if (sslMinVer == "TLS1.2") {
      options.emplace_back("ssl_protocol_version");
      options.emplace_back(std::to_string(4));
    } else {
      throw minifi::Exception(ExceptionType::PROCESSOR_EXCEPTION, "Invalid SSL Minimum Version specified!");
    }
  }

  server_ = std::make_unique<CivetServer>(options, &callbacks_, &logger_);

  context->getProperty(BatchSize, batch_size_);
  logger_->log_debug("ListenHTTP using %s: %zu", std::string(BatchSize.name), batch_size_);

  handler_ = std::make_unique<Handler>(basePath, context, std::move(authDNPattern),
    headersAsAttributesPattern.empty() ? std::nullopt : std::make_optional<utils::Regex>(headersAsAttributesPattern));
  server_->addHandler(basePath, handler_.get());

  if (randomPort) {
    const auto& vec = server_->getListeningPorts();
    if (vec.size() != 1) {
      logger_->log_error("Random port is set, but there is no listening port! Server most probably failed to start!");
    } else {
      bool is_secure = isSecure();
      listeningPort = std::to_string(vec[0]);
      if (is_secure) {
        listeningPort += "s";
      }
      logger_->log_info("Listening on port %s", listeningPort);
    }
  }
}