mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
285 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d87abeecf0 | |||
| 4e28e4f741 | |||
| 80a55cedeb | |||
| d05c343602 | |||
| 33f67386fe | |||
| 56d8168dc4 | |||
| 5d87cc0558 | |||
| cb41947eb4 | |||
| 0857eba17b | |||
| 020b0db090 | |||
| bf0760fde4 | |||
| bb8e45383e | |||
| a1df576e4f | |||
| 7fb0254794 | |||
| c82d1e52cc | |||
| 846151b605 | |||
| e44e31dd5b | |||
| f7b9501662 | |||
| e12fe4cbbb | |||
| 49d2e1f135 | |||
| 8191fd8e6c | |||
| d73395e1dc | |||
| 64d001162b | |||
| bb00a23116 | |||
| 63d6e9b91b | |||
| 66eed5681a | |||
| 8ecdb11979 | |||
| 894fcc8e02 | |||
| 7f43f0f3ff | |||
| 87e03dd1ce | |||
| e5cacb465d | |||
| ee8371f753 | |||
| 081723f983 | |||
| b61f36579c | |||
| 33f53aa458 | |||
| 412ab5f063 | |||
| 11e02e901c | |||
| 65a8f4cf44 | |||
| 27d128bbb4 | |||
| 070f9bec58 | |||
| f817032513 | |||
| 17abe221c0 | |||
| 4a7a81e039 | |||
| 37fd4eb643 | |||
| 865b0e4c03 | |||
| b324921c1a | |||
| 63f72caf30 | |||
| 99ac17b90a | |||
| 4b0ed9ee88 | |||
| 20056f6cda | |||
| 3b35279b16 | |||
| 27deb44df5 | |||
| 24a3ef949b | |||
| bc3e098964 | |||
| c247dcdd7b | |||
| 793ae9855e | |||
| 9fa426d51b | |||
| cec6288a99 | |||
| 9639578c2a | |||
| 743ecbd365 | |||
| 084c643973 | |||
| 824e7682e4 | |||
| f9074684dd | |||
| ddff782133 | |||
| 3051152103 | |||
| 06026bb47d | |||
| 226388ae27 | |||
| ea7548b4cc | |||
| c7486ead96 | |||
| 90a291214c | |||
| c111c42a86 | |||
| 6fb5b63018 | |||
| ec56dfa35e | |||
| 943cd51b67 | |||
| 301faa074c | |||
| dc0481e832 | |||
| 4f8fcdbaf7 | |||
| b80aa7fee3 | |||
| c384be02c9 | |||
| d17ac3bb40 | |||
| c7554ccac2 | |||
| 35ef1c7bae | |||
| d87d0672a8 | |||
| 3da42fd1e8 | |||
| 503aa61325 | |||
| e4c276d0c2 | |||
| e07f7691a8 | |||
| 623ab4a96e | |||
| e1efa337a2 | |||
| 549cdf2f7d | |||
| 3c522386e9 | |||
| c202aa9ce9 | |||
| e3e28c6231 | |||
| 4e05368086 | |||
| e1afe74fe2 | |||
| 461acb02f5 | |||
| 415edc237c | |||
| e20ecd2574 | |||
| ab477b5631 | |||
| 0823d5c7f2 | |||
| 1cc6930363 | |||
| 4297500928 | |||
| a58f042614 | |||
| 469c6bc2b6 | |||
| 887074efd2 | |||
| 9c2c15ca45 | |||
| 1b3b098329 | |||
| 6f7075e3aa | |||
| ccbddd8842 | |||
| 879dd261c2 | |||
| 52f5eb5980 | |||
| ea2f69a0d7 | |||
| 9f2064a8ed | |||
| e3750d9ddf | |||
| c1eee3012e | |||
| 6b08babbd2 | |||
| 215b81342e | |||
| 06bfa7e08b | |||
| 3d83cbb872 | |||
| 8a803b30f6 | |||
| 80be649de7 | |||
| 9648f950f5 | |||
| 6b9ffc8bec | |||
| d903053faf | |||
| 676f1b5a26 | |||
| b8dec12f15 | |||
| fc9b223acc | |||
| ba824089d7 | |||
| 1a2faf09e0 | |||
| 5a43bb8149 | |||
| 0104614656 | |||
| 77a77f6d2d | |||
| 089b9daa1c | |||
| ba34ea4ee8 | |||
| 2917b8a005 | |||
| dcf24d45a2 | |||
| 75fdb06696 | |||
| e00ad37580 | |||
| 5cfb70c2b4 | |||
| 2a70c45697 | |||
| c58b00580e | |||
| 7c60e69c33 | |||
| 33e94891ee | |||
| 73e0729f63 | |||
| 21c529229c | |||
| 63643e6386 | |||
| 6cc2edce99 | |||
| d122ff3ca8 | |||
| 14c6d526b4 | |||
| 28e07bca16 | |||
| faa5f1d802 | |||
| 9d3365df54 | |||
| 6ff84d34d1 | |||
| b845425cd0 | |||
| 89519c88e2 | |||
| ff813bf99d | |||
| cf475bcb50 | |||
| bc80d7c789 | |||
| b7566f6961 | |||
| 0542fdb8e4 | |||
| 78c474c744 | |||
| 88411a1f52 | |||
| ae6cf70bc4 | |||
| 68d1281759 | |||
| 0308d60cb2 | |||
| 59f5fdbb33 | |||
| 13184f5f80 | |||
| 8d9a477edb | |||
| 85b4abbf16 | |||
| e42a358da8 | |||
| f008fe4539 | |||
| ddf41d29ef | |||
| 3f88a46c4a | |||
| 242706ea34 | |||
| a9f5f8683f | |||
| 60c2213893 | |||
| eb2d28bca2 | |||
| 86f637a246 | |||
| 2c07ec4600 | |||
| 871d8d67b0 | |||
| 7299713195 | |||
| 96afa7e108 | |||
| 55f57af0b9 | |||
| 6b35cd0116 | |||
| 99f2229e48 | |||
| b9641048fc | |||
| e9c6c6e609 | |||
| 40db42108f | |||
| 24bb1387d6 | |||
| d0bd4afb0b | |||
| 78ea786abd | |||
| 9cac2c9ceb | |||
| 0cff3245df | |||
| 0e3925db3f | |||
| c9a13d214b | |||
| 0954af2d4c | |||
| 7c1c952f5a | |||
| a6edfc730a | |||
| c1264bfedc | |||
| 90a5b6ceb0 | |||
| eb240ad2e5 | |||
| 88c961f37e | |||
| b952376968 | |||
| 5dd605d3a2 | |||
| 9c0c98b1ed | |||
| 615867322d | |||
| 02d3cd5909 | |||
| 47e5af15ea | |||
| a5c239c174 | |||
| c2afc5ca44 | |||
| cee062d4c9 | |||
| b21dc8cbe0 | |||
| e1133a2dcb | |||
| e273fec93c | |||
| 95d0b073bd | |||
| 9c7d841b37 | |||
| f086bf5310 | |||
| 6613d7b7ad | |||
| 6adf130bf3 | |||
| b6b2eaf5bc | |||
| eb4b7c70a9 | |||
| 84661ea6ed | |||
| 041122908c | |||
| 401de608df | |||
| 726c64cf10 | |||
| e1f781a21a | |||
| 72b81badad | |||
| 17428a8fbf | |||
| 6e1879dfae | |||
| eb1d2e04bc | |||
| c909ffa758 | |||
| ff5677ad19 | |||
| 8b1b31ac20 | |||
| 953600c177 | |||
| 536e7eb7f2 | |||
| 6d66721ba1 | |||
| 3b29cd0bdc | |||
| 109b624dfe | |||
| 0ed70c4d9f | |||
| a50b7591ca | |||
| bf8fc11b53 | |||
| bc4a613b6d | |||
| 4bb001351c | |||
| e155ba44bb | |||
| a4a9637738 | |||
| 5292142046 | |||
| cc5147ad72 | |||
| fffbf1a669 | |||
| d37bc0fb4d | |||
| 6d60dc8839 | |||
| b713a3a651 | |||
| 7e8db1dc68 | |||
| 316add860b | |||
| 79ce6f1745 | |||
| 09fdf4eacd | |||
| 143b2dd15a | |||
| e2c4e9d95c | |||
| d87082f04b | |||
| cc14855ba0 | |||
| 56c418745f | |||
| 4ce9911837 | |||
| 559c407552 | |||
| a2f4e29a7b | |||
| b8cf739d27 | |||
| aec2f9521d | |||
| 7b55ecdc59 | |||
| e9575bcb78 | |||
| 308aeb187b | |||
| 05d18f2bc5 | |||
| 3da4a0ac69 | |||
| 9d12b3f20e | |||
| 852a374748 | |||
| 3b5bab3308 | |||
| 69e75f4a67 | |||
| b0fd4befb1 | |||
| 3e80666a74 | |||
| 3e4567bae8 | |||
| db075d8cf9 | |||
| 16df0ef37e | |||
| f1a2ac5108 | |||
| e5743b358d | |||
| 1184bbe4cb | |||
| 9dcffda7ae | |||
| e5903635e2 | |||
| 510b4eaaae |
@@ -0,0 +1,26 @@
|
||||
name: CIFuzz
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Build Fuzzers
|
||||
id: build
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'cpp-httplib'
|
||||
dry-run: false
|
||||
language: c++
|
||||
- name: Run Fuzzers
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'cpp-httplib'
|
||||
fuzz-seconds: 600
|
||||
dry-run: false
|
||||
language: c++
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: artifacts
|
||||
path: ./out/artifacts
|
||||
@@ -20,16 +20,19 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
- name: install brotli library on ubuntu
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt-get install -y libbrotli-dev
|
||||
run: sudo apt update && sudo apt-get install -y libbrotli-dev
|
||||
- name: install brotli library on macOS
|
||||
if: matrix.os == 'macOS-latest'
|
||||
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 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: |
|
||||
|
||||
@@ -10,10 +10,15 @@ example/redirect
|
||||
example/sse*
|
||||
example/upload
|
||||
example/*.pem
|
||||
test/httplib.cc
|
||||
test/httplib.h
|
||||
test/test
|
||||
test/server_fuzzer
|
||||
test/test_proxy
|
||||
test/test_split
|
||||
test/test.xcodeproj/xcuser*
|
||||
test/test.xcodeproj/*/xcuser*
|
||||
test/*.o
|
||||
test/*.pem
|
||||
test/*.srl
|
||||
|
||||
|
||||
+12
-22
@@ -60,26 +60,11 @@
|
||||
]]
|
||||
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
|
||||
|
||||
# On systems without Git installed, there were errors since execute_process seemed to not throw an error without it?
|
||||
find_package(Git QUIET)
|
||||
if(Git_FOUND)
|
||||
# Gets the latest tag as a string like "v0.6.6"
|
||||
# Can silently fail if git isn't on the system
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0
|
||||
OUTPUT_VARIABLE _raw_version_string
|
||||
ERROR_VARIABLE _git_tag_error
|
||||
)
|
||||
endif()
|
||||
# Get the CPPHTTPLIB_VERSION value and use it as a version
|
||||
# This gets the string with the CPPHTTPLIB_VERSION value from the header.
|
||||
# This is so the maintainer doesn't actually need to update this manually.
|
||||
file(STRINGS httplib.h _raw_version_string REGEX "CPPHTTPLIB_VERSION \"([0-9]+\\.[0-9]+\\.[0-9]+)\"")
|
||||
|
||||
# execute_process can fail silenty, so check for an error
|
||||
# if there was an error, just use the user agent as a version
|
||||
if(_git_tag_error OR NOT Git_FOUND)
|
||||
message(WARNING "cpp-httplib failed to find the latest Git tag, falling back to using user agent as the version.")
|
||||
# Get the user agent and use it as a version
|
||||
# This gets the string with the user agent from the header.
|
||||
# This is so the maintainer doesn't actually need to update this manually.
|
||||
file(STRINGS httplib.h _raw_version_string REGEX "User\-Agent.*cpp\-httplib/([0-9]+\.?)+")
|
||||
endif()
|
||||
# Needed since git tags have "v" prefixing them.
|
||||
# Also used if the fallback to user agent string is being used.
|
||||
string(REGEX MATCH "([0-9]+\\.?)+" _httplib_version "${_raw_version_string}")
|
||||
@@ -187,6 +172,11 @@ if(HTTPLIB_COMPILE)
|
||||
$<BUILD_INTERFACE:${_httplib_build_includedir}/httplib.h>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/httplib.h>
|
||||
)
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
VERSION ${${PROJECT_NAME}_VERSION}
|
||||
SOVERSION ${${PROJECT_NAME}_VERSION_MAJOR}
|
||||
)
|
||||
else()
|
||||
# This is for header-only.
|
||||
set(_INTERFACE_OR_PUBLIC INTERFACE)
|
||||
@@ -235,9 +225,9 @@ target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
|
||||
# Set the definitions to enable optional features
|
||||
target_compile_definitions(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_BROTLI}>:"CPPHTTPLIB_BROTLI_SUPPORT">
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_ZLIB}>:"CPPHTTPLIB_ZLIB_SUPPORT">
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_OPENSSL}>:"CPPHTTPLIB_OPENSSL_SUPPORT">
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_BROTLI}>:CPPHTTPLIB_BROTLI_SUPPORT>
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_ZLIB}>:CPPHTTPLIB_ZLIB_SUPPORT>
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_OPENSSL}>:CPPHTTPLIB_OPENSSL_SUPPORT>
|
||||
)
|
||||
|
||||
# Cmake's find_package search path is different based on the system
|
||||
|
||||
@@ -5,10 +5,78 @@ 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!
|
||||
|
||||
Server Example
|
||||
--------------
|
||||
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
|
||||
|
||||
```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");
|
||||
});
|
||||
|
||||
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");
|
||||
|
||||
// HTTPS
|
||||
httplib::Client cli("https://cpp-httplib-server.yhirose.repl.co");
|
||||
|
||||
auto res = cli.Get("/hi");
|
||||
res->status;
|
||||
res->body;
|
||||
```
|
||||
|
||||
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
|
||||
------
|
||||
|
||||
```c++
|
||||
#include <httplib.h>
|
||||
@@ -87,24 +155,39 @@ 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.
|
||||
### File request handler
|
||||
|
||||
```cpp
|
||||
// The handler is called right before the response is sent to a client
|
||||
svr.set_file_request_handler([](const Request &req, Response &res) {
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
NOTE: These static file server methods are not thread-safe.
|
||||
|
||||
### Logging
|
||||
|
||||
@@ -125,6 +208,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) {
|
||||
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
|
||||
@@ -138,12 +254,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) {
|
||||
@@ -160,12 +277,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;
|
||||
@@ -181,7 +297,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; });
|
||||
});
|
||||
```
|
||||
|
||||
@@ -191,13 +307,13 @@ 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) {
|
||||
[&](size_t offset, DataSink &sink) {
|
||||
if (/* there is still data */) {
|
||||
std::vector<char> data;
|
||||
// prepare data...
|
||||
sink.write(data.data(), data.size());
|
||||
} else {
|
||||
done(); // No more data
|
||||
sink.done(); // No more data
|
||||
}
|
||||
return true; // return 'false' if you want to cancel the process.
|
||||
});
|
||||
@@ -209,6 +325,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);
|
||||
@@ -222,7 +339,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.
|
||||
@@ -242,6 +359,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
|
||||
@@ -252,7 +370,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
|
||||
@@ -264,13 +382,18 @@ Please see [Server example](https://github.com/yhirose/cpp-httplib/blob/master/e
|
||||
|
||||
### 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`.
|
||||
|
||||
`ThreadPool` is used as a default task queue, and the default thread count is set to value from `std::thread::hardware_concurrency()`.
|
||||
If you want to set the thread count at runtime, there is no convenient way... But here is how.
|
||||
|
||||
You can change the thread count by setting `CPPHTTPLIB_THREAD_POOL_COUNT`.
|
||||
```cpp
|
||||
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.
|
||||
|
||||
```cpp
|
||||
class YourThreadPoolTaskQueue : public TaskQueue {
|
||||
public:
|
||||
@@ -295,8 +418,8 @@ svr.new_task_queue = [] {
|
||||
};
|
||||
```
|
||||
|
||||
Client Example
|
||||
--------------
|
||||
Client
|
||||
------
|
||||
|
||||
```c++
|
||||
#include <httplib.h>
|
||||
@@ -325,6 +448,28 @@ 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()`.
|
||||
|
||||
```c++
|
||||
enum Error {
|
||||
Success = 0,
|
||||
Unknown,
|
||||
Connection,
|
||||
BindIPAddress,
|
||||
Read,
|
||||
Write,
|
||||
ExceedRedirectCount,
|
||||
Canceled,
|
||||
SSLConnection,
|
||||
SSLLoadingCerts,
|
||||
SSLServerVerification,
|
||||
UnsupportedMultipartBoundaryChars
|
||||
};
|
||||
```
|
||||
|
||||
### GET with HTTP headers
|
||||
@@ -411,7 +556,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;
|
||||
@@ -438,12 +583,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);
|
||||
@@ -452,6 +597,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
|
||||
@@ -546,7 +706,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.
|
||||
|
||||
@@ -554,27 +714,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
|
||||
|
||||
SSLServer svr("./cert.pem", "./key.pem");
|
||||
|
||||
SSLClient cli("localhost", 8080);
|
||||
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
|
||||
@@ -607,13 +750,29 @@ res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
|
||||
res->body; // Compressed data
|
||||
```
|
||||
|
||||
Use `poll` instead of `select`
|
||||
------------------------------
|
||||
|
||||
`select` system call is used as default since it's more widely supported. If you want to let cpp-httplib use `poll` instead, you can do so with `CPPHTTPLIB_USE_POLL`.
|
||||
|
||||
|
||||
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
|
||||
@@ -638,12 +797,14 @@ Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32
|
||||
#include <httplib.h>
|
||||
```
|
||||
|
||||
Note: Cygwin on Windows is not supported.
|
||||
Note: cpp-httplib officially supports only the latest Visual Studio. It might work with former versions of Visual Studio, but I can no longer verify it. Pull requests are always welcome for the older versions of Visual Studio unless they break the C++11 conformance.
|
||||
|
||||
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
|
||||
-----------------
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
FROM alpine as builder
|
||||
WORKDIR /src/example
|
||||
RUN apk add g++ make openssl-dev zlib-dev brotli-dev
|
||||
COPY ./httplib.h /src
|
||||
COPY ./example/hello.cc /src/example
|
||||
COPY ./example/Makefile /src/example
|
||||
RUN make hello
|
||||
|
||||
FROM alpine
|
||||
RUN apk --no-cache add brotli libstdc++
|
||||
COPY --from=builder /src/example/hello /bin/hello
|
||||
CMD ["/bin/hello"]
|
||||
+9
-6
@@ -1,14 +1,17 @@
|
||||
|
||||
#CXX = clang++
|
||||
CXXFLAGS = -std=c++11 -I.. -Wall -Wextra -pthread
|
||||
CXXFLAGS = -O2 -std=c++11 -I.. -Wall -Wextra -pthread
|
||||
|
||||
OPENSSL_DIR = /usr/local/opt/openssl
|
||||
PREFIX = /usr/local
|
||||
#PREFIX = $(shell brew --prefix)
|
||||
|
||||
OPENSSL_DIR = $(PREFIX)/opt/openssl@1.1
|
||||
#OPENSSL_DIR = $(PREFIX)/opt/openssl@3
|
||||
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
|
||||
|
||||
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-static -lbrotlienc-static -lbrotlidec-static
|
||||
BROTLI_DIR = $(PREFIX)/opt/brotli
|
||||
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
|
||||
|
||||
all: server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark
|
||||
|
||||
@@ -47,4 +50,4 @@ pem:
|
||||
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
|
||||
|
||||
clean:
|
||||
rm server client hello simplecli simplesvr upload redirect ssesvr sselci benchmark *.pem
|
||||
rm server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark *.pem
|
||||
|
||||
+1
-1
@@ -15,5 +15,5 @@ int main(void) {
|
||||
res.set_content("Hello World!", "text/plain");
|
||||
});
|
||||
|
||||
svr.listen("localhost", 8080);
|
||||
svr.listen("0.0.0.0", 8080);
|
||||
}
|
||||
|
||||
+2
-11
@@ -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_;
|
||||
};
|
||||
|
||||
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#/usr/bin/env bash
|
||||
for i in {1..10000}
|
||||
do
|
||||
echo "#### $i ####"
|
||||
curl -X POST -F image_file=@$1 http://localhost:1234/post > /dev/null
|
||||
done
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
project(
|
||||
'cpp-httplib',
|
||||
'cpp',
|
||||
license: 'MIT',
|
||||
default_options: [
|
||||
'cpp_std=c++11',
|
||||
'buildtype=release',
|
||||
'b_ndebug=if-release',
|
||||
'b_lto=true',
|
||||
'warning_level=3'
|
||||
],
|
||||
meson_version: '>=0.47.0'
|
||||
)
|
||||
|
||||
# Check just in case downstream decides to edit the source
|
||||
# and add a project version
|
||||
version = meson.project_version()
|
||||
python3 = find_program('python3')
|
||||
if version == 'undefined'
|
||||
# Meson doesn't have regular expressions, but since it is implemented
|
||||
# in python we can be sure we can use it to parse the file manually
|
||||
version = run_command(
|
||||
python3, '-c', 'import re; raw_version = re.search("User\-Agent.*cpp\-httplib/([0-9]+\.?)+", open("httplib.h").read()).group(0); print(re.search("([0-9]+\\.?)+", raw_version).group(0))',
|
||||
check: true
|
||||
).stdout().strip()
|
||||
endif
|
||||
|
||||
message('cpp-httplib version ' + version)
|
||||
|
||||
deps = [dependency('threads')]
|
||||
args = []
|
||||
|
||||
openssl_dep = dependency('openssl', version: ['>=1.1.1', '<1.1.2'], required: get_option('cpp-httplib_openssl'))
|
||||
if openssl_dep.found()
|
||||
deps += openssl_dep
|
||||
args += '-DCPPHTTPLIB_OPENSSL_SUPPORT'
|
||||
endif
|
||||
|
||||
zlib_dep = dependency('zlib', required: get_option('cpp-httplib_zlib'))
|
||||
if zlib_dep.found()
|
||||
deps += zlib_dep
|
||||
args += '-DCPPHTTPLIB_ZLIB_SUPPORT'
|
||||
endif
|
||||
|
||||
brotli_deps = [dependency('libbrotlicommon', required: get_option('cpp-httplib_brotli'))]
|
||||
brotli_deps += dependency('libbrotlidec', required: get_option('cpp-httplib_brotli'))
|
||||
brotli_deps += dependency('libbrotlienc', required: get_option('cpp-httplib_brotli'))
|
||||
|
||||
brotli_found_all = true
|
||||
foreach brotli_dep : brotli_deps
|
||||
if not brotli_dep.found()
|
||||
brotli_found_all = false
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if brotli_found_all
|
||||
deps += brotli_deps
|
||||
args += '-DCPPHTTPLIB_BROTLI_SUPPORT'
|
||||
endif
|
||||
|
||||
cpp_httplib_dep = dependency('', required: false)
|
||||
|
||||
if get_option('cpp-httplib_compile')
|
||||
httplib_ch = custom_target(
|
||||
'split',
|
||||
input: 'httplib.h',
|
||||
output: ['httplib.cc', 'httplib.h'],
|
||||
command: [python3, files('split.py'), '--out', meson.current_build_dir()],
|
||||
install: true,
|
||||
install_dir: [false, get_option('includedir')]
|
||||
)
|
||||
lib = library(
|
||||
'cpp-httplib',
|
||||
sources: httplib_ch,
|
||||
dependencies: deps,
|
||||
cpp_args: args,
|
||||
version: version,
|
||||
install: true
|
||||
)
|
||||
cpp_httplib_dep = declare_dependency(compile_args: args, dependencies: deps, link_with: lib, sources: httplib_ch[1])
|
||||
|
||||
import('pkgconfig').generate(
|
||||
lib,
|
||||
description: 'A C++ HTTP/HTTPS server and client library',
|
||||
extra_cflags: args,
|
||||
url: 'https://github.com/yhirose/cpp-httplib',
|
||||
version: version
|
||||
)
|
||||
else
|
||||
install_headers('httplib.h')
|
||||
cpp_httplib_dep = declare_dependency(compile_args: args, dependencies: deps, include_directories: include_directories('.'))
|
||||
|
||||
import('pkgconfig').generate(
|
||||
name: 'cpp-httplib',
|
||||
description: 'A C++ HTTP/HTTPS server and client library',
|
||||
install_dir: join_paths(get_option('datadir'), 'pkgconfig'),
|
||||
url: 'https://github.com/yhirose/cpp-httplib',
|
||||
version: version
|
||||
)
|
||||
endif
|
||||
|
||||
if meson.version().version_compare('>=0.54.0')
|
||||
meson.override_dependency('cpp-httplib', cpp_httplib_dep)
|
||||
endif
|
||||
|
||||
if get_option('cpp-httplib_test')
|
||||
subdir('test')
|
||||
endif
|
||||
@@ -0,0 +1,9 @@
|
||||
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
option('cpp-httplib_openssl', type: 'feature', value: 'auto', description: 'Enable OpenSSL support')
|
||||
option('cpp-httplib_zlib', type: 'feature', value: 'auto', description: 'Enable zlib support')
|
||||
option('cpp-httplib_brotli', type: 'feature', value: 'auto', description: 'Enable Brotli support')
|
||||
option('cpp-httplib_compile', type: 'boolean', value: false, description: 'Split the header into a compilable header & source file')
|
||||
option('cpp-httplib_test', type: 'boolean', value: false, description: 'Build tests')
|
||||
@@ -1,32 +1,67 @@
|
||||
#!/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:
|
||||
lines = f.readlines()
|
||||
inImplementation = False
|
||||
|
||||
if PythonVersion < 3:
|
||||
os.makedirs('out')
|
||||
cur_dir = os.path.dirname(sys.argv[0])
|
||||
lib_name = 'httplib'
|
||||
header_name = '/' + lib_name + '.h'
|
||||
source_name = '/' + lib_name + '.' + args.extension
|
||||
# get the input file
|
||||
in_file = cur_dir + header_name
|
||||
# get the output file
|
||||
h_out = args.out + header_name
|
||||
cc_out = args.out + source_name
|
||||
|
||||
# if the modification time of the out file is after the in file,
|
||||
# don't split (as it is already finished)
|
||||
do_split = True
|
||||
|
||||
if os.path.exists(h_out):
|
||||
in_time = os.path.getmtime(in_file)
|
||||
out_time = os.path.getmtime(h_out)
|
||||
do_split = in_time > out_time
|
||||
|
||||
if do_split:
|
||||
with open(in_file) as f:
|
||||
lines = f.readlines()
|
||||
|
||||
python_version = sys.version_info[0]
|
||||
if python_version < 3:
|
||||
os.makedirs(args.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')
|
||||
os.makedirs(args.out, exist_ok=True)
|
||||
|
||||
in_implementation = False
|
||||
cc_out = args.out + source_name
|
||||
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))
|
||||
else:
|
||||
print("{} and {} are up to date".format(h_out, cc_out))
|
||||
|
||||
+47
-9
@@ -1,35 +1,73 @@
|
||||
CXX = clang++
|
||||
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion # -fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS -fsanitize=address
|
||||
|
||||
#CXX = clang++
|
||||
CXXFLAGS = -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits -Wconversion
|
||||
PREFIX = /usr/local
|
||||
#PREFIX = $(shell brew --prefix)
|
||||
|
||||
OPENSSL_DIR = /usr/local/opt/openssl@1.1
|
||||
OPENSSL_DIR = $(PREFIX)/opt/openssl@1.1
|
||||
#OPENSSL_DIR = $(PREFIX)/opt/openssl@3
|
||||
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
|
||||
|
||||
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
||||
|
||||
BROTLI_DIR = /usr/local/opt/brotli
|
||||
BROTLI_DIR = $(PREFIX)/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
|
||||
|
||||
# By default, use standalone_fuzz_target_runner.
|
||||
# This runner does no fuzzing, but simply executes the inputs
|
||||
# provided via parameters.
|
||||
# Run e.g. "make all LIB_FUZZING_ENGINE=/path/to/libFuzzer.a"
|
||||
# to link the fuzzer(s) against a real fuzzing engine.
|
||||
# OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE.
|
||||
LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o
|
||||
|
||||
all : test test_split
|
||||
./test
|
||||
|
||||
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)
|
||||
|
||||
# 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.
|
||||
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)
|
||||
|
||||
# Runs server_fuzzer.cc based on value of $(LIB_FUZZING_ENGINE).
|
||||
# Usage: make fuzz_test LIB_FUZZING_ENGINE=/path/to/libFuzzer
|
||||
fuzz_test: server_fuzzer
|
||||
./server_fuzzer fuzzing/corpus/*
|
||||
|
||||
# Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
|
||||
server_fuzzer : fuzzing/server_fuzzer.cc ../httplib.h standalone_fuzz_target_runner.o
|
||||
$(CXX) -o $@ -I.. $(CXXFLAGS) $< $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread
|
||||
|
||||
# Standalone fuzz runner, which just reads inputs from fuzzing/corpus/ dir and
|
||||
# feeds it to server_fuzzer.
|
||||
standalone_fuzz_target_runner.o : fuzzing/standalone_fuzz_target_runner.cpp
|
||||
$(CXX) -o $@ -I.. $(CXXFLAGS) -c $<
|
||||
|
||||
httplib.cc : ../httplib.h
|
||||
python3 ../split.py -o .
|
||||
|
||||
cert.pem:
|
||||
openssl genrsa 2048 > key.pem
|
||||
openssl req -new -batch -config test.conf -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
|
||||
openssl req -x509 -config test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
|
||||
openssl genrsa 2048 > rootCA.key.pem
|
||||
openssl req -x509 -new -batch -config test.rootCA.conf -key rootCA.key.pem -days 1024 > rootCA.cert.pem
|
||||
openssl genrsa 2048 > client.key.pem
|
||||
openssl req -new -batch -config test.conf -key client.key.pem | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client.cert.pem
|
||||
openssl genrsa -passout pass:test123! 2048 > key_encrypted.pem
|
||||
openssl req -new -batch -config test.conf -key key_encrypted.pem | openssl x509 -days 3650 -req -signkey key_encrypted.pem > cert_encrypted.pem
|
||||
#c_rehash .
|
||||
|
||||
clean:
|
||||
rm -f test test_proxy pem *.0 *.1 *.srl
|
||||
rm -f test test_split test_proxy server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
#CXX = clang++
|
||||
# Do not add default sanitizer flags here as OSS-fuzz adds its own sanitizer flags.
|
||||
CXXFLAGS += -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I../.. -I. -Wall -Wextra -Wtype-limits -Wconversion
|
||||
|
||||
OPENSSL_DIR = /usr/local/opt/openssl@1.1
|
||||
|
||||
# Using full path to libssl and libcrypto to avoid accidentally picking openssl libs brought in by msan.
|
||||
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -I$(OPENSSL_DIR)/lib /usr/local/lib/libssl.a /usr/local/lib/libcrypto.a
|
||||
|
||||
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
|
||||
|
||||
# Runs all the tests and also fuzz tests against seed corpus.
|
||||
all : server_fuzzer
|
||||
./server_fuzzer corpus/*
|
||||
|
||||
# Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
|
||||
server_fuzzer : server_fuzzer.cc ../../httplib.h
|
||||
# $(CXX) $(CXXFLAGS) -o $@ $< -Wl,-Bstatic $(OPENSSL_SUPPORT) -Wl,-Bdynamic -ldl $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread
|
||||
$(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread
|
||||
zip -q -r server_fuzzer_seed_corpus.zip corpus
|
||||
|
||||
clean:
|
||||
rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip
|
||||
@@ -0,0 +1 @@
|
||||
PUT /search/sample?a=12 HTTP/1.1
|
||||
@@ -0,0 +1,5 @@
|
||||
GET /hello.htm HTTP/1.1
|
||||
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
|
||||
Accept-Language: en-us
|
||||
Accept-Encoding: gzip, deflate
|
||||
Connection: Keep-Alive
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,88 @@
|
||||
#include <httplib.h>
|
||||
#include <memory>
|
||||
|
||||
class FuzzedStream : public httplib::Stream {
|
||||
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_; }
|
||||
memcpy(ptr, data_ + read_pos_, size);
|
||||
read_pos_ += size;
|
||||
return static_cast<ssize_t>(size);
|
||||
}
|
||||
|
||||
ssize_t write(const char *ptr, size_t size) override {
|
||||
response_.append(ptr, size);
|
||||
return static_cast<int>(size);
|
||||
}
|
||||
|
||||
ssize_t write(const char *ptr) { return write(ptr, strlen(ptr)); }
|
||||
|
||||
ssize_t write(const std::string &s) { return write(s.data(), s.size()); }
|
||||
|
||||
std::string get_remote_addr() const { return ""; }
|
||||
|
||||
bool is_readable() const override { return true; }
|
||||
|
||||
bool is_writable() const override { return true; }
|
||||
|
||||
void get_remote_ip_and_port(std::string &ip, int &port) const override {
|
||||
ip = "127.0.0.1";
|
||||
port = 8080;
|
||||
}
|
||||
|
||||
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) {
|
||||
bool connection_close = false;
|
||||
process_request(stream, /*last_connection=*/false, connection_close,
|
||||
nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
static FuzzableServer g_server;
|
||||
|
||||
extern "C" int LLVMFuzzerInitialize(int * /*argc*/, char *** /*argv*/) {
|
||||
g_server.Get(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) {
|
||||
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");
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
FuzzedStream stream{data, size};
|
||||
g_server.ProcessFuzzedRequest(stream);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
# Sources: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
|
||||
|
||||
# misc
|
||||
"HTTP/1.1"
|
||||
|
||||
# verbs
|
||||
"CONNECT"
|
||||
"DELETE"
|
||||
"GET"
|
||||
"HEAD"
|
||||
"OPTIONS"
|
||||
"PATCH"
|
||||
"POST"
|
||||
"PUT"
|
||||
"TRACE"
|
||||
|
||||
|
||||
# Webdav/caldav verbs
|
||||
"ACL"
|
||||
"BASELINE-CONTROL"
|
||||
"BIND"
|
||||
"CHECKIN"
|
||||
"CHECKOUT"
|
||||
"COPY"
|
||||
"LABEL"
|
||||
"LINK"
|
||||
"LOCK"
|
||||
"MERGE"
|
||||
"MKACTIVITY"
|
||||
"MKCALENDAR"
|
||||
"MKCOL"
|
||||
"MKREDIRECTREF"
|
||||
"MKWORKSPACE"
|
||||
"MOVE"
|
||||
"ORDERPATCH"
|
||||
"PRI"
|
||||
"PROPFIND"
|
||||
"PROPPATCH"
|
||||
"REBIND"
|
||||
"REPORT"
|
||||
"SEARCH"
|
||||
"UNBIND"
|
||||
"UNCHECKOUT"
|
||||
"UNLINK"
|
||||
"UNLOCK"
|
||||
"UPDATE"
|
||||
"UPDATEREDIRECTREF"
|
||||
"VERSION-CONTROL"
|
||||
|
||||
|
||||
# Fields
|
||||
"A-IM"
|
||||
"Accept"
|
||||
"Accept-Charset"
|
||||
"Accept-Datetime"
|
||||
"Accept-Encoding"
|
||||
"Accept-Language"
|
||||
"Accept-Patch"
|
||||
"Accept-Ranges"
|
||||
"Access-Control-Allow-Credentials"
|
||||
"Access-Control-Allow-Headers"
|
||||
"Access-Control-Allow-Methods"
|
||||
"Access-Control-Allow-Origin"
|
||||
"Access-Control-Expose-Headers"
|
||||
"Access-Control-Max-Age"
|
||||
"Access-Control-Request-Headers"
|
||||
"Access-Control-Request-Method"
|
||||
"Age"
|
||||
"Allow"
|
||||
"Alt-Svc"
|
||||
"Authorization"
|
||||
"Cache-Control"
|
||||
"Connection"
|
||||
"Connection:"
|
||||
"Content-Disposition"
|
||||
"Content-Encoding"
|
||||
"Content-Language"
|
||||
"Content-Length"
|
||||
"Content-Location"
|
||||
"Content-MD5"
|
||||
"Content-Range"
|
||||
"Content-Security-Policy"
|
||||
"Content-Type"
|
||||
"Cookie"
|
||||
"DNT"
|
||||
"Date"
|
||||
"Delta-Base"
|
||||
"ETag"
|
||||
"Expect"
|
||||
"Expires"
|
||||
"Forwarded"
|
||||
"From"
|
||||
"Front-End-Https"
|
||||
"HTTP2-Settings"
|
||||
"Host"
|
||||
"IM"
|
||||
"If-Match"
|
||||
"If-Modified-Since"
|
||||
"If-None-Match"
|
||||
"If-Range"
|
||||
"If-Unmodified-Since"
|
||||
"Last-Modified"
|
||||
"Link"
|
||||
"Location"
|
||||
"Max-Forwards"
|
||||
"Origin"
|
||||
"P3P"
|
||||
"Pragma"
|
||||
"Proxy-Authenticate"
|
||||
"Proxy-Authorization"
|
||||
"Proxy-Connection"
|
||||
"Public-Key-Pins"
|
||||
"Range"
|
||||
"Referer"
|
||||
"Refresh"
|
||||
"Retry-After"
|
||||
"Save-Data"
|
||||
"Server"
|
||||
"Set-Cookie"
|
||||
"Status"
|
||||
"Strict-Transport-Security"
|
||||
"TE"
|
||||
"Timing-Allow-Origin"
|
||||
"Tk"
|
||||
"Trailer"
|
||||
"Transfer-Encoding"
|
||||
"Upgrade"
|
||||
"Upgrade-Insecure-Requests"
|
||||
"User-Agent"
|
||||
"Vary"
|
||||
"Via"
|
||||
"WWW-Authenticate"
|
||||
"Warning"
|
||||
"X-ATT-DeviceId"
|
||||
"X-Content-Duration"
|
||||
"X-Content-Security-Policy"
|
||||
"X-Content-Type-Options"
|
||||
"X-Correlation-ID"
|
||||
"X-Csrf-Token"
|
||||
"X-Forwarded-For"
|
||||
"X-Forwarded-Host"
|
||||
"X-Forwarded-Proto"
|
||||
"X-Frame-Options"
|
||||
"X-Http-Method-Override"
|
||||
"X-Powered-By"
|
||||
"X-Request-ID"
|
||||
"X-Requested-With"
|
||||
"X-UA-Compatible"
|
||||
"X-UIDH"
|
||||
"X-Wap-Profile"
|
||||
"X-WebKit-CSP"
|
||||
"X-XSS-Protection"
|
||||
|
||||
# Source: string and character literals in httplib.h
|
||||
" "
|
||||
"&"
|
||||
", "
|
||||
"-"
|
||||
"--"
|
||||
"."
|
||||
".."
|
||||
":"
|
||||
"="
|
||||
" = = "
|
||||
"0123456789abcdef"
|
||||
"%02X"
|
||||
"%0A"
|
||||
"\\x0a\\x0d"
|
||||
"%0D"
|
||||
"%20"
|
||||
"%27"
|
||||
"%2B"
|
||||
"%2C"
|
||||
"%3A"
|
||||
"%3B"
|
||||
"application/javascript"
|
||||
"application/json"
|
||||
"application/pdf"
|
||||
"application/xhtml+xml"
|
||||
"application/xml"
|
||||
"application/x-www-form-urlencoded"
|
||||
"Bad Request"
|
||||
"boundary="
|
||||
"bytes="
|
||||
"chunked"
|
||||
"close"
|
||||
"CONNECT"
|
||||
"css"
|
||||
"Forbidden"
|
||||
"Found"
|
||||
"gif"
|
||||
"gzip"
|
||||
"html"
|
||||
"ico"
|
||||
"image/gif"
|
||||
"image/jpg"
|
||||
"image/png"
|
||||
"image/svg+xml"
|
||||
"image/x-icon"
|
||||
"index.html"
|
||||
"Internal Server Error"
|
||||
"jpeg"
|
||||
"js"
|
||||
"json"
|
||||
"Location"
|
||||
"Moved Permanently"
|
||||
"multipart/form-data"
|
||||
"Not Found"
|
||||
"Not Modified"
|
||||
"OK"
|
||||
"pdf"
|
||||
"png"
|
||||
"Range"
|
||||
"REMOTE_ADDR"
|
||||
"See Other"
|
||||
"svg"
|
||||
"text/"
|
||||
"text/css"
|
||||
"text/html"
|
||||
"text/plain"
|
||||
"txt"
|
||||
"Unsupported Media Type"
|
||||
"xhtml"
|
||||
"xml"
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
// This runner does not do any fuzzing, but allows us to run the fuzz target
|
||||
// on the test corpus or on a single file,
|
||||
// e.g. the one that comes from a bug report.
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
// Forward declare the "fuzz target" interface.
|
||||
// We deliberately keep this inteface simple and header-free.
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
|
||||
// It reads all files passed as parameters and feeds their contents
|
||||
// one by one into the fuzz target (LLVMFuzzerTestOneInput).
|
||||
int main(int argc, char **argv) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::ifstream in(argv[i]);
|
||||
in.seekg(0, in.end);
|
||||
size_t length = static_cast<size_t>(in.tellg());
|
||||
in.seekg (0, in.beg);
|
||||
std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
|
||||
// Allocate exactly length bytes so that we reliably catch buffer overflows.
|
||||
std::vector<char> bytes(length);
|
||||
in.read(bytes.data(), static_cast<std::streamsize>(bytes.size()));
|
||||
LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
|
||||
bytes.size());
|
||||
std::cout << "Execution successful" << std::endl;
|
||||
}
|
||||
std::cout << "Execution finished" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
+5790
-2420
File diff suppressed because it is too large
Load Diff
+6845
-14038
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -0,0 +1,110 @@
|
||||
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
gtest_dep = dependency('gtest', main: true)
|
||||
openssl = find_program('openssl')
|
||||
test_conf = files('test.conf')
|
||||
|
||||
key_pem = custom_target(
|
||||
'key_pem',
|
||||
output: 'key.pem',
|
||||
command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
|
||||
)
|
||||
|
||||
temp_req = custom_target(
|
||||
'temp_req',
|
||||
input: key_pem,
|
||||
output: 'temp_req',
|
||||
command: [openssl, 'req', '-new', '-batch', '-config', test_conf, '-key', '@INPUT@', '-out', '@OUTPUT@']
|
||||
)
|
||||
|
||||
cert_pem = custom_target(
|
||||
'cert_pem',
|
||||
input: [temp_req, key_pem],
|
||||
output: 'cert.pem',
|
||||
command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '3650', '-req', '-signkey', '@INPUT1@', '-out', '@OUTPUT@']
|
||||
)
|
||||
|
||||
cert2_pem = custom_target(
|
||||
'cert2_pem',
|
||||
input: key_pem,
|
||||
output: 'cert2.pem',
|
||||
command: [openssl, 'req', '-x509', '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
|
||||
)
|
||||
|
||||
key_encrypted_pem = custom_target(
|
||||
'key_encrypted_pem',
|
||||
output: 'key_encrypted.pem',
|
||||
command: [openssl, 'genrsa', '-passout', 'pass:test123!', '-out', '@OUTPUT@', '2048']
|
||||
)
|
||||
|
||||
cert_encrypted_pem = custom_target(
|
||||
'cert_encrypted_pem',
|
||||
input: key_encrypted_pem,
|
||||
output: 'cert_encrypted.pem',
|
||||
command: [openssl, 'req', '-x509', '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
|
||||
)
|
||||
|
||||
rootca_key_pem = custom_target(
|
||||
'rootca_key_pem',
|
||||
output: 'rootCA.key.pem',
|
||||
command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
|
||||
)
|
||||
|
||||
rootca_cert_pem = custom_target(
|
||||
'rootca_cert_pem',
|
||||
input: rootca_key_pem,
|
||||
output: 'rootCA.cert.pem',
|
||||
command: [openssl, 'req', '-x509', '-new', '-batch', '-config', files('test.rootCA.conf'), '-key', '@INPUT@', '-days', '1024', '-out', '@OUTPUT@']
|
||||
)
|
||||
|
||||
client_key_pem = custom_target(
|
||||
'client_key_pem',
|
||||
output: 'client.key.pem',
|
||||
command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
|
||||
)
|
||||
|
||||
client_temp_req = custom_target(
|
||||
'client_temp_req',
|
||||
input: client_key_pem,
|
||||
output: 'client_temp_req',
|
||||
command: [openssl, 'req', '-new', '-batch', '-config', test_conf, '-key', '@INPUT@', '-out', '@OUTPUT@']
|
||||
)
|
||||
|
||||
client_cert_pem = custom_target(
|
||||
'client_cert_pem',
|
||||
input: [client_temp_req, rootca_cert_pem, rootca_key_pem],
|
||||
output: 'client.cert.pem',
|
||||
command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '370', '-req', '-CA', '@INPUT1@', '-CAkey', '@INPUT2@', '-CAcreateserial', '-out', '@OUTPUT@']
|
||||
)
|
||||
|
||||
# Copy test files to the build directory
|
||||
configure_file(input: 'ca-bundle.crt', output: 'ca-bundle.crt', copy: true)
|
||||
configure_file(input: 'image.jpg', output: 'image.jpg', copy: true)
|
||||
subdir(join_paths('www', 'dir'))
|
||||
subdir(join_paths('www2', 'dir'))
|
||||
subdir(join_paths('www3', 'dir'))
|
||||
|
||||
test(
|
||||
'main',
|
||||
executable(
|
||||
'main',
|
||||
'test.cc',
|
||||
dependencies: [
|
||||
cpp_httplib_dep,
|
||||
gtest_dep
|
||||
]
|
||||
),
|
||||
depends: [
|
||||
key_pem,
|
||||
cert_pem,
|
||||
cert2_pem,
|
||||
rootca_key_pem,
|
||||
rootca_cert_pem,
|
||||
client_key_pem,
|
||||
client_cert_pem
|
||||
],
|
||||
workdir: meson.current_build_dir(),
|
||||
timeout: 300
|
||||
)
|
||||
@@ -1 +0,0 @@
|
||||
docker-compose down --rmi all
|
||||
@@ -1 +0,0 @@
|
||||
docker-compose up -d
|
||||
+1772
-193
File diff suppressed because it is too large
Load Diff
@@ -16,3 +16,6 @@ emailAddress = test@email.address
|
||||
|
||||
[req_attributes]
|
||||
challengePassword = 1234
|
||||
|
||||
[SAN]
|
||||
subjectAltName=IP:127.0.0.1
|
||||
|
||||
+27
-30
@@ -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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
configure_file(input: 'index.html', output: 'index.html', copy: true)
|
||||
configure_file(input: 'test.abcde', output: 'test.abcde', copy: true)
|
||||
configure_file(input: 'test.html', output: 'test.html', copy: true)
|
||||
@@ -0,0 +1,6 @@
|
||||
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
configure_file(input: 'index.html', output: 'index.html', copy: true)
|
||||
configure_file(input: 'test.html', output: 'test.html', copy: true)
|
||||
@@ -0,0 +1,6 @@
|
||||
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
configure_file(input: 'index.html', output: 'index.html', copy: true)
|
||||
configure_file(input: 'test.html', output: 'test.html', copy: true)
|
||||
Reference in New Issue
Block a user