A C++ header-only HTTP/HTTPS server and client library

Overview

cpp-httplib

A C++11 single-file header-only cross platform HTTP/HTTPS library.

It's extremely easy to setup. Just include the httplib.h file in your code!

NOTE: This is a multi-threaded 'blocking' HTTP library. If you are looking for a 'non-blocking' library, this is not the one that you want.

Simple examples

Server

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"

// HTTP
httplib::Server svr;

// HTTPS
httplib::SSLServer svr;

svr.Get("/hi", [](const httplib::Request &, httplib::Response &res) {
  res.set_content("Hello World!", "text/plain");
});

svr.listen("0.0.0.0", 8080);

Client

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"

// HTTP
httplib::Client cli("http://cpp-httplib-server.yhirose.repl.co");

// HTTPS
httplib::Client cli("https://cpp-httplib-server.yhirose.repl.co");

auto res = cli.Get("/hi");
res->status;
res->body;

Try out the examples on Repl.it!

  1. Run server at https://repl.it/@yhirose/cpp-httplib-server
  2. Run client at https://repl.it/@yhirose/cpp-httplib-client

Server

#include <httplib.h>

int main(void)
{
  using namespace httplib;

  Server svr;

  svr.Get("/hi", [](const Request& req, Response& res) {
    res.set_content("Hello World!", "text/plain");
  });

  svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
    auto numbers = req.matches[1];
    res.set_content(numbers, "text/plain");
  });

  svr.Get("/body-header-param", [](const Request& req, Response& res) {
    if (req.has_header("Content-Length")) {
      auto val = req.get_header_value("Content-Length");
    }
    if (req.has_param("key")) {
      auto val = req.get_param_value("key");
    }
    res.set_content(req.body, "text/plain");
  });

  svr.Get("/stop", [&](const Request& req, Response& res) {
    svr.stop();
  });

  svr.listen("localhost", 1234);
}

Post, Put, Delete and Options methods are also supported.

Bind a socket to multiple interfaces and any available port

int port = svr.bind_to_any_port("0.0.0.0");
svr.listen_after_bind();

Static File Server

// Mount / to ./www directory
auto ret = svr.set_mount_point("/", "./www");
if (!ret) {
  // The specified base directory doesn't exist...
}

// Mount /public to ./www directory
ret = svr.set_mount_point("/public", "./www");

// Mount /public to ./www1 and ./www2 directories
ret = svr.set_mount_point("/public", "./www1"); // 1st order to search
ret = svr.set_mount_point("/public", "./www2"); // 2nd order to search

// Remove mount /
ret = svr.remove_mount_point("/");

// Remove mount /public
ret = svr.remove_mount_point("/public");
// User defined file extension and MIME type mappings
svr.set_file_extension_and_mimetype_mapping("cc", "text/x-c");
svr.set_file_extension_and_mimetype_mapping("cpp", "text/x-c");
svr.set_file_extension_and_mimetype_mapping("hh", "text/x-h");

The followings are built-in mappings:

Extension MIME Type Extension MIME Type
css text/css mpga audio/mpeg
csv text/csv weba audio/webm
txt text/plain wav audio/wave
vtt text/vtt otf font/otf
html, htm text/html ttf font/ttf
apng image/apng woff font/woff
avif image/avif woff2 font/woff2
bmp image/bmp 7z application/x-7z-compressed
gif image/gif atom application/atom+xml
png image/png pdf application/pdf
svg image/svg+xml mjs, js application/javascript
webp image/webp json application/json
ico image/x-icon rss application/rss+xml
tif image/tiff tar application/x-tar
tiff image/tiff xhtml, xht application/xhtml+xml
jpeg, jpg image/jpeg xslt application/xslt+xml
mp4 video/mp4 xml application/xml
mpeg video/mpeg gz application/gzip
webm video/webm zip application/zip
mp3 audio/mp3 wasm application/wasm

NOTE: These static file server methods are not thread-safe.

Logging

svr.set_logger([](const auto& req, const auto& res) {
  your_logger(req, res);
});

Error handler

svr.set_error_handler([](const auto& req, auto& res) {
  auto fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
  char buf[BUFSIZ];
  snprintf(buf, sizeof(buf), fmt, res.status);
  res.set_content(buf, "text/html");
});

Exception handler

The exception handler gets called if a user routing handler throws an error.

svr.set_exception_handler([](const auto& req, auto& res, std::exception &e) {
  res.status = 500;
  auto fmt = "<h1>Error 500</h1><p>%s</p>";
  char buf[BUFSIZ];
  snprintf(buf, sizeof(buf), fmt, e.what());
  res.set_content(buf, "text/html");
});

Pre routing handler

svr.set_pre_routing_handler([](const auto& req, auto& res) -> bool {
  if (req.path == "/hello") {
    res.set_content("world", "text/html");
    return Server::HandlerResponse::Handled;
  }
  return Server::HandlerResponse::Unhandled;
});

Post routing handler

svr.set_post_routing_handler([](const auto& req, auto& res) {
  res.set_header("ADDITIONAL_HEADER", "value");
});

'multipart/form-data' POST data

