text:
#pragma once

#include <cstring>
#include <functional>
#include <iostream>
#include <string_view>
#include <sys/stat.h>
#include <sys/types.h>
#if not defined(_WIN32)
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <unistd.h>
#endif

#if __linux__ // the sendfile header does not exists on macos.
#include <sys/sendfile.h>
#endif

#include <unordered_map>

#include <boost/lexical_cast.hpp>

#include <li/http_server/error.hh>
#include <li/http_server/http_top_header_builder.hh>
#include <li/http_server/input_buffer.hh>
#include <li/http_server/output_buffer.hh>
#include <li/http_server/symbols.hh>
#include <li/http_server/tcp_server.hh>
#include <li/http_server/url_unescape.hh>

#include <li/http_server/content_types.hh>

namespace li {

namespace http_async_impl {

static char* date_buf = nullptr;
static int date_buf_size = 0;

using ::li::content_types; // static std::unordered_map<std::string_view, std::string_view>
                           // content_types

static thread_local std::unordered_map<std::string, std::pair<std::string_view, std::string_view>>
    static_files;

#ifndef _WIN32
http_top_header_builder http_top_header [[gnu::weak]];
#else
__declspec(selectany) http_top_header_builder http_top_header;
#endif

template <typename FIBER> struct generic_http_ctx {

  generic_http_ctx(input_buffer& _rb, FIBER& _fiber) : rb(_rb), fiber(_fiber) {
    get_parameters_map.reserve(10);
    response_headers.reserve(20);

    output_stream = output_buffer(50 * 1024, [&](const char* d, int s) { fiber.write(d, s); });

    headers_stream =
        output_buffer(1000, [&](const char* d, int s) { output_stream << std::string_view(d, s); });

    json_stream = output_buffer(
        50 * 1024, [&](const char* d, int s) { output_stream << std::string_view(d, s); });
  }

  generic_http_ctx& operator=(const generic_http_ctx&) = delete;
  generic_http_ctx(const generic_http_ctx&) = delete;

  std::string_view header(const char* key) {
    if (!header_map.size())
      index_headers();
    return header_map[key];
  }

  std::string_view cookie(const char* key) {
    if (!cookie_map.size())
      index_cookies();
    return cookie_map[key];
  }

  std::string_view get_parameter(const char* key) {
    if (!url_.size())
      parse_first_line();
    return get_parameters_map[key];
  }

  // std::string_view post_parameter(const char* key)
  // {
  //   if (!is_body_read_)
  //   {
  //     //read_whole_body();
  //     parse_post_parameters();
  //   }
  //   return post_parameters_map[key];
  // }

  // std::string_view read_body(char* buf, int buf_size)
  // {
  //   // Try to read Content-Length

  //   // if part of the body is in the request buffer
  //   //  return it and mark it as read.
  //   // otherwise call read on the socket.

  //   // handle chunked encoding here if needed.
  // }

  // void sendfile(std::string path)
  // {
  //   char buffer[10200];
  //   //std::cout << uint64_t(output_stream.buffer_) << " " << uint64_t(output_buffer_space) <<
  //   std::endl; output_buffer output_stream(buffer, sizeof(buffer));

  //   struct stat stat_buf;
  //   int read_fd = open (path.c_str(), O_RDONLY);
  //   fstat (read_fd, &stat_buf);

  //   format_top_headers(output_stream);
  //   output_stream << headers_stream.to_string_view();
  //   output_stream << "Content-Length: " << size_t(stat_buf.st_size) << "\r\n\r\n"; //Add body
  //   auto m = output_stream.to_string_view();
  //   write(m.data(), m.size());

  //   off_t offset = 0;
  //   while (true)
  //   {
  //     int ret = ::sendfile(socket_fd, read_fd, &offset, stat_buf.st_size);
  //     if (ret == EAGAIN)
  //       write(nullptr, 0);
  //     else break;
  //   }
  // }

  std::string_view url() {
    if (!url_.size())
      parse_first_line();
    return url_;
  }
  std::string_view method() {
    if (!method_.size())
      parse_first_line();
    return method_;
  }
  std::string_view http_version() {
    if (!url_.size())
      parse_first_line();
    return http_version_;
  }

  inline void format_top_headers(output_buffer& output_stream) {
    if (status_code_ == 200)
      output_stream << http_top_header.top_header_200();
    else
      output_stream << "HTTP/1.1 " << status_ << http_top_header.top_header();
  }

  void prepare_request() {
    // parse_first_line();
    response_headers.clear();
    content_length_ = 0;
    chunked_ = 0;

    for (int i = 1; i < header_lines.size() - 1; i++) {
      const char* line_end = header_lines[i + 1]; // last line is just an empty line.
      const char* cur = header_lines[i];

      if (*cur != 'C' and *cur != 'c')
        continue;

      std::string_view key = split(cur, line_end, ':');

      auto get_value = [&] {
        std::string_view value = split(cur, line_end, '\r');
        while (value[0] == ' ')
          value = std::string_view(value.data() + 1, value.size() - 1);
        return value;
      };

      if (key == "Content-Length")
        content_length_ = atoi(get_value().data());
      else if (key == "Content-Type") {
        content_type_ = get_value();
        chunked_ = (content_type_ == "chunked");
      }
    }
  }

  // void respond(std::string s) {return respond(std::string_view(s)); }

  // void respond(const char* s)
  // {
  //   return respond(std::string_view(s, strlen(s)));
  // }

  void respond(const std::string_view& s) {
    response_written_ = true;
    format_top_headers(output_stream);
    headers_stream.flush();                                             // flushes to output_stream.
    output_stream << "Content-Length: " << s.size() << "\r\n\r\n" << s; // Add body
  }

  template <typename O> void respond_json(const O& obj) {
    response_written_ = true;
    json_stream.reset();
    json_encode(json_stream, obj);

    format_top_headers(output_stream);
    headers_stream.flush(); // flushes to output_stream.
    output_stream << "Content-Length: " << json_stream.to_string_view().size() << "\r\n\r\n";
    json_stream.flush(); // flushes to output_stream.
  }

  template <typename F> void respond_json_generator(int N, F callback) {
    response_written_ = true;
    json_stream.reset();
    json_encode_generator(json_stream, N, callback);

    format_top_headers(output_stream);
    headers_stream.flush(); // flushes to output_stream.
    output_stream << "Content-Length: " << json_stream.to_string_view().size() << "\r\n\r\n";
    json_stream.flush(); // flushes to output_stream.
  }

  void respond_if_needed() {
    if (!response_written_) {
      response_written_ = true;

      format_top_headers(output_stream);
      output_stream << headers_stream.to_string_view();
      output_stream << "Content-Length: 0\r\n\r\n"; // Add body
    }
  }

  void set_header(std::string_view k, std::string_view v) {
    headers_stream << k << ": " << v << "\r\n";
  }

  void set_cookie(std::string_view k, std::string_view v) {
    headers_stream << "Set-Cookie: " << k << '=' << v << "\r\n";
  }

  void set_status(int status) {

    status_code_ = status;
    switch (status) {
    case 200:
      status_ = "200 OK";
      break;
    case 201:
      status_ = "201 Created";
      break;
    case 204:
      status_ = "204 No Content";
      break;
    case 301:
      status_ = "301 Moved Permanently";
      break;
    case 302:
      status_ = "302 Object moved";
      break;
    case 303:
      status_ = "303 See Other";
      break;
    case 304:
      status_ = "304 Not Modified";
      break;
    case 307:
      status_ = "307 Temporary redirect";
      break;
    case 400:
      status_ = "400 Bad Request";
      break;
    case 401:
      status_ = "401 Unauthorized";
      break;
    case 402:
      status_ = "402 Payment Required";
      break;
    case 403:
      status_ = "403 Forbidden";
      break;
    case 404:
      status_ = "404 Not Found";
      break;
    case 405:
      status_ = "405 HTTP verb used to access this page is not allowed (method not allowed)";
      break;
    case 406:
      status_ = "406 Client browser does not accept the MIME type of the requested page";
      break;
    case 409:
      status_ = "409 Conflict";
      break;
    case 500:
      status_ = "500 Internal Server Error";
      break;
    default:
      status_ = "200 OK";
      break;
    }
  }

  // Send a file.
  void send_file(const char* path) {

#ifndef _WIN32 // Linux / Macos version with sendfile

    // Open the file in non blocking mode.
    int fd = open(path, O_RDONLY);
    if (fd == -1)
      throw http_error::not_found("File not found.");

    // Get file size
    size_t file_size = lseek(fd, (size_t)0, SEEK_END);

    // Set content type header.
    size_t ext_pos = std::string_view(path).rfind('.');
    std::string_view content_type("");
    if (ext_pos != std::string::npos) {
      auto type_itr = content_types.find(std::string_view(path).substr(ext_pos + 1).data());
      if (type_itr != content_types.end()) {
        content_type = type_itr->second;
        set_header("Content-Type", content_type);
      }
    }

    // Writing the http headers.
    response_written_ = true;
    format_top_headers(output_stream);
    headers_stream.flush(); // flushes headers to output_stream.
    output_stream << "Content-Length: " << file_size << "\r\n\r\n";
    output_stream.flush();

    off_t offset = 0;
    lseek(fd, (size_t)0, 0);
    while (offset < file_size) {
#if __APPLE__ // sendfile on macos is slightly different...
      off_t nwritten = 0;
      int ret = ::sendfile(fd, socket_fd, offset, &nwritten, nullptr, 0);
      offset += nwritten;
      if (ret == 0 && nwritten == 0) break; // end of file.
#else
      int ret = ::sendfile(socket_fd, fd, &offset, file_size - offset);
#endif
      if (ret != -1) {
        if (offset < file_size) {
          continue; // this->fiber.yield();
        }
      } else if (errno == EAGAIN) {
        this->fiber.yield();
      } else {
        close(fd);
        std::cerr << "Internal error: sendfile failed: " << strerror(errno) << std::endl;
        throw http_error::not_found("Internal error: sendfile failed.");
      }
    }

    close(fd);

#else // Windows impl with basic read write.

    // Open file.
    FILE* fd = fopen(path, "r");
    if (fd == nullptr)
      throw http_error::not_found("File not found.");

    // Get file size.
    DWORD file_size = 0;
    GetFileSize(fd, &file_size);
    // Writing the http headers.
    response_written_ = true;
    format_top_headers(output_stream);
    headers_stream.flush(); // flushes to output_stream.
    output_stream << "Content-Length: " << file_size << "\r\n\r\n"; // Add body
    output_stream.flush();

    // Read the file and write it to the socket.
    size_t nread = 1;
    size_t offset = 0;
    while (nread != 0) {
      char buffer[4096];
      nread = _fread_nolock(buffer, sizeof(buffer), file_size - offset, fd);
      offset += nread;
      this->fiber.write(buffer, nread);
    }
    if (!feof(fd))
      throw http_error::not_found("Internal error: Could not reach the end of file.");

#endif
  }

#if 0
  // Send a static file. Not used anymore, todo if we want beter performances: implement
  // a multiplatform file cache.
  void send_static_file(const char* path, int cache_duration_second) {
    auto it = static_files.find(path);
    if (static_files.end() == it or !it->second.first.size()) {

      int fd = open(path, O_RDONLY);
      if (fd == -1)
        throw http_error::not_found("File not found.");

      int file_size = lseek(fd, (size_t)0, SEEK_END);
      auto content =
          std::string_view((char*)mmap(0, file_size, PROT_READ, MAP_SHARED, fd, 0), file_size);
      if (!content.data())
        throw http_error::not_found("File not found.");
      close(fd);

      size_t ext_pos = std::string_view(path).rfind('.');
      std::string_view content_type("");
      if (ext_pos != std::string::npos) {
        auto type_itr = content_types.find(std::string_view(path).substr(ext_pos + 1).data());
        if (type_itr != content_types.end()) {
          content_type = type_itr->second;
          set_header("Content-Type", content_type);
        }
      }
      static_files.insert({path, {content, content_type}});

      respond(content);
    } else {
      if (it->second.second.size()) {
        set_header("Content-Type", it->second.second);
      }
      respond(it->second.first);
    }
  }
#endif

  void add_header_line(const char* l) { header_lines.push_back(l); }
  const char* last_header_line() { return header_lines.back(); }

  // split a string, starting from cur and ending with split_char.
  // Advance cur to the end of the split.
  std::string_view split(const char*& cur, const char* line_end, char split_char) {

    const char* start = cur;
    while (start < (line_end - 1) and *start == split_char)
      start++;

#if 0
    const char* end = (const char*)memchr(start + 1, split_char, line_end - start - 2);
    if (!end) end = line_end - 1;
#else
    const char* end = start + 1;
    while (end < (line_end - 1) and *end != split_char)
      end++;
#endif
    cur = end + 1;
    if (*end == split_char)
      return std::string_view(start, cur - start - 1);
    else
      return std::string_view(start, cur - start);
  }

  void index_headers() {
    for (int i = 1; i < header_lines.size() - 1; i++) {
      const char* line_end = header_lines[i + 1]; // last line is just an empty line.
      const char* cur = header_lines[i];

      std::string_view key = split(cur, line_end, ':');
      std::string_view value = split(cur, line_end, '\r');
      while (value[0] == ' ')
        value = std::string_view(value.data() + 1, value.size() - 1);
      header_map[key] = value;
      // std::cout << key << " -> " << value << std::endl;
    }
  }

  void index_cookies() {
    std::string_view cookies = header("Cookie");
    if (!cookies.data())
      return;
    const char* line_end = &cookies.back() + 1;
    const char* cur = &cookies.front();
    while (cur < line_end) {

      std::string_view key = split(cur, line_end, '=');
      std::string_view value = split(cur, line_end, ';');
      while (key[0] == ' ')
        key = std::string_view(key.data() + 1, key.size() - 1);
      cookie_map[key] = value;
    }
  }

  template <typename C> void url_decode_parameters(std::string_view content, C kv_callback) {
    const char* c = content.data();
    const char* end = c + content.size();
    if (c < end) {
      while (c < end) {
        std::string_view key = split(c, end, '=');
        std::string_view value = split(c, end, '&');
        kv_callback(key, value);
        // printf("kv: '%.*s' -> '%.*s'\n", key.size(), key.data(), value.size(), value.data());
      }
    }
  }

  void parse_first_line() {
    const char* c = header_lines[0];
    const char* end = header_lines[1];

    method_ = split(c, end, ' ');
    url_ = split(c, end, ' ');
    http_version_ = split(c, end, '\r');

    // url get parameters.
    c = url_.data();
    end = c + url_.size();
    url_ = split(c, end, '?');
    get_parameters_string_ = std::string_view(c, end - c);
  }

  std::string_view get_parameters_string() {
    if (!get_parameters_string_.data())
      parse_first_line();
    return get_parameters_string_;
  }
  template <typename F> void parse_get_parameters(F processor) {
    url_decode_parameters(get_parameters_string(), processor);
  }

  template <typename F> void read_body(F callback) {
    is_body_read_ = true;

    if (!chunked_ and !content_length_)
      body_end_ = body_start.data();
    else if (content_length_) {
      std::string_view res;
      int n_body_read = 0;

      // First return part of the body already in memory.
      int l = std::min(int(body_start.size()), content_length_);
      callback(std::string_view(body_start.data(), l));
      n_body_read += l;

      while (content_length_ > n_body_read) {
        std::string_view part = rb.read_more_str(fiber);
        int l = part.size();
        int bl = std::min(l, content_length_ - n_body_read);
        part = std::string_view(part.data(), bl);
        callback(part);
        rb.free(part);
        body_end_ = part.data();
        n_body_read += part.size();
      }

    } else if (chunked_) {
      // Chunked decoding.
      assert(0);
      // const char* cur = body_start.data();
      // int chunked_size = strtol(rb.read_until(read, cur, '\r').data(), nullptr, 16);
      // cur++; // skip \n
      // while (chunked_size > 0) {
      //   // Read chunk.
      //   std::string_view chunk = rb.read_n(read, cur, chunked_size);
      //   callback(chunk);
      //   rb.free(chunk);
      //   cur += chunked_size + 2; // skip \r\n.

      //   // Read next chunk size.
      //   chunked_size = strtol(rb.read_until(read, cur, '\r').data(), nullptr, 16);
      //   cur++; // skip \n
      // }
      // cur += 2; // skip the terminaison chunk.
      // body_end_ = cur;
      // body_ = std::string_view(body_start.data(), cur - body_start.data());
    }
  }

  std::string_view read_whole_body() {
    if (!chunked_ and !content_length_) {
      is_body_read_ = true;
      body_end_ = body_start.data();
      return std::string_view(); // No body.
    }

    if (content_length_) {
      body_ = rb.read_n(fiber, body_start.data(), content_length_);
      body_end_ = body_.data() + content_length_;
    } else if (chunked_) {
      // Chunked decoding.
      char* out = (char*)body_start.data();
      const char* cur = body_start.data();
      int chunked_size = strtol(rb.read_until(fiber, cur, '\r').data(), nullptr, 16);
      cur++; // skip \n
      while (chunked_size > 0) {
        // Read chunk.
        std::string_view chunk = rb.read_n(fiber, cur, chunked_size);
        cur += chunked_size + 2; // skip \r\n.
        // Copy the body into a contiguous string.
        if (out + chunk.size() > chunk.data()) // use memmove if overlap.
          std::memmove(out, chunk.data(), chunk.size());
        else
          std::memcpy(out, chunk.data(), chunk.size());

        out += chunk.size();

        // Read next chunk size.
        chunked_size = strtol(rb.read_until(fiber, cur, '\r').data(), nullptr, 16);
        cur++; // skip \n
      }
      cur += 2; // skip the terminaison chunk.
      body_end_ = cur;
      body_ = std::string_view(body_start.data(), out - body_start.data());
    }

    is_body_read_ = true;
    return body_;
  }

  void read_multipart_formdata() {}

  template <typename F> void post_iterate(F kv_callback) {
    if (is_body_read_) // already in memory.
      url_decode_parameters(body_, kv_callback);
    else // stream the body.
    {
      std::string_view current_key;

      read_body([](std::string_view part) {
        // read key if needed.
        // if (!current_key.size())
        // call kv callback if some value is available.
      });
    }
  }

  // Read post parameters in the body.
  std::unordered_map<std::string_view, std::string_view> post_parameters() {
    if (content_type_ == "application/x-www-form-urlencoded") {
      if (!is_body_read_)
        read_whole_body();
      url_decode_parameters(body_, [&](auto key, auto value) { post_parameters_map[key] = value; });
      return post_parameters_map;
    } else {
      // fixme: return bad request here.
    }
    return post_parameters_map;
  }

  void prepare_next_request() {
    if (!is_body_read_)
      read_whole_body();

    // std::cout <<"free line0: " << uint64_t(header_lines[0]) << std::endl;
    // std::cout << rb.current_size() << " " << rb.cursor << std::endl;
    rb.free(header_lines[0], body_end_);
    // std::cout << rb.current_size() << " " << rb.cursor << std::endl;
    // rb.cursor = rb.end = 0;
    // assert(rb.cursor == 0);
    headers_stream.reset();
    status_ = "200 OK";
    method_ = std::string_view();
    url_ = std::string_view();
    http_version_ = std::string_view();
    content_type_ = std::string_view();
    header_map.clear();
    cookie_map.clear();
    response_headers.clear();
    get_parameters_map.clear();
    post_parameters_map.clear();
    get_parameters_string_ = std::string_view();
    response_written_ = false;
  }

  void flush_responses() { output_stream.flush(); }

  int socket_fd;
  input_buffer& rb;

  int status_code_ = 200;
  const char* status_ = "200 OK";
  std::string_view method_;
  std::string_view url_;
  std::string_view http_version_;
  std::string_view content_type_;
  bool chunked_;
  int content_length_;
  std::unordered_map<std::string_view, std::string_view> header_map;
  std::unordered_map<std::string_view, std::string_view> cookie_map;
  std::vector<std::pair<std::string_view, std::string_view>> response_headers;
  std::unordered_map<std::string_view, std::string_view> get_parameters_map;
  std::unordered_map<std::string_view, std::string_view> post_parameters_map;
  std::string_view get_parameters_string_;
  // std::vector<std::string> strings_saver;

  bool is_body_read_ = false;
  std::string body_local_buffer_;
  std::string_view body_;
  std::string_view body_start;
  const char* body_end_ = nullptr;
  std::vector<const char*> header_lines;
  FIBER& fiber;

  output_buffer headers_stream;
  bool response_written_ = false;

  output_buffer output_stream;
  output_buffer json_stream;
};
using http_ctx = generic_http_ctx<async_fiber_context>;

template <typename F> auto make_http_processor(F handler) {
  return [handler](auto& fiber) {
    try {
      input_buffer rb;
      bool socket_is_valid = true;

      auto ctx = generic_http_ctx(rb, fiber);
      ctx.socket_fd = fiber.socket_fd;

      while (true) {
        ctx.is_body_read_ = false;
        ctx.header_lines.clear();
        ctx.header_lines.reserve(100);
        // Read until there is a complete header.
        int header_start = rb.cursor;
        int header_end = rb.cursor;
        assert(header_start >= 0);
        assert(header_end >= 0);
        assert(ctx.header_lines.size() == 0);
        ctx.add_header_line(rb.data() + header_end);
        assert(ctx.header_lines.size() == 1);

        bool complete_header = false;

        if (rb.empty())
          if (!rb.read_more(fiber))
            return;

        const char* cur = rb.data() + header_end;
        const char* rbend = rb.data() + rb.end - 3;
        while (!complete_header) {
          // Look for end of header and save header lines.
#if 0
          // Memchr optimization. Does not seem to help but I can't find why.
          while (cur < rbend) {
           cur = (const char*) memchr(cur, '\r', 1 + rbend - cur);
           if (!cur) {
             cur = rbend + 1;
             break;
           }
           if (cur[1] == '\n') { // \n already checked by memchr.
#else
          while ((cur - rb.data()) < rb.end - 3) {
            if (cur[0] == '\r' and cur[1] == '\n') {
#endif
          cur += 2; // skip \r\n
          ctx.add_header_line(cur);
          // If we read \r\n twice the header is complete.
          if (cur[0] == '\r' and cur[1] == '\n') {
            complete_header = true;
            cur += 2; // skip \r\n
            header_end = cur - rb.data();
            break;
          }
        }
        else cur++;
      }

      // Read more data from the socket if the headers are not complete.
      if (!complete_header && 0 == rb.read_more(fiber))
        return;
    }

    // Header is complete. Process it.
    // Run the handler.
    assert(rb.cursor <= rb.end);
    ctx.body_start = std::string_view(rb.data() + header_end, rb.end - header_end);
    ctx.prepare_request();
    handler(ctx);
    assert(rb.cursor <= rb.end);

    // Update the cursor the beginning of the next request.
    ctx.prepare_next_request();
    // if read buffer is empty, we can flush the output buffer.
    if (rb.empty())
      ctx.flush_responses();
  }
}
catch (const std::runtime_error& e) {
  std::cerr << "Error: " << e.what() << std::endl;
  return;
}
};
}

} // namespace http_async_impl
} // namespace li

ext: hh

max_stars_repo_name: theonewolf/lithium

max_issues_repo_name: theonewolf/lithium

max_forks_repo_name: theonewolf/lithium


text:
/**
 *    Copyright (C) 2018-present MongoDB, Inc.
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the Server Side Public License, version 1,
 *    as published by MongoDB, Inc.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    Server Side Public License for more details.
 *
 *    You should have received a copy of the Server Side Public License
 *    along with this program. If not, see
 *    <http://www.mongodb.com/licensing/server-side-public-license>.
 *
 *    As a special exception, the copyright holders give permission to link the
 *    code of portions of this program with the OpenSSL library under certain
 *    conditions as described in each individual source file and distribute
 *    linked combinations including the program with the OpenSSL library. You
 *    must comply with the Server Side Public License in all respects for
 *    all of the code used other than as permitted herein. If you modify file(s)
 *    with this exception, you may extend this exception to your version of the
 *    file(s), but you are not obligated to do so. If you do not wish to do so,
 *    delete this exception statement from your version. If you delete this
 *    exception statement from all source files in the program, then also delete
 *    it in the license file.
 */

#include "mongo/db/server_options_helpers.h"

#ifdef _WIN32
#include <direct.h>
#else
#define SYSLOG_NAMES
#include <syslog.h>
#endif
#include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>
#include <fmt/format.h>
#include <ios>
#include <iostream>

#include "mongo/base/status.h"
#include "mongo/bson/json.h"
#include "mongo/bson/util/builder.h"
#include "mongo/config.h"
#include "mongo/db/server_options.h"
#include "mongo/idl/server_parameter.h"
#include "mongo/logv2/log.h"
#include "mongo/logv2/log_component.h"
#include "mongo/logv2/log_component_settings.h"
#include "mongo/logv2/log_manager.h"
#include "mongo/transport/message_compressor_registry.h"
#include "mongo/util/cmdline_utils/censor_cmdline.h"
#include "mongo/util/fail_point.h"
#include "mongo/util/net/sock.h"
#include "mongo/util/net/socket_utils.h"
#include "mongo/util/net/ssl_options.h"
#include "mongo/util/options_parser/startup_options.h"
#include "mongo/util/str.h"

#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl

using std::endl;
using std::string;

namespace mongo {

/*
 * SERVER-11160 syslog.h does not define facilitynames under solaris.
 * syslog.h exports preprocessor macro INTERNAL_NOPRI if
 * facilitynames is provided. This will be used to determine
 * if facilitynames should be defined here.
 * These could also go into a syslog.h compatibility header.
 * We are using INTERNAL_NOPRI as the indicator macro for facilitynames
 * because it's defined alongside facilitynames in the syslog.h headers
 * that support SYSLOG_NAMES.
 */

namespace {

#if defined(SYSLOG_NAMES)
#if !defined(INTERNAL_NOPRI)

typedef struct _code {
    const char* c_name;
    int c_val;
} CODE;

CODE facilitynames[] = {{"auth", LOG_AUTH},     {"cron", LOG_CRON},     {"daemon", LOG_DAEMON},
                        {"kern", LOG_KERN},     {"lpr", LOG_LPR},       {"mail", LOG_MAIL},
                        {"news", LOG_NEWS},     {"security", LOG_AUTH}, /* DEPRECATED */
                        {"syslog", LOG_SYSLOG}, {"user", LOG_USER},     {"uucp", LOG_UUCP},
                        {"local0", LOG_LOCAL0}, {"local1", LOG_LOCAL1}, {"local2", LOG_LOCAL2},
                        {"local3", LOG_LOCAL3}, {"local4", LOG_LOCAL4}, {"local5", LOG_LOCAL5},
                        {"local6", LOG_LOCAL6}, {"local7", LOG_LOCAL7}, {nullptr, -1}};

#endif  // !defined(INTERNAL_NOPRI)
#endif  // defined(SYSLOG_NAMES)

Status setArgvArray(const std::vector<std::string>& argv) {
    BSONArrayBuilder b;
    std::vector<std::string> censoredArgv = argv;
    cmdline_utils::censorArgsVector(&censoredArgv);
    for (size_t i = 0; i < censoredArgv.size(); i++) {
        b << censoredArgv[i];
    }
    serverGlobalParams.argvArray = b.arr();
    return Status::OK();
}

Status setParsedOpts(const moe::Environment& params) {
    serverGlobalParams.parsedOpts = params.toBSON();
    cmdline_utils::censorBSONObj(&serverGlobalParams.parsedOpts);
    return Status::OK();
}
}  // namespace

Status validateBaseOptions(const moe::Environment& params) {
    if (params.count("verbose")) {
        std::string verbosity = params["verbose"].as<std::string>();

        // Skip this for backwards compatibility.  See SERVER-11471.
        if (verbosity != "true") {
            for (std::string::iterator iterator = verbosity.begin(); iterator != verbosity.end();
                 iterator++) {
                if (*iterator != 'v') {
                    return Status(ErrorCodes::BadValue,
                                  "The \"verbose\" option string cannot contain any characters "
                                  "other than \"v\"");
                }
            }
        }
    }

    if (params.count("setParameter")) {
        const auto parameters = params["setParameter"].as<std::map<std::string, std::string>>();

        const bool enableTestCommandsValue = ([&parameters] {
            const auto etc = parameters.find("enableTestCommands");
            if (etc == parameters.end()) {
                return false;
            }
            const auto& val = etc->second;
            return (0 == val.compare("1")) || (0 == val.compare("true"));
        })();

        if (enableTestCommandsValue) {
            // Only register failpoint server parameters if enableTestCommands=1.
            globalFailPointRegistry().registerAllFailPointsAsServerParameters();
        } else {
            // Deregister test-only parameters.
            ServerParameterSet::getNodeParameterSet()->disableTestParameters();
            ServerParameterSet::getClusterParameterSet()->disableTestParameters();
        }

        // Must come after registerAllFailPointsAsServerParameters() above.
        auto* paramSet = ServerParameterSet::getNodeParameterSet();
        for (const auto& setParam : parameters) {
            auto* param = paramSet->getIfExists(setParam.first);

            if (!param) {
                return {ErrorCodes::BadValue,
                        str::stream() << "Unknown --setParameter '" << setParam.first << "'"};
            }

            if (!param->isEnabled()) {
                return {ErrorCodes::BadValue,
                        str::stream() << "--setParameter '" << setParam.first
                                      << "' only available when used with 'enableTestCommands'"};
            }
        }
    }

    return Status::OK();
}

Status canonicalizeBaseOptions(moe::Environment* params) {
    // Handle both the "--verbose" string argument and the "-vvvv" arguments at the same time so
    // that we ensure that we set the log level to the maximum of the options provided
    int logLevel = -1;
    for (std::string s = ""; s.length() <= 14; s.append("v")) {
        if (!s.empty() && params->count(s) && (*params)[s].as<bool>() == true) {
            logLevel = s.length();
        }

        if (params->count("verbose")) {
            std::string verbosity;
            params->get("verbose", &verbosity).transitional_ignore();
            if (s == verbosity ||
                // Treat a verbosity of "true" the same as a single "v".  See SERVER-11471.
                (s == "v" && verbosity == "true")) {
                logLevel = s.length();
            }
        }

        // Remove all "v" options we have already handled
        Status ret = params->remove(s);
        if (!ret.isOK()) {
            return ret;
        }
    }

    if (logLevel != -1) {
        Status ret = params->set("systemLog.verbosity", moe::Value(logLevel));
        if (!ret.isOK()) {
            return ret;
        }
        ret = params->remove("verbose");
        if (!ret.isOK()) {
            return ret;
        }
    }

    if (params->count("logpath")) {
        std::string logpath;
        Status ret = params->get("logpath", &logpath);
        if (!ret.isOK()) {
            return ret;
        }
        if (logpath.empty()) {
            return Status(ErrorCodes::BadValue, "logpath cannot be empty if supplied");
        }
        ret = params->set("systemLog.destination", moe::Value(std::string("file")));
        if (!ret.isOK()) {
            return ret;
        }
        ret = params->set("systemLog.path", moe::Value(logpath));
        if (!ret.isOK()) {
            return ret;
        }
        ret = params->remove("logpath");
        if (!ret.isOK()) {
            return ret;
        }
    }

    // "systemLog.destination" comes from the config file, so override it if "syslog" is set
    // since that comes from the command line.
    if (params->count("syslog") && (*params)["syslog"].as<bool>() == true) {
        Status ret = params->set("systemLog.destination", moe::Value(std::string("syslog")));
        if (!ret.isOK()) {
            return ret;
        }
        ret = params->remove("syslog");
        if (!ret.isOK()) {
            return ret;
        }
    }

    return Status::OK();
}

Status setupBaseOptions(const std::vector<std::string>& args) {
    Status ret = setArgvArray(args);
    if (!ret.isOK()) {
        return ret;
    }

    return Status::OK();
}

namespace server_options_detail {
StatusWith<BSONObj> applySetParameterOptions(const std::map<std::string, std::string>& toApply,
                                             ServerParameterSet& parameterSet) {
    using namespace fmt::literals;
    BSONObjBuilder summaryBuilder;
    for (const auto& [name, value] : toApply) {
        auto sp = parameterSet.getIfExists(name);
        if (!sp)
            return Status(ErrorCodes::BadValue,
                          "Illegal --setParameter parameter: \"{}\""_format(name));
        if (!sp->allowedToChangeAtStartup())
            return Status(ErrorCodes::BadValue,
                          "Cannot use --setParameter to set \"{}\" at startup"_format(name));
        BSONObjBuilder sub(summaryBuilder.subobjStart(name));
        sp->append(nullptr, sub, "default");
        Status status = sp->setFromString(value);
        if (!status.isOK())
            return Status(ErrorCodes::BadValue,
                          "Bad value for parameter \"{}\": {}"_format(name, status.reason()));
        sp->append(nullptr, sub, "value");
    }
    return summaryBuilder.obj();
}
}  // namespace server_options_detail

Status storeBaseOptions(const moe::Environment& params) {
    Status ret = setParsedOpts(params);
    if (!ret.isOK()) {
        return ret;
    }

    if (params.count("systemLog.verbosity")) {
        int verbosity = params["systemLog.verbosity"].as<int>();
        if (verbosity < 0) {
            // This can only happen in YAML config
            return Status(ErrorCodes::BadValue,
                          "systemLog.verbosity YAML Config cannot be negative");
        }
        logv2::LogManager::global().getGlobalSettings().setMinimumLoggedSeverity(
            mongo::logv2::LogComponent::kDefault, logv2::LogSeverity::Debug(verbosity));
    }

    // log component hierarchy verbosity levels
    for (int i = 0; i < int(logv2::LogComponent::kNumLogComponents); ++i) {
        logv2::LogComponent component = static_cast<logv2::LogComponent::Value>(i);
        if (component == logv2::LogComponent::kDefault) {
            continue;
        }
        const string dottedName = "systemLog.component." + component.getDottedName() + ".verbosity";
        if (params.count(dottedName)) {
            int verbosity = params[dottedName].as<int>();
            // Clear existing log level if log level is negative.
            if (verbosity < 0) {
                logv2::LogManager::global().getGlobalSettings().clearMinimumLoggedSeverity(
                    component);
            } else {
                logv2::LogManager::global().getGlobalSettings().setMinimumLoggedSeverity(
                    component, logv2::LogSeverity::Debug(verbosity));
            }
        }
    }

    if (params.count("enableExperimentalStorageDetailsCmd")) {
        serverGlobalParams.experimental.storageDetailsCmdEnabled =
            params["enableExperimentalStorageDetailsCmd"].as<bool>();
    }

    if (params.count("systemLog.quiet")) {
        serverGlobalParams.quiet.store(params["systemLog.quiet"].as<bool>());
    }

    if (params.count("systemLog.traceAllExceptions")) {
        DBException::traceExceptions.store(params["systemLog.traceAllExceptions"].as<bool>());
    }

    if (params.count("systemLog.timeStampFormat")) {
        std::string formatterName = params["systemLog.timeStampFormat"].as<string>();
        if (formatterName == "iso8601-utc") {
            serverGlobalParams.logTimestampFormat = logv2::LogTimestampFormat::kISO8601UTC;
            setDateFormatIsLocalTimezone(false);
        } else if (formatterName == "iso8601-local") {
            serverGlobalParams.logTimestampFormat = logv2::LogTimestampFormat::kISO8601Local;
            setDateFormatIsLocalTimezone(true);
        } else {
            StringBuilder sb;
            sb << "Value of logTimestampFormat must be one of iso8601-utc "
               << "or iso8601-local; not \"" << formatterName << "\".";
            return Status(ErrorCodes::BadValue, sb.str());
        }
    }

    if (params.count("systemLog.destination")) {
        std::string systemLogDestination = params["systemLog.destination"].as<std::string>();
        if (systemLogDestination == "file") {
            if (params.count("systemLog.path")) {
                serverGlobalParams.logpath = params["systemLog.path"].as<std::string>();
            } else {
                return Status(ErrorCodes::BadValue,
                              "systemLog.path is required if systemLog.destination is to a "
                              "file");
            }
        } else if (systemLogDestination == "syslog") {
            if (params.count("systemLog.path")) {
                return Status(ErrorCodes::BadValue,
                              "Can only use systemLog.path if systemLog.destination is to a "
                              "file");
            }
            serverGlobalParams.logWithSyslog = true;
        } else {
            StringBuilder sb;
            sb << "Bad value for systemLog.destination: " << systemLogDestination
               << ".  Supported targets are: (syslog|file)";
            return Status(ErrorCodes::BadValue, sb.str());
        }
    } else {
        if (params.count("systemLog.path")) {
            return Status(ErrorCodes::BadValue,
                          "Can only use systemLog.path if systemLog.destination is to a file");
        }
    }

#ifndef _WIN32
    if (params.count("systemLog.syslogFacility")) {
        std::string facility = params["systemLog.syslogFacility"].as<string>();
        bool set = false;
        // match facility string to facility value
        size_t facilitynamesLength = sizeof(facilitynames) / sizeof(facilitynames[0]);
        for (unsigned long i = 0; i < facilitynamesLength && facilitynames[i].c_name != nullptr;
             i++) {
            if (!facility.compare(facilitynames[i].c_name)) {
                serverGlobalParams.syslogFacility = facilitynames[i].c_val;
                set = true;
            }
        }
        if (!set) {
            StringBuilder sb;
            sb << "ERROR: syslogFacility must be set to a string representing one of the "
               << "possible syslog facilities";
            return Status(ErrorCodes::BadValue, sb.str());
        }
    } else {
        serverGlobalParams.syslogFacility = LOG_USER;
    }
#endif  // _WIN32

    if (params.count("systemLog.logAppend") && params["systemLog.logAppend"].as<bool>() == true) {
        serverGlobalParams.logAppend = true;
    }

    if (params.count("systemLog.logRotate")) {
        std::string logRotateParam = params["systemLog.logRotate"].as<string>();
        if (logRotateParam == "reopen") {
            serverGlobalParams.logRenameOnRotate = false;

            if (serverGlobalParams.logAppend == false) {
                return Status(ErrorCodes::BadValue,
                              "logAppend must equal true if logRotate is set to reopen");
            }
        } else if (logRotateParam == "rename") {
            serverGlobalParams.logRenameOnRotate = true;
        } else {
            return Status(ErrorCodes::BadValue,
                          "unsupported value for logRotate " + logRotateParam);
        }
    }

    if (!serverGlobalParams.logpath.empty() && serverGlobalParams.logWithSyslog) {
        return Status(ErrorCodes::BadValue, "Cant use both a logpath and syslog ");
    }

    if (params.count("processManagement.pidFilePath")) {
        serverGlobalParams.pidFile = params["processManagement.pidFilePath"].as<string>();
    }

    if (params.count("processManagement.timeZoneInfo")) {
        serverGlobalParams.timeZoneInfoPath = params["processManagement.timeZoneInfo"].as<string>();
    }

    if (params.count("setParameter")) {
        auto swObj = server_options_detail::applySetParameterOptions(
            params["setParameter"].as<std::map<std::string, std::string>>(),
            *ServerParameterSet::getNodeParameterSet());
        if (!swObj.isOK())
            return swObj.getStatus();
        if (const BSONObj& obj = swObj.getValue(); !obj.isEmpty())
            LOGV2(5760901, "Applied --setParameter options", "serverParameters"_attr = obj);
    }

    if (params.count("operationProfiling.slowOpThresholdMs")) {
        serverGlobalParams.slowMS = params["operationProfiling.slowOpThresholdMs"].as<int>();
    }

    if (params.count("operationProfiling.slowOpSampleRate")) {
        serverGlobalParams.sampleRate = params["operationProfiling.slowOpSampleRate"].as<double>();
    }

    if (params.count("operationProfiling.filter")) {
        try {
            serverGlobalParams.defaultProfileFilter =
                fromjson(params["operationProfiling.filter"].as<std::string>()).getOwned();
        } catch (AssertionException& e) {
            // Add more context to the error
            uasserted(ErrorCodes::FailedToParse,
                      str::stream()
                          << "Failed to parse option operationProfiling.filter: " << e.reason());
        }
    }

    return Status::OK();
}

}  // namespace mongo

ext: cpp

max_stars_repo_name: benety/mongo

max_issues_repo_name: benety/mongo

max_forks_repo_name: benety/mongo


text:
/*!
 * @name      CerberusAnymalControlBase.hpp
 * @author    Samuel Zimmermann
 * @email     zsamuel@ethz.ch
 * @date      April 30, 2020
 *
 * Copyright (C) 2020 Robotic Systems Lab, ETH Zurich.
 * All rights reserved.
 * http://www.rsl.ethz.ch/
 */

#pragma once

// C++
#include <memory>

// Boost
#include <boost/thread.hpp>

// Eigen
#include <Eigen/Core>

// Learning Controller
#include "cerberus_anymal_utils/GraphLoader.hpp"

namespace cerberus_anymal_control {

//!@brief Fixed variable number of joints since controller only works with 12 joints.
static constexpr unsigned int numberOfJoints = 12;

using GenCoordinates = Eigen::Matrix<double, 19, 1>;
using GenVelocities = Eigen::Matrix<double, 18, 1>;
using Twist = Eigen::Matrix<double, 6, 1>;

template <typename ConcreteQuadrupedController>
class CerberusAnymalControlBase {
 public:
  CerberusAnymalControlBase();
  ~CerberusAnymalControlBase() = default;

