mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf084e1db1 | |||
| e0e5898601 | |||
| dfec2de5b5 | |||
| 04002d57bd | |||
| 38a7706c8b | |||
| abaf875c42 | |||
| 5f76cb01c7 | |||
| ae54e833ea | |||
| 0dd3659de5 | |||
| 999f6abd2c | |||
| 48da75dd35 | |||
| 4f84eeb298 | |||
| a5b4cfadb9 |
+14
-10
@@ -1,6 +1,6 @@
|
||||
#[[
|
||||
Build options:
|
||||
* BUILD_SHARED_LIBS (default off) builds as a static library (if HTTPLIB_COMPILE is ON)
|
||||
* 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)
|
||||
@@ -60,17 +60,21 @@
|
||||
]]
|
||||
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
|
||||
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.
|
||||
@@ -101,7 +105,7 @@ if(HTTPLIB_COMPILE)
|
||||
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 compression support." ON)
|
||||
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)
|
||||
|
||||
@@ -311,6 +311,13 @@ httplib::Headers headers = {
|
||||
};
|
||||
auto res = cli.Get("/hi", headers);
|
||||
```
|
||||
or
|
||||
```c++
|
||||
cli.set_default_headers({
|
||||
{ "Accept-Encoding", "gzip, deflate" }
|
||||
});
|
||||
auto res = cli.Get("/hi");
|
||||
```
|
||||
|
||||
### POST
|
||||
|
||||
@@ -447,6 +454,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.
|
||||
@@ -461,6 +471,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.
|
||||
|
||||
+128
-135
@@ -5,181 +5,174 @@
|
||||
# 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.
|
||||
|
||||
function(brotli_err_msg _err_msg)
|
||||
# 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 "${_err_msg}")
|
||||
message(FATAL_ERROR "${_brotli_version_error_msg}")
|
||||
elseif(NOT Brotli_FIND_QUIETLY)
|
||||
message(WARNING "${_err_msg}")
|
||||
message(WARNING "${_brotli_version_error_msg}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# If they asked for a specific version, warn/fail since we don't support it.
|
||||
if(Brotli_FIND_VERSION)
|
||||
brotli_err_msg("FindBrotli.cmake doesn't have version support!")
|
||||
endif()
|
||||
|
||||
# Since both decoder & encoder require the common lib (I think), force its requirement..
|
||||
# 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)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
pkg_check_modules(Brotli_common_STATIC QUIET IMPORTED_TARGET libbrotlicommon)
|
||||
pkg_check_modules(Brotli_decoder_STATIC QUIET IMPORTED_TARGET libbrotlidec)
|
||||
pkg_check_modules(Brotli_encoder_STATIC QUIET IMPORTED_TARGET libbrotlienc)
|
||||
else()
|
||||
pkg_check_modules(Brotli_common QUIET IMPORTED_TARGET libbrotlicommon)
|
||||
pkg_check_modules(Brotli_decoder QUIET IMPORTED_TARGET libbrotlidec)
|
||||
pkg_check_modules(Brotli_encoder QUIET IMPORTED_TARGET libbrotlienc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Only used if the PkgConfig libraries aren't used.
|
||||
find_path(Brotli_INCLUDE_DIR
|
||||
NAMES "brotli/decode.h" "brotli/encode.h"
|
||||
PATH_SUFFIXES "include" "includes"
|
||||
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)
|
||||
|
||||
# Also check if Brotli_decoder was defined, as it can be passed by the end-user
|
||||
if(NOT TARGET PkgConfig::Brotli_decoder AND NOT Brotli_decoder)
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
list(APPEND _brotli_decoder_lib_names
|
||||
"brotlidec-static"
|
||||
"libbrotlidec-static"
|
||||
)
|
||||
else()
|
||||
list(APPEND _brotli_decoder_lib_names
|
||||
"brotlidec"
|
||||
"libbrotlidec"
|
||||
)
|
||||
endif()
|
||||
find_library(Brotli_decoder
|
||||
NAMES ${_brotli_decoder_lib_names}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"lib64"
|
||||
"libs"
|
||||
"libs64"
|
||||
"lib/x86_64-linux-gnu"
|
||||
)
|
||||
# Just used for PkgConfig stuff in the loop below
|
||||
set(_brotli_stat_str "")
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
set(_brotli_stat_str "_STATIC")
|
||||
endif()
|
||||
|
||||
# Also check if Brotli_encoder was defined, as it can be passed by the end-user
|
||||
if(NOT TARGET PkgConfig::Brotli_encoder AND NOT Brotli_encoder)
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
list(APPEND _brotli_encoder_lib_names
|
||||
"brotlienc-static"
|
||||
"libbrotlienc-static"
|
||||
)
|
||||
else()
|
||||
list(APPEND _brotli_encoder_lib_names
|
||||
"brotlienc"
|
||||
"libbrotlienc"
|
||||
)
|
||||
# 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()
|
||||
find_library(Brotli_encoder
|
||||
NAMES ${_brotli_encoder_lib_names}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"lib64"
|
||||
"libs"
|
||||
"libs64"
|
||||
"lib/x86_64-linux-gnu"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Also check if Brotli_common was defined, as it can be passed by the end-user
|
||||
if(NOT TARGET PkgConfig::Brotli_common AND NOT Brotli_common)
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
list(APPEND _brotli_common_lib_names
|
||||
"brotlicommon-static"
|
||||
"libbrotlicommon-static"
|
||||
)
|
||||
else()
|
||||
list(APPEND _brotli_common_lib_names
|
||||
"brotlicommon"
|
||||
"libbrotlicommon"
|
||||
)
|
||||
endif()
|
||||
find_library(Brotli_common
|
||||
NAMES ${_brotli_common_lib_names}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"lib64"
|
||||
"libs"
|
||||
"libs64"
|
||||
"lib/x86_64-linux-gnu"
|
||||
)
|
||||
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})
|
||||
|
||||
set(_brotli_req_vars "")
|
||||
# Generic loop to either create all the aliases for the end-user, or throw errors/warnings.
|
||||
# Note that the case here needs to match the case we used elsewhere in this file.
|
||||
foreach(_target_name "common" "decoder" "encoder")
|
||||
# The PkgConfig IMPORTED_TARGET has PkgConfig:: prefixed to it.
|
||||
if(TARGET PkgConfig::Brotli_${_target_name})
|
||||
add_library(Brotli::${_target_name} ALIAS PkgConfig::Brotli_${_target_name})
|
||||
|
||||
if(Brotli_FIND_REQUIRED_${_target_name})
|
||||
# The PkgConfig version of the library has a slightly different path to its lib.
|
||||
# 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_${_target_name}_STATIC_LINK_LIBRARIES")
|
||||
list(APPEND _brotli_req_vars "Brotli_${_component_name}_STATIC_LIBRARIES")
|
||||
else()
|
||||
list(APPEND _brotli_req_vars "Brotli_${_target_name}_LINK_LIBRARIES")
|
||||
list(APPEND _brotli_req_vars "Brotli_${_component_name}_LINK_LIBRARIES")
|
||||
endif()
|
||||
endif()
|
||||
# This will only trigger for libraries we found using find_library
|
||||
elseif(Brotli_${_target_name})
|
||||
add_library("Brotli::${_target_name}" UNKNOWN IMPORTED)
|
||||
# Safety-check the includes dir
|
||||
if(NOT Brotli_INCLUDE_DIR)
|
||||
brotli_err_msg("Failed to find Brotli's includes directory. Try manually defining \"Brotli_INCLUDE_DIR\" to Brotli's header path on your system.")
|
||||
endif()
|
||||
# Attach the literal library and include dir to the IMPORTED target for the end-user
|
||||
set_target_properties("Brotli::${_target_name}" PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Brotli_INCLUDE_DIR}"
|
||||
IMPORTED_LOCATION "${Brotli_${_target_name}}"
|
||||
|
||||
# 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"
|
||||
)
|
||||
# Attach the library from find_library to our required vars (if it's required)
|
||||
if(Brotli_FIND_REQUIRED_${_target_name})
|
||||
list(APPEND _brotli_req_vars "Brotli_${_target_name}")
|
||||
endif()
|
||||
# This will only happen if it's a required library but we didn't find it.
|
||||
elseif(Brotli_FIND_REQUIRED_${_target_name})
|
||||
# Only bother with an error/failure if they actually required the lib.
|
||||
brotli_err_msg("Failed to find Brotli's ${_target_name} library. Try manually defining \"Brotli_${_target_name}\" to its path on your system.")
|
||||
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_req_vars}
|
||||
FOUND_VAR
|
||||
Brotli_FOUND
|
||||
REQUIRED_VARS
|
||||
Brotli_INCLUDE_DIR
|
||||
${_brotli_required_targets}
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
|
||||
if(Brotli_FOUND)
|
||||
include(FindPackageMessage)
|
||||
foreach(_lib_name ${_brotli_req_vars})
|
||||
# TODO: remove this if/when The Cmake PkgConfig file fixes the non-quiet message about libbrotlicommon being found.
|
||||
if(${_lib_name} MATCHES "common")
|
||||
# This avoids a duplicate "Found Brotli: /usr/lib/libbrotlicommon.so" type message.
|
||||
continue()
|
||||
endif()
|
||||
# Double-expand the var to get the actual path instead of the variable's name.
|
||||
find_package_message(Brotli "Found Brotli: ${${_lib_name}}"
|
||||
"[${${_lib_name}}][${Brotli_INCLUDE_DIR}]"
|
||||
)
|
||||
endforeach()
|
||||
# Restore the original find library ordering
|
||||
if(BROTLI_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_brotli_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
endif()
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
|
||||
#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
|
||||
|
||||
@@ -17,7 +17,7 @@ int main(void) {
|
||||
auto scheme_host_port = "http://localhost:8080";
|
||||
#endif
|
||||
|
||||
auto res = httplib::Client2(scheme_host_port).Get("/hi");
|
||||
auto res = httplib::Client(scheme_host_port).Get("/hi");
|
||||
|
||||
if (res) {
|
||||
cout << res->status << endl;
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
using namespace std;
|
||||
|
||||
int main(void) {
|
||||
httplib::Client2("http://localhost:1234")
|
||||
httplib::Client("http://localhost:1234")
|
||||
.Get("/event1", [&](const char *data, size_t data_length) {
|
||||
std::cout << string(data, data_length);
|
||||
return true;
|
||||
|
||||
@@ -199,7 +199,7 @@ using socket_t = int;
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) && defined(OPENSSL_USE_APPLINK)
|
||||
#include <openssl/applink.c>
|
||||
#endif
|
||||
|
||||
@@ -225,6 +225,7 @@ inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) {
|
||||
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
#include <brotli/decode.h>
|
||||
#include <brotli/encode.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -701,9 +702,16 @@ public:
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers,
|
||||
ContentReceiver content_receiver,
|
||||
Progress progress);
|
||||
std::shared_ptr<Response> Get(const char *path,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver);
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver);
|
||||
std::shared_ptr<Response> Get(const char *path,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver,
|
||||
Progress progress);
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver,
|
||||
@@ -780,6 +788,8 @@ public:
|
||||
|
||||
void stop();
|
||||
|
||||
void set_default_headers(Headers headers);
|
||||
|
||||
void set_tcp_nodelay(bool on);
|
||||
void set_socket_options(SocketOptions socket_options);
|
||||
|
||||
@@ -788,6 +798,7 @@ public:
|
||||
void set_write_timeout(time_t sec, time_t usec = 0);
|
||||
|
||||
void set_basic_auth(const char *username, const char *password);
|
||||
void set_bearer_token_auth(const char *token);
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
void set_digest_auth(const char *username, const char *password);
|
||||
#endif
|
||||
@@ -803,6 +814,7 @@ public:
|
||||
|
||||
void set_proxy(const char *host, int port);
|
||||
void set_proxy_basic_auth(const char *username, const char *password);
|
||||
void set_proxy_bearer_token_auth(const char *token);
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
void set_proxy_digest_auth(const char *username, const char *password);
|
||||
#endif
|
||||
@@ -835,6 +847,9 @@ protected:
|
||||
mutable std::mutex socket_mutex_;
|
||||
std::recursive_mutex request_mutex_;
|
||||
|
||||
// Default headers
|
||||
Headers default_headers_;
|
||||
|
||||
// Settings
|
||||
std::string client_cert_path_;
|
||||
std::string client_key_path_;
|
||||
@@ -848,6 +863,7 @@ protected:
|
||||
|
||||
std::string basic_auth_username_;
|
||||
std::string basic_auth_password_;
|
||||
std::string bearer_token_auth_token_;
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
std::string digest_auth_username_;
|
||||
std::string digest_auth_password_;
|
||||
@@ -869,6 +885,7 @@ protected:
|
||||
|
||||
std::string proxy_basic_auth_username_;
|
||||
std::string proxy_basic_auth_password_;
|
||||
std::string proxy_bearer_token_auth_token_;
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
std::string proxy_digest_auth_username_;
|
||||
std::string proxy_digest_auth_password_;
|
||||
@@ -886,6 +903,7 @@ protected:
|
||||
write_timeout_usec_ = rhs.write_timeout_usec_;
|
||||
basic_auth_username_ = rhs.basic_auth_username_;
|
||||
basic_auth_password_ = rhs.basic_auth_password_;
|
||||
bearer_token_auth_token_ = rhs.bearer_token_auth_token_;
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
digest_auth_username_ = rhs.digest_auth_username_;
|
||||
digest_auth_password_ = rhs.digest_auth_password_;
|
||||
@@ -901,6 +919,7 @@ protected:
|
||||
proxy_port_ = rhs.proxy_port_;
|
||||
proxy_basic_auth_username_ = rhs.proxy_basic_auth_username_;
|
||||
proxy_basic_auth_password_ = rhs.proxy_basic_auth_password_;
|
||||
proxy_bearer_token_auth_token_ = rhs.proxy_bearer_token_auth_token_;
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_;
|
||||
proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_;
|
||||
@@ -960,6 +979,9 @@ public:
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers,
|
||||
ContentReceiver content_receiver,
|
||||
Progress progress);
|
||||
std::shared_ptr<Response> Get(const char *path,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver);
|
||||
std::shared_ptr<Response> Get(const char *path, const Headers &headers,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver);
|
||||
@@ -967,6 +989,10 @@ public:
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver,
|
||||
Progress progress);
|
||||
std::shared_ptr<Response> Get(const char *path,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver,
|
||||
Progress progress);
|
||||
|
||||
std::shared_ptr<Response> Head(const char *path);
|
||||
std::shared_ptr<Response> Head(const char *path, const Headers &headers);
|
||||
@@ -1037,6 +1063,8 @@ public:
|
||||
|
||||
void stop();
|
||||
|
||||
void set_default_headers(Headers headers);
|
||||
|
||||
void set_tcp_nodelay(bool on);
|
||||
void set_socket_options(SocketOptions socket_options);
|
||||
|
||||
@@ -1045,6 +1073,7 @@ public:
|
||||
void set_write_timeout(time_t sec, time_t usec = 0);
|
||||
|
||||
void set_basic_auth(const char *username, const char *password);
|
||||
void set_bearer_token_auth(const char *token);
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
void set_digest_auth(const char *username, const char *password);
|
||||
#endif
|
||||
@@ -1060,6 +1089,7 @@ public:
|
||||
|
||||
void set_proxy(const char *host, int port);
|
||||
void set_proxy_basic_auth(const char *username, const char *password);
|
||||
void set_proxy_bearer_token_auth(const char *token);
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
void set_proxy_digest_auth(const char *username, const char *password);
|
||||
#endif
|
||||
@@ -1088,51 +1118,6 @@ private:
|
||||
#endif
|
||||
}; // namespace httplib
|
||||
|
||||
inline void Get(std::vector<Request> &requests, const char *path,
|
||||
const Headers &headers) {
|
||||
Request req;
|
||||
req.method = "GET";
|
||||
req.path = path;
|
||||
req.headers = headers;
|
||||
requests.emplace_back(std::move(req));
|
||||
}
|
||||
|
||||
inline void Get(std::vector<Request> &requests, const char *path) {
|
||||
Get(requests, path, Headers());
|
||||
}
|
||||
|
||||
inline void Post(std::vector<Request> &requests, const char *path,
|
||||
const Headers &headers, const std::string &body,
|
||||
const char *content_type) {
|
||||
Request req;
|
||||
req.method = "POST";
|
||||
req.path = path;
|
||||
req.headers = headers;
|
||||
if (content_type) { req.headers.emplace("Content-Type", content_type); }
|
||||
req.body = body;
|
||||
requests.emplace_back(std::move(req));
|
||||
}
|
||||
|
||||
inline void Post(std::vector<Request> &requests, const char *path,
|
||||
const std::string &body, const char *content_type) {
|
||||
Post(requests, path, Headers(), body, content_type);
|
||||
}
|
||||
|
||||
inline void Post(std::vector<Request> &requests, const char *path,
|
||||
size_t content_length, ContentProvider content_provider,
|
||||
const char *content_type) {
|
||||
Request req;
|
||||
req.method = "POST";
|
||||
req.headers = Headers();
|
||||
req.path = path;
|
||||
req.content_length = content_length;
|
||||
req.content_provider = content_provider;
|
||||
|
||||
if (content_type) { req.headers.emplace("Content-Type", content_type); }
|
||||
|
||||
requests.emplace_back(std::move(req));
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
class SSLServer : public Server {
|
||||
public:
|
||||
@@ -2157,8 +2142,39 @@ inline EncodingType encoding_type(const Request &req, const Response &res) {
|
||||
return EncodingType::None;
|
||||
}
|
||||
|
||||
class compressor {
|
||||
public:
|
||||
virtual ~compressor(){};
|
||||
|
||||
typedef std::function<bool(const char *data, size_t data_len)> Callback;
|
||||
virtual bool compress(const char *data, size_t data_length, bool last,
|
||||
Callback callback) = 0;
|
||||
};
|
||||
|
||||
class decompressor {
|
||||
public:
|
||||
virtual ~decompressor() {}
|
||||
|
||||
virtual bool is_valid() const = 0;
|
||||
|
||||
typedef std::function<bool(const char *data, size_t data_len)> Callback;
|
||||
virtual bool decompress(const char *data, size_t data_length,
|
||||
Callback callback) = 0;
|
||||
};
|
||||
|
||||
class nocompressor : public compressor {
|
||||
public:
|
||||
~nocompressor(){};
|
||||
|
||||
bool compress(const char *data, size_t data_length, bool /*last*/,
|
||||
Callback callback) override {
|
||||
if (!data_length) { return true; }
|
||||
return callback(data, data_length);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
class gzip_compressor {
|
||||
class gzip_compressor : public compressor {
|
||||
public:
|
||||
gzip_compressor() {
|
||||
std::memset(&strm_, 0, sizeof(strm_));
|
||||
@@ -2172,8 +2188,8 @@ public:
|
||||
|
||||
~gzip_compressor() { deflateEnd(&strm_); }
|
||||
|
||||
template <typename T>
|
||||
bool compress(const char *data, size_t data_length, bool last, T callback) {
|
||||
bool compress(const char *data, size_t data_length, bool last,
|
||||
Callback callback) override {
|
||||
assert(is_valid_);
|
||||
|
||||
auto flush = last ? Z_FINISH : Z_NO_FLUSH;
|
||||
@@ -2206,7 +2222,7 @@ private:
|
||||
z_stream strm_;
|
||||
};
|
||||
|
||||
class gzip_decompressor {
|
||||
class gzip_decompressor : public decompressor {
|
||||
public:
|
||||
gzip_decompressor() {
|
||||
std::memset(&strm_, 0, sizeof(strm_));
|
||||
@@ -2223,10 +2239,10 @@ public:
|
||||
|
||||
~gzip_decompressor() { inflateEnd(&strm_); }
|
||||
|
||||
bool is_valid() const { return is_valid_; }
|
||||
bool is_valid() const override { return is_valid_; }
|
||||
|
||||
template <typename T>
|
||||
bool decompress(const char *data, size_t data_length, T callback) {
|
||||
bool decompress(const char *data, size_t data_length,
|
||||
Callback callback) override {
|
||||
assert(is_valid_);
|
||||
|
||||
int ret = Z_OK;
|
||||
@@ -2262,7 +2278,52 @@ private:
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
class brotli_decompressor {
|
||||
class brotli_compressor : public compressor {
|
||||
public:
|
||||
brotli_compressor() {
|
||||
state_ = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
~brotli_compressor() { BrotliEncoderDestroyInstance(state_); }
|
||||
|
||||
bool compress(const char *data, size_t data_length, bool last,
|
||||
Callback callback) override {
|
||||
std::array<uint8_t, 16384> buff{};
|
||||
|
||||
auto operation = last ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
|
||||
auto available_in = data_length;
|
||||
auto next_in = reinterpret_cast<const uint8_t *>(data);
|
||||
|
||||
for (;;) {
|
||||
if (last) {
|
||||
if (BrotliEncoderIsFinished(state_)) { break; }
|
||||
} else {
|
||||
if (!available_in) { break; }
|
||||
}
|
||||
|
||||
auto available_out = buff.size();
|
||||
auto next_out = buff.data();
|
||||
|
||||
if (!BrotliEncoderCompressStream(state_, operation, &available_in,
|
||||
&next_in, &available_out, &next_out,
|
||||
nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto output_bytes = buff.size() - available_out;
|
||||
if (output_bytes) {
|
||||
callback(reinterpret_cast<const char *>(buff.data()), output_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
BrotliEncoderState *state_ = nullptr;
|
||||
};
|
||||
|
||||
class brotli_decompressor : public decompressor {
|
||||
public:
|
||||
brotli_decompressor() {
|
||||
decoder_s = BrotliDecoderCreateInstance(0, 0, 0);
|
||||
@@ -2274,13 +2335,14 @@ public:
|
||||
if (decoder_s) { BrotliDecoderDestroyInstance(decoder_s); }
|
||||
}
|
||||
|
||||
bool is_valid() const { return decoder_s; }
|
||||
bool is_valid() const override { return decoder_s; }
|
||||
|
||||
template <typename T>
|
||||
bool decompress(const char *data, size_t data_length, T callback) {
|
||||
bool decompress(const char *data, size_t data_length,
|
||||
Callback callback) override {
|
||||
if (decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
|
||||
decoder_r == BROTLI_DECODER_RESULT_ERROR)
|
||||
decoder_r == BROTLI_DECODER_RESULT_ERROR) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t *next_in = (const uint8_t *)data;
|
||||
size_t avail_in = data_length;
|
||||
@@ -2491,32 +2553,29 @@ bool prepare_content_receiver(T &x, int &status, ContentReceiver receiver,
|
||||
bool decompress, U callback) {
|
||||
if (decompress) {
|
||||
std::string encoding = x.get_header_value("Content-Encoding");
|
||||
std::shared_ptr<decompressor> decompressor;
|
||||
|
||||
if (encoding.find("gzip") != std::string::npos ||
|
||||
encoding.find("deflate") != std::string::npos) {
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
gzip_decompressor decompressor;
|
||||
if (decompressor.is_valid()) {
|
||||
ContentReceiver out = [&](const char *buf, size_t n) {
|
||||
return decompressor.decompress(
|
||||
buf, n,
|
||||
[&](const char *buf, size_t n) { return receiver(buf, n); });
|
||||
};
|
||||
return callback(out);
|
||||
} else {
|
||||
status = 500;
|
||||
return false;
|
||||
}
|
||||
decompressor = std::make_shared<gzip_decompressor>();
|
||||
#else
|
||||
status = 415;
|
||||
return false;
|
||||
#endif
|
||||
} else if (encoding.find("br") != std::string::npos) {
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
brotli_decompressor decompressor;
|
||||
if (decompressor.is_valid()) {
|
||||
decompressor = std::make_shared<brotli_decompressor>();
|
||||
#else
|
||||
status = 415;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (decompressor) {
|
||||
if (decompressor->is_valid()) {
|
||||
ContentReceiver out = [&](const char *buf, size_t n) {
|
||||
return decompressor.decompress(
|
||||
return decompressor->decompress(
|
||||
buf, n,
|
||||
[&](const char *buf, size_t n) { return receiver(buf, n); });
|
||||
};
|
||||
@@ -2525,17 +2584,12 @@ bool prepare_content_receiver(T &x, int &status, ContentReceiver receiver,
|
||||
status = 500;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
status = 415;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ContentReceiver out = [&](const char *buf, size_t n) {
|
||||
return receiver(buf, n);
|
||||
};
|
||||
|
||||
return callback(out);
|
||||
}
|
||||
|
||||
@@ -2628,10 +2682,10 @@ inline ssize_t write_content(Stream &strm, ContentProvider content_provider,
|
||||
return static_cast<ssize_t>(offset - begin_offset);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename T, typename U>
|
||||
inline ssize_t write_content_chunked(Stream &strm,
|
||||
ContentProvider content_provider,
|
||||
T is_shutting_down, EncodingType type) {
|
||||
T is_shutting_down, U &compressor) {
|
||||
size_t offset = 0;
|
||||
auto data_available = true;
|
||||
ssize_t total_written_length = 0;
|
||||
@@ -2639,10 +2693,6 @@ inline ssize_t write_content_chunked(Stream &strm,
|
||||
auto ok = true;
|
||||
DataSink data_sink;
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
detail::gzip_compressor compressor;
|
||||
#endif
|
||||
|
||||
data_sink.write = [&](const char *d, size_t l) {
|
||||
if (!ok) { return; }
|
||||
|
||||
@@ -2650,22 +2700,13 @@ inline ssize_t write_content_chunked(Stream &strm,
|
||||
offset += l;
|
||||
|
||||
std::string payload;
|
||||
if (type == EncodingType::Gzip) {
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
if (!compressor.compress(d, l, false,
|
||||
[&](const char *data, size_t data_len) {
|
||||
payload.append(data, data_len);
|
||||
return true;
|
||||
})) {
|
||||
ok = false;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else if (type == EncodingType::Brotli) {
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
#endif
|
||||
} else {
|
||||
payload = std::string(d, l);
|
||||
if (!compressor.compress(d, l, false,
|
||||
[&](const char *data, size_t data_len) {
|
||||
payload.append(data, data_len);
|
||||
return true;
|
||||
})) {
|
||||
ok = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!payload.empty()) {
|
||||
@@ -2685,32 +2726,25 @@ inline ssize_t write_content_chunked(Stream &strm,
|
||||
|
||||
data_available = false;
|
||||
|
||||
if (type == EncodingType::Gzip) {
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
std::string payload;
|
||||
if (!compressor.compress(nullptr, 0, true,
|
||||
[&](const char *data, size_t data_len) {
|
||||
payload.append(data, data_len);
|
||||
return true;
|
||||
})) {
|
||||
std::string payload;
|
||||
if (!compressor.compress(nullptr, 0, true,
|
||||
[&](const char *data, size_t data_len) {
|
||||
payload.append(data, data_len);
|
||||
return true;
|
||||
})) {
|
||||
ok = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!payload.empty()) {
|
||||
// Emit chunked response header and footer for each chunk
|
||||
auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
|
||||
if (write_data(strm, chunk.data(), chunk.size())) {
|
||||
total_written_length += chunk.size();
|
||||
} else {
|
||||
ok = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!payload.empty()) {
|
||||
// Emit chunked response header and footer for each chunk
|
||||
auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
|
||||
if (write_data(strm, chunk.data(), chunk.size())) {
|
||||
total_written_length += chunk.size();
|
||||
} else {
|
||||
ok = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (type == EncodingType::Brotli) {
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
#endif
|
||||
}
|
||||
|
||||
static const std::string done_marker("0\r\n\r\n");
|
||||
@@ -3270,6 +3304,14 @@ make_basic_authentication_header(const std::string &username,
|
||||
return std::make_pair(key, field);
|
||||
}
|
||||
|
||||
inline std::pair<std::string, std::string>
|
||||
make_bearer_token_authentication_header(const std::string &token,
|
||||
bool is_proxy = false) {
|
||||
auto field = "Bearer " + token;
|
||||
auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
|
||||
return std::make_pair(key, field);
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
inline std::pair<std::string, std::string> make_digest_authentication_header(
|
||||
const Request &req, const std::map<std::string, std::string> &auth,
|
||||
@@ -3918,25 +3960,33 @@ inline bool Server::write_response(Stream &strm, bool close_connection,
|
||||
}
|
||||
|
||||
if (type != detail::EncodingType::None) {
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
std::string compressed;
|
||||
std::shared_ptr<detail::compressor> compressor;
|
||||
|
||||
if (type == detail::EncodingType::Gzip) {
|
||||
detail::gzip_compressor compressor;
|
||||
if (!compressor.compress(res.body.data(), res.body.size(), true,
|
||||
[&](const char *data, size_t data_len) {
|
||||
compressed.append(data, data_len);
|
||||
return true;
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
compressor = std::make_shared<detail::gzip_compressor>();
|
||||
res.set_header("Content-Encoding", "gzip");
|
||||
#endif
|
||||
} else if (type == detail::EncodingType::Brotli) {
|
||||
// TODO:
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
compressor = std::make_shared<detail::brotli_compressor>();
|
||||
res.set_header("Content-Encoding", "brotli");
|
||||
#endif
|
||||
}
|
||||
|
||||
res.body.swap(compressed);
|
||||
#endif
|
||||
if (compressor) {
|
||||
std::string compressed;
|
||||
|
||||
if (!compressor->compress(res.body.data(), res.body.size(), true,
|
||||
[&](const char *data, size_t data_len) {
|
||||
compressed.append(data, data_len);
|
||||
return true;
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
res.body.swap(compressed);
|
||||
}
|
||||
}
|
||||
|
||||
auto length = std::to_string(res.body.size());
|
||||
@@ -3999,8 +4049,23 @@ Server::write_content_with_provider(Stream &strm, const Request &req,
|
||||
}
|
||||
} else {
|
||||
auto type = detail::encoding_type(req, res);
|
||||
|
||||
std::shared_ptr<detail::compressor> compressor;
|
||||
if (type == detail::EncodingType::Gzip) {
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
compressor = std::make_shared<detail::gzip_compressor>();
|
||||
#endif
|
||||
} else if (type == detail::EncodingType::Brotli) {
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
compressor = std::make_shared<detail::brotli_compressor>();
|
||||
#endif
|
||||
} else {
|
||||
compressor = std::make_shared<detail::nocompressor>();
|
||||
}
|
||||
assert(compressor != nullptr);
|
||||
|
||||
if (detail::write_content_chunked(strm, res.content_provider_,
|
||||
is_shutting_down, type) < 0) {
|
||||
is_shutting_down, *compressor) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -4688,6 +4753,16 @@ inline bool ClientImpl::write_request(Stream &strm, const Request &req,
|
||||
proxy_basic_auth_username_, proxy_basic_auth_password_, true));
|
||||
}
|
||||
|
||||
if (!bearer_token_auth_token_.empty()) {
|
||||
headers.insert(make_bearer_token_authentication_header(
|
||||
bearer_token_auth_token_, false));
|
||||
}
|
||||
|
||||
if (!proxy_bearer_token_auth_token_.empty()) {
|
||||
headers.insert(make_bearer_token_authentication_header(
|
||||
proxy_bearer_token_auth_token_, true));
|
||||
}
|
||||
|
||||
detail::write_headers(bstrm, req, headers);
|
||||
|
||||
// Flush buffer
|
||||
@@ -4734,7 +4809,8 @@ inline std::shared_ptr<Response> ClientImpl::send_with_content_provider(
|
||||
ContentProvider content_provider, const char *content_type) {
|
||||
Request req;
|
||||
req.method = method;
|
||||
req.headers = headers;
|
||||
req.headers = default_headers_;
|
||||
req.headers.insert(headers.begin(), headers.end());
|
||||
req.path = path;
|
||||
|
||||
if (content_type) { req.headers.emplace("Content-Type", content_type); }
|
||||
@@ -4874,7 +4950,8 @@ ClientImpl::Get(const char *path, const Headers &headers, Progress progress) {
|
||||
Request req;
|
||||
req.method = "GET";
|
||||
req.path = path;
|
||||
req.headers = headers;
|
||||
req.headers = default_headers_;
|
||||
req.headers.insert(headers.begin(), headers.end());
|
||||
req.progress = std::move(progress);
|
||||
|
||||
auto res = std::make_shared<Response>();
|
||||
@@ -4906,6 +4983,13 @@ ClientImpl::Get(const char *path, const Headers &headers,
|
||||
std::move(progress));
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
ClientImpl::Get(const char *path, ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver) {
|
||||
return Get(path, Headers(), std::move(response_handler), content_receiver,
|
||||
Progress());
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
ClientImpl::Get(const char *path, const Headers &headers,
|
||||
ResponseHandler response_handler,
|
||||
@@ -4914,6 +4998,13 @@ ClientImpl::Get(const char *path, const Headers &headers,
|
||||
Progress());
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
ClientImpl::Get(const char *path, ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver, Progress progress) {
|
||||
return Get(path, Headers(), std::move(response_handler), content_receiver,
|
||||
progress);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
ClientImpl::Get(const char *path, const Headers &headers,
|
||||
ResponseHandler response_handler,
|
||||
@@ -4921,7 +5012,8 @@ ClientImpl::Get(const char *path, const Headers &headers,
|
||||
Request req;
|
||||
req.method = "GET";
|
||||
req.path = path;
|
||||
req.headers = headers;
|
||||
req.headers = default_headers_;
|
||||
req.headers.insert(headers.begin(), headers.end());
|
||||
req.response_handler = std::move(response_handler);
|
||||
req.content_receiver = std::move(content_receiver);
|
||||
req.progress = std::move(progress);
|
||||
@@ -4938,7 +5030,8 @@ inline std::shared_ptr<Response> ClientImpl::Head(const char *path,
|
||||
const Headers &headers) {
|
||||
Request req;
|
||||
req.method = "HEAD";
|
||||
req.headers = headers;
|
||||
req.headers = default_headers_;
|
||||
req.headers.insert(headers.begin(), headers.end());
|
||||
req.path = path;
|
||||
|
||||
auto res = std::make_shared<Response>();
|
||||
@@ -5117,7 +5210,8 @@ inline std::shared_ptr<Response> ClientImpl::Delete(const char *path,
|
||||
const char *content_type) {
|
||||
Request req;
|
||||
req.method = "DELETE";
|
||||
req.headers = headers;
|
||||
req.headers = default_headers_;
|
||||
req.headers.insert(headers.begin(), headers.end());
|
||||
req.path = path;
|
||||
|
||||
if (content_type) { req.headers.emplace("Content-Type", content_type); }
|
||||
@@ -5136,8 +5230,9 @@ inline std::shared_ptr<Response> ClientImpl::Options(const char *path,
|
||||
const Headers &headers) {
|
||||
Request req;
|
||||
req.method = "OPTIONS";
|
||||
req.headers = default_headers_;
|
||||
req.headers.insert(headers.begin(), headers.end());
|
||||
req.path = path;
|
||||
req.headers = headers;
|
||||
|
||||
auto res = std::make_shared<Response>();
|
||||
|
||||
@@ -5180,6 +5275,10 @@ inline void ClientImpl::set_basic_auth(const char *username,
|
||||
basic_auth_password_ = password;
|
||||
}
|
||||
|
||||
inline void ClientImpl::set_bearer_token_auth(const char *token) {
|
||||
bearer_token_auth_token_ = token;
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
inline void ClientImpl::set_digest_auth(const char *username,
|
||||
const char *password) {
|
||||
@@ -5192,6 +5291,10 @@ inline void ClientImpl::set_keep_alive(bool on) { keep_alive_ = on; }
|
||||
|
||||
inline void ClientImpl::set_follow_location(bool on) { follow_location_ = on; }
|
||||
|
||||
inline void ClientImpl::set_default_headers(Headers headers) {
|
||||
default_headers_ = std::move(headers);
|
||||
}
|
||||
|
||||
inline void ClientImpl::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; }
|
||||
|
||||
inline void ClientImpl::set_socket_options(SocketOptions socket_options) {
|
||||
@@ -5215,6 +5318,10 @@ inline void ClientImpl::set_proxy_basic_auth(const char *username,
|
||||
proxy_basic_auth_password_ = password;
|
||||
}
|
||||
|
||||
inline void ClientImpl::set_proxy_bearer_token_auth(const char *token) {
|
||||
proxy_bearer_token_auth_token_ = token;
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
inline void ClientImpl::set_proxy_digest_auth(const char *username,
|
||||
const char *password) {
|
||||
@@ -5939,12 +6046,24 @@ inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
Progress progress) {
|
||||
return cli_->Get(path, headers, content_receiver, progress);
|
||||
}
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver) {
|
||||
return cli_->Get(path, Headers(), response_handler, content_receiver);
|
||||
}
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
const Headers &headers,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver) {
|
||||
return cli_->Get(path, headers, response_handler, content_receiver);
|
||||
}
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver,
|
||||
Progress progress) {
|
||||
return cli_->Get(path, Headers(), response_handler, content_receiver,
|
||||
progress);
|
||||
}
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
const Headers &headers,
|
||||
ResponseHandler response_handler,
|
||||
@@ -6095,6 +6214,10 @@ inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); }
|
||||
|
||||
inline void Client::stop() { cli_->stop(); }
|
||||
|
||||
inline void Client::set_default_headers(Headers headers) {
|
||||
cli_->set_default_headers(std::move(headers));
|
||||
}
|
||||
|
||||
inline void Client::set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); }
|
||||
inline void Client::set_socket_options(SocketOptions socket_options) {
|
||||
cli_->set_socket_options(socket_options);
|
||||
@@ -6113,6 +6236,9 @@ inline void Client::set_write_timeout(time_t sec, time_t usec) {
|
||||
inline void Client::set_basic_auth(const char *username, const char *password) {
|
||||
cli_->set_basic_auth(username, password);
|
||||
}
|
||||
inline void Client::set_bearer_token_auth(const char *token) {
|
||||
cli_->set_bearer_token_auth(token);
|
||||
}
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
inline void Client::set_digest_auth(const char *username,
|
||||
const char *password) {
|
||||
@@ -6140,6 +6266,9 @@ inline void Client::set_proxy_basic_auth(const char *username,
|
||||
const char *password) {
|
||||
cli_->set_proxy_basic_auth(username, password);
|
||||
}
|
||||
inline void Client::set_proxy_bearer_token_auth(const char *token) {
|
||||
cli_->set_proxy_bearer_token_auth(token);
|
||||
}
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
inline void Client::set_proxy_digest_auth(const char *username,
|
||||
const char *password) {
|
||||
|
||||
+154
-98
@@ -294,10 +294,10 @@ TEST(ChunkedEncodingTest, FromHTTPWatch) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 443;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 80;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
cli.set_connection_timeout(2);
|
||||
|
||||
@@ -306,7 +306,7 @@ TEST(ChunkedEncodingTest, FromHTTPWatch) {
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
|
||||
std::string out;
|
||||
httplib::detail::read_file("./image.jpg", out);
|
||||
detail::read_file("./image.jpg", out);
|
||||
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ(out, res->body);
|
||||
@@ -317,10 +317,10 @@ TEST(ChunkedEncodingTest, WithContentReceiver) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 443;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 80;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
cli.set_connection_timeout(2);
|
||||
|
||||
@@ -334,7 +334,7 @@ TEST(ChunkedEncodingTest, WithContentReceiver) {
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
|
||||
std::string out;
|
||||
httplib::detail::read_file("./image.jpg", out);
|
||||
detail::read_file("./image.jpg", out);
|
||||
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ(out, body);
|
||||
@@ -345,16 +345,16 @@ TEST(ChunkedEncodingTest, WithResponseHandlerAndContentReceiver) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 443;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 80;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
cli.set_connection_timeout(2);
|
||||
|
||||
std::string body;
|
||||
auto res = cli.Get(
|
||||
"/httpgallery/chunked/chunkedimage.aspx?0.4153841143030137", Headers(),
|
||||
"/httpgallery/chunked/chunkedimage.aspx?0.4153841143030137",
|
||||
[&](const Response &response) {
|
||||
EXPECT_EQ(200, response.status);
|
||||
return true;
|
||||
@@ -366,34 +366,53 @@ TEST(ChunkedEncodingTest, WithResponseHandlerAndContentReceiver) {
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
|
||||
std::string out;
|
||||
httplib::detail::read_file("./image.jpg", out);
|
||||
detail::read_file("./image.jpg", out);
|
||||
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ(out, body);
|
||||
}
|
||||
|
||||
TEST(DefaultHeadersTest, FromHTTPBin) {
|
||||
Client cli("httpbin.org");
|
||||
cli.set_default_headers({make_range_header({{1, 10}})});
|
||||
cli.set_connection_timeout(5);
|
||||
|
||||
{
|
||||
auto res = cli.Get("/range/32");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("bcdefghijk", res->body);
|
||||
EXPECT_EQ(206, res->status);
|
||||
}
|
||||
|
||||
{
|
||||
auto res = cli.Get("/range/32");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("bcdefghijk", res->body);
|
||||
EXPECT_EQ(206, res->status);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RangeTest, FromHTTPBin) {
|
||||
auto host = "httpbin.org";
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 443;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 80;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
cli.set_connection_timeout(5);
|
||||
|
||||
{
|
||||
httplib::Headers headers;
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
auto res = cli.Get("/range/32");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("abcdefghijklmnopqrstuvwxyzabcdef", res->body);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
{
|
||||
httplib::Headers headers = {httplib::make_range_header({{1, -1}})};
|
||||
Headers headers = {make_range_header({{1, -1}})};
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("bcdefghijklmnopqrstuvwxyzabcdef", res->body);
|
||||
@@ -401,7 +420,7 @@ TEST(RangeTest, FromHTTPBin) {
|
||||
}
|
||||
|
||||
{
|
||||
httplib::Headers headers = {httplib::make_range_header({{1, 10}})};
|
||||
Headers headers = {make_range_header({{1, 10}})};
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("bcdefghijk", res->body);
|
||||
@@ -409,7 +428,7 @@ TEST(RangeTest, FromHTTPBin) {
|
||||
}
|
||||
|
||||
{
|
||||
httplib::Headers headers = {httplib::make_range_header({{0, 31}})};
|
||||
Headers headers = {make_range_header({{0, 31}})};
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("abcdefghijklmnopqrstuvwxyzabcdef", res->body);
|
||||
@@ -417,7 +436,7 @@ TEST(RangeTest, FromHTTPBin) {
|
||||
}
|
||||
|
||||
{
|
||||
httplib::Headers headers = {httplib::make_range_header({{0, -1}})};
|
||||
Headers headers = {make_range_header({{0, -1}})};
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("abcdefghijklmnopqrstuvwxyzabcdef", res->body);
|
||||
@@ -425,7 +444,7 @@ TEST(RangeTest, FromHTTPBin) {
|
||||
}
|
||||
|
||||
{
|
||||
httplib::Headers headers = {httplib::make_range_header({{0, 32}})};
|
||||
Headers headers = {make_range_header({{0, 32}})};
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(416, res->status);
|
||||
@@ -437,10 +456,10 @@ TEST(ConnectionErrorTest, InvalidHost) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 443;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 80;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
cli.set_connection_timeout(2);
|
||||
|
||||
@@ -452,9 +471,9 @@ TEST(ConnectionErrorTest, InvalidHost2) {
|
||||
auto host = "httpbin.org/";
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
httplib::SSLClient cli(host);
|
||||
SSLClient cli(host);
|
||||
#else
|
||||
httplib::Client cli(host);
|
||||
Client cli(host);
|
||||
#endif
|
||||
cli.set_connection_timeout(2);
|
||||
|
||||
@@ -467,10 +486,10 @@ TEST(ConnectionErrorTest, InvalidPort) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 44380;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 8080;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
cli.set_connection_timeout(2);
|
||||
|
||||
@@ -483,10 +502,10 @@ TEST(ConnectionErrorTest, Timeout) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 44380;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 8080;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
cli.set_connection_timeout(2);
|
||||
|
||||
@@ -499,10 +518,10 @@ TEST(CancelTest, NoCancel) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 443;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 80;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
cli.set_connection_timeout(5);
|
||||
|
||||
@@ -517,10 +536,10 @@ TEST(CancelTest, WithCancelSmallPayload) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 443;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 80;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
|
||||
auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return false; });
|
||||
@@ -533,16 +552,15 @@ TEST(CancelTest, WithCancelLargePayload) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 443;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 80;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
cli.set_connection_timeout(5);
|
||||
|
||||
uint32_t count = 0;
|
||||
httplib::Headers headers;
|
||||
auto res = cli.Get("/range/65536", headers,
|
||||
auto res = cli.Get("/range/65536",
|
||||
[&count](uint64_t, uint64_t) { return (count++ == 0); });
|
||||
ASSERT_TRUE(res == nullptr);
|
||||
}
|
||||
@@ -552,10 +570,10 @@ TEST(BaseAuthTest, FromHTTPWatch) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto port = 443;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
#else
|
||||
auto port = 80;
|
||||
httplib::Client cli(host, port);
|
||||
Client cli(host, port);
|
||||
#endif
|
||||
|
||||
{
|
||||
@@ -565,9 +583,8 @@ TEST(BaseAuthTest, FromHTTPWatch) {
|
||||
}
|
||||
|
||||
{
|
||||
auto res =
|
||||
cli.Get("/basic-auth/hello/world",
|
||||
{httplib::make_basic_authentication_header("hello", "world")});
|
||||
auto res = cli.Get("/basic-auth/hello/world",
|
||||
{make_basic_authentication_header("hello", "world")});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n",
|
||||
res->body);
|
||||
@@ -602,7 +619,7 @@ TEST(BaseAuthTest, FromHTTPWatch) {
|
||||
TEST(DigestAuthTest, FromHTTPWatch) {
|
||||
auto host = "httpbin.org";
|
||||
auto port = 443;
|
||||
httplib::SSLClient cli(host, port);
|
||||
SSLClient cli(host, port);
|
||||
|
||||
{
|
||||
auto res = cli.Get("/digest-auth/auth/hello/world");
|
||||
@@ -651,9 +668,9 @@ TEST(AbsoluteRedirectTest, Redirect) {
|
||||
auto host = "httpbin.org";
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
httplib::SSLClient cli(host);
|
||||
SSLClient cli(host);
|
||||
#else
|
||||
httplib::Client cli(host);
|
||||
Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.set_follow_location(true);
|
||||
@@ -666,9 +683,9 @@ TEST(RedirectTest, Redirect) {
|
||||
auto host = "httpbin.org";
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
httplib::SSLClient cli(host);
|
||||
SSLClient cli(host);
|
||||
#else
|
||||
httplib::Client cli(host);
|
||||
Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.set_follow_location(true);
|
||||
@@ -681,9 +698,9 @@ TEST(RelativeRedirectTest, Redirect) {
|
||||
auto host = "httpbin.org";
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
httplib::SSLClient cli(host);
|
||||
SSLClient cli(host);
|
||||
#else
|
||||
httplib::Client cli(host);
|
||||
Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.set_follow_location(true);
|
||||
@@ -696,9 +713,9 @@ TEST(TooManyRedirectTest, Redirect) {
|
||||
auto host = "httpbin.org";
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
httplib::SSLClient cli(host);
|
||||
SSLClient cli(host);
|
||||
#else
|
||||
httplib::Client cli(host);
|
||||
Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.set_follow_location(true);
|
||||
@@ -709,7 +726,7 @@ TEST(TooManyRedirectTest, Redirect) {
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(YahooRedirectTest, Redirect) {
|
||||
httplib::Client cli("yahoo.com");
|
||||
Client cli("yahoo.com");
|
||||
|
||||
auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
@@ -723,7 +740,7 @@ TEST(YahooRedirectTest, Redirect) {
|
||||
|
||||
#if 0
|
||||
TEST(HttpsToHttpRedirectTest, Redirect) {
|
||||
httplib::SSLClient cli("httpbin.org");
|
||||
SSLClient cli("httpbin.org");
|
||||
cli.set_follow_location(true);
|
||||
auto res =
|
||||
cli.Get("/redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302");
|
||||
@@ -772,7 +789,7 @@ TEST(RedirectToDifferentPort, Redirect) {
|
||||
}
|
||||
|
||||
TEST(UrlWithSpace, Redirect) {
|
||||
httplib::SSLClient cli("edge.forgecdn.net");
|
||||
SSLClient cli("edge.forgecdn.net");
|
||||
cli.set_follow_location(true);
|
||||
|
||||
auto res = cli.Get("/files/2595/310/Neat 1.4-17.jar");
|
||||
@@ -1227,22 +1244,22 @@ protected:
|
||||
[&](const Request &req, Response & /*res*/) {
|
||||
EXPECT_EQ("close", req.get_header_value("Connection"));
|
||||
})
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
.Get("/gzip",
|
||||
#if defined(CPPHTTPLIB_ZLIB_SUPPORT) || defined(CPPHTTPLIB_BROTLI_SUPPORT)
|
||||
.Get("/compress",
|
||||
[&](const Request & /*req*/, Response &res) {
|
||||
res.set_content(
|
||||
"12345678901234567890123456789012345678901234567890123456789"
|
||||
"01234567890123456789012345678901234567890",
|
||||
"text/plain");
|
||||
})
|
||||
.Get("/nogzip",
|
||||
.Get("/nocompress",
|
||||
[&](const Request & /*req*/, Response &res) {
|
||||
res.set_content(
|
||||
"12345678901234567890123456789012345678901234567890123456789"
|
||||
"01234567890123456789012345678901234567890",
|
||||
"application/octet-stream");
|
||||
})
|
||||
.Post("/gzipmultipart",
|
||||
.Post("/compress-multipart",
|
||||
[&](const Request &req, Response & /*res*/) {
|
||||
EXPECT_EQ(2u, req.files.size());
|
||||
ASSERT_TRUE(!req.has_file("???"));
|
||||
@@ -2091,7 +2108,7 @@ TEST_F(ServerTest, PutLargeFileWithGzip) {
|
||||
|
||||
TEST_F(ServerTest, PutContentWithDeflate) {
|
||||
cli_.set_compress(false);
|
||||
httplib::Headers headers;
|
||||
Headers headers;
|
||||
headers.emplace("Content-Encoding", "deflate");
|
||||
// PUT in deflate format:
|
||||
auto res = cli_.Put("/put", headers,
|
||||
@@ -2103,7 +2120,7 @@ TEST_F(ServerTest, PutContentWithDeflate) {
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamedChunkedWithGzip) {
|
||||
httplib::Headers headers;
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "gzip, deflate");
|
||||
|
||||
auto res = cli_.Get("/streamed-chunked", headers);
|
||||
@@ -2113,7 +2130,7 @@ TEST_F(ServerTest, GetStreamedChunkedWithGzip) {
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamedChunkedWithGzip2) {
|
||||
httplib::Headers headers;
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "gzip, deflate");
|
||||
|
||||
auto res = cli_.Get("/streamed-chunked2", headers);
|
||||
@@ -2123,6 +2140,28 @@ TEST_F(ServerTest, GetStreamedChunkedWithGzip2) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
TEST_F(ServerTest, GetStreamedChunkedWithBrotli) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "brotli");
|
||||
|
||||
auto res = cli_.Get("/streamed-chunked", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ(std::string("123456789"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamedChunkedWithBrotli2) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "brotli");
|
||||
|
||||
auto res = cli_.Get("/streamed-chunked2", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ(std::string("123456789"), res->body);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(ServerTest, Patch) {
|
||||
auto res = cli_.Patch("/patch", "PATCH", "text/plain");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
@@ -2267,7 +2306,7 @@ TEST_F(ServerTest, KeepAlive) {
|
||||
EXPECT_EQ("close", res->get_header_value("Connection"));
|
||||
|
||||
res = cli_.Post(
|
||||
"/empty", 0, [&](size_t, size_t, httplib::DataSink &) { return true; },
|
||||
"/empty", 0, [&](size_t, size_t, DataSink &) { return true; },
|
||||
"text/plain");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -2285,7 +2324,7 @@ TEST_F(ServerTest, KeepAlive) {
|
||||
TEST_F(ServerTest, Gzip) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "gzip, deflate");
|
||||
auto res = cli_.Get("/gzip", headers);
|
||||
auto res = cli_.Get("/compress", headers);
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
|
||||
@@ -2298,8 +2337,7 @@ TEST_F(ServerTest, Gzip) {
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GzipWithoutAcceptEncoding) {
|
||||
Headers headers;
|
||||
auto res = cli_.Get("/gzip", headers);
|
||||
auto res = cli_.Get("/compress");
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_TRUE(res->get_header_value("Content-Encoding").empty());
|
||||
@@ -2315,12 +2353,12 @@ TEST_F(ServerTest, GzipWithContentReceiver) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "gzip, deflate");
|
||||
std::string body;
|
||||
auto res =
|
||||
cli_.Get("/gzip", headers, [&](const char *data, uint64_t data_length) {
|
||||
EXPECT_EQ(data_length, 100);
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
auto res = cli_.Get("/compress", headers,
|
||||
[&](const char *data, uint64_t data_length) {
|
||||
EXPECT_EQ(data_length, 100);
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
|
||||
@@ -2337,7 +2375,7 @@ TEST_F(ServerTest, GzipWithoutDecompressing) {
|
||||
headers.emplace("Accept-Encoding", "gzip, deflate");
|
||||
|
||||
cli_.set_decompress(false);
|
||||
auto res = cli_.Get("/gzip", headers);
|
||||
auto res = cli_.Get("/compress", headers);
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
|
||||
@@ -2348,14 +2386,13 @@ TEST_F(ServerTest, GzipWithoutDecompressing) {
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GzipWithContentReceiverWithoutAcceptEncoding) {
|
||||
Headers headers;
|
||||
std::string body;
|
||||
auto res =
|
||||
cli_.Get("/gzip", headers, [&](const char *data, uint64_t data_length) {
|
||||
EXPECT_EQ(data_length, 100);
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
auto res = cli_.Get("/compress",
|
||||
[&](const char *data, uint64_t data_length) {
|
||||
EXPECT_EQ(data_length, 100);
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_TRUE(res->get_header_value("Content-Encoding").empty());
|
||||
@@ -2370,7 +2407,7 @@ TEST_F(ServerTest, GzipWithContentReceiverWithoutAcceptEncoding) {
|
||||
TEST_F(ServerTest, NoGzip) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "gzip, deflate");
|
||||
auto res = cli_.Get("/nogzip", headers);
|
||||
auto res = cli_.Get("/nocompress", headers);
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(false, res->has_header("Content-Encoding"));
|
||||
@@ -2386,12 +2423,12 @@ TEST_F(ServerTest, NoGzipWithContentReceiver) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "gzip, deflate");
|
||||
std::string body;
|
||||
auto res =
|
||||
cli_.Get("/nogzip", headers, [&](const char *data, uint64_t data_length) {
|
||||
EXPECT_EQ(data_length, 100);
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
auto res = cli_.Get("/nocompress", headers,
|
||||
[&](const char *data, uint64_t data_length) {
|
||||
EXPECT_EQ(data_length, 100);
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(false, res->has_header("Content-Encoding"));
|
||||
@@ -2410,13 +2447,30 @@ TEST_F(ServerTest, MultipartFormDataGzip) {
|
||||
};
|
||||
|
||||
cli_.set_compress(true);
|
||||
auto res = cli_.Post("/gzipmultipart", items);
|
||||
auto res = cli_.Post("/compress-multipart", items);
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
TEST_F(ServerTest, Brotli) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "br");
|
||||
auto res = cli_.Get("/compress", headers);
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("brotli", res->get_header_value("Content-Encoding"));
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("19", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
|
||||
"7890123456789012345678901234567890",
|
||||
res->body);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Sends a raw request to a server listening at HOST:PORT.
|
||||
static bool send_request(time_t read_timeout_sec, const std::string &req,
|
||||
std::string *resp = nullptr) {
|
||||
@@ -2964,7 +3018,7 @@ TEST(SSLClientServerTest, ClientCertPresent) {
|
||||
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_connection_timeout(30);
|
||||
|
||||
@@ -3035,7 +3089,7 @@ TEST(SSLClientServerTest, MemoryClientCertPresent) {
|
||||
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, client_cert, client_private_key);
|
||||
SSLClient cli(HOST, PORT, client_cert, client_private_key);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_connection_timeout(30);
|
||||
|
||||
@@ -3061,7 +3115,7 @@ TEST(SSLClientServerTest, ClientCertMissing) {
|
||||
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT);
|
||||
SSLClient cli(HOST, PORT);
|
||||
auto res = cli.Get("/test");
|
||||
cli.set_connection_timeout(30);
|
||||
ASSERT_TRUE(res == nullptr);
|
||||
@@ -3083,7 +3137,7 @@ TEST(SSLClientServerTest, TrustDirOptional) {
|
||||
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_connection_timeout(30);
|
||||
|
||||
@@ -3104,24 +3158,24 @@ TEST(CleanupTest, WSACleanup) {
|
||||
|
||||
// #ifndef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
// TEST(NoSSLSupport, SimpleInterface) {
|
||||
// httplib::Client cli("https://yahoo.com");
|
||||
// Client cli("https://yahoo.com");
|
||||
// ASSERT_FALSE(cli.is_valid());
|
||||
// }
|
||||
// #endif
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(InvalidScheme, SimpleInterface) {
|
||||
httplib::Client cli("scheme://yahoo.com");
|
||||
Client cli("scheme://yahoo.com");
|
||||
ASSERT_FALSE(cli.is_valid());
|
||||
}
|
||||
|
||||
TEST(NoScheme, SimpleInterface) {
|
||||
httplib::Client cli("yahoo.com:80");
|
||||
Client cli("yahoo.com:80");
|
||||
ASSERT_TRUE(cli.is_valid());
|
||||
}
|
||||
|
||||
TEST(YahooRedirectTest2, SimpleInterface) {
|
||||
httplib::Client cli("http://yahoo.com");
|
||||
Client cli("http://yahoo.com");
|
||||
|
||||
auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
@@ -3134,7 +3188,7 @@ TEST(YahooRedirectTest2, SimpleInterface) {
|
||||
}
|
||||
|
||||
TEST(YahooRedirectTest3, SimpleInterface) {
|
||||
httplib::Client cli("https://yahoo.com");
|
||||
Client cli("https://yahoo.com");
|
||||
|
||||
auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
@@ -3148,20 +3202,22 @@ TEST(YahooRedirectTest3, SimpleInterface) {
|
||||
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
TEST(DecodeWithChunkedEncoding, BrotliEncoding) {
|
||||
httplib::Client cli("https://cdnjs.cloudflare.com");
|
||||
auto res = cli.Get("/ajax/libs/jquery/3.5.1/jquery.js", {{"Accept-Encoding", "brotli"}});
|
||||
Client cli("https://cdnjs.cloudflare.com");
|
||||
auto res = cli.Get("/ajax/libs/jquery/3.5.1/jquery.js",
|
||||
{{"Accept-Encoding", "brotli"}});
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ(287630, res->body.size());
|
||||
EXPECT_EQ("application/javascript; charset=utf-8", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("application/javascript; charset=utf-8",
|
||||
res->get_header_value("Content-Type"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
TEST(HttpsToHttpRedirectTest2, SimpleInterface) {
|
||||
auto res =
|
||||
httplib::Client("https://httpbin.org")
|
||||
Client("https://httpbin.org")
|
||||
.set_follow_location(true)
|
||||
.Get("/redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user