Compare commits

...

116 Commits

Author SHA1 Message Date
yhirose 1cc6930363 Append '_Online' suffix to Unit test names that access external servers 2021-08-23 13:02:19 -04:00
yhirose 4297500928 Fix #1024 2021-08-17 09:28:17 -04:00
Thomas Behn a58f042614 Don't define INVALID_SOCKET if it has been defined already (i.e. by libpcap) (#1021)
Co-authored-by: Thomas Behn <Thomas.Behn@meinberg.de>
2021-08-10 08:29:27 -04:00
yhirose 469c6bc2b6 Fix #1017 2021-08-02 15:44:50 -04:00
Joel Rosdahl 887074efd2 Add test of httplib.h split into .h + .cc (#1015)
In order to test the split version (.h + .cc via split.py):

- Added a test_split program in the test directory whose main purpose is
  to verify that it works to compile and link the test case code against
  the split httplib.h version.
- Moved types needed for test cases to the “header part” of httplib.h.
  Also added forward declarations of functions needed by test cases.
- Added an include_httplib.cc file which is linked together with test.cc
  to verify that inline keywords have not been forgotten.

The changes to httplib.h just move code around (or add forward
declarations), with one exception: detail::split and
detail::process_client_socket have been converted to non-template
functions (taking an std::function instead of using a type parameter for
the function) and forward-declared instead. This avoids having to move
the templates to the “header part”.
2021-07-31 09:53:30 -04:00
Joel Rosdahl 9c2c15ca45 Add missing template method implementations (#1013)
When using the split version of httplib.h the templated implementation
of e.g. Client::set_connection_timeout ends up in httplib.cc and
therefore results in a linker error since the needed template
specialization has not been instantiated. Fix this by moving the
implementation of template methods into the part that ends up in
httplib.h after the split.

Fixes #1008.
2021-07-30 10:05:49 -04:00
Joel Rosdahl 1b3b098329 Avoid hardcoded ports in RedirectToDifferentPort.Redirect test (#1012)
The RedirectToDifferentPort.Redirect test assumes that port 8080 and
8081 are available on localhost. They aren’t on my system so the test
fails. Improve this by binding to available ports instead of hardcoded
ones.
2021-07-30 10:04:02 -04:00
Joel Rosdahl 6f7075e3aa Improve split script (#1011)
- Added shebang and made the script executable.
- Added help text.
- Added -o/--out argument for specifying output directory.
- Added -e/--extension argument for specifying file extension of the
  implementation file.
- Made the script find httplib.h next to split.py instead of the current
  working directory. This makes it possible to call the script from
  another directory.
- Simplified code structure slightly.
- Improved variable naming to follow Python conventions.
2021-07-30 10:03:05 -04:00
yhirose ccbddd8842 Allow LargeRandomData test only on Windows 2021-07-22 22:17:31 -04:00
yosh-matsuda 879dd261c2 Fix gzip compression/decompression over 4 GiB data size (#1002)
* Fix gzip compression/decompression over 4 GiB data size

* Add gzip test for large random data
2021-07-22 22:07:40 -04:00
xxrl 52f5eb5980 [Fix] ca_cert_path/ce_cert_store lose (#1004)
When redirect from http to https, user setting for ca_cert will lose

issue: #1003
2021-07-22 21:41:41 -04:00
Gregor Jasny ea2f69a0d7 Add httplib::Error to std::string function (#999)
Fixes: #978
2021-07-19 21:17:44 -04:00
Gregor Jasny 9f2064a8ed Fix remaining test warnings (#1001)
* Use portable way to encode ESC

'\e' is a GNU extension

* Use length specifier for size_t
2021-07-19 21:17:18 -04:00
yhirose e3750d9ddf Simplefied server APIs 2021-07-17 18:09:30 -04:00
yhirose c1eee3012e Fix #998 2021-07-17 17:18:56 -04:00
Gregor Jasny 6b08babbd2 Use googletest 1.11.0 (#1000)
* Update googletest to version 1.11.0

* Fix test warnings
2021-07-17 13:21:03 -04:00
yhirose 215b81342e Added a test case for #996 2021-07-15 08:24:06 -04:00
yhirose 06bfa7e08b Fix #979 2021-07-14 22:49:49 -04:00
yhirose 3d83cbb872 Improve string compare performance 2021-07-12 23:51:56 -04:00
yhirose 8a803b30f6 Fix #990 2021-07-12 23:46:25 -04:00
yhirose 80be649de7 Fix #961 2021-06-26 18:26:33 -04:00
yhirose 9648f950f5 Updated README 2021-06-18 08:45:50 -04:00
Gregor Jasny 6b9ffc8bec Remove dead code (#965) 2021-06-18 07:20:34 -04:00
Simon Edlund d903053faf Update httplib.h (#964)
operator""_ replaced by operator""_t
2021-06-17 10:57:25 -04:00
yhirose 676f1b5a26 Updated the user agent string 2021-06-14 08:43:12 -04:00
Baruch Nissenbaum b8dec12f15 Limit SSL_ERROR_WANT_READ retries to 1 sec (#957)
retry with 1ms delays to prevent CPU hoggin
2021-06-14 08:41:20 -04:00
yhirose fc9b223acc Updated copyright year 2021-06-11 14:45:35 -04:00
CncGpp ba824089d7 Fix code err code 401 when the password is empty in base_auth. (#958) 2021-06-11 14:39:33 -04:00
Andrea Pappacoda 1a2faf09e0 Add header-only Meson support (#955)
* Add header-only Meson support
This allows users to call `dependency('httplib')` and have the include
directory automatically configured

* Rename `httplib` to `cpp-httplib`
2021-06-05 16:45:00 -04:00
yhirose 5a43bb8149 Implemented #946 in a different way 2021-06-02 13:45:47 -04:00
yhirose 0104614656 Code refactoring 2021-06-02 08:11:31 -04:00
yhirose 77a77f6d2d Added set_default_headers on Server 2021-05-23 19:06:28 -04:00
Mathias Laurin 089b9daa1c Fix virtual call in ClientImpl::~ClientImpl() (#942)
* Fix virtual call in ClientImpl::~ClientImpl()

This fixes a warning in clang tidy:

> Call to virtual method 'ClientImpl::shutdown_ssl' during
> destruction bypasses virtual dispatch

ClientImpl::~ClientImpl() calls lock_socket_and_shutdown_and_close()
that itself calls shutdown_ssl().  However, shutdown_ssl() is virtual
and C++ does not perform virtual dispatch in destructors, which results
in the wrong overload being called.

This change adds a non-virtual shutdown_ssl_impl() function that is
called from ~SSLClient().  We also inline sock_socket_and_shutdown_and_close()
and removes the virtual call in ~ClientImpl().

* Inline and remove lock_socket_and_shutdown_and_close()

The function only has one caller.
2021-05-22 20:15:20 -04:00
yhirose ba34ea4ee8 Fix #944 2021-05-22 19:24:50 -04:00
Baruch Nissenbaum 2917b8a005 Explicit cast from size_t to uInt (#941)
* Explicit cast from size_t to uInt

* static_cast<uInt> instead of C style cast
2021-05-19 18:03:59 -04:00
Joseph Huang dcf24d45a2 fix ssesvr use of deleted function (#938) 2021-05-18 23:19:15 -04:00
yhirose 75fdb06696 Added a missing member in copy_settings. 2021-05-15 09:14:44 -04:00
Alex Hornung e00ad37580 Add option to bypass URL encode of path (#934) 2021-05-15 08:48:25 -04:00
Vincent Stumpf 5cfb70c2b4 Fix some shadowed variable warnings (#935) 2021-05-15 08:46:16 -04:00
Alessio Pollero 2a70c45697 Fix client.cc code, since res.error() without operator overloading… (#921)
* Fix client.cc code, since res.error() without operator overloading causing error in Xcode

* Add unit test to check new error to string with operator overloading

* Add inline as requested in code review comment
2021-05-01 13:29:23 -04:00
Aswin Raj Kharel c58b00580e reserving before encoding (#912) 2021-04-24 16:19:14 -04:00
Ken Schalk 7c60e69c33 Remove redunant call to close_socket (#911) 2021-04-23 17:07:19 -04:00
yhirose 33e94891ee Updated test.cc 2021-04-22 08:04:46 -04:00
yhirose 73e0729f63 Change sink.write() to return boolean 2021-04-22 07:14:08 -04:00
yhirose 21c529229c Fixed timeout issues 2021-04-22 07:14:08 -04:00
yhirose 63643e6386 Code format 2021-04-13 20:52:49 -04:00
yhirose 6cc2edce99 Added set_address_family 2021-04-13 20:49:52 -04:00
yhirose d122ff3ca8 Code formatting 2021-04-13 12:38:45 -04:00
James Young 14c6d526b4 Use newer version-flexible TLS/SSL method (#904) 2021-04-13 09:11:38 -04:00
Philipp Hasper 28e07bca16 Fixed minor code smells (#901) 2021-04-09 14:55:21 -04:00
yhirose faa5f1d802 Additional changes for #889 2021-04-05 16:13:41 -04:00
yhirose 9d3365df54 Fix #889 2021-04-05 11:40:53 -04:00
yhirose 6ff84d34d1 Another simpler implementation of #890 (#891) 2021-04-02 18:25:04 -04:00
yhirose b845425cd0 Fix #878 2021-03-16 19:42:44 -04:00
yhirose 89519c88e2 Fix #874 2021-03-10 15:57:56 -05:00
yhirose ff813bf99d Fix #863 2021-02-17 15:36:56 -05:00
yhirose cf475bcb50 Fix #860 2021-02-12 12:21:43 -05:00
yhirose bc80d7c789 Fixed ClientStop test problem 2021-02-06 20:12:30 -05:00
yhirose b7566f6961 Resolve #852 2021-02-02 22:09:35 -05:00
Nikolas 0542fdb8e4 Add exception handler (#845)
* Add exception handler

* revert content reader changes

* Add test for and fix exception handler

* Fix warning in test

* Readd exception test, improve readme note, don't rethrow errors, remove exception handler response
2021-01-28 17:19:11 -05:00
yhirose 78c474c744 Update README 2021-01-27 11:59:42 -05:00
yhirose 88411a1f52 Fix #846 2021-01-27 14:35:32 +00:00
yhirose ae6cf70bc4 Updated README 2021-01-26 08:38:28 -05:00
yhirose 68d1281759 Resolve #839 2021-01-23 13:33:27 -05:00
yhirose 0308d60cb2 Resolve #831 (#835) 2021-01-23 12:23:06 -05:00
yhirose 59f5fdbb33 Resolve #840 2021-01-23 11:43:01 -05:00
Anonymous 13184f5f80 Return Server& from handler setters (#836)
* Update httplib.h

* Update httplib.h

* Update httplib.h

* Update httplib.h
2021-01-22 09:20:21 -05:00
Eric Lee 8d9a477edb No content check (#823)
* No content check

* unit test for no content

* fixing merge conflict break

* oops during manual merge conflict
2021-01-13 17:51:40 -05:00
yhirose 85b4abbf16 Updated the simple example 2021-01-07 19:56:33 -05:00
yhirose e42a358da8 Updated README 2021-01-07 19:00:24 -05:00
yhirose f008fe4539 Added middleware support (#816) 2021-01-07 18:40:52 -05:00
yhirose ddf41d29ef Added const *char and size_t interface 2021-01-06 22:39:58 -05:00
yhirose 3f88a46c4a Code format 2020-12-31 18:14:28 -05:00
yhirose 242706ea34 Fix #820 2020-12-31 18:14:05 -05:00
yhirose a9f5f8683f Fixed warnings on Visual C++ 2020-12-31 11:35:11 -05:00
yhirose 60c2213893 Fix #817 2020-12-31 10:58:44 -05:00
yhirose eb2d28bca2 Code cleanup 2020-12-31 10:37:06 -05:00
Yuri Santos 86f637a246 Added encode_uri_param tests with UTF-8 characters (#818)
Remove additional lines between tests
2020-12-30 23:06:36 -05:00
yhirose 2c07ec4600 Code cleanup 2020-12-29 09:39:19 -05:00
yhirose 871d8d67b0 Made Request paramater const in handle_file_request 2020-12-28 22:03:44 -05:00
Anonymous 7299713195 Fix readme Response::set_chunked_content_provider (#811)
`Response::set_chunked_content_provider` has formal parameters, not one.
2020-12-25 19:55:57 -05:00
yhirose 96afa7e108 Updated README 2020-12-21 13:40:32 -05:00
yhirose 55f57af0b9 Update README 2020-12-21 09:27:36 -05:00
yhirose 6b35cd0116 Updated README 2020-12-21 08:15:06 -05:00
yhirose 99f2229e48 Updated README 2020-12-19 22:43:31 -05:00
yhirose b9641048fc Switch to hghttp2.org/httpbin for redirect test. (#538) 2020-12-19 20:27:52 -05:00
yhirose e9c6c6e609 Code format 2020-12-19 20:14:53 -05:00
yhirose 40db42108f Fixed problem with invalid requests including spaces in URL path 2020-12-19 12:03:08 -05:00
Anonymous 24bb1387d6 Update README.md (#806) 2020-12-19 11:12:44 -05:00
Jeremie Rahm d0bd4afb0b Ensure socket is closed after processing in SSLServer (#804) 2020-12-18 19:29:36 -05:00
Yuri Santos 78ea786abd [PR] Special function to encode query params (#801)
* Special function to encode query params

* Fix #include <iomanip>

* Added unescaped charsets to encode_query_param

* Unit tests for encode_query_param
2020-12-18 17:51:11 -05:00
Miosame 9cac2c9ceb typo: specitic => specific (#802) 2020-12-18 15:12:21 -05:00
Anonymous 0cff3245df Extend built-in extension MIME mapping (#799)
* Update README.md

* Update httplib.h

* Update httplib.h

* Update httplib.h

* Update httplib.h

* Remove duplicate cases

Someone left a bunch of duplicate cases, idiot, couldn't have been me.

* Reformat

Modify spacing and whatnot

* Update README.md
2020-12-18 09:32:19 -05:00
yhirose 0e3925db3f Fixed build error 2020-12-18 00:07:48 +00:00
yhirose c9a13d214b Changed not to use string_view 2020-12-17 18:48:27 -05:00
yhirose 0954af2d4c Use user-defined literals for file extention match 2020-12-17 18:27:04 -05:00
yhirose 7c1c952f5a Don't allow invalid status code format (It sould be a three-digit code.) 2020-12-15 20:25:24 -05:00
yhirose a6edfc730a Added a unit test for static file with range 2020-12-15 18:47:51 -05:00
yhirose c1264bfedc Fix problem with mp4 w/ Range header 2020-12-14 22:41:05 -05:00
yhirose 90a5b6ceb0 Updated README 2020-12-04 19:39:39 -05:00
yhirose eb240ad2e5 Code cleanup 2020-12-03 16:03:12 -05:00
yhirose 88c961f37e Removed std::atomic<Error> error_ 2020-12-01 15:17:34 +00:00
yhirose b952376968 Fixed warning 2020-12-01 03:50:55 +00:00
yhirose 5dd605d3a2 Fix #762 2020-11-30 21:49:31 -05:00
Seunghwan Hong 9c0c98b1ed Add keep_alive_timeout guide on README.md (#778) 2020-11-30 07:11:22 -05:00
yhirose 615867322d Fixed build errors and apply clangformat 2020-11-29 12:29:18 -05:00
David Wu 02d3cd5909 Fix multiple threading bugs including #699 and #697 2020-11-29 12:29:15 -05:00
yhirose 47e5af15ea Updated README 2020-11-22 09:22:40 -05:00
yhirose a5c239c174 Fix #765 2020-11-21 16:35:31 -05:00
yhirose c2afc5ca44 Added chunked content provider support on client 2020-11-21 08:46:50 -05:00
yhirose cee062d4c9 Fixed unit tests due to the change in #763 2020-11-19 21:04:46 -05:00
Unkorunk b21dc8cbe0 Fix incorrect content_encoding for Brotli (#763) 2020-11-19 12:39:20 -05:00
372046933 e1133a2dcb std::tolower is undefined if the argument's value is neither representable as unsigned char nor equal to EOF (#761)
Co-authored-by: taoxu <taoxu@bilibili.com>
2020-11-19 09:21:40 -05:00
yhirose e273fec93c Fixed Visual Studio setup 2020-11-19 09:17:59 -05:00
yhirose 95d0b073bd Fix #754 2020-11-15 08:13:08 -05:00
vawen 9c7d841b37 Fix: #746 Compile error under VS2015 (#747)
Co-authored-by: jigarcia@vaxtor.es <jigarcia@vaxtor.es>
2020-11-10 08:41:53 -05:00
15 changed files with 16090 additions and 17724 deletions
+2 -2
View File
@@ -26,13 +26,13 @@ jobs:
run: brew install brotli
- name: make
if: matrix.os != 'windows-latest'
run: cd test && make
run: cd test && make -j2
- name: check fuzz test target
if: matrix.os == 'ubuntu-latest'
run: cd test && make -f Makefile.fuzz_test
- name: setup msbuild on windows
if: matrix.os == 'windows-latest'
uses: warrenbuckley/Setup-MSBuild@v1
uses: microsoft/setup-msbuild@v1.0.2
- name: make-windows
if: matrix.os == 'windows-latest'
run: |
+3
View File
@@ -10,8 +10,11 @@ example/redirect
example/sse*
example/upload
example/*.pem
test/httplib.cc
test/httplib.h
test/test
test/test_proxy
test/test_split
test/test.xcodeproj/xcuser*
test/test.xcodeproj/*/xcuser*
test/*.pem
+146 -56
View File
@@ -5,9 +5,9 @@ cpp-httplib
A C++11 single-file header-only cross platform HTTP/HTTPS library.
It's extremely easy to setup. Just include **httplib.h** file in your code!
It's extremely easy to setup. Just include the **httplib.h** file in your code!
NOTE: This is a 'blocking' HTTP library. If you are looking for a 'non-blocking' library, this is not the one that you want.
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
---------------
@@ -15,8 +15,15 @@ Simple examples
#### Server
```c++
#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");
});
@@ -27,12 +34,18 @@ svr.listen("0.0.0.0", 8080);
#### Client
```c++
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"
// HTTP
httplib::Client cli("http://cpp-httplib-server.yhirose.repl.co");
auto res = cli.Get("/hi");
// HTTPS
httplib::Client cli("https://cpp-httplib-server.yhirose.repl.co");
res->status; // 200
res->body; // "Hello World!"
auto res = cli.Get("/hi");
res->status;
res->body;
```
### Try out the examples on Repl.it!
@@ -40,6 +53,33 @@ res->body; // "Hello World!"
1. Run server at https://repl.it/@yhirose/cpp-httplib-server
2. Run client at https://repl.it/@yhirose/cpp-httplib-client
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.
```c++
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"
// Server
httplib::SSLServer svr("./cert.pem", "./key.pem");
// Client
httplib::Client cli("https://localhost:1234"); // scheme + host
httplib::SSLClient cli("localhost:1234"); // host
// 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.
Server
------
@@ -120,24 +160,30 @@ svr.set_file_extension_and_mimetype_mapping("hh", "text/x-h");
The followings are built-in mappings:
| Extension | MIME Type |
| :-------- | :--------------------- |
| txt | text/plain |
| html, htm | text/html |
| css | text/css |
| jpeg, jpg | image/jpg |
| png | image/png |
| gif | image/gif |
| svg | image/svg+xml |
| ico | image/x-icon |
| json | application/json |
| pdf | application/pdf |
| js | application/javascript |
| wasm | application/wasm |
| xml | application/xml |
| xhtml | application/xhtml+xml |
| 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 the static file server methods are not thread safe.
NOTE: These static file server methods are not thread-safe.
### Logging
@@ -158,6 +204,39 @@ svr.set_error_handler([](const auto& req, auto& res) {
});
```
### Exception handler
The exception handler gets called if a user routing handler throws an error.
```cpp
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
```cpp
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
```cpp
svr.set_post_routing_handler([](const auto& req, auto& res) {
res.set_header("ADDITIONAL_HEADER", "value");
});
```
### 'multipart/form-data' POST data
```cpp
@@ -171,12 +250,13 @@ svr.Post("/multipart", [&](const auto& req, auto& res) {
});
```
### Receive content with Content receiver
### Receive content with a content receiver
```cpp
svr.Post("/content_receiver",
[&](const Request &req, Response &res, const ContentReader &content_reader) {
if (req.is_multipart_form_data()) {
// NOTE: `content_reader` is blocking until every form data field is read
MultipartFormDataItems files;
content_reader(
[&](const MultipartFormData &file) {
@@ -193,12 +273,11 @@ svr.Post("/content_receiver",
body.append(data, data_length);
return true;
});
res.set_content(body, "text/plain");
}
});
```
### Send content with Content provider
### Send content with the content provider
```cpp
const size_t DATA_CHUNK_SIZE = 4;
@@ -214,7 +293,7 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
return true; // return 'false' if you want to cancel the process.
},
[data] { delete data; });
[data](bool success) { delete data; });
});
```
@@ -242,6 +321,7 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
```cpp
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);
@@ -255,7 +335,7 @@ svr.Get("/chunked", [&](const Request& req, Response& res) {
### 'Expect: 100-continue' handler
As default, the server sends `100 Continue` response for `Expect: 100-continue` header.
By default, the server sends a `100 Continue` response for an `Expect: 100-continue` header.
```cpp
// Send a '417 Expectation Failed' response.
@@ -275,6 +355,7 @@ svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
```cpp
svr.set_keep_alive_max_count(2); // Default is 5
svr.set_keep_alive_timeout(10); // Default is 5
```
### Timeout
@@ -285,7 +366,7 @@ svr.set_write_timeout(5, 0); // 5 seconds
svr.set_idle_interval(0, 100000); // 100 milliseconds
```
### Set maximum payload length for reading request body
### Set maximum payload length for reading a request body
```c++
svr.set_payload_max_length(1024 * 1024 * 512); // 512MB
@@ -363,6 +444,7 @@ 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
@@ -470,7 +552,7 @@ cli.set_read_timeout(5, 0); // 5 seconds
cli.set_write_timeout(5, 0); // 5 seconds
```
### Receive content with Content receiver
### Receive content with a content receiver
```c++
std::string body;
@@ -497,12 +579,12 @@ auto res = cli.Get(
});
```
### Send content with Content provider
### Send content with a content provider
```cpp
std::string body = ...;
auto res = cli_.Post(
auto res = cli.Post(
"/stream", body.size(),
[](size_t offset, size_t length, DataSink &sink) {
sink.write(body.data() + offset, length);
@@ -511,6 +593,21 @@ auto res = cli_.Post(
"text/plain");
```
### Chunked transfer encoding
```cpp
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
```cpp
@@ -605,7 +702,7 @@ res = cli.Get("/");
res->status; // 200
```
### Use a specitic network interface
### Use a specific network interface
NOTE: This feature is not available on Windows, yet.
@@ -613,27 +710,10 @@ NOTE: This feature is not available on Windows, yet.
cli.set_interface("eth0"); // Interface name, IP address or host name
```
OpenSSL 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.
```c++
#define CPPHTTPLIB_OPENSSL_SUPPORT
httplib::SSLServer svr("./cert.pem", "./key.pem");
httplib::SSLClient cli("localhost", 1234); // or `httplib::Client cli("https://localhost:1234");`
cli.set_ca_cert_path("./ca-bundle.crt");
cli.enable_server_certificate_verification(true);
```
Compression
-----------
The server can applie compression to the following MIME type contents:
The server can apply compression to the following MIME type contents:
* all text types except text/event-stream
* image/svg+xml
@@ -669,10 +749,20 @@ res->body; // Compressed data
Split httplib.h into .h and .cc
-------------------------------
```bash
> python3 split.py
> ls out
httplib.h httplib.cc
```console
$ ./split.py -h
usage: split.py [-h] [-e EXTENSION] [-o OUT]
This script splits httplib.h into .h and .cc parts.
optional arguments:
-h, --help show this help message and exit
-e EXTENSION, --extension EXTENSION
extension of the implementation file (default: cc)
-o OUT, --out OUT where to write the files (default: out)
$ ./split.py
Wrote out/httplib.h and out/httplib.cc
```
NOTE
@@ -697,12 +787,12 @@ Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32
#include <httplib.h>
```
Note: Cygwin on Windows is not supported.
Note: Windows 8 or lower and Cygwin on Windows are not supported.
License
-------
MIT license (© 2020 Yuji Hirose)
MIT license (© 2021 Yuji Hirose)
Special Thanks To
-----------------
+2 -11
View File
@@ -1,10 +1,3 @@
//
// sse.cc
//
// Copyright (c) 2020 Yuji Hirose. All rights reserved.
// MIT License
//
#include <atomic>
#include <chrono>
#include <condition_variable>
@@ -20,8 +13,6 @@ using namespace std;
class EventDispatcher {
public:
EventDispatcher() {
id_ = 0;
cid_ = -1;
}
void wait_event(DataSink *sink) {
@@ -41,8 +32,8 @@ public:
private:
mutex m_;
condition_variable cv_;
atomic_int id_;
atomic_int cid_;
atomic_int id_{0};
atomic_int cid_{-1};
string message_;
};
+2097 -936
View File
File diff suppressed because it is too large Load Diff
+7
View File
@@ -0,0 +1,7 @@
project('cpp-httplib', 'cpp', license: 'MIT')
cpp_httplib_dep = declare_dependency(include_directories: include_directories('.'))
if meson.version().version_compare('>=0.54.0')
meson.override_dependency('cpp-httplib', cpp_httplib_dep)
endif
Regular → Executable
+40 -25
View File
@@ -1,32 +1,47 @@
#!/usr/bin/env python3
"""This script splits httplib.h into .h and .cc parts."""
import argparse
import os
import sys
border = '// ----------------------------------------------------------------------------'
PythonVersion = sys.version_info[0];
args_parser = argparse.ArgumentParser(description=__doc__)
args_parser.add_argument(
"-e", "--extension", help="extension of the implementation file (default: cc)",
default="cc"
)
args_parser.add_argument(
"-o", "--out", help="where to write the files (default: out)", default="out"
)
args = args_parser.parse_args()
with open('httplib.h') as f:
cur_dir = os.path.dirname(sys.argv[0])
with open(cur_dir + '/httplib.h') as f:
lines = f.readlines()
inImplementation = False
if PythonVersion < 3:
os.makedirs('out')
else:
os.makedirs('out', exist_ok=True)
with open('out/httplib.h', 'w') as fh:
with open('out/httplib.cc', 'w') as fc:
fc.write('#include "httplib.h"\n')
fc.write('namespace httplib {\n')
for line in lines:
isBorderLine = border in line
if isBorderLine:
inImplementation = not inImplementation
else:
if inImplementation:
fc.write(line.replace('inline ', ''))
pass
else:
fh.write(line)
pass
fc.write('} // namespace httplib\n')
python_version = sys.version_info[0]
if python_version < 3:
os.makedirs(args.out)
else:
os.makedirs(args.out, exist_ok=True)
in_implementation = False
h_out = args.out + '/httplib.h'
cc_out = args.out + '/httplib.' + args.extension
with open(h_out, 'w') as fh, open(cc_out, 'w') as fc:
fc.write('#include "httplib.h"\n')
fc.write('namespace httplib {\n')
for line in lines:
is_border_line = border in line
if is_border_line:
in_implementation = not in_implementation
elif in_implementation:
fc.write(line.replace('inline ', ''))
else:
fh.write(line)
fc.write('} // namespace httplib\n')
print("Wrote {} and {}".format(h_out, cc_out))
+16 -6
View File
@@ -1,5 +1,5 @@
#CXX = clang++
CXXFLAGS = -g -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits -Wconversion #-fsanitize=address
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion #-fsanitize=address
OPENSSL_DIR = /usr/local/opt/openssl@1.1
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
@@ -9,17 +9,27 @@ ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
BROTLI_DIR = /usr/local/opt/brotli
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
all : test
TEST_ARGS = gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
all : test test_split
./test
# Note: The intention of test_split is to verify that it works to compile and
# link the split httplib.h, so there is normally no need to execute it.
proxy : test_proxy
./test_proxy
test : test.cc ../httplib.h Makefile cert.pem
$(CXX) -o test $(CXXFLAGS) test.cc gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
test : test.cc include_httplib.cc ../httplib.h Makefile cert.pem
$(CXX) -o $@ -I.. $(CXXFLAGS) test.cc include_httplib.cc $(TEST_ARGS)
test_split : test.cc ../httplib.h httplib.cc Makefile cert.pem
$(CXX) -o $@ $(CXXFLAGS) test.cc httplib.cc $(TEST_ARGS)
test_proxy : test_proxy.cc ../httplib.h Makefile cert.pem
$(CXX) -o test_proxy $(CXXFLAGS) test_proxy.cc gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
$(CXX) -o $@ -I.. $(CXXFLAGS) test_proxy.cc $(TEST_ARGS)
httplib.cc : ../httplib.h
python3 ../split.py -o .
cert.pem:
openssl genrsa 2048 > key.pem
@@ -32,4 +42,4 @@ cert.pem:
#c_rehash .
clean:
rm -f test test_proxy pem *.0 *.1 *.srl
rm -f test test_proxy pem *.0 *.1 *.srl httplib.h httplib.cc
+37 -37
View File
@@ -1,28 +1,26 @@
#include <memory>
#include <httplib.h>
#include <memory>
class FuzzedStream : public httplib::Stream {
public:
FuzzedStream(const uint8_t* data, size_t size)
public:
FuzzedStream(const uint8_t *data, size_t size)
: data_(data), size_(size), read_pos_(0) {}
ssize_t read(char* ptr, size_t size) override {
if (size + read_pos_ > size_) {
size = size_ - read_pos_;
}
ssize_t read(char *ptr, size_t size) override {
if (size + read_pos_ > size_) { size = size_ - read_pos_; }
memcpy(ptr, data_ + read_pos_, size);
read_pos_ += size;
return size;
return static_cast<ssize_t>(size);
}
ssize_t write(const char* ptr, size_t size) override {
ssize_t write(const char *ptr, size_t size) override {
response_.append(ptr, size);
return static_cast<int>(size);
}
int write(const char* ptr) { return write(ptr, strlen(ptr)); }
ssize_t write(const char *ptr) { return write(ptr, strlen(ptr)); }
int write(const std::string& s) { return write(s.data(), s.size()); }
ssize_t write(const std::string &s) { return write(s.data(), s.size()); }
std::string get_remote_addr() const { return ""; }
@@ -35,16 +33,18 @@ class FuzzedStream : public httplib::Stream {
port = 8080;
}
private:
const uint8_t* data_;
socket_t socket() const override { return 0; }
private:
const uint8_t *data_;
size_t size_;
size_t read_pos_;
std::string response_;
};
class FuzzableServer : public httplib::Server {
public:
void ProcessFuzzedRequest(FuzzedStream& stream) {
public:
void ProcessFuzzedRequest(FuzzedStream &stream) {
bool connection_close = false;
process_request(stream, /*last_connection=*/false, connection_close,
nullptr);
@@ -53,36 +53,36 @@ class FuzzableServer : public httplib::Server {
static FuzzableServer g_server;
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
extern "C" int LLVMFuzzerInitialize(int * /*argc*/, char *** /*argv*/) {
g_server.Get(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
[&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
g_server.Post(R"(.*)",
[&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
g_server.Post(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
g_server.Put(R"(.*)",
[&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
g_server.Patch(R"(.*)",
[&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
g_server.Put(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Patch(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Delete(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Options(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Delete(
R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
g_server.Options(
R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedStream stream{data, size};
g_server.ProcessFuzzedRequest(stream);
return 0;
}
}
+5790 -2420
View File
File diff suppressed because it is too large Load Diff
+6845 -14038
View File
File diff suppressed because it is too large Load Diff
+19 -4
View File
@@ -27,13 +27,28 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <cstdio>
#include "gtest/gtest.h"
GTEST_API_ int main(int argc, char **argv) {
std::cout << "Running main() from gtest_main.cc\n";
#if GTEST_OS_ESP8266 || GTEST_OS_ESP32
#if GTEST_OS_ESP8266
extern "C" {
#endif
void setup() {
testing::InitGoogleTest();
}
void loop() { RUN_ALL_TESTS(); }
#if GTEST_OS_ESP8266
}
#endif
#else
GTEST_API_ int main(int argc, char **argv) {
printf("Running main() from %s\n", __FILE__);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#endif
+5
View File
@@ -0,0 +1,5 @@
// The sole purpose of this file is to include httplib.h in a separate
// compilation unit, thus verifying that inline keywords have not been forgotten
// when linked together with test.cc.
#include <httplib.h>
+1054 -159
View File
File diff suppressed because it is too large Load Diff
+27 -30
View File
@@ -8,29 +8,29 @@ using namespace httplib;
template <typename T>
void ProxyTest(T& cli, bool basic) {
cli.set_proxy("localhost", basic ? 3128 : 3129);
auto res = cli.Get("/get");
auto res = cli.Get("/httpbin/get");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(407, res->status);
}
TEST(ProxyTest, NoSSLBasic) {
Client cli("httpbin.org");
Client cli("nghttp2.org");
ProxyTest(cli, true);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(ProxyTest, SSLBasic) {
SSLClient cli("httpbin.org");
SSLClient cli("nghttp2.org");
ProxyTest(cli, true);
}
TEST(ProxyTest, NoSSLDigest) {
Client cli("httpbin.org");
Client cli("nghttp2.org");
ProxyTest(cli, false);
}
TEST(ProxyTest, SSLDigest) {
SSLClient cli("httpbin.org");
SSLClient cli("nghttp2.org");
ProxyTest(cli, false);
}
#endif
@@ -54,29 +54,27 @@ void RedirectProxyText(T& cli, const char *path, bool basic) {
EXPECT_EQ(200, res->status);
}
#if 0
TEST(RedirectTest, HTTPBinNoSSLBasic) {
Client cli("httpbin.org");
RedirectProxyText(cli, "/redirect/2", true);
Client cli("nghttp2.org");
RedirectProxyText(cli, "/httpbin/redirect/2", true);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(RedirectTest, HTTPBinNoSSLDigest) {
Client cli("httpbin.org");
RedirectProxyText(cli, "/redirect/2", false);
Client cli("nghttp2.org");
RedirectProxyText(cli, "/httpbin/redirect/2", false);
}
TEST(RedirectTest, HTTPBinSSLBasic) {
SSLClient cli("httpbin.org");
RedirectProxyText(cli, "/redirect/2", true);
SSLClient cli("nghttp2.org");
RedirectProxyText(cli, "/httpbin/redirect/2", true);
}
TEST(RedirectTest, HTTPBinSSLDigest) {
SSLClient cli("httpbin.org");
RedirectProxyText(cli, "/redirect/2", false);
SSLClient cli("nghttp2.org");
RedirectProxyText(cli, "/httpbin/redirect/2", false);
}
#endif
#endif
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(RedirectTest, YouTubeNoSSLBasic) {
@@ -218,7 +216,8 @@ TEST(DigestAuthTest, NoSSL) {
// ----------------------------------------------------------------------------
void KeepAliveTest(Client& cli, bool basic) {
template <typename T>
void KeepAliveTest(T& cli, bool basic) {
cli.set_proxy("localhost", basic ? 3128 : 3129);
if (basic) {
cli.set_proxy_basic_auth("hello", "world");
@@ -234,20 +233,20 @@ void KeepAliveTest(Client& cli, bool basic) {
#endif
{
auto res = cli.Get("/get");
auto res = cli.Get("/httpbin/get");
EXPECT_EQ(200, res->status);
}
{
auto res = cli.Get("/redirect/2");
auto res = cli.Get("/httpbin/redirect/2");
EXPECT_EQ(200, res->status);
}
{
std::vector<std::string> paths = {
"/digest-auth/auth/hello/world/MD5",
"/digest-auth/auth/hello/world/SHA-256",
"/digest-auth/auth/hello/world/SHA-512",
"/digest-auth/auth-int/hello/world/MD5",
"/httpbin/digest-auth/auth/hello/world/MD5",
"/httpbin/digest-auth/auth/hello/world/SHA-256",
"/httpbin/digest-auth/auth/hello/world/SHA-512",
"/httpbin/digest-auth/auth-int/hello/world/MD5",
};
for (auto path: paths) {
@@ -258,34 +257,32 @@ void KeepAliveTest(Client& cli, bool basic) {
}
{
int count = 100;
int count = 10;
while (count--) {
auto res = cli.Get("/get");
auto res = cli.Get("/httpbin/get");
EXPECT_EQ(200, res->status);
}
}
}
#if 0
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(KeepAliveTest, NoSSLWithBasic) {
Client cli("httpbin.org");
Client cli("nghttp2.org");
KeepAliveTest(cli, true);
}
TEST(KeepAliveTest, SSLWithBasic) {
SSLClient cli("httpbin.org");
SSLClient cli("nghttp2.org");
KeepAliveTest(cli, true);
}
TEST(KeepAliveTest, NoSSLWithDigest) {
Client cli("httpbin.org");
Client cli("nghttp2.org");
KeepAliveTest(cli, false);
}
TEST(KeepAliveTest, SSLWithDigest) {
SSLClient cli("httpbin.org");
SSLClient cli("nghttp2.org");
KeepAliveTest(cli, false);
}
#endif
#endif