 protected:
  virtual void initialize() = 0;
  virtual void loadParameters(const std::string& path);
  void advance();

  //! @brief Pointer to the specific learning controller
  std::unique_ptr<ConcreteQuadrupedController> quadrupedController_;

  //! @brief Graph for the learning controller
  GraphLoader<float> graph_;

 protected:
  //! @brief Coordinates for the controller
  //! Position(x,y,z),Orientation(w,x,y,z),JointPositions(LF_HAA,LF_HFE,LF_KFE,RF_HAA,RF_HFE,RF_KFE,LH_HAA,LH_HFE,LH_KFE,RH_HAA,RH_HFE,RH_KFE)
  GenCoordinates genCoordinates_;
  //! LinearVelocity(x,y,z),AngularVelocity(x,y,z),JointVelocities(LF_HAA,LF_HFE,LF_KFE,RF_HAA,RF_HFE,RF_KFE,LH_HAA,LH_HFE,LH_KFE,RH_HAA,RH_HFE,RH_KFE)
  GenVelocities genVelocities_;
  //! LinearVelocity(x,y,z), AngularVelocity(x,y,z)
  Twist desTwist_;
  Eigen::VectorXd desJointPositions_;

  //! @brief Mutex for the controller data
  mutable boost::shared_mutex data_mutex_;

