Compare commits

...

9 Commits

Author SHA1 Message Date
yhirose adf58bf474 Release v0.28.0 2025-11-25 21:06:51 -05:00
yhirose 337fbb0793 Fix #2279
Enhance request handling: add support for requests without Content-Length or Transfer-Encoding headers
2025-11-25 20:30:43 -05:00
Copilot 9e7861b0b4 Add #undef _res after including resolv.h to prevent macro conflicts (#2280)
* Initial plan

* Add #undef _res after including resolv.h to prevent macro conflicts

Co-authored-by: yhirose <357397+yhirose@users.noreply.github.com>

* Complete task - added #undef _res after resolv.h include

Co-authored-by: yhirose <357397+yhirose@users.noreply.github.com>

* Remove accidentally committed codeql build artifacts

Co-authored-by: yhirose <357397+yhirose@users.noreply.github.com>

* Add inline comment explaining why #undef _res is necessary

Co-authored-by: yhirose <357397+yhirose@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: yhirose <357397+yhirose@users.noreply.github.com>
2025-11-25 20:00:10 -05:00
Clarkok Zhang 27ee115a60 Fix android getaddrinfo issue (#2273)
Co-authored-by: Clarkok Zhang <clarkok8@gmail.com>
2025-11-14 16:48:21 -05:00
Clarkok Zhang 59882752aa Add Client::Post with both content provider and receiver (#2268)
Co-authored-by: Clarkok Zhang <clarkok8@gmail.com>
2025-11-14 14:52:06 -05:00
yhirose 61e9f7ce8f Fix #2270 2025-11-14 14:17:04 -05:00
VZ 1acf18876f CMake: Add HTTPLIB_SHARED option, don't define BUILD_SHARED_LIBS (#2266)
To avoid surprises in the projects consuming the library, don't define
BUILD_SHARED_LIBS option ourselves but just use its value, if provided,
to define HTTPLIB_SHARED option which can be also set directly to
specify whether we should build static or shared library.

Closes #2263.
2025-11-10 22:17:43 -05:00
chansikpark 4b2b851dbb Fix HTTP 414 errors hanging until timeout (#2260)
* Fix HTTP 414 errors hanging until timeout

* All errors (status code 400+) close the connection

* 🧹

---------

Co-authored-by: Wor Ker <worker@factory>
2025-11-02 22:23:42 -05:00
yhirose 551f96d4a2 Remove REMOTE_PORT dependency from UnixSocketTest.PeerPid 2025-10-27 20:40:12 -04:00
5 changed files with 614 additions and 90 deletions
+2
View File
@@ -23,6 +23,8 @@ example/one_time_request
!example/one_time_request.*
example/server_and_client
!example/server_and_client.*
example/accept_header
!example/accept_header.*
example/*.pem
test/httplib.cc
test/httplib.h
+17 -9
View File
@@ -1,6 +1,6 @@
#[[
Build options:
* BUILD_SHARED_LIBS (default off) builds as a shared library (if HTTPLIB_COMPILE is ON)
* Standard BUILD_SHARED_LIBS is supported and sets HTTPLIB_SHARED default value.
* HTTPLIB_USE_OPENSSL_IF_AVAILABLE (default on)
* HTTPLIB_USE_ZLIB_IF_AVAILABLE (default on)
* HTTPLIB_USE_BROTLI_IF_AVAILABLE (default on)
@@ -13,6 +13,7 @@
* HTTPLIB_USE_NON_BLOCKING_GETADDRINFO (default on)
* HTTPLIB_COMPILE (default off)
* HTTPLIB_INSTALL (default on)
* HTTPLIB_SHARED (default off) builds as a shared library (if HTTPLIB_COMPILE is ON)
* HTTPLIB_TEST (default off)
* BROTLI_USE_STATIC_LIBS - tells Cmake to use the static Brotli libs (only works if you have them installed).
* OPENSSL_USE_STATIC_LIBS - tells Cmake to use the static OpenSSL libs (only works if you have them installed).
@@ -109,12 +110,20 @@ option(HTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN "Enable feature to load system cer
option(HTTPLIB_USE_NON_BLOCKING_GETADDRINFO "Enables the non-blocking alternatives for getaddrinfo." ON)
option(HTTPLIB_REQUIRE_ZSTD "Requires ZSTD to be found & linked, or fails build." OFF)
option(HTTPLIB_USE_ZSTD_IF_AVAILABLE "Uses ZSTD (if available) to enable zstd 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)
# Necessary for Windows if building shared libs
# See https://stackoverflow.com/a/40743080
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
# Defaults to static library but respects standard BUILD_SHARED_LIBS if set
include(CMakeDependentOption)
cmake_dependent_option(HTTPLIB_SHARED "Build the library as a shared library instead of static. Has no effect if using header-only."
"${BUILD_SHARED_LIBS}" HTTPLIB_COMPILE OFF
)
if(HTTPLIB_SHARED)
set(HTTPLIB_LIB_TYPE SHARED)
if(WIN32)
# Necessary for Windows if building shared libs
# See https://stackoverflow.com/a/40743080
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
else()
set(HTTPLIB_LIB_TYPE STATIC)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
@@ -230,8 +239,7 @@ if(HTTPLIB_COMPILE)
# split.py puts output in "out"
set(_httplib_build_includedir "${CMAKE_CURRENT_BINARY_DIR}/out")
# This will automatically be either static or shared based on the value of BUILD_SHARED_LIBS
add_library(${PROJECT_NAME} "${_httplib_build_includedir}/httplib.cc")
add_library(${PROJECT_NAME} ${HTTPLIB_LIB_TYPE} "${_httplib_build_includedir}/httplib.cc")
target_sources(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${_httplib_build_includedir}/httplib.h>
+11 -4
View File
@@ -44,9 +44,10 @@ httplib::Client cli("http://yhirose.github.io");
// HTTPS
httplib::Client cli("https://yhirose.github.io");
auto res = cli.Get("/hi");
res->status;
res->body;
if (auto res = cli.Get("/hi")) {
res->status;
res->body;
}
```
SSL Support
@@ -190,7 +191,7 @@ int main(void)
}
```
`Post`, `Put`, `Delete` and `Options` methods are also supported.
`Post`, `Put`, `Patch`, `Delete` and `Options` methods are also supported.
### Bind a socket to multiple interfaces and any available port
@@ -853,6 +854,12 @@ auto res = cli.Post("/multipart", items);
res = cli.Put("/resource/foo", "text", "text/plain");
```
### PATCH
```c++
res = cli.Patch("/resource/foo", "text", "text/plain");
```
### DELETE
```c++
+336 -64
View File
@@ -8,8 +8,8 @@
#ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_VERSION "0.27.0"
#define CPPHTTPLIB_VERSION_NUM "0x001B00"
#define CPPHTTPLIB_VERSION "0.28.0"
#define CPPHTTPLIB_VERSION_NUM "0x001C00"
/*
* Platform compatibility check
@@ -257,6 +257,7 @@ using socklen_t = int;
#include <netinet/in.h>
#ifdef __linux__
#include <resolv.h>
#undef _res // Undefine _res macro to avoid conflicts with user code (#2278)
#endif
#include <csignal>
#include <netinet/tcp.h>
@@ -1421,14 +1422,18 @@ public:
Result Post(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Post(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Params &params);
Result Post(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers);
Result Post(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, const Params &params);
Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
@@ -1439,14 +1444,18 @@ public:
Result Put(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Put(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Params &params);
Result Put(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers);
Result Put(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, const Params &params);
Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
@@ -1457,14 +1466,18 @@ public:
Result Patch(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Patch(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Params &params);
Result Patch(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, const Params &params);
Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
@@ -1712,17 +1725,19 @@ private:
template <typename ClientType> void setup_redirect_client(ClientType &client);
bool handle_request(Stream &strm, Request &req, Response &res,
bool close_connection, Error &error);
std::unique_ptr<Response> send_with_content_provider(
std::unique_ptr<Response> send_with_content_provider_and_receiver(
Request &req, const char *body, size_t content_length,
ContentProvider content_provider,
ContentProviderWithoutLength content_provider_without_length,
const std::string &content_type, Error &error);
Result send_with_content_provider(
const std::string &content_type, ContentReceiver content_receiver,
Error &error);
Result send_with_content_provider_and_receiver(
const std::string &method, const std::string &path,
const Headers &headers, const char *body, size_t content_length,
ContentProvider content_provider,
ContentProviderWithoutLength content_provider_without_length,
const std::string &content_type, UploadProgress progress);
const std::string &content_type, ContentReceiver content_receiver,
UploadProgress progress);
ContentProviderWithoutLength get_multipart_content_provider(
const std::string &boundary, const UploadFormDataItems &items,
const FormDataProviderItems &provider_items) const;
@@ -1775,14 +1790,18 @@ public:
Result Post(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Post(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Params &params);
Result Post(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers);
Result Post(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, const Params &params);
Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Post(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
@@ -1793,14 +1812,18 @@ public:
Result Put(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Put(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Params &params);
Result Put(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers);
Result Put(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, const Params &params);
Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Put(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
@@ -1811,14 +1834,18 @@ public:
Result Patch(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Patch(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Params &params);
Result Patch(const std::string &path, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers);
Result Patch(const std::string &path, const Headers &headers, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, size_t content_length, ContentProvider content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, ContentProviderWithoutLength content_provider, const std::string &content_type, ContentReceiver content_receiver, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, const Params &params);
Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, UploadProgress progress = nullptr);
Result Patch(const std::string &path, const Headers &headers, const UploadFormDataItems &items, const std::string &boundary, UploadProgress progress = nullptr);
@@ -3809,22 +3836,30 @@ inline int getaddrinfo_with_timeout(const char *node, const char *service,
// Fallback implementation using thread-based timeout for other Unix systems
struct GetAddrInfoState {
~GetAddrInfoState() {
if (info) { freeaddrinfo(info); }
}
std::mutex mutex;
std::condition_variable result_cv;
bool completed = false;
int result = EAI_SYSTEM;
std::string node = node;
std::string service = service;
struct addrinfo hints = hints;
std::string node;
std::string service;
struct addrinfo hints;
struct addrinfo *info = nullptr;
};
// Allocate on the heap, so the resolver thread can keep using the data.
auto state = std::make_shared<GetAddrInfoState>();
state->node = node;
state->service = service;
state->hints = *hints;
std::thread resolve_thread([=]() {
auto thread_result = getaddrinfo(
state->node.c_str(), state->service.c_str(), hints, &state->info);
std::thread resolve_thread([state]() {
auto thread_result =
getaddrinfo(state->node.c_str(), state->service.c_str(), &state->hints,
&state->info);
std::lock_guard<std::mutex> lock(state->mutex);
state->result = thread_result;
@@ -3842,6 +3877,7 @@ inline int getaddrinfo_with_timeout(const char *node, const char *service,
// Operation completed within timeout
resolve_thread.join();
*res = state->info;
state->info = nullptr; // Pass ownership to caller
return state->result;
} else {
// Timeout occurred
@@ -7692,7 +7728,8 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
if (need_apply_ranges) { apply_ranges(req, res, content_type, boundary); }
// Prepare additional headers
if (close_connection || req.get_header_value("Connection") == "close") {
if (close_connection || req.get_header_value("Connection") == "close" ||
400 <= res.status) { // Don't leave connections open after errors
res.set_header("Connection", "close");
} else {
std::string s = "timeout=";
@@ -7895,7 +7932,11 @@ inline bool Server::read_content_core(
size_t /*len*/) { return receiver(buf, n); };
}
if (req.method == "DELETE" && !req.has_header("Content-Length")) {
// RFC 7230 Section 3.3.3: If this is a request message and none of the above
// are true (no Transfer-Encoding and no Content-Length), then the message
// body length is zero (no message body is present).
if (!req.has_header("Content-Length") &&
!detail::is_chunked_transfer_encoding(req.headers)) {
return true;
}
@@ -8403,8 +8444,6 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
// Check if the request URI doesn't exceed the limit
if (req.target.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) {
Headers dummy;
detail::read_headers(strm, dummy);
res.status = StatusCode::UriTooLong_414;
output_error_log(Error::ExceedUriMaxLength, &req);
return write_response(strm, close_connection, req, res);
@@ -9388,11 +9427,13 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
return true;
}
inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
inline std::unique_ptr<Response>
ClientImpl::send_with_content_provider_and_receiver(
Request &req, const char *body, size_t content_length,
ContentProvider content_provider,
ContentProviderWithoutLength content_provider_without_length,
const std::string &content_type, Error &error) {
const std::string &content_type, ContentReceiver content_receiver,
Error &error) {
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
@@ -9465,15 +9506,24 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
}
}
if (content_receiver) {
req.content_receiver =
[content_receiver](const char *data, size_t data_length,
size_t /*offset*/, size_t /*total_length*/) {
return content_receiver(data, data_length);
};
}
auto res = detail::make_unique<Response>();
return send(req, *res, error) ? std::move(res) : nullptr;
}
inline Result ClientImpl::send_with_content_provider(
inline Result ClientImpl::send_with_content_provider_and_receiver(
const std::string &method, const std::string &path, const Headers &headers,
const char *body, size_t content_length, ContentProvider content_provider,
ContentProviderWithoutLength content_provider_without_length,
const std::string &content_type, UploadProgress progress) {
const std::string &content_type, ContentReceiver content_receiver,
UploadProgress progress) {
Request req;
req.method = method;
req.headers = headers;
@@ -9485,9 +9535,10 @@ inline Result ClientImpl::send_with_content_provider(
auto error = Error::Success;
auto res = send_with_content_provider(
auto res = send_with_content_provider_and_receiver(
req, body, content_length, std::move(content_provider),
std::move(content_provider_without_length), content_type, error);
std::move(content_provider_without_length), content_type,
std::move(content_receiver), error);
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
return Result{std::move(res), error, std::move(req.headers), last_ssl_error_,
@@ -9816,6 +9867,15 @@ inline Result ClientImpl::Post(const std::string &path, size_t content_length,
content_type, progress);
}
inline Result ClientImpl::Post(const std::string &path, size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return Post(path, Headers(), content_length, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result ClientImpl::Post(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
@@ -9824,6 +9884,15 @@ inline Result ClientImpl::Post(const std::string &path,
progress);
}
inline Result ClientImpl::Post(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return Post(path, Headers(), std::move(content_provider), content_type,
std::move(content_receiver), progress);
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
const Params &params) {
auto query = detail::params_to_query_str(params);
@@ -9864,17 +9933,18 @@ inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
const char *body, size_t content_length,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("POST", path, headers, body, content_length,
nullptr, nullptr, content_type, progress);
return send_with_content_provider_and_receiver(
"POST", path, headers, body, content_length, nullptr, nullptr,
content_type, nullptr, progress);
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
const std::string &body,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("POST", path, headers, body.data(),
body.size(), nullptr, nullptr, content_type,
progress);
return send_with_content_provider_and_receiver(
"POST", path, headers, body.data(), body.size(), nullptr, nullptr,
content_type, nullptr, progress);
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
@@ -9882,18 +9952,40 @@ inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
ContentProvider content_provider,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("POST", path, headers, nullptr,
content_length, std::move(content_provider),
nullptr, content_type, progress);
return send_with_content_provider_and_receiver(
"POST", path, headers, nullptr, content_length,
std::move(content_provider), nullptr, content_type, nullptr, progress);
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
DownloadProgress progress) {
return send_with_content_provider_and_receiver(
"POST", path, headers, nullptr, content_length,
std::move(content_provider), nullptr, content_type,
std::move(content_receiver), std::move(progress));
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr,
std::move(content_provider), content_type,
progress);
return send_with_content_provider_and_receiver(
"POST", path, headers, nullptr, 0, nullptr, std::move(content_provider),
content_type, nullptr, progress);
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
DownloadProgress progress) {
return send_with_content_provider_and_receiver(
"POST", path, headers, nullptr, 0, nullptr, std::move(content_provider),
content_type, std::move(content_receiver), std::move(progress));
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
@@ -9903,10 +9995,10 @@ inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
const auto &boundary = detail::make_multipart_data_boundary();
const auto &content_type =
detail::serialize_multipart_formdata_get_content_type(boundary);
return send_with_content_provider(
return send_with_content_provider_and_receiver(
"POST", path, headers, nullptr, 0, nullptr,
get_multipart_content_provider(boundary, items, provider_items),
content_type, progress);
content_type, nullptr, progress);
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
@@ -9968,6 +10060,15 @@ inline Result ClientImpl::Put(const std::string &path, size_t content_length,
content_type, progress);
}
inline Result ClientImpl::Put(const std::string &path, size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return Put(path, Headers(), content_length, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result ClientImpl::Put(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
@@ -9976,6 +10077,15 @@ inline Result ClientImpl::Put(const std::string &path,
progress);
}
inline Result ClientImpl::Put(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return Put(path, Headers(), std::move(content_provider), content_type,
std::move(content_receiver), progress);
}
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
const Params &params) {
auto query = detail::params_to_query_str(params);
@@ -10016,17 +10126,18 @@ inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
const char *body, size_t content_length,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("PUT", path, headers, body, content_length,
nullptr, nullptr, content_type, progress);
return send_with_content_provider_and_receiver(
"PUT", path, headers, body, content_length, nullptr, nullptr,
content_type, nullptr, progress);
}
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
const std::string &body,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("PUT", path, headers, body.data(),
body.size(), nullptr, nullptr, content_type,
progress);
return send_with_content_provider_and_receiver(
"PUT", path, headers, body.data(), body.size(), nullptr, nullptr,
content_type, nullptr, progress);
}
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
@@ -10034,18 +10145,40 @@ inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
ContentProvider content_provider,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("PUT", path, headers, nullptr,
content_length, std::move(content_provider),
nullptr, content_type, progress);
return send_with_content_provider_and_receiver(
"PUT", path, headers, nullptr, content_length,
std::move(content_provider), nullptr, content_type, nullptr, progress);
}
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return send_with_content_provider_and_receiver(
"PUT", path, headers, nullptr, content_length,
std::move(content_provider), nullptr, content_type,
std::move(content_receiver), progress);
}
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("PUT", path, headers, nullptr, 0, nullptr,
std::move(content_provider), content_type,
progress);
return send_with_content_provider_and_receiver(
"PUT", path, headers, nullptr, 0, nullptr, std::move(content_provider),
content_type, nullptr, progress);
}
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return send_with_content_provider_and_receiver(
"PUT", path, headers, nullptr, 0, nullptr, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
@@ -10055,10 +10188,10 @@ inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
const auto &boundary = detail::make_multipart_data_boundary();
const auto &content_type =
detail::serialize_multipart_formdata_get_content_type(boundary);
return send_with_content_provider(
return send_with_content_provider_and_receiver(
"PUT", path, headers, nullptr, 0, nullptr,
get_multipart_content_provider(boundary, items, provider_items),
content_type, progress);
content_type, nullptr, progress);
}
inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
@@ -10122,6 +10255,15 @@ inline Result ClientImpl::Patch(const std::string &path, size_t content_length,
content_type, progress);
}
inline Result ClientImpl::Patch(const std::string &path, size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return Patch(path, Headers(), content_length, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result ClientImpl::Patch(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
@@ -10130,6 +10272,15 @@ inline Result ClientImpl::Patch(const std::string &path,
progress);
}
inline Result ClientImpl::Patch(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return Patch(path, Headers(), std::move(content_provider), content_type,
std::move(content_receiver), progress);
}
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
const Params &params) {
auto query = detail::params_to_query_str(params);
@@ -10170,18 +10321,18 @@ inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
const char *body, size_t content_length,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("PATCH", path, headers, body,
content_length, nullptr, nullptr,
content_type, progress);
return send_with_content_provider_and_receiver(
"PATCH", path, headers, body, content_length, nullptr, nullptr,
content_type, nullptr, progress);
}
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
const std::string &body,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("PATCH", path, headers, body.data(),
body.size(), nullptr, nullptr, content_type,
progress);
return send_with_content_provider_and_receiver(
"PATCH", path, headers, body.data(), body.size(), nullptr, nullptr,
content_type, nullptr, progress);
}
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
@@ -10189,18 +10340,40 @@ inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
ContentProvider content_provider,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("PATCH", path, headers, nullptr,
content_length, std::move(content_provider),
nullptr, content_type, progress);
return send_with_content_provider_and_receiver(
"PATCH", path, headers, nullptr, content_length,
std::move(content_provider), nullptr, content_type, nullptr, progress);
}
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return send_with_content_provider_and_receiver(
"PATCH", path, headers, nullptr, content_length,
std::move(content_provider), nullptr, content_type,
std::move(content_receiver), progress);
}
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
UploadProgress progress) {
return send_with_content_provider("PATCH", path, headers, nullptr, 0, nullptr,
std::move(content_provider), content_type,
progress);
return send_with_content_provider_and_receiver(
"PATCH", path, headers, nullptr, 0, nullptr, std::move(content_provider),
content_type, nullptr, progress);
}
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return send_with_content_provider_and_receiver(
"PATCH", path, headers, nullptr, 0, nullptr, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
@@ -10210,10 +10383,10 @@ inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
const auto &boundary = detail::make_multipart_data_boundary();
const auto &content_type =
detail::serialize_multipart_formdata_get_content_type(boundary);
return send_with_content_provider(
return send_with_content_provider_and_receiver(
"PATCH", path, headers, nullptr, 0, nullptr,
get_multipart_content_provider(boundary, items, provider_items),
content_type, progress);
content_type, nullptr, progress);
}
inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
@@ -11605,12 +11778,28 @@ inline Result Client::Post(const std::string &path, size_t content_length,
return cli_->Post(path, content_length, std::move(content_provider),
content_type, progress);
}
inline Result Client::Post(const std::string &path, size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return cli_->Post(path, content_length, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result Client::Post(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
UploadProgress progress) {
return cli_->Post(path, std::move(content_provider), content_type, progress);
}
inline Result Client::Post(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return cli_->Post(path, std::move(content_provider), content_type,
std::move(content_receiver), progress);
}
inline Result Client::Post(const std::string &path, const Headers &headers,
size_t content_length,
ContentProvider content_provider,
@@ -11619,6 +11808,15 @@ inline Result Client::Post(const std::string &path, const Headers &headers,
return cli_->Post(path, headers, content_length, std::move(content_provider),
content_type, progress);
}
inline Result Client::Post(const std::string &path, const Headers &headers,
size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
DownloadProgress progress) {
return cli_->Post(path, headers, content_length, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result Client::Post(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
@@ -11626,6 +11824,14 @@ inline Result Client::Post(const std::string &path, const Headers &headers,
return cli_->Post(path, headers, std::move(content_provider), content_type,
progress);
}
inline Result Client::Post(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
DownloadProgress progress) {
return cli_->Post(path, headers, std::move(content_provider), content_type,
std::move(content_receiver), progress);
}
inline Result Client::Post(const std::string &path, const Params &params) {
return cli_->Post(path, params);
}
@@ -11660,8 +11866,8 @@ inline Result Client::Post(const std::string &path, const Headers &headers,
const std::string &content_type,
ContentReceiver content_receiver,
DownloadProgress progress) {
return cli_->Post(path, headers, body, content_type, content_receiver,
progress);
return cli_->Post(path, headers, body, content_type,
std::move(content_receiver), progress);
}
inline Result Client::Put(const std::string &path) { return cli_->Put(path); }
@@ -11698,12 +11904,28 @@ inline Result Client::Put(const std::string &path, size_t content_length,
return cli_->Put(path, content_length, std::move(content_provider),
content_type, progress);
}
inline Result Client::Put(const std::string &path, size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return cli_->Put(path, content_length, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result Client::Put(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
UploadProgress progress) {
return cli_->Put(path, std::move(content_provider), content_type, progress);
}
inline Result Client::Put(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return cli_->Put(path, std::move(content_provider), content_type,
std::move(content_receiver), progress);
}
inline Result Client::Put(const std::string &path, const Headers &headers,
size_t content_length,
ContentProvider content_provider,
@@ -11712,6 +11934,15 @@ inline Result Client::Put(const std::string &path, const Headers &headers,
return cli_->Put(path, headers, content_length, std::move(content_provider),
content_type, progress);
}
inline Result Client::Put(const std::string &path, const Headers &headers,
size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return cli_->Put(path, headers, content_length, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result Client::Put(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
@@ -11719,6 +11950,14 @@ inline Result Client::Put(const std::string &path, const Headers &headers,
return cli_->Put(path, headers, std::move(content_provider), content_type,
progress);
}
inline Result Client::Put(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return cli_->Put(path, headers, std::move(content_provider), content_type,
std::move(content_receiver), progress);
}
inline Result Client::Put(const std::string &path, const Params &params) {
return cli_->Put(path, params);
}
@@ -11794,12 +12033,28 @@ inline Result Client::Patch(const std::string &path, size_t content_length,
return cli_->Patch(path, content_length, std::move(content_provider),
content_type, progress);
}
inline Result Client::Patch(const std::string &path, size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return cli_->Patch(path, content_length, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result Client::Patch(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
UploadProgress progress) {
return cli_->Patch(path, std::move(content_provider), content_type, progress);
}
inline Result Client::Patch(const std::string &path,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return cli_->Patch(path, std::move(content_provider), content_type,
std::move(content_receiver), progress);
}
inline Result Client::Patch(const std::string &path, const Headers &headers,
size_t content_length,
ContentProvider content_provider,
@@ -11808,6 +12063,15 @@ inline Result Client::Patch(const std::string &path, const Headers &headers,
return cli_->Patch(path, headers, content_length, std::move(content_provider),
content_type, progress);
}
inline Result Client::Patch(const std::string &path, const Headers &headers,
size_t content_length,
ContentProvider content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return cli_->Patch(path, headers, content_length, std::move(content_provider),
content_type, std::move(content_receiver), progress);
}
inline Result Client::Patch(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
@@ -11815,6 +12079,14 @@ inline Result Client::Patch(const std::string &path, const Headers &headers,
return cli_->Patch(path, headers, std::move(content_provider), content_type,
progress);
}
inline Result Client::Patch(const std::string &path, const Headers &headers,
ContentProviderWithoutLength content_provider,
const std::string &content_type,
ContentReceiver content_receiver,
UploadProgress progress) {
return cli_->Patch(path, headers, std::move(content_provider), content_type,
std::move(content_receiver), progress);
}
inline Result Client::Patch(const std::string &path, const Params &params) {
return cli_->Patch(path, params);
}
+248 -13
View File
@@ -196,7 +196,7 @@ TEST_F(UnixSocketTest, PeerPid) {
std::string remote_port_val;
svr.Get(pattern_, [&](const httplib::Request &req, httplib::Response &res) {
res.set_content(content_, "text/plain");
remote_port_val = req.get_header_value("REMOTE_PORT");
remote_port_val = std::to_string(req.remote_port);
});
std::thread t{[&] {
@@ -3423,6 +3423,39 @@ protected:
EXPECT_EQ(req.body, LARGE_DATA);
res.set_content(req.body, "text/plain");
})
.Post("/post-loopback",
[&](const Request &, Response &res,
ContentReader const &content_reader) {
std::string body;
content_reader([&](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
res.set_content(body, "text/plain");
})
.Put("/put-loopback",
[&](const Request &, Response &res,
ContentReader const &content_reader) {
std::string body;
content_reader([&](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
res.set_content(body, "text/plain");
})
.Patch("/patch-loopback",
[&](const Request &, Response &res,
ContentReader const &content_reader) {
std::string body;
content_reader([&](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
res.set_content(body, "text/plain");
})
.Put("/empty-no-content-type",
[&](const Request &req, Response &res) {
EXPECT_EQ(req.body, "");
@@ -4289,10 +4322,21 @@ TEST_F(ServerTest, TooLongRequest) {
}
request += "_NG";
auto start = std::chrono::high_resolution_clock::now();
cli_.set_keep_alive(true);
auto res = cli_.Get(request.c_str());
auto end = std::chrono::high_resolution_clock::now();
auto elapsed =
std::chrono::duration_cast<std::chrono::milliseconds>(end - start)
.count();
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::UriTooLong_414, res->status);
EXPECT_LE(elapsed, 100);
EXPECT_EQ("close", res->get_header_value("Connection"));
EXPECT_FALSE(cli_.is_socket_open());
}
TEST_F(ServerTest, AlmostTooLongRequest) {
@@ -4363,10 +4407,21 @@ TEST_F(ServerTest, LongHeader) {
}
TEST_F(ServerTest, LongQueryValue) {
auto start = std::chrono::high_resolution_clock::now();
cli_.set_keep_alive(true);
auto res = cli_.Get(LONG_QUERY_URL.c_str());
auto end = std::chrono::high_resolution_clock::now();
auto elapsed =
std::chrono::duration_cast<std::chrono::milliseconds>(end - start)
.count();
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::UriTooLong_414, res->status);
EXPECT_LE(elapsed, 100);
EXPECT_EQ("close", res->get_header_value("Connection"));
EXPECT_FALSE(cli_.is_socket_open());
}
TEST_F(ServerTest, TooLongQueryValue) {
@@ -4460,6 +4515,7 @@ TEST_F(ServerTest, HeaderCountExceedsLimit) {
}
// This should fail due to exceeding header count limit
cli_.set_keep_alive(true);
auto res = cli_.Get("/hi", headers);
// The request should either fail or return 400 Bad Request
@@ -4470,6 +4526,9 @@ TEST_F(ServerTest, HeaderCountExceedsLimit) {
// Or the request should fail entirely
EXPECT_FALSE(res);
}
EXPECT_EQ("close", res->get_header_value("Connection"));
EXPECT_FALSE(cli_.is_socket_open());
}
TEST_F(ServerTest, PercentEncoding) {
@@ -4524,6 +4583,7 @@ TEST_F(ServerTest, HeaderCountSecurityTest) {
}
// Try to POST with excessive headers
cli_.set_keep_alive(true);
auto res = cli_.Post("/", attack_headers, "test_data", "text/plain");
// Should either fail or return 400 Bad Request due to security limit
@@ -4534,6 +4594,9 @@ TEST_F(ServerTest, HeaderCountSecurityTest) {
// Request failed, which is the expected behavior for DoS protection
EXPECT_FALSE(res);
}
EXPECT_EQ("close", res->get_header_value("Connection"));
EXPECT_FALSE(cli_.is_socket_open());
}
TEST_F(ServerTest, MultipartFormData) {
@@ -5153,6 +5216,94 @@ TEST_F(ServerTest, PostWithContentProviderWithoutLengthAbort) {
EXPECT_EQ(Error::Canceled, res.error());
}
TEST_F(ServerTest, PostLoopBack) {
std::string body;
auto res = cli_.Post(
"/post-loopback", 9,
[](size_t /*offset*/, size_t length, DataSink &sink) {
EXPECT_EQ(9u, length);
sink.write("123", 3);
sink.write("456", 3);
sink.write("789", 3);
return true;
},
"text/plain",
[&body](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ("123456789", body);
}
TEST_F(ServerTest, PutLoopBack) {
std::string body;
auto res = cli_.Put(
"/put-loopback", 9,
[](size_t /*offset*/, size_t length, DataSink &sink) {
EXPECT_EQ(9u, length);
sink.write("123", 3);
sink.write("456", 3);
sink.write("789", 3);
return true;
},
"text/plain",
[&body](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ("123456789", body);
}
TEST_F(ServerTest, PatchLoopBack) {
std::string body;
auto res = cli_.Patch(
"/patch-loopback", 9,
[](size_t /*offset*/, size_t length, DataSink &sink) {
EXPECT_EQ(9u, length);
sink.write("123", 3);
sink.write("456", 3);
sink.write("789", 3);
return true;
},
"text/plain",
[&body](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ("123456789", body);
}
TEST_F(ServerTest, PostLoopBackWithoutRequestContentLength) {
std::string body;
auto res = cli_.Post(
"/post-loopback",
[](size_t /*offset*/, DataSink &sink) {
sink.write("123", 3);
sink.write("456", 3);
sink.write("789", 3);
sink.done();
return true;
},
"text/plain",
[&body](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ("123456789", body);
}
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
TEST_F(ServerTest, PutWithContentProviderWithGzip) {
cli_.set_compress(true);
@@ -5854,6 +6005,20 @@ TEST_F(ServerTest, TooManyRedirect) {
EXPECT_EQ(Error::ExceedRedirectCount, res.error());
}
TEST_F(ServerTest, BadRequestLineCancelsKeepAlive) {
Request req;
req.method = "FOOBAR";
req.path = "/hi";
cli_.set_keep_alive(true);
auto res = cli_.send(req);
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::BadRequest_400, res->status);
EXPECT_EQ("close", res->get_header_value("Connection"));
EXPECT_FALSE(cli_.is_socket_open());
}
TEST_F(ServerTest, StartTime) { auto res = cli_.Get("/test-start-time"); }
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
@@ -11236,7 +11401,8 @@ TEST(ForwardedHeadersTest, NoProxiesSetting) {
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(observed_xff, "203.0.113.66");
EXPECT_TRUE(observed_remote_addr == "::1" || observed_remote_addr == "127.0.0.1");
EXPECT_TRUE(observed_remote_addr == "::1" ||
observed_remote_addr == "127.0.0.1");
}
TEST(ForwardedHeadersTest, NoForwardedHeaders) {
@@ -11269,7 +11435,8 @@ TEST(ForwardedHeadersTest, NoForwardedHeaders) {
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(observed_xff, "");
EXPECT_TRUE(observed_remote_addr == "::1" || observed_remote_addr == "127.0.0.1");
EXPECT_TRUE(observed_remote_addr == "::1" ||
observed_remote_addr == "127.0.0.1");
}
TEST(ForwardedHeadersTest, SingleTrustedProxy_UsesIPBeforeTrusted) {
@@ -11296,7 +11463,8 @@ TEST(ForwardedHeadersTest, SingleTrustedProxy_UsesIPBeforeTrusted) {
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get("/ip", {{"X-Forwarded-For", "198.51.100.23, 203.0.113.66"}});
auto res =
cli.Get("/ip", {{"X-Forwarded-For", "198.51.100.23, 203.0.113.66"}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
@@ -11330,8 +11498,7 @@ TEST(ForwardedHeadersTest, MultipleTrustedProxies_UsesClientIP) {
Client cli(HOST, PORT);
auto res = cli.Get(
"/ip",
{{"X-Forwarded-For", "198.51.100.23, 203.0.113.66, 192.0.2.45"}});
"/ip", {{"X-Forwarded-For", "198.51.100.23, 203.0.113.66, 192.0.2.45"}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
@@ -11364,8 +11531,8 @@ TEST(ForwardedHeadersTest, TrustedProxyNotInHeader_UsesFirstFromXFF) {
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get("/ip",
{{"X-Forwarded-For", "198.51.100.23, 198.51.100.24"}});
auto res =
cli.Get("/ip", {{"X-Forwarded-For", "198.51.100.23, 198.51.100.24"}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
@@ -11399,8 +11566,7 @@ TEST(ForwardedHeadersTest, LastHopTrusted_SelectsImmediateLeftIP) {
Client cli(HOST, PORT);
auto res = cli.Get(
"/ip",
{{"X-Forwarded-For", "198.51.100.23, 203.0.113.66, 192.0.2.45"}});
"/ip", {{"X-Forwarded-For", "198.51.100.23, 203.0.113.66, 192.0.2.45"}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
@@ -11433,9 +11599,8 @@ TEST(ForwardedHeadersTest, HandlesWhitespaceAroundIPs) {
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get(
"/ip",
{{"X-Forwarded-For", " 198.51.100.23 , 203.0.113.66 , 192.0.2.45 "}});
auto res = cli.Get("/ip", {{"X-Forwarded-For",
" 198.51.100.23 , 203.0.113.66 , 192.0.2.45 "}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
@@ -11444,3 +11609,73 @@ TEST(ForwardedHeadersTest, HandlesWhitespaceAroundIPs) {
EXPECT_EQ(observed_xff, "198.51.100.23 , 203.0.113.66 , 192.0.2.45");
EXPECT_EQ(observed_remote_addr, "203.0.113.66");
}
TEST(ServerRequestParsingTest, RequestWithoutContentLengthOrTransferEncoding) {
Server svr;
svr.Post("/post", [&](const Request &req, Response &res) {
res.set_content(req.body, "text/plain");
});
svr.Put("/put", [&](const Request &req, Response &res) {
res.set_content(req.body, "text/plain");
});
svr.Patch("/patch", [&](const Request &req, Response &res) {
res.set_content(req.body, "text/plain");
});
svr.Delete("/delete", [&](const Request &req, Response &res) {
res.set_content(req.body, "text/plain");
});
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
std::string resp;
// POST without Content-Length
ASSERT_TRUE(send_request(5,
"POST /post HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: close\r\n"
"\r\n",
&resp));
EXPECT_TRUE(resp.find("HTTP/1.1 200 OK") == 0);
// PUT without Content-Length
resp.clear();
ASSERT_TRUE(send_request(5,
"PUT /put HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: close\r\n"
"\r\n",
&resp));
EXPECT_TRUE(resp.find("HTTP/1.1 200 OK") == 0);
// PATCH without Content-Length
resp.clear();
ASSERT_TRUE(send_request(5,
"PATCH /patch HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: close\r\n"
"\r\n",
&resp));
EXPECT_TRUE(resp.find("HTTP/1.1 200 OK") == 0);
// DELETE without Content-Length
resp.clear();
ASSERT_TRUE(send_request(5,
"DELETE /delete HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: close\r\n"
"\r\n",
&resp));
EXPECT_TRUE(resp.find("HTTP/1.1 200 OK") == 0);
}