svr.Post("/multipart", [&](const auto& req, auto& res) {
  auto size = req.files.size();
  auto ret = req.has_file("name1");
  const auto& file = req.get_file_value("name1");
  // file.filename;
  // file.content_type;
  // file.content;
});

Receive content with a content receiver

svr.Post("/content_receiver",
  [&](const Request &req, Response &res, const ContentReader &content_reader) {
    if (req.is_multipart_form_data()) {
      MultipartFormDataItems files;
      content_reader(
        [&](const MultipartFormData &file) {
          files.push_back(file);
          return true;
        },
        [&](const char *data, size_t data_length) {
          files.back().content.append(data, data_length);
          return true;
        });
    } else {
      std::string body;
      content_reader([&](const char *data, size_t data_length) {
        body.append(data, data_length);
        return true;
      });
      res.set_content(body, "text/plain");
    }
  });

Send content with the content provider

const size_t DATA_CHUNK_SIZE = 4;

svr.Get("/stream", [&](const Request &req, Response &res) {
  auto data = new std::string("abcdefg");

  res.set_content_provider(
    data->size(), // Content length
    "text/plain", // Content type
    [data](size_t offset, size_t length, DataSink &sink) {
      const auto &d = *data;
      sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
      return true; // return 'false' if you want to cancel the process.
    },
    [data] { delete data; });
});

Without content length:

svr.Get("/stream", [&](const Request &req, Response &res) {
  res.set_content_provider(
    "text/plain", // Content type
    [&](size_t offset, size_t length, DataSink &sink) {
      if (/* there is still data */) {
        std::vector<char> data;
        // prepare data...
        sink.write(data.data(), data.size());
      } else {
        sink.done(); // No more data
      }
      return true; // return 'false' if you want to cancel the process.
    });
});

Chunked transfer encoding

svr.Get("/chunked", [&](const Request& req, Response& res) {
  res.set_chunked_content_provider(
    "text/plain",
    [](size_t offset, DataSink &sink) {
      sink.write("123", 3);
      sink.write("345", 3);
      sink.write("789", 3);
      sink.done(); // No more data
      return true; // return 'false' if you want to cancel the process.
    }
  );
});

'Expect: 100-continue' handler

By default, the server sends a 100 Continue response for an Expect: 100-continue header.

// Send a '417 Expectation Failed' response.
svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
  return 417;
});
// Send a final status without reading the message body.
svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
  return res.status = 401;
});

Keep-Alive connection

svr.set_keep_alive_max_count(2); // Default is 5
svr.set_keep_alive_timeout(10);  // Default is 5

Timeout

svr.set_read_timeout(5, 0); // 5 seconds
svr.set_write_timeout(5, 0); // 5 seconds
svr.set_idle_interval(0, 100000); // 100 milliseconds

Set maximum payload length for reading a request body

svr.set_payload_max_length(1024 * 1024 * 512); // 512MB

Server-Sent Events

Please see Server example and Client example.

Default thread pool support

ThreadPool is used as a default task queue, and the default thread count is 8, or std::thread::hardware_concurrency(). You can change it with CPPHTTPLIB_THREAD_POOL_COUNT.

If you want to set the thread count at runtime, there is no convenient way... But here is how.

svr.new_task_queue = [] { return new ThreadPool(12); };

Override the default thread pool with yours

You can supply your own thread pool implementation according to your need.

class YourThreadPoolTaskQueue : public TaskQueue {
public:
  YourThreadPoolTaskQueue(size_t n) {
    pool_.start_with_thread_count(n);
  }

  virtual void enqueue(std::function<void()> fn) override {
    pool_.enqueue(fn);
  }

  virtual void shutdown() override {
    pool_.shutdown_gracefully();
  }

private:
  YourThreadPool pool_;
};

svr.new_task_queue = [] {
  return new YourThreadPoolTaskQueue(12);
};

Client

#include <httplib.h>
#include <iostream>

int main(void)
{
  httplib::Client cli("localhost", 1234);

  if (auto res = cli.Get("/hi")) {
    if (res->status == 200) {
      std::cout << res->body << std::endl;
    }
  } else {
    auto err = res.error();
    ...
  }
}

NOTE: Constructor with scheme-host-port string is now supported!

httplib::Client cli("localhost");
httplib::Client cli("localhost:8080");
httplib::Client cli("http://localhost");
httplib::Client cli("http://localhost:8080");
httplib::Client cli("https://localhost");
httplib::SSLClient cli("localhost");

Error code

Here is the list of errors from Result::error().

enum Error {
  Success = 0,
  Unknown,
  Connection,
  BindIPAddress,
  Read,
  Write,
  ExceedRedirectCount,
  Canceled,
  SSLConnection,
  SSLLoadingCerts,
  SSLServerVerification,
  UnsupportedMultipartBoundaryChars
};

GET with HTTP headers

httplib::Headers headers = {
  { "Accept-Encoding", "gzip, deflate" }
};
auto res = cli.Get("/hi", headers);

or

cli.set_default_headers({
  { "Accept-Encoding", "gzip, deflate" }
});
auto res = cli.Get("/hi");

POST

res = cli.Post("/post", "text", "text/plain");
res = cli.Post("/person", "name=john1&note=coder", "application/x-www-form-urlencoded");