  //! @brief Checks that data has arrived
  bool hasBodyVelocityData_;
  bool hasJointPositionData_;
  bool initializedGraph_;
};

} // namespace cerberus_anymal_control

#include "CerberusAnymalControlBase.tpp"

ext: hpp


text:
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <iostream>
#include <string>

namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
using tcp = net::ip::tcp;

int main(int argc, char** argv)
{
	try {
        // Check command line arguments.
        if (argc != 4 && argc != 5)
        {
            std::cerr <<
                "Usage: http-client-sync <host> <port> <target> [<HTTP version: 1.0 or 1.1(default)>]\n" <<
                "Example:\n" <<
                "    http-client-sync www.example.com 80 /\n" <<
                "    http-client-sync www.example.com 80 / 1.0\n";
            return EXIT_FAILURE;
        }

        auto const host = argv[1];
        auto const port = argv[2];
        auto const target = argv[3];
        int version = argc == 5 && !std::strcmp("1.0", argv[4]) ? 10 : 11;

        net::io_context ioc;

        tcp::resolver resolver(ioc);
        beast::tcp_stream stream(ioc);

        auto const results = resolver.resolve(host, port);

        stream.connect(results);

        http::request<http::string_body> req{ http::verb::get, target, version };
        req.set(http::field::host, host);
        req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);

        // send the http request to the remote host
        http::write(stream, req);

        // Receive the HTTP response
        beast::flat_buffer buffer;
        http::response<http::dynamic_body> res;
        http::read(stream, buffer, res);

        std::cout << res << std::endl;

        beast::error_code ec;
        stream.socket().shutdown(tcp::socket::shutdown_both, ec);

        if (ec && ec != beast::errc::not_connected) {
            throw beast::system_error{ ec };
        }
	}
	catch (const std::exception& ex) {
		std::cerr << ex.what() << std::endl;
        return EXIT_FAILURE;
	}
    return EXIT_SUCCESS;
}

max_stars_repo_name: pvthuyet/books

max_issues_repo_name: pvthuyet/books

max_forks_repo_name: pvthuyet/books


text: #include <boost/beast/websocket/option.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino