mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-04-13 20:28:30 +00:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3da4a0ac69 | ||
|
|
9d12b3f20e | ||
|
|
852a374748 | ||
|
|
3b5bab3308 | ||
|
|
69e75f4a67 | ||
|
|
b0fd4befb1 | ||
|
|
3e80666a74 | ||
|
|
3e4567bae8 | ||
|
|
db075d8cf9 | ||
|
|
16df0ef37e | ||
|
|
f1a2ac5108 | ||
|
|
e5743b358d | ||
|
|
1184bbe4cb | ||
|
|
9dcffda7ae | ||
|
|
e5903635e2 | ||
|
|
510b4eaaae | ||
|
|
d7e63b4316 | ||
|
|
e5dd410256 | ||
|
|
951e46929e | ||
|
|
c8adac30f4 | ||
|
|
b2b4f7635f | ||
|
|
649b1d2172 | ||
|
|
dc5f9ba164 | ||
|
|
cf084e1db1 | ||
|
|
e0e5898601 | ||
|
|
dfec2de5b5 | ||
|
|
04002d57bd | ||
|
|
38a7706c8b | ||
|
|
abaf875c42 | ||
|
|
5f76cb01c7 | ||
|
|
ae54e833ea | ||
|
|
0dd3659de5 | ||
|
|
999f6abd2c | ||
|
|
48da75dd35 | ||
|
|
4f84eeb298 | ||
|
|
a5b4cfadb9 | ||
|
|
3e906a9b8c | ||
|
|
110393eadb | ||
|
|
98caa8c058 | ||
|
|
ef65f09608 | ||
|
|
e130cf3a3b | ||
|
|
8a348f17fd | ||
|
|
797d1f27e8 | ||
|
|
6cde600922 | ||
|
|
342c3ab293 | ||
|
|
6cce7951fc | ||
|
|
e9058e5639 | ||
|
|
2538a85486 | ||
|
|
8c501022b3 | ||
|
|
9f5db2d1aa | ||
|
|
12540fe8d3 | ||
|
|
29a06f852a | ||
|
|
0e9cfd9f49 | ||
|
|
90da199aba | ||
|
|
366d073490 | ||
|
|
9ca1fa8b18 | ||
|
|
15c4106a36 | ||
|
|
72ce293fed | ||
|
|
b476b55771 | ||
|
|
0db9d21eb0 | ||
|
|
5ddaf949d0 | ||
|
|
457a5a7501 | ||
|
|
2ce080c2cb | ||
|
|
6ad25b6cf0 | ||
|
|
3dff60eb16 | ||
|
|
5038314b21 | ||
|
|
6e1297cab0 | ||
|
|
7de743c962 | ||
|
|
964fb5e5ca | ||
|
|
c4f3f9529b | ||
|
|
887def9490 | ||
|
|
bad6b2d22f | ||
|
|
3d47a51430 | ||
|
|
0a2cb20223 | ||
|
|
ce502a73e1 | ||
|
|
010e4479f4 | ||
|
|
70e193374a | ||
|
|
6b22409217 | ||
|
|
969cccd52a | ||
|
|
4a9c048bbc | ||
|
|
bfabbec8c7 | ||
|
|
3e9c06cf79 | ||
|
|
29677540ae | ||
|
|
71fcfeb912 | ||
|
|
c7d22e451f | ||
|
|
42f9f9107f | ||
|
|
7cd25fbd63 |
25
.github/workflows/test.yaml
vendored
25
.github/workflows/test.yaml
vendored
@@ -8,10 +8,31 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macOS-latest, ubuntu-latest]
|
||||
os: [macOS-latest, ubuntu-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- name: prepare git for checkout on windows
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
- name: checkout
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v2
|
||||
- name: install brotli library on ubuntu
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: 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
|
||||
- name: setup msbuild on windows
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: warrenbuckley/Setup-MSBuild@v1
|
||||
- name: make-windows
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
cd test
|
||||
msbuild.exe test.sln /verbosity:minimal /t:Build "/p:Configuration=Release;Platform=x64"
|
||||
x64\Release\test.exe
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,7 +7,7 @@ example/simplecli
|
||||
example/simplesvr
|
||||
example/benchmark
|
||||
example/redirect
|
||||
example/sse
|
||||
example/sse*
|
||||
example/upload
|
||||
example/*.pem
|
||||
test/test
|
||||
|
||||
108
CMakeLists.txt
108
CMakeLists.txt
@@ -1,10 +1,15 @@
|
||||
#[[
|
||||
Build options:
|
||||
* BUILD_SHARED_LIBS (default off) builds as a shared library (if HTTPLIB_COMPILE is ON)
|
||||
* HTTPLIB_USE_OPENSSL_IF_AVAILABLE (default on)
|
||||
* HTTPLIB_USE_ZLIB_IF_AVAILABLE (default on)
|
||||
* HTTPLIB_REQUIRE_OPENSSL (default off)
|
||||
* HTTPLIB_REQUIRE_ZLIB (default off)
|
||||
* HTTPLIB_USE_BROTLI_IF_AVAILABLE (default on)
|
||||
* HTTPLIB_REQUIRE_BROTLI (default off)
|
||||
* HTTPLIB_COMPILE (default off)
|
||||
* BROTLI_USE_STATIC_LIBS - tells Cmake to use the static Brotli libs (only works if you have them installed).
|
||||
* OPENSSL_USE_STATIC_LIBS - tells Cmake to use the static OpenSSL libs (only works if you have them installed).
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@@ -36,10 +41,11 @@
|
||||
* HTTPLIB_HEADER_PATH - this is the full path to the installed header (e.g. /usr/include/httplib.h).
|
||||
* HTTPLIB_IS_USING_OPENSSL - a bool for if OpenSSL support is enabled.
|
||||
* HTTPLIB_IS_USING_ZLIB - a bool for if ZLIB support is enabled.
|
||||
* HTTPLIB_IS_USING_BROTLI - a bool for if Brotli support is enabled.
|
||||
* HTTPLIB_IS_COMPILED - a bool for if the library is compiled, or otherwise header-only.
|
||||
* HTTPLIB_INCLUDE_DIR - the root path to httplib's header (e.g. /usr/include).
|
||||
* HTTPLIB_LIBRARY - the full path to the library if compiled (e.g. /usr/lib/libhttplib.so).
|
||||
* HTTPLIB_VERSION - the project's version string.
|
||||
* httplib_VERSION or HTTPLIB_VERSION - the project's version string.
|
||||
* HTTPLIB_FOUND - a bool for if the target was found.
|
||||
|
||||
Want to use precompiled headers (Cmake feature since v3.16)?
|
||||
@@ -50,20 +56,26 @@
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
FindPython3 requires Cmake v3.12
|
||||
ARCH_INDEPENDENT option of write_basic_package_version_file() requires Cmake v3.14
|
||||
]]
|
||||
cmake_minimum_required(VERSION 3.12.0 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
|
||||
|
||||
# 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 describe --tags --abbrev=0
|
||||
OUTPUT_VARIABLE _raw_version_string
|
||||
ERROR_VARIABLE _git_tag_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
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE _raw_version_string
|
||||
ERROR_VARIABLE _git_tag_error
|
||||
)
|
||||
endif()
|
||||
|
||||
# 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)
|
||||
message(WARNING "cpp-httplib failed to find the latest git tag, falling back to using user agent as the 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.
|
||||
@@ -85,9 +97,16 @@ option(HTTPLIB_REQUIRE_ZLIB "Requires ZLIB to be found & linked, or fails build.
|
||||
# Allow for a build to casually enable OpenSSL/ZLIB support, but silenty continue if not found.
|
||||
# Make these options so their automatic use can be specifically disabled (as needed)
|
||||
option(HTTPLIB_USE_OPENSSL_IF_AVAILABLE "Uses OpenSSL (if available) to enable HTTPS support." ON)
|
||||
option(HTTPLIB_USE_ZLIB_IF_AVAILABLE "Uses ZLIB (if available) to enable compression support." ON)
|
||||
option(HTTPLIB_USE_ZLIB_IF_AVAILABLE "Uses ZLIB (if available) to enable Zlib compression support." ON)
|
||||
# Lets you compile the program as a regular library instead of header-only
|
||||
option(HTTPLIB_COMPILE "If ON, uses a Python script to split the header into a compilable header & source file (requires Python v3)." OFF)
|
||||
# Just setting this variable here for people building in-tree
|
||||
if(HTTPLIB_COMPILE)
|
||||
set(HTTPLIB_IS_COMPILED TRUE)
|
||||
endif()
|
||||
|
||||
option(HTTPLIB_REQUIRE_BROTLI "Requires Brotli to be found & linked, or fails build." OFF)
|
||||
option(HTTPLIB_USE_BROTLI_IF_AVAILABLE "Uses Brotli (if available) to enable Brotli decompression support." ON)
|
||||
# Defaults to static library
|
||||
option(BUILD_SHARED_LIBS "Build the library as a shared library instead of static. Has no effect if using header-only." OFF)
|
||||
if (BUILD_SHARED_LIBS AND WIN32 AND HTTPLIB_COMPILE)
|
||||
@@ -104,11 +123,33 @@ if(HTTPLIB_REQUIRE_OPENSSL)
|
||||
elseif(HTTPLIB_USE_OPENSSL_IF_AVAILABLE)
|
||||
find_package(OpenSSL ${_HTTPLIB_OPENSSL_MIN_VER} COMPONENTS Crypto SSL QUIET)
|
||||
endif()
|
||||
# Just setting this variable here for people building in-tree
|
||||
if(OPENSSL_FOUND)
|
||||
set(HTTPLIB_IS_USING_OPENSSL TRUE)
|
||||
endif()
|
||||
|
||||
if(HTTPLIB_REQUIRE_ZLIB)
|
||||
find_package(ZLIB REQUIRED)
|
||||
elseif(HTTPLIB_USE_ZLIB_IF_AVAILABLE)
|
||||
find_package(ZLIB QUIET)
|
||||
endif()
|
||||
# Just setting this variable here for people building in-tree
|
||||
# FindZLIB doesn't have a ZLIB_FOUND variable, so check the target.
|
||||
if(TARGET ZLIB::ZLIB)
|
||||
set(HTTPLIB_IS_USING_ZLIB TRUE)
|
||||
endif()
|
||||
|
||||
# Adds our cmake folder to the search path for find_package
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
if(HTTPLIB_REQUIRE_BROTLI)
|
||||
find_package(Brotli COMPONENTS encoder decoder common REQUIRED)
|
||||
elseif(HTTPLIB_USE_BROTLI_IF_AVAILABLE)
|
||||
find_package(Brotli COMPONENTS encoder decoder common QUIET)
|
||||
endif()
|
||||
# Just setting this variable here for people building in-tree
|
||||
if(Brotli_FOUND)
|
||||
set(HTTPLIB_IS_USING_BROTLI TRUE)
|
||||
endif()
|
||||
|
||||
# Used for default, common dirs that the end-user can change (if needed)
|
||||
# like CMAKE_INSTALL_INCLUDEDIR or CMAKE_INSTALL_DATADIR
|
||||
@@ -180,33 +221,25 @@ target_include_directories(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
# Always require threads
|
||||
target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
Threads::Threads
|
||||
# Needed for Windows libs on Mingw, as the pragma comment(lib, "xyz") aren't triggered.
|
||||
$<$<PLATFORM_ID:Windows>:ws2_32>
|
||||
$<$<PLATFORM_ID:Windows>:crypt32>
|
||||
$<$<PLATFORM_ID:Windows>:cryptui>
|
||||
# Can't put multiple targets in a single generator expression or it bugs out.
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_BROTLI}>:Brotli::common>
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_BROTLI}>:Brotli::encoder>
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_BROTLI}>:Brotli::decoder>
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_ZLIB}>:ZLIB::ZLIB>
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_OPENSSL}>:OpenSSL::SSL>
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_OPENSSL}>:OpenSSL::Crypto>
|
||||
)
|
||||
|
||||
# We check for the target when using IF_AVAILABLE since it's possible we didn't find it.
|
||||
if(HTTPLIB_USE_OPENSSL_IF_AVAILABLE AND TARGET OpenSSL::SSL AND TARGET OpenSSL::Crypto OR HTTPLIB_REQUIRE_OPENSSL)
|
||||
target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
OpenSSL::SSL OpenSSL::Crypto
|
||||
)
|
||||
target_compile_definitions(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
)
|
||||
set(HTTPLIB_IS_USING_OPENSSL TRUE)
|
||||
else()
|
||||
set(HTTPLIB_IS_USING_OPENSSL FALSE)
|
||||
endif()
|
||||
|
||||
# We check for the target when using IF_AVAILABLE since it's possible we didn't find it.
|
||||
if(HTTPLIB_USE_ZLIB_IF_AVAILABLE AND TARGET ZLIB::ZLIB OR HTTPLIB_REQUIRE_ZLIB)
|
||||
target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
ZLIB::ZLIB
|
||||
)
|
||||
target_compile_definitions(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
CPPHTTPLIB_ZLIB_SUPPORT
|
||||
)
|
||||
set(HTTPLIB_IS_USING_ZLIB TRUE)
|
||||
else()
|
||||
set(HTTPLIB_IS_USING_ZLIB FALSE)
|
||||
endif()
|
||||
# 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">
|
||||
)
|
||||
|
||||
# Cmake's find_package search path is different based on the system
|
||||
# See https://cmake.org/cmake/help/latest/command/find_package.html for the list
|
||||
@@ -261,6 +294,9 @@ install(FILES "${_httplib_build_includedir}/httplib.h" DESTINATION ${CMAKE_INSTA
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
# Install it so it can be used later by the httplibConfig.cmake file.
|
||||
# Put it in the same dir as our config file instead of a global path so we don't potentially stomp on other packages.
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindBrotli.cmake"
|
||||
DESTINATION ${_TARGET_INSTALL_CMAKEDIR}
|
||||
)
|
||||
|
||||
|
||||
188
README.md
188
README.md
@@ -2,16 +2,46 @@ cpp-httplib
|
||||
===========
|
||||
|
||||
[](https://github.com/yhirose/cpp-httplib/actions)
|
||||
[](https://ci.appveyor.com/project/yhirose/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!
|
||||
|
||||
For Windows users: Please read [this note](https://github.com/yhirose/cpp-httplib#windows).
|
||||
NOTE: This is a 'blocking' HTTP library. If you are looking for a 'non-blocking' library, this is not the one that you want.
|
||||
|
||||
Server Example
|
||||
--------------
|
||||
Simple examples
|
||||
---------------
|
||||
|
||||
#### Server
|
||||
|
||||
```c++
|
||||
httplib::Server 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++
|
||||
httplib::Client cli("http://cpp-httplib-server.yhirose.repl.co");
|
||||
|
||||
auto res = cli.Get("/hi");
|
||||
|
||||
res->status; // 200
|
||||
res->body; // "Hello World!"
|
||||
```
|
||||
|
||||
### Try out the examples on Repl.it!
|
||||
|
||||
1. Run server at https://repl.it/@yhirose/cpp-httplib-server
|
||||
2. Run client at https://repl.it/@yhirose/cpp-httplib-client
|
||||
|
||||
Server
|
||||
------
|
||||
|
||||
```c++
|
||||
#include <httplib.h>
|
||||
@@ -178,6 +208,7 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
|
||||
|
||||
res.set_content_provider(
|
||||
data->size(), // Content length
|
||||
"text/plain", // Content type
|
||||
[data](size_t offset, size_t length, DataSink &sink) {
|
||||
const auto &d = *data;
|
||||
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
|
||||
@@ -187,6 +218,25 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
|
||||
});
|
||||
```
|
||||
|
||||
Without content length:
|
||||
|
||||
```cpp
|
||||
svr.Get("/stream", [&](const Request &req, Response &res) {
|
||||
res.set_content_provider(
|
||||
"text/plain", // Content type
|
||||
[&](size_t offset, size_t length, DataSink &sink) {
|
||||
if (/* there is still data */) {
|
||||
std::vector<char> data;
|
||||
// prepare data...
|
||||
sink.write(data.data(), data.size());
|
||||
} else {
|
||||
sink.done(); // No more data
|
||||
}
|
||||
return true; // return 'false' if you want to cancel the process.
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Chunked transfer encoding
|
||||
|
||||
```cpp
|
||||
@@ -196,7 +246,7 @@ svr.Get("/chunked", [&](const Request& req, Response& res) {
|
||||
sink.write("123", 3);
|
||||
sink.write("345", 3);
|
||||
sink.write("789", 3);
|
||||
sink.done();
|
||||
sink.done(); // No more data
|
||||
return true; // return 'false' if you want to cancel the process.
|
||||
}
|
||||
);
|
||||
@@ -243,7 +293,7 @@ svr.set_payload_max_length(1024 * 1024 * 512); // 512MB
|
||||
|
||||
### Server-Sent Events
|
||||
|
||||
Please check [here](https://github.com/yhirose/cpp-httplib/blob/master/example/sse.cc).
|
||||
Please see [Server example](https://github.com/yhirose/cpp-httplib/blob/master/example/ssesvr.cc) and [Client example](https://github.com/yhirose/cpp-httplib/blob/master/example/ssecli.cc).
|
||||
|
||||
### Default thread pool support
|
||||
|
||||
@@ -278,8 +328,8 @@ svr.new_task_queue = [] {
|
||||
};
|
||||
```
|
||||
|
||||
Client Example
|
||||
--------------
|
||||
Client
|
||||
------
|
||||
|
||||
```c++
|
||||
#include <httplib.h>
|
||||
@@ -287,16 +337,29 @@ Client Example
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// IMPORTANT: 1st parameter must be a hostname or an IP adress string.
|
||||
httplib::Client cli("localhost", 1234);
|
||||
|
||||
auto res = cli.Get("/hi");
|
||||
if (res && res->status == 200) {
|
||||
std::cout << res->body << std::endl;
|
||||
if (auto res = cli.Get("/hi")) {
|
||||
if (res->status == 200) {
|
||||
std::cout << res->body << std::endl;
|
||||
}
|
||||
} else {
|
||||
auto err = res.error();
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
NOTE: Constructor with scheme-host-port string is now supported!
|
||||
|
||||
```c++
|
||||
httplib::Client cli("localhost");
|
||||
httplib::Client cli("localhost:8080");
|
||||
httplib::Client cli("http://localhost");
|
||||
httplib::Client cli("http://localhost:8080");
|
||||
httplib::Client cli("https://localhost");
|
||||
```
|
||||
|
||||
### GET with HTTP headers
|
||||
|
||||
```c++
|
||||
@@ -305,19 +368,12 @@ httplib::Headers headers = {
|
||||
};
|
||||
auto res = cli.Get("/hi", headers);
|
||||
```
|
||||
|
||||
### GET with Content Receiver
|
||||
|
||||
or
|
||||
```c++
|
||||
std::string body;
|
||||
|
||||
auto res = cli.Get("/large-data",
|
||||
[&](const char *data, size_t data_length) {
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
|
||||
assert(res->body.empty());
|
||||
cli.set_default_headers({
|
||||
{ "Accept-Encoding", "gzip, deflate" }
|
||||
});
|
||||
auto res = cli.Get("/hi");
|
||||
```
|
||||
|
||||
### POST
|
||||
@@ -390,8 +446,19 @@ cli.set_write_timeout(5, 0); // 5 seconds
|
||||
|
||||
### Receive content with Content receiver
|
||||
|
||||
```c++
|
||||
std::string body;
|
||||
|
||||
auto res = cli.Get("/large-data",
|
||||
[&](const char *data, size_t data_length) {
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
```
|
||||
|
||||
```cpp
|
||||
std::string body;
|
||||
|
||||
auto res = cli.Get(
|
||||
"/stream", Headers(),
|
||||
[&](const Response &response) {
|
||||
@@ -408,6 +475,7 @@ auto res = cli.Get(
|
||||
|
||||
```cpp
|
||||
std::string body = ...;
|
||||
|
||||
auto res = cli_.Post(
|
||||
"/stream", body.size(),
|
||||
[](size_t offset, size_t length, DataSink &sink) {
|
||||
@@ -423,13 +491,12 @@ auto res = cli_.Post(
|
||||
httplib::Client client(url, port);
|
||||
|
||||
// prints: 0 / 000 bytes => 50% complete
|
||||
std::shared_ptr<httplib::Response> res =
|
||||
cli.Get("/", [](uint64_t len, uint64_t total) {
|
||||
printf("%lld / %lld bytes => %d%% complete\n",
|
||||
len, total,
|
||||
(int)(len*100/total));
|
||||
return true; // return 'false' if you want to cancel the request.
|
||||
}
|
||||
auto res = cli.Get("/", [](uint64_t len, uint64_t total) {
|
||||
printf("%lld / %lld bytes => %d%% complete\n",
|
||||
len, total,
|
||||
(int)(len*100/total));
|
||||
return true; // return 'false' if you want to cancel the request.
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
@@ -443,6 +510,9 @@ cli.set_basic_auth("user", "pass");
|
||||
|
||||
// Digest Authentication
|
||||
cli.set_digest_auth("user", "pass");
|
||||
|
||||
// Bearer Token Authentication
|
||||
cli.set_bearer_token_auth("token");
|
||||
```
|
||||
|
||||
NOTE: OpenSSL is required for Digest Authentication.
|
||||
@@ -457,6 +527,9 @@ cli.set_proxy_basic_auth("user", "pass");
|
||||
|
||||
// Digest Authentication
|
||||
cli.set_proxy_digest_auth("user", "pass");
|
||||
|
||||
// Bearer Token Authentication
|
||||
cli.set_proxy_bearer_token_auth("pass");
|
||||
```
|
||||
|
||||
NOTE: OpenSSL is required for Digest Authentication.
|
||||
@@ -482,29 +555,15 @@ httplib::make_range_header({{0, 0}, {-1, 1}}) // 'Range: bytes=0-0, -1'
|
||||
### Keep-Alive connection
|
||||
|
||||
```cpp
|
||||
cli.set_keep_alive_max_count(2); // Default is 5
|
||||
httplib::Client cli("localhost", 1234);
|
||||
|
||||
std::vector<Request> requests;
|
||||
Get(requests, "/get-request1");
|
||||
Get(requests, "/get-request2");
|
||||
Post(requests, "/post-request1", "text", "text/plain");
|
||||
Post(requests, "/post-request2", "text", "text/plain");
|
||||
cli.Get("/hello"); // with "Connection: close"
|
||||
|
||||
const size_t DATA_CHUNK_SIZE = 4;
|
||||
std::string data("abcdefg");
|
||||
Post(requests, "/post-request-with-content-provider",
|
||||
data.size(),
|
||||
[&](size_t offset, size_t length, DataSink &sink){
|
||||
sink.write(&data[offset], std::min(length, DATA_CHUNK_SIZE));
|
||||
},
|
||||
"text/plain");
|
||||
cli.set_keep_alive(true);
|
||||
cli.Get("/world");
|
||||
|
||||
std::vector<Response> responses;
|
||||
if (cli.send(requests, responses)) {
|
||||
for (const auto& res: responses) {
|
||||
...
|
||||
}
|
||||
}
|
||||
cli.set_keep_alive(false);
|
||||
cli.Get("/last-request"); // with "Connection: close"
|
||||
```
|
||||
|
||||
### Redirect
|
||||
@@ -533,32 +592,39 @@ OpenSSL Support
|
||||
|
||||
SSL support is available with `CPPHTTPLIB_OPENSSL_SUPPORT`. `libssl` and `libcrypto` should be linked.
|
||||
|
||||
NOTE: cpp-httplib supports 1.1.1 (until 2023-09-11) and 1.0.2 (2019-12-31).
|
||||
NOTE: cpp-httplib currently supports only version 1.1.1.
|
||||
|
||||
```c++
|
||||
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
|
||||
SSLServer svr("./cert.pem", "./key.pem");
|
||||
httplib::SSLServer svr("./cert.pem", "./key.pem");
|
||||
|
||||
SSLClient cli("localhost", 8080);
|
||||
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);
|
||||
```
|
||||
|
||||
Zlib Support
|
||||
------------
|
||||
Compression
|
||||
-----------
|
||||
|
||||
'gzip' compression is available with `CPPHTTPLIB_ZLIB_SUPPORT`. `libz` should be linked.
|
||||
The server can applie compression to the following MIME type contents:
|
||||
|
||||
The server applies gzip compression to the following MIME type contents:
|
||||
|
||||
* all text types
|
||||
* all text types except text/event-stream
|
||||
* image/svg+xml
|
||||
* application/javascript
|
||||
* application/json
|
||||
* application/xml
|
||||
* application/xhtml+xml
|
||||
|
||||
### Zlib Support
|
||||
|
||||
'gzip' compression is available with `CPPHTTPLIB_ZLIB_SUPPORT`. `libz` should be linked.
|
||||
|
||||
### Brotli Support
|
||||
|
||||
Brotli compression is available with `CPPHTTPLIB_BROTLI_SUPPORT`. Necessary libraries should be linked.
|
||||
Please see https://github.com/google/brotli for more detail.
|
||||
|
||||
### Compress request body on client
|
||||
|
||||
```c++
|
||||
@@ -570,7 +636,7 @@ res = cli.Post("/resource/foo", "...", "text/plain");
|
||||
|
||||
```c++
|
||||
cli.set_decompress(false);
|
||||
res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate"}});
|
||||
res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
|
||||
res->body; // Compressed data
|
||||
```
|
||||
|
||||
|
||||
14
appveyor.yml
14
appveyor.yml
@@ -1,14 +0,0 @@
|
||||
image:
|
||||
- Visual Studio 2019
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
build_script:
|
||||
- cmd: >-
|
||||
cd test
|
||||
|
||||
msbuild.exe test.sln /verbosity:minimal /t:Build /p:Configuration=Release;Platform=%PLATFORM%
|
||||
|
||||
test_script:
|
||||
- cmd: x64\Release\test.exe
|
||||
178
cmake/FindBrotli.cmake
Normal file
178
cmake/FindBrotli.cmake
Normal file
@@ -0,0 +1,178 @@
|
||||
# A simple FindBrotli package for Cmake's find_package function.
|
||||
# Note: This find package doesn't have version support, as the version file doesn't seem to be installed on most systems.
|
||||
#
|
||||
# If you want to find the static packages instead of shared (the default), define BROTLI_USE_STATIC_LIBS as TRUE.
|
||||
# The targets will have the same names, but it will use the static libs.
|
||||
#
|
||||
# Valid find_package COMPONENTS names: "decoder", "encoder", and "common"
|
||||
# Note that if you're requiring "decoder" or "encoder", then "common" will be automatically added as required.
|
||||
#
|
||||
# Defines the libraries (if found): Brotli::decoder, Brotli::encoder, Brotli::common
|
||||
# and the includes path variable: Brotli_INCLUDE_DIR
|
||||
#
|
||||
# If it's failing to find the libraries, try setting BROTLI_ROOT_DIR to the folder containing your library & include dir.
|
||||
|
||||
# If they asked for a specific version, warn/fail since we don't support it.
|
||||
# TODO: if they start distributing the version somewhere, implement finding it.
|
||||
# But currently there's a version header that doesn't seem to get installed.
|
||||
if(Brotli_FIND_VERSION)
|
||||
set(_brotli_version_error_msg "FindBrotli.cmake doesn't have version support!")
|
||||
# If the package is required, throw a fatal error
|
||||
# Otherwise, if not running quietly, we throw a warning
|
||||
if(Brotli_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "${_brotli_version_error_msg}")
|
||||
elseif(NOT Brotli_FIND_QUIETLY)
|
||||
message(WARNING "${_brotli_version_error_msg}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Since both decoder & encoder require the common lib, force its requirement..
|
||||
# if the user is requiring either of those other libs.
|
||||
if(Brotli_FIND_REQUIRED_decoder OR Brotli_FIND_REQUIRED_encoder)
|
||||
set(Brotli_FIND_REQUIRED_common TRUE)
|
||||
endif()
|
||||
|
||||
# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
|
||||
# Credit to FindOpenSSL.cmake for this
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
set(_brotli_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
if(WIN32)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
else()
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Make PkgConfig optional, since some users (mainly Windows) don't have it.
|
||||
# But it's a lot more clean than manually using find_library.
|
||||
find_package(PkgConfig QUIET)
|
||||
|
||||
# Only used if the PkgConfig libraries aren't used.
|
||||
find_path(Brotli_INCLUDE_DIR
|
||||
NAMES
|
||||
"brotli/decode.h"
|
||||
"brotli/encode.h"
|
||||
HINTS
|
||||
${BROTLI_ROOT_DIR}
|
||||
PATH_SUFFIXES
|
||||
"include"
|
||||
"includes"
|
||||
DOC "The path to Brotli's include directory."
|
||||
)
|
||||
# Hides this var from the GUI
|
||||
mark_as_advanced(Brotli_INCLUDE_DIR)
|
||||
|
||||
# Just used for PkgConfig stuff in the loop below
|
||||
set(_brotli_stat_str "")
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
set(_brotli_stat_str "_STATIC")
|
||||
endif()
|
||||
|
||||
# Lets us know we are using the PkgConfig libraries
|
||||
# Will be set false if any non-pkgconf vars are used
|
||||
set(_brotli_using_pkgconf TRUE)
|
||||
|
||||
# Each string here is "ComponentName;LiteralName" (the semi-colon is a delimiter)
|
||||
foreach(_listvar "common;common" "decoder;dec" "encoder;enc")
|
||||
# Split the component name and literal library name from the listvar
|
||||
list(GET _listvar 0 _component_name)
|
||||
list(GET _listvar 1 _libname)
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
# These need to be GLOBAL for MinGW when making ALIAS libraries against them.
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
# Have to use _STATIC to tell PkgConfig to find the static libs.
|
||||
pkg_check_modules(Brotli_${_component_name}_STATIC QUIET GLOBAL IMPORTED_TARGET libbrotli${_libname})
|
||||
else()
|
||||
pkg_check_modules(Brotli_${_component_name} QUIET GLOBAL IMPORTED_TARGET libbrotli${_libname})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Check if the target was already found by Pkgconf
|
||||
if(TARGET PkgConfig::Brotli_${_component_name} OR TARGET PkgConfig::Brotli_${_component_name}_STATIC)
|
||||
# Can't use generators for ALIAS targets, so you get this jank
|
||||
add_library(Brotli::${_component_name} ALIAS PkgConfig::Brotli_${_component_name}${_brotli_stat_str})
|
||||
|
||||
# Tells HANDLE_COMPONENTS we found the component
|
||||
set(Brotli_${_component_name}_FOUND TRUE)
|
||||
if(Brotli_FIND_REQUIRED_${_component_name})
|
||||
# If the lib is required, we can add its literal path as a required var for FindPackageHandleStandardArgs
|
||||
# Since it won't accept the PkgConfig targets
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
list(APPEND _brotli_req_vars "Brotli_${_component_name}_STATIC_LIBRARIES")
|
||||
else()
|
||||
list(APPEND _brotli_req_vars "Brotli_${_component_name}_LINK_LIBRARIES")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Skip searching for the libs with find_library since it was already found by Pkgconf
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Lets us know we aren't using the PkgConfig libraries
|
||||
set(_brotli_using_pkgconf FALSE)
|
||||
if(Brotli_FIND_REQUIRED_${_component_name})
|
||||
# If it's required, we can set the name used in find_library as a required var for FindPackageHandleStandardArgs
|
||||
list(APPEND _brotli_req_vars "Brotli_${_component_name}")
|
||||
endif()
|
||||
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
list(APPEND _brotli_lib_names
|
||||
"brotli${_libname}-static"
|
||||
"libbrotli${_libname}-static"
|
||||
)
|
||||
else()
|
||||
list(APPEND _brotli_lib_names
|
||||
"brotli${_libname}"
|
||||
"libbrotli${_libname}"
|
||||
)
|
||||
endif()
|
||||
|
||||
find_library(Brotli_${_component_name}
|
||||
NAMES ${_brotli_lib_names}
|
||||
HINTS ${BROTLI_ROOT_DIR}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"lib64"
|
||||
"libs"
|
||||
"libs64"
|
||||
"lib/x86_64-linux-gnu"
|
||||
)
|
||||
# Hide the library variable from the Cmake GUI
|
||||
mark_as_advanced(Brotli_${_component_name})
|
||||
|
||||
# Unset since otherwise it'll stick around for the next loop and break things
|
||||
unset(_brotli_lib_names)
|
||||
|
||||
# Check if find_library found the library
|
||||
if(Brotli_${_component_name})
|
||||
# Tells HANDLE_COMPONENTS we found the component
|
||||
set(Brotli_${_component_name}_FOUND TRUE)
|
||||
|
||||
add_library("Brotli::${_component_name}" UNKNOWN IMPORTED)
|
||||
# Attach the literal library and include dir to the IMPORTED target for the end-user
|
||||
set_target_properties("Brotli::${_component_name}" PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Brotli_INCLUDE_DIR}"
|
||||
IMPORTED_LOCATION "${Brotli_${_component_name}}"
|
||||
)
|
||||
else()
|
||||
# Tells HANDLE_COMPONENTS we found the component
|
||||
set(Brotli_${_component_name}_FOUND FALSE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
# Sets Brotli_FOUND, and fails the find_package(Brotli) call if it was REQUIRED but missing libs.
|
||||
find_package_handle_standard_args(Brotli
|
||||
FOUND_VAR
|
||||
Brotli_FOUND
|
||||
REQUIRED_VARS
|
||||
Brotli_INCLUDE_DIR
|
||||
${_brotli_required_targets}
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
|
||||
# Restore the original find library ordering
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_brotli_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
endif()
|
||||
@@ -1,42 +1,50 @@
|
||||
|
||||
#CXX = clang++
|
||||
CXXFLAGS = -std=c++14 -I.. -Wall -Wextra -pthread
|
||||
CXXFLAGS = -std=c++11 -I.. -Wall -Wextra -pthread
|
||||
|
||||
OPENSSL_DIR = /usr/local/opt/openssl
|
||||
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
|
||||
|
||||
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
||||
|
||||
all: server client hello simplecli simplesvr upload redirect sse benchmark
|
||||
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
|
||||
|
||||
all: server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark
|
||||
|
||||
server : server.cc ../httplib.h Makefile
|
||||
$(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
$(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
client : client.cc ../httplib.h Makefile
|
||||
$(CXX) -o client $(CXXFLAGS) client.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
$(CXX) -o client $(CXXFLAGS) client.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
hello : hello.cc ../httplib.h Makefile
|
||||
$(CXX) -o hello $(CXXFLAGS) hello.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
$(CXX) -o hello $(CXXFLAGS) hello.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
simplecli : simplecli.cc ../httplib.h Makefile
|
||||
$(CXX) -o simplecli $(CXXFLAGS) simplecli.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
$(CXX) -o simplecli $(CXXFLAGS) simplecli.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
simplesvr : simplesvr.cc ../httplib.h Makefile
|
||||
$(CXX) -o simplesvr $(CXXFLAGS) simplesvr.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
$(CXX) -o simplesvr $(CXXFLAGS) simplesvr.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
upload : upload.cc ../httplib.h Makefile
|
||||
$(CXX) -o upload $(CXXFLAGS) upload.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
$(CXX) -o upload $(CXXFLAGS) upload.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
redirect : redirect.cc ../httplib.h Makefile
|
||||
$(CXX) -o redirect $(CXXFLAGS) redirect.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
$(CXX) -o redirect $(CXXFLAGS) redirect.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
sse : sse.cc ../httplib.h Makefile
|
||||
$(CXX) -o sse $(CXXFLAGS) sse.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
ssesvr : ssesvr.cc ../httplib.h Makefile
|
||||
$(CXX) -o ssesvr $(CXXFLAGS) ssesvr.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
ssecli : ssecli.cc ../httplib.h Makefile
|
||||
$(CXX) -o ssecli $(CXXFLAGS) ssecli.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
benchmark : benchmark.cc ../httplib.h Makefile
|
||||
$(CXX) -o benchmark $(CXXFLAGS) benchmark.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
$(CXX) -o benchmark $(CXXFLAGS) benchmark.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
|
||||
|
||||
pem:
|
||||
openssl genrsa 2048 > key.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 sse benchmark *.pem
|
||||
rm server client hello simplecli simplesvr upload redirect ssesvr sselci benchmark *.pem
|
||||
|
||||
@@ -23,12 +23,12 @@ int main(void) {
|
||||
httplib::Client cli("localhost", 8080);
|
||||
#endif
|
||||
|
||||
auto res = cli.Get("/hi");
|
||||
if (res) {
|
||||
if (auto res = cli.Get("/hi")) {
|
||||
cout << res->status << endl;
|
||||
cout << res->get_header_value("Content-Type") << endl;
|
||||
cout << res->body << endl;
|
||||
} else {
|
||||
cout << "error code: " << res.error() << std::endl;
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto result = cli.get_openssl_verify_result();
|
||||
if (result) {
|
||||
|
||||
@@ -8,24 +8,21 @@
|
||||
#include <httplib.h>
|
||||
#include <iostream>
|
||||
|
||||
#define CA_CERT_FILE "./ca-bundle.crt"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(void) {
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto res = httplib::Client2("https://localhost:8080")
|
||||
.set_ca_cert_path(CA_CERT_FILE)
|
||||
// .enable_server_certificate_verification(true)
|
||||
.Get("/hi");
|
||||
auto scheme_host_port = "https://localhost:8080";
|
||||
#else
|
||||
auto res = httplib::Client2("http://localhost:8080").Get("/hi");
|
||||
auto scheme_host_port = "http://localhost:8080";
|
||||
#endif
|
||||
|
||||
if (res) {
|
||||
if (auto res = httplib::Client(scheme_host_port).Get("/hi")) {
|
||||
cout << res->status << endl;
|
||||
cout << res->get_header_value("Content-Type") << endl;
|
||||
cout << res->body << endl;
|
||||
} else {
|
||||
cout << res.error() << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -46,7 +46,7 @@ string dump_multipart_files(const MultipartFormDataMap &files) {
|
||||
snprintf(buf, sizeof(buf), "content type: %s\n", file.content_type.c_str());
|
||||
s += buf;
|
||||
|
||||
snprintf(buf, sizeof(buf), "text length: %lu\n", file.content.size());
|
||||
snprintf(buf, sizeof(buf), "text length: %zu\n", file.content.size());
|
||||
s += buf;
|
||||
|
||||
s += "----------------\n";
|
||||
|
||||
21
example/ssecli.cc
Normal file
21
example/ssecli.cc
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// ssecli.cc
|
||||
//
|
||||
// Copyright (c) 2019 Yuji Hirose. All rights reserved.
|
||||
// MIT License
|
||||
//
|
||||
|
||||
#include <httplib.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(void) {
|
||||
httplib::Client("http://localhost:1234")
|
||||
.Get("/event1", [&](const char *data, size_t data_length) {
|
||||
std::cout << string(data, data_length);
|
||||
return true;
|
||||
});
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -79,20 +79,20 @@ int main(void) {
|
||||
|
||||
svr.Get("/event1", [&](const Request & /*req*/, Response &res) {
|
||||
cout << "connected to event1..." << endl;
|
||||
res.set_header("Content-Type", "text/event-stream");
|
||||
res.set_chunked_content_provider([&](size_t /*offset*/, DataSink &sink) {
|
||||
ed.wait_event(&sink);
|
||||
return true;
|
||||
});
|
||||
res.set_chunked_content_provider("text/event-stream",
|
||||
[&](size_t /*offset*/, DataSink &sink) {
|
||||
ed.wait_event(&sink);
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
svr.Get("/event2", [&](const Request & /*req*/, Response &res) {
|
||||
cout << "connected to event2..." << endl;
|
||||
res.set_header("Content-Type", "text/event-stream");
|
||||
res.set_chunked_content_provider([&](size_t /*offset*/, DataSink &sink) {
|
||||
ed.wait_event(&sink);
|
||||
return true;
|
||||
});
|
||||
res.set_chunked_content_provider("text/event-stream",
|
||||
[&](size_t /*offset*/, DataSink &sink) {
|
||||
ed.wait_event(&sink);
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
thread t([&] {
|
||||
@@ -6,6 +6,7 @@
|
||||
set(HTTPLIB_IS_USING_OPENSSL @HTTPLIB_IS_USING_OPENSSL@)
|
||||
set(HTTPLIB_IS_USING_ZLIB @HTTPLIB_IS_USING_ZLIB@)
|
||||
set(HTTPLIB_IS_COMPILED @HTTPLIB_COMPILE@)
|
||||
set(HTTPLIB_IS_USING_BROTLI @HTTPLIB_IS_USING_BROTLI@)
|
||||
set(HTTPLIB_VERSION @PROJECT_VERSION@)
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
@@ -26,6 +27,14 @@ if(@HTTPLIB_IS_USING_ZLIB@)
|
||||
find_dependency(ZLIB REQUIRED)
|
||||
endif()
|
||||
|
||||
if(@HTTPLIB_IS_USING_BROTLI@)
|
||||
# Needed so we can use our own FindBrotli.cmake in this file.
|
||||
# Note that the FindBrotli.cmake file is installed in the same dir as this file.
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
||||
set(BROTLI_USE_STATIC_LIBS @BROTLI_USE_STATIC_LIBS@)
|
||||
find_dependency(Brotli COMPONENTS common encoder decoder REQUIRED)
|
||||
endif()
|
||||
|
||||
# Mildly useful for end-users
|
||||
# Not really recommended to be used though
|
||||
set_and_check(HTTPLIB_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_FULL_INCLUDEDIR@")
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
|
||||
#CXX = clang++
|
||||
CXXFLAGS = -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits -Wconversion
|
||||
OPENSSL_DIR = /usr/local/opt/openssl
|
||||
|
||||
OPENSSL_DIR = /usr/local/opt/openssl@1.1
|
||||
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 -lbrotlienc -lbrotlidec
|
||||
|
||||
all : test
|
||||
./test
|
||||
|
||||
@@ -12,10 +17,10 @@ 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) -pthread
|
||||
$(CXX) -o test $(CXXFLAGS) test.cc gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
|
||||
|
||||
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) -pthread
|
||||
$(CXX) -o test_proxy $(CXXFLAGS) test_proxy.cc gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
|
||||
|
||||
cert.pem:
|
||||
openssl genrsa 2048 > key.pem
|
||||
|
||||
1000
test/test.cc
1000
test/test.cc
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@
|
||||
<ProjectGuid>{6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>test</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
@@ -97,6 +97,7 @@
|
||||
<AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
|
||||
<AdditionalUsingDirectories>
|
||||
</AdditionalUsingDirectories>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -114,6 +115,7 @@
|
||||
<AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
|
||||
<AdditionalUsingDirectories>
|
||||
</AdditionalUsingDirectories>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -133,6 +135,7 @@
|
||||
<AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
|
||||
<AdditionalUsingDirectories>
|
||||
</AdditionalUsingDirectories>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -154,6 +157,7 @@
|
||||
<AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
|
||||
<AdditionalUsingDirectories>
|
||||
</AdditionalUsingDirectories>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -171,4 +175,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
using namespace std;
|
||||
using namespace httplib;
|
||||
|
||||
void ProxyTest(Client& cli, bool basic) {
|
||||
template <typename T>
|
||||
void ProxyTest(T& cli, bool basic) {
|
||||
cli.set_proxy("localhost", basic ? 3128 : 3129);
|
||||
auto res = cli.Get("/get");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
@@ -36,7 +37,8 @@ TEST(ProxyTest, SSLDigest) {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void RedirectProxyText(Client& cli, const char *path, bool basic) {
|
||||
template <typename T>
|
||||
void RedirectProxyText(T& cli, const char *path, bool basic) {
|
||||
cli.set_proxy("localhost", basic ? 3128 : 3129);
|
||||
if (basic) {
|
||||
cli.set_proxy_basic_auth("hello", "world");
|
||||
@@ -52,6 +54,7 @@ void RedirectProxyText(Client& 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);
|
||||
@@ -73,6 +76,7 @@ TEST(RedirectTest, HTTPBinSSLDigest) {
|
||||
RedirectProxyText(cli, "/redirect/2", false);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(RedirectTest, YouTubeNoSSLBasic) {
|
||||
@@ -98,7 +102,8 @@ TEST(RedirectTest, YouTubeSSLDigest) {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void BaseAuthTestFromHTTPWatch(Client& cli) {
|
||||
template <typename T>
|
||||
void BaseAuthTestFromHTTPWatch(T& cli) {
|
||||
cli.set_proxy("localhost", 3128);
|
||||
cli.set_proxy_basic_auth("hello", "world");
|
||||
|
||||
@@ -155,7 +160,8 @@ TEST(BaseAuthTest, SSL) {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
void DigestAuthTestFromHTTPWatch(Client& cli) {
|
||||
template <typename T>
|
||||
void DigestAuthTestFromHTTPWatch(T& cli) {
|
||||
cli.set_proxy("localhost", 3129);
|
||||
cli.set_proxy_digest_auth("hello", "world");
|
||||
|
||||
@@ -222,66 +228,46 @@ void KeepAliveTest(Client& cli, bool basic) {
|
||||
#endif
|
||||
}
|
||||
|
||||
cli.set_keep_alive_max_count(4);
|
||||
cli.set_follow_location(true);
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
cli.set_digest_auth("hello", "world");
|
||||
#endif
|
||||
|
||||
std::vector<Request> requests;
|
||||
{
|
||||
auto res = cli.Get("/get");
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
{
|
||||
auto res = cli.Get("/redirect/2");
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
Get(requests, "/get");
|
||||
Get(requests, "/redirect/2");
|
||||
{
|
||||
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",
|
||||
};
|
||||
|
||||
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",
|
||||
};
|
||||
|
||||
for (auto path : paths) {
|
||||
Get(requests, path.c_str());
|
||||
for (auto path: paths) {
|
||||
auto res = cli.Get(path.c_str());
|
||||
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res->body);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int count = 100;
|
||||
while (count--) {
|
||||
Get(requests, "/get");
|
||||
auto res = cli.Get("/get");
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Response> responses;
|
||||
auto ret = cli.send(requests, responses);
|
||||
ASSERT_TRUE(ret == true);
|
||||
ASSERT_TRUE(requests.size() == responses.size());
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
{
|
||||
auto &res = responses[i++];
|
||||
EXPECT_EQ(200, res.status);
|
||||
}
|
||||
|
||||
{
|
||||
auto &res = responses[i++];
|
||||
EXPECT_EQ(200, res.status);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
int count = static_cast<int>(paths.size());
|
||||
while (count--) {
|
||||
auto &res = responses[i++];
|
||||
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res.body);
|
||||
EXPECT_EQ(200, res.status);
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < responses.size(); i++) {
|
||||
auto &res = responses[i];
|
||||
EXPECT_EQ(200, res.status);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(KeepAliveTest, NoSSLWithBasic) {
|
||||
Client cli("httpbin.org");
|
||||
KeepAliveTest(cli, true);
|
||||
@@ -292,7 +278,6 @@ TEST(KeepAliveTest, SSLWithBasic) {
|
||||
KeepAliveTest(cli, true);
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(KeepAliveTest, NoSSLWithDigest) {
|
||||
Client cli("httpbin.org");
|
||||
KeepAliveTest(cli, false);
|
||||
@@ -303,3 +288,4 @@ TEST(KeepAliveTest, SSLWithDigest) {
|
||||
KeepAliveTest(cli, false);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user