POST with parameters

httplib::Params params;
params.emplace("name", "john");
params.emplace("note", "coder");

auto res = cli.Post("/post", params);

or

httplib::Params params{
  { "name", "john" },
  { "note", "coder" }
};

auto res = cli.Post("/post", params);

POST with Multipart Form Data

httplib::MultipartFormDataItems items = {
  { "text1", "text default", "", "" },
  { "text2", "aωb", "", "" },
  { "file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain" },
  { "file2", "{\n  \"world\", true\n}\n", "world.json", "application/json" },
  { "file3", "", "", "application/octet-stream" },
};

auto res = cli.Post("/multipart", items);

PUT

res = cli.Put("/resource/foo", "text", "text/plain");

DELETE

res = cli.Delete("/resource/foo");

OPTIONS

res = cli.Options("*");
res = cli.Options("/resource/foo");

Timeout

cli.set_connection_timeout(0, 300000); // 300 milliseconds
cli.set_read_timeout(5, 0); // 5 seconds
cli.set_write_timeout(5, 0); // 5 seconds

Receive content with a content receiver

std::string body;

auto res = cli.Get("/large-data",
  [&](const char *data, size_t data_length) {
    body.append(data, data_length);
    return true;
  });
std::string body;

auto res = cli.Get(
  "/stream", Headers(),
  [&](const Response &response) {
    EXPECT_EQ(200, response.status);
    return true; // return 'false' if you want to cancel the request.
  },
  [&](const char *data, size_t data_length) {
    body.append(data, data_length);
    return true; // return 'false' if you want to cancel the request.
  });

Send content with a content provider

std::string body = ...;

auto res = cli.Post(
  "/stream", body.size(),
  [](size_t offset, size_t length, DataSink &sink) {
    sink.write(body.data() + offset, length);
    return true; // return 'false' if you want to cancel the request.
  },
  "text/plain");

Chunked transfer encoding

auto res = cli.Post(
  "/stream",
  [](size_t offset, DataSink &sink) {
    sink.os << "chunked data 1";
    sink.os << "chunked data 2";
    sink.os << "chunked data 3";
    sink.done();
    return true; // return 'false' if you want to cancel the request.
  },
  "text/plain");

With Progress Callback

httplib::Client client(url, port);

// prints: 0 / 000 bytes => 50% complete
auto res = cli.Get("/", [](uint64_t len, uint64_t total) {
  printf("%lld / %lld bytes => %d%% complete\n",
    len, total,
    (int)(len*100/total));
  return true; // return 'false' if you want to cancel the request.
}
);

progress

Authentication

// Basic Authentication
cli.set_basic_auth("user", "pass");

// Digest Authentication
cli.set_digest_auth("user", "pass");

// Bearer Token Authentication
cli.set_bearer_token_auth("token");

NOTE: OpenSSL is required for Digest Authentication.

Proxy server support

cli.set_proxy("host", port);

// Basic Authentication
cli.set_proxy_basic_auth("user", "pass");

// Digest Authentication
cli.set_proxy_digest_auth("user", "pass");

// Bearer Token Authentication
cli.set_proxy_bearer_token_auth("pass");

NOTE: OpenSSL is required for Digest Authentication.

Range

httplib::Client cli("httpbin.org");

auto res = cli.Get("/range/32", {
  httplib::make_range_header({{1, 10}}) // 'Range: bytes=1-10'
});
// res->status should be 206.
// res->body should be "bcdefghijk".
httplib::make_range_header({{1, 10}, {20, -1}})      // 'Range: bytes=1-10, 20-'
httplib::make_range_header({{100, 199}, {500, 599}}) // 'Range: bytes=100-199, 500-599'
httplib::make_range_header({{0, 0}, {-1, 1}})        // 'Range: bytes=0-0, -1'

Keep-Alive connection

httplib::Client cli("localhost", 1234);

cli.Get("/hello");         // with "Connection: close"

cli.set_keep_alive(true);
cli.Get("/world");

cli.set_keep_alive(false);
cli.Get("/last-request");  // with "Connection: close"

Redirect

httplib::Client cli("yahoo.com");

auto res = cli.Get("/");
res->status; // 301

cli.set_follow_location(true);
res = cli.Get("/");
res->status; // 200

Use a specific network interface

NOTE: This feature is not available on Windows, yet.

cli.set_interface("eth0"); // Interface name, IP address or host name

Compression

The server can apply compression to the following MIME type contents:

  • all text types except text/event-stream
  • image/svg+xml
  • application/javascript
  • application/json
  • application/xml
  • application/xhtml+xml

Zlib Support

'gzip' compression is available with CPPHTTPLIB_ZLIB_SUPPORT. libz should be linked.

Brotli Support

Brotli compression is available with CPPHTTPLIB_BROTLI_SUPPORT. Necessary libraries should be linked. Please see https://github.com/google/brotli for more detail.

Compress request body on client

cli.set_compress(true);
res = cli.Post("/resource/foo", "...", "text/plain");

Compress response body on client

cli.set_decompress(false);
res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
res->body; // Compressed data

SSL Support

SSL support is available with CPPHTTPLIB_OPENSSL_SUPPORT. libssl and libcrypto should be linked.

