Compare commits

...

14 Commits

Author SHA1 Message Date
yhirose ddff782133 Release v0.9.9 2021-11-26 20:46:38 -05:00
yhirose 3051152103 Fix #1102 (#1108) 2021-11-26 20:44:58 -05:00
yhirose 06026bb47d Code formating 2021-11-23 10:53:05 -05:00
yhirose 226388ae27 Resolve #1100 2021-11-23 10:47:30 -05:00
Scott Graham ea7548b4cc Remove stray ; causing warning with -Wextra-semi (#1099) 2021-11-22 07:16:07 -05:00
Rodolphe c7486ead96 accept protobuf encoding (#1096)
Co-authored-by: rodolphe <rodolphe@zen.ly>
2021-11-17 13:14:31 -05:00
yhirose 90a291214c Update Makefile 2021-11-15 23:08:49 -05:00
Andrea Pappacoda c111c42a86 build(meson): feature args in pkg-config file (#1092)
Follow-up for #1090. The args are now also added to the pkg-config file.
2021-11-15 22:50:33 -05:00
yhirose 6fb5b63018 Fix #1093. Remove meson-build tests from GitHubActions (#1094) 2021-11-15 22:49:40 -05:00
yhirose ec56dfa35e Fix #1085 (#1091) 2021-11-15 14:37:10 -05:00
Andrea Pappacoda 943cd51b67 build(meson): pass feature args to dependency consumers (#1090)
Fixes #1087
2021-11-15 14:03:25 -05:00
Yuji Hirose 301faa074c Added test case for #1065 2021-10-29 07:29:23 -04:00
DavidKorczynski dc0481e832 Add CIFuzz integration (#1079)
Signed-off-by: David Korczynski <david@adalogics.com>
2021-10-27 12:19:21 -04:00
zhenyolka 4f8fcdbaf7 Allow to specify server IP address (#1067)
* Allow to specify server IP address

* Reimplement in set_hostname_addr_map

* Add tests for set_hostname_addr_map

* Fix tests after implement set_hostname_addr_map

* SpecifyServerIPAddressTest.RealHostname typo
2021-10-16 15:05:55 -04:00
8 changed files with 185 additions and 130 deletions
+26
View File
@@ -0,0 +1,26 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'cpp-httplib'
dry-run: false
language: c++
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'cpp-httplib'
fuzz-seconds: 600
dry-run: false
language: c++
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts
-52
View File
@@ -39,55 +39,3 @@ jobs:
cd test
msbuild.exe test.sln /verbosity:minimal /t:Build "/p:Configuration=Release;Platform=x64"
x64\Release\test.exe
meson-build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
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
- uses: actions/checkout@v2
- name: Install dependencies on Linux
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get -qq update && sudo apt-get -qq install meson libssl-dev zlib1g-dev libbrotli-dev libgtest-dev
- name: Install dependencies on MacOS
if: matrix.os == 'macos-latest'
run: brew install meson openssl brotli googletest
- name: Setup MSVC on Windows
if: matrix.os == 'windows-latest'
uses: ilammy/msvc-dev-cmd@v1
# It is necessary to remove MinGW and StrawberryPerl as they both provide
# GCC. This causes issues because CMake prefers to use MSVC, while Meson
# uses GCC, if found, causing linking errors.
- name: Install dependencies on Windows
if: matrix.os == 'windows-latest'
run: |
choco uninstall mingw strawberryperl --yes --all-versions --remove-dependencies --skip-autouninstaller --no-color
Remove-Item -Path C:\Strawberry -Recurse
choco install pkgconfiglite --yes --skip-virus-check --no-color
pip install meson ninja
Invoke-WebRequest -Uri https://github.com/google/googletest/archive/refs/heads/master.zip -OutFile googletest-master.zip
Expand-Archive -Path googletest-master.zip
cd googletest-master\googletest-master
cmake -S . -B build -DINSTALL_GTEST=ON -DBUILD_GMOCK=OFF -Dgtest_hide_internal_symbols=ON -DCMAKE_INSTALL_PREFIX=C:/googletest
cmake --build build --config=Release
cmake --install build --config=Release
cd ..\..
- name: Build and test
run: |
meson setup build -Dcpp-httplib_test=true -Dpkg_config_path=C:\googletest\lib\pkgconfig -Db_vscrt=static_from_buildtype
meson test --no-stdsplit --print-errorlogs -C build
+4 -20
View File
@@ -60,27 +60,11 @@
]]
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
# On systems without Git installed, there were errors since execute_process seemed to not throw an error without it?
find_package(Git QUIET)
if(Git_FOUND)
# Gets the latest tag as a string like "v0.6.6"
# Can silently fail if git isn't on the system
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE _raw_version_string
ERROR_VARIABLE _git_tag_error
)
endif()
# Get the user agent and use it as a version
# This gets the string with the user agent from the header.
# This is so the maintainer doesn't actually need to update this manually.
file(STRINGS httplib.h _raw_version_string REGEX "User\-Agent.*cpp\-httplib/([0-9]+\.?)+")
# execute_process can fail silenty, so check for an error
# if there was an error, just use the user agent as a version
if(_git_tag_error OR NOT Git_FOUND)
message(WARNING "cpp-httplib failed to find the latest Git tag, falling back to using user agent as the version.")
# Get the user agent and use it as a version
# This gets the string with the user agent from the header.
# This is so the maintainer doesn't actually need to update this manually.
file(STRINGS httplib.h _raw_version_string REGEX "User\-Agent.*cpp\-httplib/([0-9]+\.?)+")
endif()
# Needed since git tags have "v" prefixing them.
# Also used if the fallback to user agent string is being used.
string(REGEX MATCH "([0-9]+\\.?)+" _httplib_version "${_raw_version_string}")
+8 -5
View File
@@ -1,14 +1,17 @@
#CXX = clang++
CXXFLAGS = -std=c++11 -I.. -Wall -Wextra -pthread
OPENSSL_DIR = /usr/local/opt/openssl
PREFIX = /usr/local
#PREFIX = $(shell brew --prefix)
OPENSSL_DIR = $(PREFIX)/opt/openssl@1.1
#OPENSSL_DIR = $(PREFIX)/opt/openssl@3
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
BROTLI_DIR = /usr/local/opt/brotli
# BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon-static -lbrotlienc-static -lbrotlidec-static
BROTLI_DIR = $(PREFIX)/opt/brotli
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
all: server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark
@@ -47,4 +50,4 @@ pem:
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
clean:
rm server client hello simplecli simplesvr upload redirect ssesvr sselci benchmark *.pem
rm server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark *.pem
+85 -45
View File
@@ -505,7 +505,7 @@ public:
virtual void enqueue(std::function<void()> fn) = 0;
virtual void shutdown() = 0;
virtual void on_idle(){};
virtual void on_idle() {}
};
class ThreadPool : public TaskQueue {
@@ -955,6 +955,8 @@ public:
void stop();
void set_hostname_addr_map(const std::map<std::string, std::string> addr_map);
void set_default_headers(Headers headers);
void set_address_family(int family);
@@ -1058,6 +1060,9 @@ protected:
std::thread::id socket_requests_are_from_thread_ = std::thread::id();
bool socket_should_be_closed_when_request_is_done_ = false;
// Hostname-IP map
std::map<std::string, std::string> addr_map_;
// Default headers
Headers default_headers_;
@@ -1285,6 +1290,8 @@ public:
void stop();
void set_hostname_addr_map(const std::map<std::string, std::string> addr_map);
void set_default_headers(Headers headers);
void set_address_family(int family);
@@ -1480,10 +1487,10 @@ inline T Response::get_header_value(const char *key, size_t id) const {
template <typename... Args>
inline ssize_t Stream::write_format(const char *fmt, const Args &...args) {
const auto bufsiz = 2048;
std::array<char, bufsiz> buf;
std::array<char, bufsiz> buf{};
#if defined(_MSC_VER) && _MSC_VER < 1900
auto sn = _snprintf_s(buf.data(), bufsiz - 1, buf.size() - 1, fmt, args...);
auto sn = _snprintf_s(buf.data(), bufsiz, _TRUNCATE, fmt, args...);
#else
auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...);
#endif
@@ -1656,14 +1663,12 @@ bool process_client_socket(socket_t sock, time_t read_timeout_sec,
time_t write_timeout_usec,
std::function<bool(Stream &)> callback);
socket_t create_client_socket(const char *host, int port, int address_family,
bool tcp_nodelay, SocketOptions socket_options,
time_t connection_timeout_sec,
time_t connection_timeout_usec,
time_t read_timeout_sec, time_t read_timeout_usec,
time_t write_timeout_sec,
time_t write_timeout_usec,
const std::string &intf, Error &error);
socket_t create_client_socket(
const char *host, const char *ip, int port, int address_family,
bool tcp_nodelay, SocketOptions socket_options,
time_t connection_timeout_sec, time_t connection_timeout_usec,
time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
time_t write_timeout_usec, const std::string &intf, Error &error);
const char *get_header_value(const Headers &headers, const char *key,
size_t id = 0, const char *def = nullptr);
@@ -2202,25 +2207,22 @@ inline ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags) {
return handle_EINTR([&]() {
return recv(sock,
#ifdef _WIN32
static_cast<char *>(ptr),
static_cast<int>(size),
static_cast<char *>(ptr), static_cast<int>(size),
#else
ptr,
size,
ptr, size,
#endif
flags);
});
}
inline ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags) {
inline ssize_t send_socket(socket_t sock, const void *ptr, size_t size,
int flags) {
return handle_EINTR([&]() {
return send(sock,
#ifdef _WIN32
static_cast<const char *>(ptr),
static_cast<int>(size),
static_cast<const char *>(ptr), static_cast<int>(size),
#else
ptr,
size,
ptr, size,
#endif
flags);
});
@@ -2453,8 +2455,8 @@ inline int shutdown_socket(socket_t sock) {
}
template <typename BindOrConnect>
socket_t create_socket(const char *host, int port, int address_family,
int socket_flags, bool tcp_nodelay,
socket_t create_socket(const char *host, const char *ip, int port,
int address_family, int socket_flags, bool tcp_nodelay,
SocketOptions socket_options,
BindOrConnect bind_or_connect) {
// Get address info
@@ -2467,9 +2469,16 @@ socket_t create_socket(const char *host, int port, int address_family,
hints.ai_flags = socket_flags;
hints.ai_protocol = 0;
// Ask getaddrinfo to convert IP in c-string to address
if (ip[0] != '\0') {
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST;
}
auto service = std::to_string(port);
if (getaddrinfo(host, service.c_str(), &hints, &result)) {
if (ip[0] != '\0' ? getaddrinfo(ip, service.c_str(), &hints, &result)
: getaddrinfo(host, service.c_str(), &hints, &result)) {
#if defined __linux__ && !defined __ANDROID__
res_init();
#endif
@@ -2604,13 +2613,13 @@ inline std::string if2ip(const std::string &ifn) {
#endif
inline socket_t create_client_socket(
const char *host, int port, int address_family, bool tcp_nodelay,
SocketOptions socket_options, time_t connection_timeout_sec,
time_t connection_timeout_usec, time_t read_timeout_sec,
time_t read_timeout_usec, time_t write_timeout_sec,
const char *host, const char *ip, int port, int address_family,
bool tcp_nodelay, SocketOptions socket_options,
time_t connection_timeout_sec, time_t connection_timeout_usec,
time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
time_t write_timeout_usec, const std::string &intf, Error &error) {
auto sock = create_socket(
host, port, address_family, 0, tcp_nodelay, std::move(socket_options),
host, ip, port, address_family, 0, tcp_nodelay, std::move(socket_options),
[&](socket_t sock2, struct addrinfo &ai) -> bool {
if (!intf.empty()) {
#ifdef USE_IF2IP
@@ -2852,6 +2861,7 @@ inline bool can_compress_content_type(const std::string &content_type) {
content_type == "application/javascript" ||
content_type == "application/json" ||
content_type == "application/xml" ||
content_type == "application/protobuf" ||
content_type == "application/xhtml+xml";
}
@@ -2980,9 +2990,7 @@ inline bool gzip_decompressor::decompress(const char *data, size_t data_length,
ret = inflate(&strm_, Z_NO_FLUSH);
if (prev_avail_in - strm_.avail_in == 0) {
return false;
}
if (prev_avail_in - strm_.avail_in == 0) { return false; }
assert(ret != Z_STREAM_ERROR);
switch (ret) {
@@ -3595,7 +3603,11 @@ inline bool parse_multipart_boundary(const std::string &content_type,
return !boundary.empty();
}
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
inline bool parse_range_header(const std::string &s, Ranges &ranges) {
#else
inline bool parse_range_header(const std::string &s, Ranges &ranges) try {
#endif
static auto re_first_range = std::regex(R"(bytes=(\d*-\d*(?:,\s*\d*-\d*)*))");
std::smatch m;
if (std::regex_match(s, m, re_first_range)) {
@@ -3627,7 +3639,11 @@ inline bool parse_range_header(const std::string &s, Ranges &ranges) try {
return all_valid_ranges;
}
return false;
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
}
#else
} catch (...) { return false; }
#endif
class MultipartFormDataParser {
public:
@@ -4418,8 +4434,7 @@ inline SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec,
: sock_(sock), read_timeout_sec_(read_timeout_sec),
read_timeout_usec_(read_timeout_usec),
write_timeout_sec_(write_timeout_sec),
write_timeout_usec_(write_timeout_usec),
read_buff_(read_buff_size_, 0) {}
write_timeout_usec_(write_timeout_usec), read_buff_(read_buff_size_, 0) {}
inline SocketStream::~SocketStream() {}
@@ -4433,9 +4448,11 @@ inline bool SocketStream::is_writable() const {
inline ssize_t SocketStream::read(char *ptr, size_t size) {
#ifdef _WIN32
size = (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
size =
(std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
#else
size = (std::min)(size, static_cast<size_t>((std::numeric_limits<ssize_t>::max)()));
size = (std::min)(size,
static_cast<size_t>((std::numeric_limits<ssize_t>::max)()));
#endif
if (read_buff_off_ < read_buff_content_size_) {
@@ -4457,7 +4474,8 @@ inline ssize_t SocketStream::read(char *ptr, size_t size) {
read_buff_content_size_ = 0;
if (size < read_buff_size_) {
auto n = read_socket(sock_, read_buff_.data(), read_buff_size_, CPPHTTPLIB_RECV_FLAGS);
auto n = read_socket(sock_, read_buff_.data(), read_buff_size_,
CPPHTTPLIB_RECV_FLAGS);
if (n <= 0) {
return n;
} else if (n <= static_cast<ssize_t>(size)) {
@@ -4478,7 +4496,8 @@ inline ssize_t SocketStream::write(const char *ptr, size_t size) {
if (!is_writable()) { return -1; }
#ifdef _WIN32
size = (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
size =
(std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
#endif
return send_socket(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS);
@@ -5079,7 +5098,7 @@ inline socket_t
Server::create_server_socket(const char *host, int port, int socket_flags,
SocketOptions socket_options) const {
return detail::create_socket(
host, port, address_family_, socket_flags, tcp_nodelay_,
host, "", port, address_family_, socket_flags, tcp_nodelay_,
std::move(socket_options),
[](socket_t sock, struct addrinfo &ai) -> bool {
if (::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
@@ -5489,6 +5508,9 @@ Server::process_request(Stream &strm, bool close_connection,
// Rounting
bool routed = false;
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
routed = routing(req, res, strm);
#else
try {
routed = routing(req, res, strm);
} catch (std::exception &e) {
@@ -5503,6 +5525,7 @@ Server::process_request(Stream &strm, bool close_connection,
res.status = 500;
res.set_header("EXCEPTION_WHAT", "UNKNOWN");
}
#endif
if (routed) {
if (res.status == -1) { res.status = req.ranges.empty() ? 200 : 206; }
@@ -5598,16 +5621,21 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
inline socket_t ClientImpl::create_client_socket(Error &error) const {
if (!proxy_host_.empty() && proxy_port_ != -1) {
return detail::create_client_socket(
proxy_host_.c_str(), proxy_port_, address_family_, tcp_nodelay_,
proxy_host_.c_str(), "", proxy_port_, address_family_, tcp_nodelay_,
socket_options_, connection_timeout_sec_, connection_timeout_usec_,
read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
write_timeout_usec_, interface_, error);
}
// Check is custom IP specified for host_
std::string ip;
auto it = addr_map_.find(host_);
if (it != addr_map_.end()) ip = it->second;
return detail::create_client_socket(
host_.c_str(), port_, address_family_, tcp_nodelay_, socket_options_,
connection_timeout_sec_, connection_timeout_usec_, read_timeout_sec_,
read_timeout_usec_, write_timeout_sec_, write_timeout_usec_, interface_,
error);
host_.c_str(), ip.c_str(), port_, address_family_, tcp_nodelay_,
socket_options_, connection_timeout_sec_, connection_timeout_usec_,
read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
write_timeout_usec_, interface_, error);
}
inline bool ClientImpl::create_and_connect_socket(Socket &socket,
@@ -5652,7 +5680,7 @@ inline void ClientImpl::close_socket(Socket &socket) {
inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
Response &res) {
std::array<char, 2048> buf;
std::array<char, 2048> buf{};
detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
@@ -5950,7 +5978,7 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
if (!req.has_header("Accept")) { req.headers.emplace("Accept", "*/*"); }
if (!req.has_header("User-Agent")) {
req.headers.emplace("User-Agent", "cpp-httplib/0.9");
req.headers.emplace("User-Agent", "cpp-httplib/0.9.9");
}
if (req.body.empty()) {
@@ -6732,6 +6760,11 @@ inline void ClientImpl::set_follow_location(bool on) { follow_location_ = on; }
inline void ClientImpl::set_url_encode(bool on) { url_encode_ = on; }
inline void ClientImpl::set_hostname_addr_map(
const std::map<std::string, std::string> addr_map) {
addr_map_ = std::move(addr_map);
}
inline void ClientImpl::set_default_headers(Headers headers) {
default_headers_ = std::move(headers);
}
@@ -7553,8 +7586,10 @@ inline Client::Client(const std::string &scheme_host_port,
#else
if (!scheme.empty() && scheme != "http") {
#endif
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
std::string msg = "'" + scheme + "' scheme is not supported.";
throw std::invalid_argument(msg);
#endif
return;
}
@@ -7855,6 +7890,11 @@ inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); }
inline void Client::stop() { cli_->stop(); }
inline void Client::set_hostname_addr_map(
const std::map<std::string, std::string> addr_map) {
cli_->set_hostname_addr_map(std::move(addr_map));
}
inline void Client::set_default_headers(Headers headers) {
cli_->set_default_headers(std::move(headers));
}
+3 -2
View File
@@ -91,17 +91,18 @@ if get_option('cpp-httplib_compile')
version: version,
install: true
)
cpp_httplib_dep = declare_dependency(link_with: lib, sources: httplib_ch[1])
cpp_httplib_dep = declare_dependency(compile_args: args, dependencies: deps, link_with: lib, sources: httplib_ch[1])
import('pkgconfig').generate(
lib,
description: 'A C++ HTTP/HTTPS server and client library',
extra_cflags: args,
url: 'https://github.com/yhirose/cpp-httplib',
version: version
)
else
install_headers('httplib.h')
cpp_httplib_dep = declare_dependency(include_directories: include_directories('.'), dependencies: deps)
cpp_httplib_dep = declare_dependency(compile_args: args, dependencies: deps, include_directories: include_directories('.'))
endif
if meson.version().version_compare('>=0.54.0')
+9 -5
View File
@@ -1,12 +1,16 @@
#CXX = clang++
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion #-fsanitize=address
CXX = clang++
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion # -fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS -fsanitize=address
OPENSSL_DIR = /usr/local/opt/openssl@1.1
PREFIX = /usr/local
#PREFIX = $(shell brew --prefix)
OPENSSL_DIR = $(PREFIX)/opt/openssl@1.1
#OPENSSL_DIR = $(PREFIX)/opt/openssl@3
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
BROTLI_DIR = /usr/local/opt/brotli
BROTLI_DIR = $(PREFIX)/opt/brotli
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
TEST_ARGS = gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
@@ -64,4 +68,4 @@ cert.pem:
#c_rehash .
clean:
rm -f test test_proxy server_fuzzer pem *.0 *.o *.1 *.srl httplib.h httplib.cc
rm -f test test_split test_proxy server_fuzzer pem *.0 *.o *.1 *.srl httplib.h httplib.cc
+50 -1
View File
@@ -37,8 +37,12 @@ MultipartFormData &get_file_value(MultipartFormDataItems &files,
auto it = std::find_if(
files.begin(), files.end(),
[&](const MultipartFormData &file) { return file.name == key; });
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
return *it;
#else
if (it != files.end()) { return *it; }
throw std::runtime_error("invalid mulitpart form data name error");
#endif
}
TEST(ConstructorTest, MoveConstructible) {
@@ -171,6 +175,12 @@ TEST(GetHeaderValueTest, RegularValue) {
EXPECT_STREQ("text/html", val);
}
TEST(GetHeaderValueTest, RegularValueWithDifferentCase) {
Headers headers = {{"Content-Type", "text/html"}, {"Dummy", "Dummy"}};
auto val = detail::get_header_value(headers, "content-type", 0, "text/plain");
EXPECT_STREQ("text/html", val);
}
TEST(GetHeaderValueTest, SetContent) {
Response res;
@@ -736,6 +746,39 @@ TEST(DigestAuthTest, FromHTTPWatch_Online) {
}
#endif
TEST(SpecifyServerIPAddressTest, AnotherHostname) {
auto host = "google.com";
auto another_host = "example.com";
auto wrong_ip = "0.0.0.0";
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
SSLClient cli(host);
#else
Client cli(host);
#endif
cli.set_hostname_addr_map({{another_host, wrong_ip}});
auto res = cli.Get("/");
ASSERT_TRUE(res);
ASSERT_EQ(301, res->status);
}
TEST(SpecifyServerIPAddressTest, RealHostname) {
auto host = "google.com";
auto wrong_ip = "0.0.0.0";
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
SSLClient cli(host);
#else
Client cli(host);
#endif
cli.set_hostname_addr_map({{host, wrong_ip}});
auto res = cli.Get("/");
ASSERT_TRUE(!res);
EXPECT_EQ(Error::Connection, res.error());
}
TEST(AbsoluteRedirectTest, Redirect_Online) {
auto host = "nghttp2.org";
@@ -1148,6 +1191,7 @@ TEST(ErrorHandlerTest, ContentLength) {
ASSERT_FALSE(svr.is_running());
}
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
TEST(ExceptionHandlerTest, ContentLength) {
Server svr;
@@ -1183,6 +1227,7 @@ TEST(ExceptionHandlerTest, ContentLength) {
thread.join();
ASSERT_FALSE(svr.is_running());
}
#endif
TEST(NoContentTest, ContentLength) {
Server svr;
@@ -3321,7 +3366,7 @@ static bool send_request(time_t read_timeout_sec, const std::string &req,
auto error = Error::Success;
auto client_sock = detail::create_client_socket(
HOST, PORT, AF_UNSPEC, false, nullptr,
HOST, "", PORT, AF_UNSPEC, false, nullptr,
/*connection_timeout_sec=*/5, 0,
/*read_timeout_sec=*/5, 0,
/*write_timeout_sec=*/5, 0, std::string(), error);
@@ -3642,6 +3687,7 @@ TEST(MountTest, Unmount) {
ASSERT_FALSE(svr.is_running());
}
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
TEST(ExceptionTest, ThrowExceptionInHandler) {
Server svr;
@@ -3670,6 +3716,7 @@ TEST(ExceptionTest, ThrowExceptionInHandler) {
listen_thread.join();
ASSERT_FALSE(svr.is_running());
}
#endif
TEST(KeepAliveTest, ReadTimeout) {
Server svr;
@@ -4476,9 +4523,11 @@ TEST(NoSSLSupport, SimpleInterface) {
}
#endif
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
TEST(InvalidScheme, SimpleInterface) {
ASSERT_ANY_THROW(Client cli("scheme://yahoo.com"));
}
#endif
TEST(NoScheme, SimpleInterface) {
Client cli("yahoo.com:80");