Compare commits

..

35 Commits

Author SHA1 Message Date
yhirose dcdb0d047b Fixed PRI request problem 2019-10-03 13:44:18 -04:00
yhirose 1f86e41d97 Changed back to select as default 2019-10-03 13:44:18 -04:00
yhirose 6d8302313c Fixed warning 2019-10-03 13:44:18 -04:00
yhirose 89440ec322 Merge pull request #232 from sux2mfgj/fix_the_invalidhost_test
Fix a test, ConnectionErrorTest::InvalidPort.
2019-10-03 13:43:48 -04:00
yhirose 5edf455d72 Merge pull request #231 from sux2mfgj/fix_the_sample
Fix a sample code of multipart/form-data POST data in the README.md.
2019-10-03 13:42:31 -04:00
Shunsuke Mie 5f49c13f95 Fix a test, ConnectionErrorTest::InvalidPort. currently, the abcde.com is valid, so I change it. The first byte doesn't permit a hyphen. 2019-10-03 21:49:11 +09:00
Shunsuke Mie 760bccc3ad fix a sample code of multipart/form-data POST data in README.md. 2019-10-03 21:23:10 +09:00
yhirose a99e02aeb3 Add HTTP/2 Connection Preface check test 2019-10-01 06:28:45 -04:00
yhirose 4aae1dcc42 Merge pull request #224 from Zefz/configuration
Allow configuration to be overriden without source editing
2019-09-30 17:07:21 -04:00
Johan Jansen f23f9a06a9 Allow configuration to be overriden without source editing 2019-09-30 22:00:17 +02:00
yhirose 46466b1e28 Merge pull request #227 from ha11owed/master
Don't exit if accept fails due to no more file descriptors
2019-09-30 07:47:27 -04:00
Alin Gherman 224119a60a Retry in case of too many sockets opened instead of stopping the server. 2019-09-30 11:48:02 +02:00
yhirose c02849e269 Removed CPPHTTPLIB_USE_POLL, added CPPHTTPLIB_USE_SELECT 2019-09-29 19:43:22 -04:00
yhirose 71979b1e88 Merge pull request #226 from Zefz/mingw-compile-fix
Fix compilation on Mingw-64
2019-09-27 17:29:33 -04:00
yhirose a62d1f79f4 Merge pull request #225 from TangHuaiZhe/master
Fix compile error in android ndk
2019-09-27 17:29:07 -04:00
zefz b14b7b0f8f Fix compilation on Mingw-64 2019-09-27 20:23:16 +02:00
Tang Huaizhe 9dbe0d855c Fix compile error in android ndk 2019-09-27 13:32:23 +08:00
yhirose 2cef8df6ae Merge pull request #223 from Zefz/cpp-style-cast
Fix several -Wold-style-cast warnings in Clang-9
2019-09-26 19:00:45 -04:00
Johan Jansen 94fc229c44 Add missing explicit const_cast 2019-09-26 22:20:33 +02:00
Johan Jansen a7052cba22 Fix several -Wold-style-cast warnings in Clang-9 2019-09-26 22:03:18 +02:00
yhirose c47c6b3910 Updated test.vcxproj 2019-09-26 13:20:53 -04:00
yhirose c946eb7699 Fixed warnings on Windows 2019-09-26 08:13:20 -04:00
yhirose 1f99ad5d6e Updated vcxproj for test 2019-09-25 08:16:15 -04:00
yhirose 96e372bad2 Changed test.yaml to use actions/checkout@v1 2019-09-20 01:07:09 -04:00
yhirose fc56f39d17 Fixed Github Actions badge problem 2019-09-20 00:43:02 -04:00
yhirose 5844432a7b Add badge for Github Actions 2019-09-20 00:31:26 -04:00
yhirose b97420f363 Add test.yaml 2019-09-20 00:01:05 -04:00
yhirose 81610ee080 Merge pull request #218 from p0lloloco/master
Add ssl_context member function to SSLClient
2019-09-18 23:08:14 -04:00
PolloLoco c7f8561472 Added ssl_context member function to SSLClient in
order to allow access to the SSL_CTX struct, for
example to load the windows cert store
2019-09-18 15:10:15 +02:00
yhirose 47bc7456d2 Merge pull request #217 from yhirose/poll
Use 'poll' instead of 'select'
2019-09-18 08:46:20 -04:00
yhirose 4ab9270660 Use 'poll' as default instead of select (Fix #215) 2019-09-18 08:42:18 -04:00
yhirose d599a36c2a Format code 2019-09-16 17:48:17 -04:00
yhirose 6f8f51496d Merge branch 'gulrak-feature-response-handler-with-content-receiver' 2019-09-15 09:17:26 -04:00
yhirose 0c293887d0 Fixed problem with redirect 2019-09-15 09:15:21 -04:00
Steffen Schuemann 7e92ffec48 Added new Client::Get variant that combines a ContentReceiver with a new ResponseHandler
While trying to implement streaming of internet radio, where a ContentReceiver is needed to handle the audio data, I had the problem, that important information about the stream data is part of the HTTP header (e.g. size of audio chunks between meta data), so I added a ResponseHandler and a new Get variant, to gain access to the header before handling the first chunk of data.

The ResponseHandler can abort the request by returning false, in the same way as the ContentReceiver.

A test case was also added.
2019-09-14 14:55:12 +02:00
5 changed files with 250 additions and 57 deletions
+17
View File
@@ -0,0 +1,17 @@
name: test
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macOS-latest, ubuntu-latest]
steps:
- name: checkout
uses: actions/checkout@v1
- name: make
run: cd test && make
+5 -3
View File
@@ -1,6 +1,7 @@
cpp-httplib
===========
[![](https://github.com/yhirose/cpp-httplib/workflows/test/badge.svg)](https://github.com/yhirose/cpp-httplib/actions)
[![Build Status](https://travis-ci.org/yhirose/cpp-httplib.svg?branch=master)](https://travis-ci.org/yhirose/cpp-httplib)
[![Bulid Status](https://ci.appveyor.com/api/projects/status/github/yhirose/cpp-httplib?branch=master&svg=true)](https://ci.appveyor.com/project/yhirose/cpp-httplib)
@@ -76,12 +77,13 @@ svr.set_error_handler([](const auto& req, auto& res) {
```cpp
svr.Post("/multipart", [&](const auto& req, auto& res) {
auto size = req.files.size();
auto ret = req.has_file("name1"));
auto ret = req.has_file("name1");
const auto& file = req.get_file_value("name1");
// file.filename;
// file.content_type;
auto body = req.body.substr(file.offset, file.length));
})
auto body = req.body.substr(file.offset, file.length);
});
```
### Stream content with Content provider
+161 -47
View File
@@ -8,6 +8,49 @@
#ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H
/*
* Configuration
*/
#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
#endif
#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND 0
#endif
#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5
#endif
#ifndef CPPHTTPLIB_READ_TIMEOUT_SECOND
#define CPPHTTPLIB_READ_TIMEOUT_SECOND 5
#endif
#ifndef CPPHTTPLIB_READ_TIMEOUT_USECOND
#define CPPHTTPLIB_READ_TIMEOUT_USECOND 0
#endif
#ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192
#endif
#ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT
#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20
#endif
#ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH
#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH (std::numeric_limits<size_t>::max)()
#endif
#ifndef CPPHTTPLIB_RECV_BUFSIZ
#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u)
#endif
#ifndef CPPHTTPLIB_THREAD_POOL_COUNT
#define CPPHTTPLIB_THREAD_POOL_COUNT 8
#endif
#ifdef _WIN32
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
@@ -45,18 +88,32 @@ typedef int ssize_t;
#include <winsock2.h>
#include <ws2tcpip.h>
#ifndef WSA_FLAG_NO_HANDLE_INHERIT
#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
#endif
#ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib")
#endif
#ifndef strcasecmp
#define strcasecmp _stricmp
#endif // strcasecmp
typedef SOCKET socket_t;
#else
#ifdef CPPHTTPLIB_USE_POLL
#define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout)
#endif
#else // not _WIN32
#include <arpa/inet.h>
#include <cstring>
#include <netdb.h>
#include <netinet/in.h>
#ifdef CPPHTTPLIB_USE_POLL
#include <poll.h>
#endif
#include <pthread.h>
#include <signal.h>
#include <sys/select.h>
@@ -70,6 +127,7 @@ typedef int socket_t;
#include <assert.h>
#include <atomic>
#include <condition_variable>
#include <errno.h>
#include <fcntl.h>
#include <fstream>
#include <functional>
@@ -104,20 +162,6 @@ inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) {
#include <zlib.h>
#endif
/*
* Configuration
*/
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND 0
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5
#define CPPHTTPLIB_READ_TIMEOUT_SECOND 5
#define CPPHTTPLIB_READ_TIMEOUT_USECOND 0
#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192
#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20
#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH (std::numeric_limits<size_t>::max)()
#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u)
#define CPPHTTPLIB_THREAD_POOL_COUNT 8
namespace httplib {
namespace detail {
@@ -153,6 +197,9 @@ typedef std::function<bool(const char *data, size_t data_length, size_t offset,
typedef std::function<bool(uint64_t current, uint64_t total)> Progress;
struct Response;
typedef std::function<bool(const Response &response)> ResponseHandler;
struct MultipartFile {
std::string filename;
std::string content_type;
@@ -188,6 +235,7 @@ struct Request {
// for client
size_t redirect_count = CPPHTTPLIB_REDIRECT_MAX_COUNT;
ResponseHandler response_handler;
ContentReceiver content_receiver;
Progress progress;
@@ -354,7 +402,7 @@ private:
pool_.jobs_.pop_front();
}
assert(true == (bool)fn);
assert(true == static_cast<bool>(fn));
fn();
}
}
@@ -518,6 +566,15 @@ public:
ContentReceiver content_receiver,
Progress progress);
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, const Headers &headers,
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);
@@ -684,6 +741,8 @@ public:
long get_openssl_verify_result() const;
SSL_CTX* ssl_context() const noexcept;
private:
virtual bool process_and_close_socket(
socket_t sock, size_t request_count,
@@ -973,6 +1032,15 @@ inline int close_socket(socket_t sock) {
}
inline int select_read(socket_t sock, time_t sec, time_t usec) {
#ifdef CPPHTTPLIB_USE_POLL
struct pollfd pfd_read;
pfd_read.fd = sock;
pfd_read.events = POLLIN;
auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
return poll(&pfd_read, 1, timeout);
#else
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
@@ -982,9 +1050,26 @@ inline int select_read(socket_t sock, time_t sec, time_t usec) {
tv.tv_usec = static_cast<long>(usec);
return select(static_cast<int>(sock + 1), &fds, nullptr, nullptr, &tv);
#endif
}
inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
#ifdef CPPHTTPLIB_USE_POLL
struct pollfd pfd_read;
pfd_read.fd = sock;
pfd_read.events = POLLIN | POLLOUT;
auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
if (poll(&pfd_read, 1, timeout) > 0 &&
pfd_read.revents & (POLLIN | POLLOUT)) {
int error = 0;
socklen_t len = sizeof(error);
return getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) >= 0 &&
!error;
}
return false;
#else
fd_set fdsr;
FD_ZERO(&fdsr);
FD_SET(sock, &fdsr);
@@ -996,20 +1081,15 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
tv.tv_sec = static_cast<long>(sec);
tv.tv_usec = static_cast<long>(usec);
if (select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv) < 0) {
return false;
} else if (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw)) {
if (select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv) > 0 &&
(FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
int error = 0;
socklen_t len = sizeof(error);
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &len) < 0 ||
error) {
return false;
}
} else {
return false;
return getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &len) >= 0 &&
!error;
}
return true;
return false;
#endif
}
template <typename T>
@@ -1096,9 +1176,9 @@ socket_t create_socket(const char *host, int port, Fn fn,
// Make 'reuse address' option available
int yes = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&yes), sizeof(yes));
#ifdef SO_REUSEPORT
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&yes, sizeof(yes));
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, reinterpret_cast<char*>(&yes), sizeof(yes));
#endif
// bind or connect
@@ -1137,10 +1217,10 @@ inline std::string get_remote_addr(socket_t sock) {
struct sockaddr_storage addr;
socklen_t len = sizeof(addr);
if (!getpeername(sock, (struct sockaddr *)&addr, &len)) {
if (!getpeername(sock, reinterpret_cast<struct sockaddr *>(&addr), &len)) {
char ipstr[NI_MAXHOST];
if (!getnameinfo((struct sockaddr *)&addr, len, ipstr, sizeof(ipstr),
if (!getnameinfo(reinterpret_cast<struct sockaddr *>(&addr), len, ipstr, sizeof(ipstr),
nullptr, 0, NI_NUMERICHOST)) {
return ipstr;
}
@@ -1222,7 +1302,7 @@ inline bool compress(std::string &content) {
if (ret != Z_OK) { return false; }
strm.avail_in = content.size();
strm.next_in = (Bytef *)content.data();
strm.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(content.data()));
std::string compressed;
@@ -1230,7 +1310,7 @@ inline bool compress(std::string &content) {
char buff[bufsiz];
do {
strm.avail_out = bufsiz;
strm.next_out = (Bytef *)buff;
strm.next_out = reinterpret_cast<Bytef*>(buff);
ret = deflate(&strm, Z_FINISH);
assert(ret != Z_STREAM_ERROR);
compressed.append(buff, bufsiz - strm.avail_out);
@@ -1267,13 +1347,13 @@ public:
int ret = Z_OK;
strm.avail_in = data_length;
strm.next_in = (Bytef *)data;
strm.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef *>(data));
const auto bufsiz = 16384;
char buff[bufsiz];
do {
strm.avail_out = bufsiz;
strm.next_out = (Bytef *)buff;
strm.next_out = reinterpret_cast<Bytef*>(buff);
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR);
@@ -1555,6 +1635,7 @@ inline bool redirect(T &cli, const Request &req, Response &res,
new_req.headers = req.headers;
new_req.body = req.body;
new_req.redirect_count = req.redirect_count - 1;
new_req.response_handler = req.response_handler;
new_req.content_receiver = req.content_receiver;
new_req.progress = req.progress;
@@ -2241,7 +2322,7 @@ inline void Server::stop() {
}
inline bool Server::parse_request_line(const char *s, Request &req) {
static std::regex re("(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS) "
static std::regex re("(GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH|PRI) "
"(([^?]+)(?:\\?(.+?))?) (HTTP/1\\.[01])\r\n");
std::cmatch m;
@@ -2499,6 +2580,12 @@ inline bool Server::listen_internal() {
socket_t sock = accept(svr_sock_, nullptr, nullptr);
if (sock == INVALID_SOCKET) {
if (errno == EMFILE) {
// The per-process limit of open file descriptors has been reached.
// Try to accept new connections after a short sleep.
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
if (svr_sock_ != INVALID_SOCKET) {
detail::close_socket(svr_sock_);
ret = false;
@@ -2527,13 +2614,15 @@ inline bool Server::routing(Request &req, Response &res) {
return dispatch_request(req, res, post_handlers_);
} else if (req.method == "PUT") {
return dispatch_request(req, res, put_handlers_);
} else if (req.method == "PATCH") {
return dispatch_request(req, res, patch_handlers_);
} else if (req.method == "DELETE") {
return dispatch_request(req, res, delete_handlers_);
} else if (req.method == "OPTIONS") {
return dispatch_request(req, res, options_handlers_);
} else if (req.method == "PATCH") {
return dispatch_request(req, res, patch_handlers_);
}
res.status = 400;
return false;
}
@@ -2595,7 +2684,7 @@ Server::process_request(Stream &strm, bool last_connection,
req.set_header("REMOTE_ADDR", strm.get_remote_addr());
// Body
if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") {
if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" || req.method == "PRI") {
if (!detail::read_content(strm, req, payload_max_length_, res.status,
Progress(), [&](const char *buf, size_t n) {
if (req.body.size() + n > req.body.max_size()) {
@@ -2633,7 +2722,7 @@ Server::process_request(Stream &strm, bool last_connection,
if (routing(req, res)) {
if (res.status == -1) { res.status = req.ranges.empty() ? 200 : 206; }
} else {
res.status = 404;
if (res.status == -1) { res.status = 404; }
}
return write_response(strm, last_connection, req, res);
@@ -2727,7 +2816,7 @@ inline bool Client::send(const std::vector<Request> &requests,
if (!process_and_close_socket(
sock, requests.size() - i,
[&](Stream &strm, bool last_connection, bool &connection_close) {
[&](Stream &strm, bool last_connection, bool &connection_close) -> bool {
auto &req = requests[i];
auto res = Response();
i++;
@@ -2869,6 +2958,10 @@ inline bool Client::process_request(Stream &strm, const Request &req,
connection_close = true;
}
if (req.response_handler) {
if (!req.response_handler(res)) { return false; }
}
// Body
if (req.method != "HEAD") {
detail::ContentReceiverCore out = [&](const char *buf, size_t n) {
@@ -2940,30 +3033,47 @@ Client::Get(const char *path, const Headers &headers, Progress progress) {
inline std::shared_ptr<Response> Client::Get(const char *path,
ContentReceiver content_receiver) {
Progress dummy;
return Get(path, Headers(), content_receiver, dummy);
return Get(path, Headers(), nullptr, content_receiver, dummy);
}
inline std::shared_ptr<Response> Client::Get(const char *path,
ContentReceiver content_receiver,
Progress progress) {
return Get(path, Headers(), content_receiver, progress);
return Get(path, Headers(), nullptr, content_receiver, progress);
}
inline std::shared_ptr<Response> Client::Get(const char *path,
const Headers &headers,
ContentReceiver content_receiver) {
Progress dummy;
return Get(path, headers, content_receiver, dummy);
return Get(path, headers, nullptr, content_receiver, dummy);
}
inline std::shared_ptr<Response> Client::Get(const char *path,
const Headers &headers,
ContentReceiver content_receiver,
Progress progress) {
return Get(path, headers, nullptr, content_receiver, progress);
}
inline std::shared_ptr<Response> Client::Get(const char *path,
const Headers &headers,
ResponseHandler response_handler,
ContentReceiver content_receiver) {
Progress dummy;
return Get(path, headers, response_handler, content_receiver, dummy);
}
inline std::shared_ptr<Response> Client::Get(const char *path,
const Headers &headers,
ResponseHandler response_handler,
ContentReceiver content_receiver,
Progress progress) {
Request req;
req.method = "GET";
req.path = path;
req.headers = headers;
req.response_handler = response_handler;
req.content_receiver = content_receiver;
req.progress = progress;
@@ -3192,7 +3302,7 @@ inline bool process_and_close_socket_ssl(bool is_client_request, socket_t sock,
return false;
}
auto bio = BIO_new_socket(sock, BIO_NOCLOSE);
auto bio = BIO_new_socket(static_cast<int>(sock), BIO_NOCLOSE);
SSL_set_bio(ssl, bio, bio);
if (!setup(ssl)) {
@@ -3298,13 +3408,13 @@ inline int SSLSocketStream::read(char *ptr, size_t size) {
if (SSL_pending(ssl_) > 0 ||
detail::select_read(sock_, CPPHTTPLIB_READ_TIMEOUT_SECOND,
CPPHTTPLIB_READ_TIMEOUT_USECOND) > 0) {
return SSL_read(ssl_, ptr, size);
return SSL_read(ssl_, ptr, static_cast<int>(size));
}
return -1;
}
inline int SSLSocketStream::write(const char *ptr, size_t size) {
return SSL_write(ssl_, ptr, size);
return SSL_write(ssl_, ptr, static_cast<int>(size));
}
inline int SSLSocketStream::write(const char *ptr) {
@@ -3417,6 +3527,10 @@ inline long SSLClient::get_openssl_verify_result() const {
return verify_result_;
}
inline SSL_CTX* SSLClient::ssl_context() const noexcept {
return ctx_;
}
inline bool SSLClient::process_and_close_socket(
socket_t sock, size_t request_count,
std::function<bool(Stream &strm, bool last_connection,
+47 -3
View File
@@ -242,6 +242,38 @@ TEST(ChunkedEncodingTest, WithContentReceiver) {
EXPECT_EQ(out, body);
}
TEST(ChunkedEncodingTest, WithResponseHandlerAndContentReceiver) {
auto host = "www.httpwatch.com";
auto sec = 2;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 443;
httplib::SSLClient cli(host, port, sec);
#else
auto port = 80;
httplib::Client cli(host, port, sec);
#endif
std::string body;
auto res =
cli.Get("/httpgallery/chunked/chunkedimage.aspx?0.4153841143030137", Headers(),
[&](const Response& response) {
EXPECT_EQ(200, response.status);
return true;
},
[&](const char *data, size_t data_length, uint64_t, uint64_t) {
body.append(data, data_length);
return true;
});
ASSERT_TRUE(res != nullptr);
std::string out;
httplib::detail::read_file("./image.jpg", out);
EXPECT_EQ(200, res->status);
EXPECT_EQ(out, body);
}
TEST(RangeTest, FromHTTPBin) {
auto host = "httpbin.org";
auto sec = 5;
@@ -303,7 +335,7 @@ TEST(RangeTest, FromHTTPBin) {
}
TEST(ConnectionErrorTest, InvalidHost) {
auto host = "abcde.com";
auto host = "-abcde.com";
auto sec = 2;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
@@ -504,7 +536,7 @@ TEST(YahooRedirectTest, Redirect) {
EXPECT_EQ(200, res->status);
}
TEST(Https2HttpRedirectTest, Redirect) {
TEST(HttpsToHttpRedirectTest, Redirect) {
httplib::SSLClient cli("httpbin.org");
cli.follow_location(true);
auto res = cli.Get("/redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302");
@@ -605,7 +637,7 @@ protected:
size_t DATA_CHUNK_SIZE = 4;
const auto &d = *data;
auto out_len = std::min(static_cast<size_t>(length), DATA_CHUNK_SIZE);
sink(&d[offset], out_len);
sink(&d[static_cast<size_t>(offset)], out_len);
},
[data] { delete data; });
})
@@ -1361,6 +1393,18 @@ TEST_F(ServerTest, NoMultipleHeaders) {
EXPECT_EQ(200, res->status);
}
TEST_F(ServerTest, HTTP2Magic) {
Request req;
req.method = "PRI";
req.path = "*";
req.body = "SM";
auto res = std::make_shared<Response>();
auto ret = cli_.send(req, *res);
ASSERT_TRUE(ret);
EXPECT_EQ(400, res->status);
}
TEST_F(ServerTest, KeepAlive) {
cli_.set_keep_alive_max_count(4);
+20 -4
View File
@@ -34,7 +34,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -47,7 +47,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
@@ -69,15 +69,23 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>C:\Program Files\OpenSSL-Win64\lib\VC;C:\Program Files\OpenSSL-Win64\include;$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>C:\Program Files\OpenSSL-Win64\include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files\OpenSSL-Win64\lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>C:\Program Files\OpenSSL-Win64\include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files\OpenSSL-Win64\lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@@ -87,6 +95,8 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>
</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -102,11 +112,13 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>
</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Ws2_32.lib;libssl.lib;libcrypto.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -119,6 +131,8 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>
</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -138,13 +152,15 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>
</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Ws2_32.lib;libssl.lib;libcrypto.lib;libssl.lib;libcrypto.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>