NOTE: cpp-httplib currently supports only version 1.1.1.

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"

// Server
httplib::SSLServer svr("./cert.pem", "./key.pem");

// Client
httplib::Client cli("https://localhost:1234");

// Use your CA bundle
cli.set_ca_cert_path("./ca-bundle.crt");

// Disable cert verification
cli.enable_server_certificate_verification(false);

Note: When using SSL, it seems impossible to avoid SIGPIPE in all cases, since on some operating systems, SIGPIPE can only be suppressed on a per-message basis, but there is no way to make the OpenSSL library do so for its internal communications. If your program needs to avoid being terminated on SIGPIPE, the only fully general way might be to set up a signal handler for SIGPIPE to handle or ignore it yourself.

Split httplib.h into .h and .cc

> python3 split.py
> ls out
httplib.h  httplib.cc

NOTE

g++

g++ 4.8 and below cannot build this library since <regex> in the versions are broken.

Windows

Include httplib.h before Windows.h or include Windows.h by defining WIN32_LEAN_AND_MEAN beforehand.

#include <httplib.h>
#include <Windows.h>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <httplib.h>

Note: Windows 8 or lower and Cygwin on Windows are not supported.

License

MIT license (© 2020 Yuji Hirose)

Special Thanks To

These folks made great contributions to polish this library to totally another level from a simple toy!

