Compare commits

...

87 Commits

Author SHA1 Message Date
Ivan Fefer
3da4a0ac69 Add compression buffer size customization (#644)
* add compression buffer size customization and small brotli refactor

* allocat brotli buffer once

* add init to brotli decoder buffer
2020-09-08 12:18:14 -04:00
yhirose
9d12b3f20e Fixed warnings and refactoring 2020-09-03 20:33:30 -04:00
Omkar Jadhav
852a374748 Fix server crash caused due to regex complexity while matching headers. (#632)
* Fix parsing to parse query string with single space char.

When passed ' ' as a query string, the server crashes cause of illegal memory access done in httplib::detail::split. Have added checks to make sure the split function has a valid string with length > 0.

* Fix parsing to parse query string with single space char.

* Fix server crash caused due to regex complexity while matching headers.

While parsing content-type header in multipart form request the server crashes due to the exhaustion of max iterations performed while matching the input string with content-type regex.
Have removed the regex which might use backtracking while matching and replaced it with manual string processing. Have added tests as well.

* Remove magic number

Co-authored-by: Ivan Fefer <fefer.ivan@gmail.com>

Co-authored-by: yhirose <yhirose@users.noreply.github.com>
Co-authored-by: Ivan Fefer <fefer.ivan@gmail.com>
2020-09-03 13:17:52 -04:00
Ivan Fefer
3b5bab3308 Fix gzip_decompressor in case of one chunk being exactly equal to buffer size (#636)
* add larget chunks test

* revert test

* Fix gzip decoder in case of chunk being equal to buffer size

* add test
2020-09-03 12:20:02 -04:00
yhirose
69e75f4a67 Fix #635. HTTPS request stucked with proxy (#637) 2020-09-03 12:17:53 -04:00
Omkar Jadhav
b0fd4befb1 Fix query parsing issues (#629)
* Fix parsing to parse query string with single space char.

When passed ' ' as a query string, the server crashes cause of illegal memory access done in httplib::detail::split. Have added checks to make sure the split function has a valid string with length > 0.

* Fix parsing to parse query string with single space char.
2020-08-28 09:43:28 -04:00
yhirose
3e80666a74 Fix #628 2020-08-27 19:45:28 -04:00
yhirose
3e4567bae8 Updated Repl.it examples 2020-08-27 14:16:35 -04:00
yhirose
db075d8cf9 Added Repl.it examples 2020-08-27 14:06:57 -04:00
yhirose
16df0ef37e Code cleanup 2020-08-26 12:18:49 -04:00
Ivan Fefer
f1a2ac5108 Avoid copying of content provider if possible (#627) 2020-08-26 08:56:51 -04:00
yhirose
e5743b358d Updated README 2020-08-25 20:26:53 -04:00
Ivan Fefer
1184bbe4cb Fix typo in README (#625) 2020-08-25 06:38:16 -04:00
Felix Kästner
9dcffda7ae Fix cmake execute_process working directory (#622)
Correct the working directory of the execute_process call, to get the version from git tags.
The working directory should be the the directory of this libary. Otherwise, if you include httplib
as a git submodule and call add_subdirectory, the execute_process command will be run in a wrong
directory leading to error.
2020-08-24 17:23:01 -04:00
yhirose
e5903635e2 Fix #619 2020-08-22 12:54:43 -04:00
yhirose
510b4eaaae Fix #613 2020-08-17 13:40:06 -04:00
yhirose
d7e63b4316 Update README 2020-08-16 20:49:54 -04:00
yhirose
e5dd410256 Added set_content_provider without content length 2020-08-15 05:53:49 -04:00
yhirose
951e46929e Fix #609 2020-08-14 15:01:09 -04:00
yhirose
c8adac30f4 Fix #564 again 2020-08-13 08:07:25 -04:00
yhirose
b2b4f7635f Fix #608 2020-08-11 12:11:05 -04:00
R Edgar
649b1d2172 Fix nullptr_t issue (#605)
Clang complains that `nullptr_t` should be `std::nullptr_t
2020-08-09 16:45:53 -04:00
yhirose
dc5f9ba164 Better error handling on client (#601) 2020-08-08 20:50:24 -04:00
yhirose
cf084e1db1 Fixed example build errors 2020-08-08 00:10:08 -04:00
KTGH
e0e5898601 Overhaul FindBrotli to fix weird issues (#604)
Should get rid of the issue about not being able to create an ALIAS on
MinGW, as well as the "No REQUIRED_VARS" issue.

Fixes #603 (hopefully)
2020-08-06 07:08:29 -04:00
yhirose
dfec2de5b5 Update README 2020-08-03 23:37:05 -04:00
yhirose
04002d57bd Added set_default_headers (Fix #600) 2020-08-03 22:05:37 -04:00
yhirose
38a7706c8b Removed old Keep-Alive functions 2020-08-03 22:04:40 -04:00
KTGH
abaf875c42 Fix FindBrotli when no Brotli installed (#598)
Woops.

Ref https://github.com/yhirose/cpp-httplib/issues/582#issuecomment-667537002
2020-08-01 17:08:49 -04:00
PixlRainbow
5f76cb01c7 fix #592 -- add check for static-linked OpenSSL (#595) 2020-08-01 08:10:42 -04:00
yhirose
ae54e833ea Code cleanup 2020-07-31 23:48:42 -04:00
yhirose
0dd3659de5 Updated README 2020-07-31 18:54:53 -04:00
KTGH
999f6abd2c Fix for Cmake on systems without Git (#594)
If you didn't have Git installed, execute_process never declared the
error variable, which led to it never parsing the header for a version.
So if Git wasn't installed, the version variable never got declared,
which caused errors.

This fixes that.
2020-07-31 13:46:12 -04:00
KTGH
48da75dd35 Fix FindBrotli for static libs (#593)
It wasn't linking them.
2020-07-31 13:45:21 -04:00
yhirose
4f84eeb298 Bearer Token auth support. Fix #484 2020-07-31 12:37:14 -04:00
yhirose
a5b4cfadb9 Brotli suport on server. Fix #578 2020-07-31 10:23:57 -04:00
yhirose
3e906a9b8c Fix #591 2020-07-30 18:26:18 -04:00
yhirose
110393eadb Class name change 2020-07-30 17:27:07 -04:00
yhirose
98caa8c058 Updated README 2020-07-30 17:21:49 -04:00
yhirose
ef65f09608 OpenSSL support on Visual Studio project 2020-07-30 17:19:12 -04:00
ThePiso
e130cf3a3b The piso patch 1 (#590)
* Update httplib.h

When you disconnect and reconnect from the network, your network stack rewrites and updates /etc/resolv.conf accordingly. This configuration file is needed by the DNS resolver in the C library. The C library reads the DNS configuration from /etc/resolv.conf the first time, and caches it. It doesn't check, with every lookup, if the contents of /etc/resolv.conf have changed.
the solution is to add a call to res_init(), defined in resolv.h

* Update httplib.h
2020-07-30 10:11:02 -04:00
yhirose
8a348f17fd Resolved #192 2020-07-30 01:47:54 -04:00
yhirose
797d1f27e8 Fix #357 2020-07-29 23:12:05 -04:00
yhirose
6cde600922 Simplified simplecli.cc 2020-07-29 16:04:28 -04:00
KTGH
342c3ab293 Add Brotli Cmake support (#584)
Had to create a custom FindBrotli package, as not all users have
PkgConfig installed (which Brotli uses). This file gets installed
alongside httplibConfig.cmake for the end-users convenience.

Set BROTLI_USE_STATIC_LIBS to ON if you want to find the static libs
instead of default shared.

Adds the HTTPLIB_REQUIRE_BROTLI (default off) and HTTPLIB_USE_BROTLI_IF_AVAILABLE
(default on) options, which work in the same manner as the other optional/required
dependency options.

Moved the scattered linking and definitions to a single call.

Updated some documentation about the new options.

Improved the in-tree support by setting the HTTPLIB_IS_USING_XYZ
variables in the main CMakeLists (as well as having them in the
httplibConfig.cmake file).

Fixes #582
2020-07-28 17:04:29 -04:00
yhirose
6cce7951fc Fixed build error on non Windows environments with OpenSSL 2020-07-27 22:34:35 -04:00
yhirose
e9058e5639 Fixed build error on Windows with OpenSSL 2020-07-27 22:32:31 -04:00
yhirose
2538a85486 Fix #581 2020-07-27 22:07:04 -04:00
KTGH
8c501022b3 Fix Cmake build for MinGW (#580)
Seems certain targets/hosts failed without these, as "_MSC_VER" is
undefined on MinGW, which caused the 'pragma comment(lib "libname")' to
fail.

Fixes #575
2020-07-26 12:27:03 -04:00
yhirose
9f5db2d1aa Updated README 2020-07-25 20:53:38 -04:00
yhirose
12540fe8d3 Brotli support on client 2020-07-25 20:44:02 -04:00
yhirose
29a06f852a Update README 2020-07-25 11:24:06 -04:00
yhirose
0e9cfd9f49 SSE client example 2020-07-25 11:20:57 -04:00
yhirose
90da199aba Disable compression when content-type is text/event-stream 2020-07-25 10:46:52 -04:00
yhirose
366d073490 Fixed build errors 2020-07-25 09:40:35 -04:00
yhirose
9ca1fa8b18 Fix #576 2020-07-25 09:37:57 -04:00
yhirose
15c4106a36 Added a unit test 2020-07-22 08:07:59 -04:00
yhirose
72ce293fed Removed set_timeout_sec and left set_base_dir 2020-07-20 17:15:16 -04:00
yhirose
b476b55771 Fix #557 2020-07-20 17:04:50 -04:00
yhirose
0db9d21eb0 Fix #571 2020-07-19 18:40:55 -04:00
yhirose
5ddaf949d0 Fixed build error on Windows 2020-07-19 18:32:28 -04:00
yhirose
457a5a7501 Added compressor class 2020-07-19 17:44:45 -04:00
Daniel Ottiger
2ce080c2cb include <wincrypt.h> as otherwise CertOpenSystemStoreW can not be found (#568)
- visual studio 2019, version 16.6.3
- 64 bit target
2020-07-15 10:17:18 -04:00
yhirose
6ad25b6cf0 Fix #566 2020-07-12 20:41:02 -04:00
yhirose
3dff60eb16 Fix #565 2020-07-10 08:18:28 -04:00
yhirose
5038314b21 Fix #564 2020-07-08 13:56:06 -04:00
yhirose
6e1297cab0 Fix #150 (#556) 2020-07-07 18:55:46 -04:00
yhirose
7de743c962 Code format 2020-07-04 00:11:32 -04:00
Umiade
964fb5e5ca Fix: regex can't match when proxy was set to some web debugger(e.g. Fiddler) (#553)
Co-authored-by: Umiade <hanyuchao@corp.netease.com>
2020-07-03 07:17:04 -04:00
yhirose
c4f3f9529b Fix #534 (#546) 2020-07-02 21:57:50 -04:00
Ilya Tsybulsky
887def9490 Fix logger never called when write_content_with_provider returns false (#549) 2020-07-01 17:09:43 -04:00
Ilya Tsybulsky
bad6b2d22f fix-the-code-won't compile-with-sdl-checks-on (#550) 2020-07-01 17:09:19 -04:00
rundong08
3d47a51430 Fixed comparison of integers of different signs. (#544) 2020-06-29 21:19:56 -04:00
Ron Klein
0a2cb20223 fix documentation typo (#539)
fix "adress" --> "address"
2020-06-22 18:12:22 -04:00
yhirose
ce502a73e1 Fix #531 2020-06-22 14:56:18 -04:00
yhirose
010e4479f4 Fixed test errors due to httpbin.org 2020-06-22 14:53:20 -04:00
Ahmet Karaahmetoğlu
70e193374a Fix #530 (#535) 2020-06-21 15:08:40 -04:00
yhirose
6b22409217 Code format 2020-06-18 23:33:07 -04:00
yhirose
969cccd52a Use && for parameter of boundary 2020-06-18 23:32:09 -04:00
yhirose
4a9c048bbc Fixed problem with set_socket_options 2020-06-18 23:31:41 -04:00
yhirose
bfabbec8c7 Fix #528 2020-06-18 12:20:01 -04:00
yhirose
3e9c06cf79 Fixed #527 2020-06-18 12:18:43 -04:00
yhirose
29677540ae Removed unnecessary yeid. 2020-06-16 21:33:10 -04:00
yhirose
71fcfeb912 Removed unnecessary code 2020-06-16 21:21:03 -04:00
yhirose
c7d22e451f Fixed timeout calculation bugs 2020-06-16 21:20:47 -04:00
yhirose
42f9f9107f Updated version in the User Agent string 2020-06-16 17:53:15 -04:00
yhirose
7cd25fbd63 Fix #499 2020-06-16 17:46:23 -04:00
18 changed files with 3228 additions and 1795 deletions

View File

@@ -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
View File

@@ -7,7 +7,7 @@ example/simplecli
example/simplesvr
example/benchmark
example/redirect
example/sse
example/sse*
example/upload
example/*.pem
test/test

View File

@@ -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
View File

@@ -2,16 +2,46 @@ cpp-httplib
===========
[![](https://github.com/yhirose/cpp-httplib/workflows/test/badge.svg)](https://github.com/yhirose/cpp-httplib/actions)
[![Bulid Status](https://ci.appveyor.com/api/projects/status/github/yhirose/cpp-httplib?branch=master&svg=true)](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
```

View File

@@ -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
View 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()

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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
View 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;
}

View File

@@ -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([&] {

3298
httplib.h

File diff suppressed because it is too large Load Diff

View File

@@ -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@")

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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>

View File

@@ -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