Issues
  • SSL_read timeout doesn't work on unstable network connection

    SSL_read timeout doesn't work on unstable network connection

    I'm new to native socket. now I try to use the http client to recv() from a low-bandwidth-server. Sometimes the recv() blocks forever, never returns, at that moment I attach debugger and see it's blocking at line:

    inline int SocketStream::read(char* ptr, size_t size)
    {
        return recv(sock_, ptr, static_cast<int>(size), 0);  <------blocking here
    }
    

    I see there is timeout implemented for connect(), but not for recv(). I tried to set the timeout with:

    int millisec = 1000; // 1 second
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&millisec, sizeof(int));
    

    But it doesn't take effect, I set 1 second but it still can blocking for 17 seconds, sometimes forever.

    I asked this question on stackoverflow, seems it's about WSA_FLAG_OVERLAPPED, I see the SO_OPENTYPE is set:

    #ifdef _WIN32
    #define SO_SYNCHRONOUS_NONALERT 0x20
    #define SO_OPENTYPE 0x7008
    
        int opt = SO_SYNCHRONOUS_NONALERT;
        setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char*)&opt, sizeof(opt));
    #endif
    

    From msdn :

    SO_OPENTYPE Once set, affects whether subsequent sockets that are created will be non-overlapped. The possible values for this option are SO_SYNCHRONOUS_ALERT and SO_SYNCHRONOUS_NONALERT. This option should not be used. Instead use the WSASocket function and leave the WSA_FLAG_OVERLAPPED bit in the dwFlagsparameter turned off.

    So, once the SO_OPENTYPE is set, the WSA_FLAG_OVERLAPPED doesn't work, then the SO_RCVTIMEO doesn't work, is this correct?

    I tried to delete the lines about SO_OPENTYPE, but all http requests fail.

    Any way to make the timeout work for recv()

    Thanks.

    bug 
    opened by aj3423 37
  • Timeouts don't apply to SSLClient*

    Timeouts don't apply to SSLClient*

    Hi, Loving this library so far, however I seem to have found a problem in which the timeouts do not apply to at least the SSLClient.

    #define CPPHTTPLIB_OPENSSL_SUPPORT
    #define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 2
    #define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0
    #define CPPHTTPLIB_READ_TIMEOUT_SECOND 2
    #define CPPHTTPLIB_READ_TIMEOUT_USECOND 0
    #include <httplib.h>
    

    For the following configuration, the ssl implementation waits for about 30s or so....

    httplib::SSLClient cli(C_ServerRemote, 443);
    cli.enable_server_certificate_verification(false);
    cli.set_follow_location(true);
    std::string sBuffer;
    httplib::Headers headers;
    headers.emplace("Accept-Encoding", "gzip, deflate");
    headers.emplace("Accept", "text/plain");
    auto res = cli.Get("/cli/latest", headers);
    

    The following returns in 2 seconds as expected.

    httplib::Client cli(C_ServerRemote, 80);
    cli.set_follow_location(true);
    std::tring sBuffer;
    httplib::Headers headers;
    headers.emplace("Accept-Encoding", "gzip, deflate");
    headers.emplace("Accept", "text/plain");
    auto res = cli.Get("/cli/latest", headers);
    

    Wonder if you know a fix for this?

    Sincerely, FrozenSource

    need more information to verify 
    opened by FrozenSource 36
  • Httpclient calls with OpenSSL 1.0.1e crash

    Httpclient calls with OpenSSL 1.0.1e crash

    Crash core:

    #0  0x00007fa48b4d3277 in raise () from /lib64/libc.so.6
    #1  0x00007fa48b4d4968 in abort () from /lib64/libc.so.6
    #2  0x00007fa48b515d37 in __libc_message () from /lib64/libc.so.6
    #3  0x00007fa48b51c5e4 in malloc_printerr () from /lib64/libc.so.6
    #4  0x00007fa48b521c39 in _int_realloc () from /lib64/libc.so.6
    #5  0x00007fa48b522eb2 in realloc () from /lib64/libc.so.6
    #6  0x00007fa48d2b5649 in CRYPTO_realloc () from ../lib/libcrypto.so.10
    #7  0x00007fa48d330b11 in lh_insert () from ../lib/libcrypto.so.10
    #8  0x00007fa48d3331e4 in int_thread_set_item () from ../lib/libcrypto.so.10
    #9  0x00007fa48d333d6e in ERR_get_state () from ../lib/libcrypto.so.10
    #10 0x00007fa48d333ef5 in ERR_clear_error () from ../lib/libcrypto.so.10
    #11 0x00007fa48d6665b5 in ssl23_connect () from ../lib/libssl.so.10
    #12 0x000000000049add6 in httplib::SSLClient::read_and_close_socket(int, httplib::Request&, httplib::Response&)::{lambda(ssl_st*)#1}::operator()(ssl_st*) const ()
    #13 0x000000000049ed1b in bool httplib::detail::read_and_close_socket_ssl<httplib::SSLClient::read_and_close_socket(int, httplib::Request&, httplib::Response&)::{lambda(ssl_st*)#1}, httplib::SSLClient::read_and_close_socket(int, httplib::Request&, httplib::Response&)::{lambda(ssl_st*)#2}, httplib::SSLClient::read_and_close_socket(int, httplib::Request&, httplib::Response&)::{lambda(ssl_st*, httplib::Stream&, bool, bool&)#3}>(int, unsigned long, ssl_ctx_st*, std::mutex&, httplib::SSLClient::read_and_close_socket(int, httplib::Request&, httplib::Response&)::{lambda(ssl_st*)#1}, httplib::SSLClient::read_and_close_socket(int, httplib::Request&, httplib::Response&)::{lambda(ssl_st*)#2}, httplib::SSLClient::read_and_close_socket(int, httplib::Request&, httplib::Response&)::{lambda(ssl_st*, httplib::Stream&, bool, bool&)#3}) ()
    #14 0x000000000049afb0 in httplib::SSLClient::read_and_close_socket(int, httplib::Request&, httplib::Response&) ()
    #15 0x0000000000499c88 in httplib::Client::send(httplib::Request&, httplib::Response&) ()
    #16 0x000000000049a57e in httplib::Client::Post(char const*, std::multimap<std::string, std::string, httplib::detail::ci, std::allocator<std::pair<std::string const, std::string> > > const&, std::string const&, char const*) ()
    
    bug 
    opened by y1015860449 28
  • Client keep-alive support is broken

    Client keep-alive support is broken

    Hello,

    I recently added this http library to server HTTP requests within the ccache compiler cache. Because a compilation requires up four HTTP requests I enabled keep-alive support in the Client.

    But we observed a race condition on Linux:

    1. Connection is opened and a GET request is issued. Turns out to be a cache miss
    2. Compilation starts and takes 90s, meanwhile the server closes the connection
    3. A PUT is issued on the now closed connection
    4. The ccache process receives SIGPIPE.

    Somehow the is_alive detection does not work as expected. A rough test case looks like this:

    TEST(KeepAlive, SimpleInterface_Online) {
    
      const auto host = "127.0.0.1";
      const auto port = 8080;
      const auto resourcePath = "/hi";
    
      Server svr;
    
      svr.set_keep_alive_timeout(3);
    
      svr.Get(resourcePath, [](const httplib::Request &, httplib::Response &res) {
        res.set_content("Hello World!", "text/plain");
      });
    
      auto a2 = std::async(std::launch::async, [&svr, host, port]{ svr.listen(host, port); });
    
      std::this_thread::sleep_for(std::chrono::milliseconds(200));
    
      Client cli(host, port);
      cli.set_keep_alive(true);
    
      auto result = cli.Get(resourcePath);
      ASSERT_TRUE(result);
      EXPECT_EQ(200, result->status);
    
      std::this_thread::sleep_for(std::chrono::seconds(5));
    
      result = cli.Get(resourcePath);
      ASSERT_TRUE(result);
      EXPECT_EQ(200, result->status);
    
      svr.stop();
      a2.wait();
    }
    

    Besides the non-working is_alive detection the library should set the MSG_NOSIGNAL on Linux and SO_NOSIGPIPE on Apple platforms to not badly interfere with the library host process.

    Thanks, Gregor

    bug need help 
    opened by gjasny 27
  • SSLSocketStream::read Problem

    SSLSocketStream::read Problem

    I found SSLSocketStream::read whill cause many dead block thread. I saw SSLSocketStream::read,this function call select function to check is the data is avaliable.I found the reason maybe is when the socket comming bytes is not enough to produce a ssl record, and this time server or proxy 's connection is lost.

    I don't make sure my this post is correct,i am not familiar with openssl.

    I found some info aboud SSL_read and select below: http://openssl.6102.n7.nabble.com/Graceful-shutdown-of-TLS-connection-for-blocking-sockets-tp72626p72662.html https://blog.csdn.net/dog250/article/details/5456022 https://baijiahao.baidu.com/s?id=1592012048270657934

    thanks

    need more information to verify 
    opened by xtayaitak 21
  • Middleware-like usage?

    Middleware-like usage?

    Is there any way that I could set up a handler that just intercepts all requests, sends some headers or something, and returns, moving on to the handler for that specific URL?

    Or will I have to set up the function calls myself?

    opened by ghost 20
  • Requests from browsers seem to freeze server on Windows

    Requests from browsers seem to freeze server on Windows

    I'm seeing a 5-10 second freeze in the handling of requests for the example test server whenever I make a request from a browser with the server running on a windows machine.

    This is my set-up:

    I'm running the example server on a windows machine. I've got a couple of scripts calling the /dump endpoint as fast as they can using curl. This is fine and I can have multiple clients calling dump without any issues (response times in the order of milliseconds).

    However, as soon as I make one request from a browser all other clients freeze for 5-10 seconds before continuing. The response to the browser is also fairly slow.

    This is the dump from the request from the browser that is causing the issue:

    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-US,en;q=0.9,nl;q=0.8
    Connection: keep-alive
    Host: 127.0.0.1:8080
    REMOTE_ADDR: 127.0.0.1
    REMOTE_PORT: 59759
    Sec-Fetch-Dest: document
    Sec-Fetch-Mode: navigate
    Sec-Fetch-Site: none
    Sec-Fetch-User: ?1
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36
    
    bug 
    opened by xy4455 19
  • Versioning

    Versioning

    Would it be possible for you to release a initial version (even if it is 0.1)? Using tags and the github release system. I would like to create a conan package that points to your repo for easy compilation using CMake.

    I have made a pull request to add CMake support. Once you are satisfied with it, it would be nice if you made a release so I can properly add Conan support for master and the first version number.

    enhancement 
    opened by omaralvarez 19
  • DoS/Segfault when request path contains more than 387 characters

    DoS/Segfault when request path contains more than 387 characters

    Due to that someone reported a crash on my app when passing very long parameters to the server i did some deeper investigation.

    It turns out that this is happening in httplib.

    So i tried a bit and was able to verify my finding even with your example server.cc code.

    This is the env im using:

    alpine64:~# g++ --version
    g++ (Alpine 10.2.1_pre1) 10.2.1 20201203
    

    With a not to long path everyting works as expected.

    alpine64:~# g++ server.cc -I. -g -o server
    alpine64:~# ./server
    ================================
    GET HTTP/1.1 /tinypath
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
    Accept-Encoding: gzip, deflate
    Accept-Language: de,en-US;q=0.9,en;q=0.8,es;q=0.7
    Connection: keep-alive
    DNT: 1
    Host: 192.168.0.36:8080
    REMOTE_ADDR: 192.168.0.55
    REMOTE_PORT: 49466
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36
    --------------------------------
    404 HTTP/1.1
    Content-Length: 56
    Content-Type: text/html
    Keep-Alive: timeout=5, max=5
    
    <p>Error Status: <span style='color:red;'>404</span></p>
    

    But using this request it segfaults.

    http://192.168.0.36:8080/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccddddddddddddddddddddddeeeeeeeeeeeeeeeeeeefffffffffffffffffffffffffffffffffffggggggggggggggggggggggggggggg
    
    alpine64:~# ./server
    Segmentation fault (core dumped)
    

    Even without printing the headers.

    The segfault is happening somewhere here:

    #2023 0x00005610ffe76a3c in std::regex_match<char, std::allocator<std::__cxx11::sub_match<char const*> >, std::__cxx11::regex_traits<char> > (__s=0x7f98b1e29e70 "GET /", 'a' <repeats 195 times>..., __m=..., __re=..., __f=0) at /usr/include/c++/10.2.1/bits/regex.h:2229
    #2024 0x00005610ffe6d552 in httplib::Server::parse_request_line (this=0x7fff357a30e0, s=0x7f98b1e29e70 "GET /", 'a' <repeats 195 times>..., req=...) at ./httplib.h:4528
    

    CoreDump is attached.

    core.log

    I'm somehow not able to reproduce this on my Arch, Debian and Ubuntu machine. It might be GCC version related or that alpine is using musl instead of libc. But the binary produced on alpine executed on Debian/Ubuntu/Arch crashs there too with the large request.

    Thanks in advance

    bug 
    opened by Bendr0id 17
  • [Bug] Can't upload file to VirusTotal

    [Bug] Can't upload file to VirusTotal

    Hi, i'm using VirusTotal API in order to check is file malware, so I need to upload file. I tried to do it in that way, but it have not succeeded:

    httplib::Client cli("https://www.virustotal.com");
    
    httplib::Headers headers{
    	{ "Accept", "text/plain" },
    	{ "Content-Type", "application/x-www-form-urlencoded" }
    };
    httplib::MultipartFormDataItems items{
    	{ "apikey", api_key, "", "" },
    	{ "file", std::string(buffer.begin(), buffer.end()), file_name, ""}
    };
    
    auto res = cli.Post("/vtapi/v2/file/scan", headers, items);
    

    The error that I get is: "Write (5)" I tried to do it also in another way and it have not worked too:

    httplib::Client cli("https://www.virustotal.com");
    
    httplib::Headers headers{
    	{ "Accept", "text/plain" },
    	{ "Content-Type", "application/x-www-form-urlencoded" }
    };
    httplib::Params params{
    	{ "apikey", std::string(api_key) },
    	{ "file", "data:name=" + std::string(file_path) + ";base64," + encoded }
    };
    
    auto res = cli.Post("/vtapi/v2/file/scan", headers, params);
    

    Although, I tried to use curl lib and it works great, there is a working code:

    auto params = "apikey=" + std::string(api_key) + "&file=data:name=" + std::string(file_path) + ";base64," + encoded;
    
    CURL* hnd = curl_easy_init();
    curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
    curl_easy_setopt(hnd, CURLOPT_URL, "https://www.virustotal.com/vtapi/v2/file/scan");
    struct curl_slist* headers = NULL;
    headers = curl_slist_append(headers, "Accept: text/plain");
    headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
    curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, params.c_str());
    std::string readBuffer;
    curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &readBuffer);
    CURLcode ret = curl_easy_perform(hnd);
    curl_easy_reset(hnd);
    

    Am I doing something wrong?

    need more information to verify 
    opened by sccoouut 16
  • Remove CMake Warning of

    Remove CMake Warning of "failed to find the latest Git tag"

    If you pull the source code as an archive (e.g.: https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.9.7.tar.gz) you get a CMake warning at:

    CMake Warning at cmake-build-debug/_deps/cpphttplib-src/CMakeLists.txt:78 (message):
      cpp-httplib failed to find the latest Git tag, falling back to using user
      agent as the version.
    

    This is not pretty in our build pipeline. Could you remove this warning?

    opened by theShmoo 16
  • AddressSanitizer: stack-overflow in regex_executor.tcc

    AddressSanitizer: stack-overflow in regex_executor.tcc

    Describe the bug

    AddressSanitizer: stack-overflow in regex_executor.tcc

    To Reproduce

    Built cpp-httplib using clang-10 according to the oss-fuzz script with CXXFLAGS='-O1 -fsanitize=address -fsanitize=array-bounds,bool,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr'

    commit: 696239d6e1fa93d5a5ea8b37fac1a55c2da162fc

    testcase: httplib-server_fuzzer.zip

    ASAN Output (trimmed since it was too long)
    $ ./httplib-server_fuzzer id:000002,sig:11,src:000873,time:46734119,op:havoc,rep:4,trial:4
    Reading 8611 bytes from .id:000002,sig:11,src:000873,time:46734119,op:havoc,rep:4,trial:4
    AddressSanitizer:DEADLYSIGNAL
    =================================================================
    ==2678705==ERROR: AddressSanitizer: stack-overflow on address 0x7fffff7fedc8 (pc 0x00000049ac19 bp 0x7fffff7ff610 sp 0x7fffff7fedd0 T0)
        #0 0x49ac19 in __asan_memcpy (server_fuzzer+0x49ac19)
        #1 0x69c9e6 in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_rep_once_more(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_Match_mode, long) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/regex_executor.tcc:181:18
        #2 0x698da7 in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_handle_repeat(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_Match_mode, long) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/regex_executor.tcc:212:4
        #3 0x698a42 in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_dfs(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_Match_mode, long) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/regex_executor.tcc:515:4
        #4 0x69a694 in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_handle_match(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_Match_mode, long) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/regex_executor.tcc:329:8
        [...]
        #246 0x69cb7d in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_rep_once_more(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_Match_mode, long) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/regex_executor.tcc:184:4
        #247 0x698da7 in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_handle_repeat(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_Match_mode, long) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/regex_executor.tcc:212:4
        #248 0x698a42 in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_dfs(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_Match_mode, long) /usr/lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/regex_executor.tcc:515:4
    
    SUMMARY: AddressSanitizer: stack-overflow (server_fuzzer+0x49ac19) in __asan_memcpy
    ==2678705==ABORTING
    
    
    limitation 
    opened by pietroborrello 22
  • SOCKS5 support

    SOCKS5 support

    Basic SOCKS5 Proxy support. Untested for now, and has still some issues like bounds checking for:

    • username/password
    • hostnames

    @yhirose can you have a look if i'm on the right track?

    opened by tbe 0
  • support custom plugins for HTTP 101 protocol switch

    support custom plugins for HTTP 101 protocol switch

    Adds a way to add handlers for various protocols and support alternate protocols which use HTTP for initial negotiation.

    We will not be responsible for implementing any of those handlers ourselves, but this should at least make it possible for downstream developers to insert their own middleware to partially handle websockets, IRC or other protocols within the same client or server. I have successfully created an example websocket client plugin with bidirectional support, but have not published it as it seems to have problems with high traffic flow and compatibility with some servers.

    opened by PixlRainbow 8
  • Client logging in case of errors

    Client logging in case of errors

    A client calls the logger only in case of successful request completion, no matter the HTTP status is successful or not. However, in case of an error, for example, httplib::Read the logger is not called. As a result, my application log does not contain a log record of a request content. Well, I can of course add this capability to my application logic. But don't you think this could be better addressed in a library, if it in any case supports logging?

    To tell the truth, I don't know what is the correct solution, I'm thinking loud ...

    enhancement 
    opened by miketsts 6
Releases(v0.10.8)
Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and 10K connections problem solution

CppServer Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and

Ivan Shynkarenka 848 Jun 26, 2022
H2O - the optimized HTTP/1, HTTP/2, HTTP/3 server

H2O - an optimized HTTP server with support for HTTP/1.x, HTTP/2 and HTTP/3 (experimental) Copyright (c) 2014-2019 DeNA Co., Ltd., Kazuho Oku, Tatsuhi

H2O 10k Jun 25, 2022
cuehttp is a modern c++ middleware framework for http(http/https)/websocket(ws/wss).

cuehttp 简介 cuehttp是一个使用Modern C++(C++17)编写的跨平台、高性能、易用的HTTP/WebSocket框架。基于中间件模式可以方便、高效、优雅的增加功能。cuehttp基于boost.asio开发,使用picohttpparser进行HTTP协议解析。内部依赖了nl

xcyl 25 Jun 21, 2022
Tiny cross-platform HTTP / HTTPS client library in C.

naett /nɛt:/ Tiny HTTP client library in C. Wraps native HTTP client functionality on macOS, Windows, Linux, iOS and Android in a single, simple non-b

Erik Agsjö 13 Jun 21, 2022
HTTP/HTTPS REST Client C Library

https_client HTTP/HTTPS REST Client C Library This library is a tiny https client library. it use only small memory(default read buffer size(H_READ_SI

HISONA 94 Jun 1, 2022
Graphical small-internet client for windows, linux, MacOS X and BSDs. Supports gemini, http, https, gopher, finger.

Graphical small-internet client for windows, linux, MacOS X and BSDs. Supports gemini, http, https, gopher, finger.

Felix Queißner 536 Jun 24, 2022
Pushpin is a reverse proxy server written in C++ that makes it easy to implement WebSocket, HTTP streaming, and HTTP long-polling services.

Pushpin is a reverse proxy server written in C++ that makes it easy to implement WebSocket, HTTP streaming, and HTTP long-polling services. The project is unique among realtime push solutions in that it is designed to address the needs of API creators. Pushpin is transparent to clients and integrates easily into an API stack.

Fanout 3.1k Jun 22, 2022
Gromox - Groupware server backend with MAPI/HTTP, RPC/HTTP, IMAP, POP3 and PHP-MAPI support for grommunio

Gromox is the central groupware server component of grommunio. It is capable of serving as a replacement for Microsoft Exchange and compatibles. Conne

grommunio 119 Jun 27, 2022
A collection of C++ HTTP libraries including an easy to use HTTP server.

Proxygen: Facebook's C++ HTTP Libraries This project comprises the core C++ HTTP abstractions used at Facebook. Internally, it is used as the basis fo

Facebook 7.5k Jun 25, 2022
websocket and http client and server library, coming with ws, a command line swiss army knife utility

Hello world IXWebSocket is a C++ library for WebSocket client and server development. It has minimal dependencies (no boost), is very simple to use an

Machine Zone, Inc. 320 Jun 22, 2022
Micro http server and client written in C++

httpp Micro http server and client written in C++ The motivation behind this little piece of code is to provide a really simple, yet efficient HTTP se

Thomas Sanchez 154 Jun 5, 2022
A project designed for the esp8266 D1 Mini or the esp8266 D1 Mini PRO to provide a wifi http server and dns server.

PS4 Server 9.00 This is a project designed for the esp8266 D1 Mini or the esp8266 D1 Mini PRO to provide a wifi http server and dns server. this is fo

null 13 Jun 7, 2022
BingBing 53 Jun 10, 2022
Tiny HTTP Server on C, using only standard libraries

hell_o Linux only. Tiny HTTP Server on C, using only standard libraries. It is unfinished yet, going to add working interface and rewrite handler late

null 3 Feb 1, 2022
Asynchronous, Header-only C++ HTTP-over-(TCP|UNIX Socket|STDIO) Library

CXXHTTP A C++ library implementing an asynchronous HTTP server and client. To clone this library, make sure you also clone the submodules. The --recur

null 25 Mar 19, 2021
modern c++(c++17), cross-platform, header-only, easy to use http framework

cinatra--一个高效易用的c++ http框架 English | 中文 目录 使用cinatra常见问题汇总(FAQ) cinatra简介 如何使用 快速示例 性能测试 注意事项 roadmap 联系方式 cinatra简介 cinatra是一个高性能易用的http框架,它是用modern

qicosmos 1.3k Jun 21, 2022
single header C(99) library to implement client-server network code for games

single header C(99) library to implement client-server network code for games

Nathan 217 Jun 16, 2022
A Tcp/Ip stack implementation on top of Solarflare ef_vi, and a C++ headers only framework for tcp multiplexing client/server.

Efvitcp Efvitcp is a tcp library using Solarflare ef_vi interface on linux, and also a tcp multiplexing framework for both C++ client and server progr

Meng Rao 17 Jun 9, 2022
tiny HTTP parser written in C (used in HTTP::Parser::XS et al.)

PicoHTTPParser Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, Shigeo Mitsunari PicoHTTPParser is a tiny, primitive, fast HTTP r

H2O 1.5k Jun 22, 2022