mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
113 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 448de6a9c6 | |||
| 6f58dc728f | |||
| 905f2d84f4 | |||
| 880f7fa62b | |||
| 8f3dbf7f21 | |||
| 924a557fa3 | |||
| d8da740597 | |||
| d45676b064 | |||
| 94d13e88a5 | |||
| 4f9d04cb8e | |||
| 9fb11986a5 | |||
| 55d04ee354 | |||
| a62a48a7b5 | |||
| c652919954 | |||
| 58753ba33c | |||
| 5706828d2c | |||
| e743b8cd57 | |||
| 9d57899352 | |||
| d03937e144 | |||
| 8fb37a449d | |||
| f0b1b5dbfd | |||
| 5f32c424c2 | |||
| f0683f2301 | |||
| 0d527e2b83 | |||
| bea3ebd7af | |||
| 380f725713 | |||
| a106bd314c | |||
| e4fd9f19ca | |||
| dfc01338eb | |||
| c4ebc31345 | |||
| d1abf96581 | |||
| 001b8a5529 | |||
| 7a3abd2768 | |||
| 4a52524f47 | |||
| 89e1e9b8fe | |||
| 98d16eb836 | |||
| bcf0c32245 | |||
| dcdb0d047b | |||
| 1f86e41d97 | |||
| 6d8302313c | |||
| 89440ec322 | |||
| 5edf455d72 | |||
| 5f49c13f95 | |||
| 760bccc3ad | |||
| a99e02aeb3 | |||
| 4aae1dcc42 | |||
| f23f9a06a9 | |||
| 46466b1e28 | |||
| 224119a60a | |||
| c02849e269 | |||
| 71979b1e88 | |||
| a62d1f79f4 | |||
| b14b7b0f8f | |||
| 9dbe0d855c | |||
| 2cef8df6ae | |||
| 94fc229c44 | |||
| a7052cba22 | |||
| c47c6b3910 | |||
| c946eb7699 | |||
| 1f99ad5d6e | |||
| 96e372bad2 | |||
| fc56f39d17 | |||
| 5844432a7b | |||
| b97420f363 | |||
| 81610ee080 | |||
| c7f8561472 | |||
| 47bc7456d2 | |||
| 4ab9270660 | |||
| d599a36c2a | |||
| 6f8f51496d | |||
| 0c293887d0 | |||
| 7e92ffec48 | |||
| 531708816a | |||
| bfec81998b | |||
| c9238434e1 | |||
| e2babf315c | |||
| c434d555bb | |||
| 359b06681b | |||
| a0fe91e84d | |||
| 80f040cf69 | |||
| 037b4fc789 | |||
| a782d1b609 | |||
| 6a03ddf912 | |||
| 1e82359329 | |||
| a4160e6ac1 | |||
| bdbfc6cfe7 | |||
| 22615f9682 | |||
| 64991a560a | |||
| d7bb402ca7 | |||
| d58deddbcc | |||
| 3629f87627 | |||
| 1b95bf8cc3 | |||
| e383b277a4 | |||
| bf541442ea | |||
| 2823a94fc1 | |||
| 5a13539e57 | |||
| 531f6ab84d | |||
| f4aaba6362 | |||
| c899462e75 | |||
| 9785cd47f2 | |||
| 579ff1a0a6 | |||
| 47312e6df9 | |||
| 66b81a1497 | |||
| 9d7b717504 | |||
| 3291bdad91 | |||
| e8799383f3 | |||
| 58f72bc8b6 | |||
| 4c58b91e40 | |||
| 06b3dee5aa | |||
| ba7f9fe4c3 | |||
| 8480850a3f | |||
| d15df874b3 | |||
| f40de531ab |
@@ -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
|
||||
@@ -1,6 +1,7 @@
|
||||
cpp-httplib
|
||||
===========
|
||||
|
||||
[](https://github.com/yhirose/cpp-httplib/actions)
|
||||
[](https://travis-ci.org/yhirose/cpp-httplib)
|
||||
[](https://ci.appveyor.com/project/yhirose/cpp-httplib)
|
||||
|
||||
@@ -76,12 +77,86 @@ 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
|
||||
|
||||
```cpp
|
||||
const uint64_t DATA_CHUNK_SIZE = 4;
|
||||
|
||||
svr.Get("/stream", [&](const Request &req, Response &res) {
|
||||
auto data = new std::string("abcdefg");
|
||||
|
||||
res.set_content_provider(
|
||||
data->size(), // Content length
|
||||
[data](uint64_t offset, uint64_t length, DataSink sink) {
|
||||
const auto &d = *data;
|
||||
sink(&d[offset], std::min(length, DATA_CHUNK_SIZE));
|
||||
},
|
||||
[data] { delete data; });
|
||||
});
|
||||
```
|
||||
|
||||
### Chunked transfer encoding
|
||||
|
||||
```cpp
|
||||
svr.Get("/chunked", [&](const Request& req, Response& res) {
|
||||
res.set_chunked_content_provider(
|
||||
[](uint64_t offset, DataSink sink, Done done) {
|
||||
sink("123", 3);
|
||||
sink("345", 3);
|
||||
sink("789", 3);
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### Default thread pool supporet
|
||||
|
||||
Set thread count to 8:
|
||||
|
||||
```cpp
|
||||
#define CPPHTTPLIB_THREAD_POOL_COUNT 8
|
||||
```
|
||||
|
||||
Disable the default thread pool:
|
||||
|
||||
```cpp
|
||||
#define CPPHTTPLIB_THREAD_POOL_COUNT 0
|
||||
```
|
||||
|
||||
### Override the default thread pool with yours
|
||||
|
||||
```cpp
|
||||
class YourThreadPoolTaskQueue : public TaskQueue {
|
||||
public:
|
||||
YourThreadPoolTaskQueue(size_t n) {
|
||||
pool_.start_with_thread_count(n);
|
||||
}
|
||||
|
||||
virtual void enqueue(std::function<void()> fn) override {
|
||||
pool_.enqueue(fn);
|
||||
}
|
||||
|
||||
virtual void shutdown() override {
|
||||
pool_.shutdown_gracefully();
|
||||
}
|
||||
|
||||
private:
|
||||
YourThreadPool pool_;
|
||||
};
|
||||
|
||||
svr.new_task_queue = [] {
|
||||
return new YourThreadPoolTaskQueue(12);
|
||||
};
|
||||
```
|
||||
|
||||
Client Example
|
||||
@@ -117,9 +192,13 @@ int main(void)
|
||||
|
||||
```c++
|
||||
std::string body;
|
||||
auto res = cli.Get("/large-data", [&](const char *data, size_t len) {
|
||||
body.append(data, len);
|
||||
});
|
||||
|
||||
auto res = cli.Get("/large-data",
|
||||
[&](const char *data, uint64_t data_length) {
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
|
||||
assert(res->body.empty());
|
||||
```
|
||||
|
||||
@@ -226,17 +305,57 @@ auto res = cli.Get("/basic-auth/hello/world", {
|
||||
httplib::Client cli("httpbin.org");
|
||||
|
||||
auto res = cli.Get("/range/32", {
|
||||
httplib::make_range_header(1, 10) // 'Range: bytes=1-10'
|
||||
httplib::make_range_header({{1, 10}}) // 'Range: bytes=1-10'
|
||||
});
|
||||
// res->status should be 206.
|
||||
// res->body should be "bcdefghijk".
|
||||
```
|
||||
|
||||
```cpp
|
||||
httplib::make_range_header({{1, 10}, {20, -1}}) // 'Range: bytes=1-10, 20-'
|
||||
httplib::make_range_header({{100, 199}, {500, 599}}) // 'Range: bytes=100-199, 500-599'
|
||||
httplib::make_range_header({{0, 0}, {-1, 1}}) // 'Range: bytes=0-0, -1'
|
||||
```
|
||||
|
||||
### Keep-Alive connection
|
||||
|
||||
```cpp
|
||||
cli.set_keep_alive_max_count(2); // Default is 5
|
||||
|
||||
std::vector<Request> requests;
|
||||
Get(requests, "/get-request1");
|
||||
Get(requests, "/get-request2");
|
||||
Post(requests, "/post-request1", "text", "text/plain");
|
||||
Post(requests, "/post-request2", "text", "text/plain");
|
||||
|
||||
std::vector<Response> responses;
|
||||
if (cli.send(requests, responses)) {
|
||||
for (const auto& res: responses) {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Redirect
|
||||
|
||||
```cpp
|
||||
httplib::Client cli("yahoo.com");
|
||||
|
||||
auto res = cli.Get("/");
|
||||
res->status; // 301
|
||||
|
||||
cli.follow_location(true);
|
||||
res = cli.Get("/");
|
||||
res->status; // 200
|
||||
```
|
||||
|
||||
OpenSSL Support
|
||||
---------------
|
||||
|
||||
SSL support is available with `CPPHTTPLIB_OPENSSL_SUPPORT`. `libssl` and `libcrypto` should be linked.
|
||||
|
||||
NOTE: cpp-httplib supports 1.1.1 (until 2023-09-11) and 1.0.2 (2019-12-31).
|
||||
|
||||
```c++
|
||||
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
|
||||
|
||||
+7
-3
@@ -1,10 +1,11 @@
|
||||
|
||||
#CXX = clang++
|
||||
CXXFLAGS = -std=c++14 -I.. -Wall -Wextra -pthread
|
||||
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib -lssl -lcrypto
|
||||
OPENSSL_DIR = /usr/local/opt/openssl
|
||||
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
|
||||
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
||||
|
||||
all: server client hello simplesvr redirect benchmark
|
||||
all: server client hello simplesvr upload redirect benchmark
|
||||
|
||||
server : server.cc ../httplib.h Makefile
|
||||
$(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
@@ -18,6 +19,9 @@ hello : hello.cc ../httplib.h Makefile
|
||||
simplesvr : simplesvr.cc ../httplib.h Makefile
|
||||
$(CXX) -o simplesvr $(CXXFLAGS) simplesvr.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
|
||||
upload : upload.cc ../httplib.h Makefile
|
||||
$(CXX) -o upload $(CXXFLAGS) upload.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
|
||||
redirect : redirect.cc ../httplib.h Makefile
|
||||
$(CXX) -o redirect $(CXXFLAGS) redirect.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
|
||||
|
||||
@@ -29,4 +33,4 @@ pem:
|
||||
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
|
||||
|
||||
clean:
|
||||
rm server client hello simplesvr redirect *.pem
|
||||
rm server client hello simplesvr upload redirect *.pem
|
||||
|
||||
+10
-2
@@ -15,6 +15,9 @@ using namespace httplib;
|
||||
int main(void) {
|
||||
// HTTP server
|
||||
Server http;
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
SSLServer https(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
|
||||
#endif
|
||||
|
||||
http.Get("/test", [](const Request & /*req*/, Response &res) {
|
||||
res.set_content("Test\n", "text/plain");
|
||||
@@ -25,8 +28,7 @@ int main(void) {
|
||||
});
|
||||
|
||||
// HTTPS server
|
||||
SSLServer https(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
https.Get("/", [=](const Request & /*req*/, Response &res) {
|
||||
res.set_redirect("/hi");
|
||||
});
|
||||
@@ -39,18 +41,24 @@ int main(void) {
|
||||
https.stop();
|
||||
http.stop();
|
||||
});
|
||||
#endif
|
||||
|
||||
// Run servers
|
||||
auto httpThread = std::thread([&]() {
|
||||
http.listen("localhost", 8080);
|
||||
});
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto httpsThread = std::thread([&]() {
|
||||
https.listen("localhost", 8081);
|
||||
});
|
||||
#endif
|
||||
|
||||
httpThread.join();
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
httpsThread.join();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// upload.cc
|
||||
//
|
||||
// Copyright (c) 2019 Yuji Hirose. All rights reserved.
|
||||
// MIT License
|
||||
//
|
||||
|
||||
#include <httplib.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
using namespace httplib;
|
||||
using namespace std;
|
||||
|
||||
const char* html = R"(
|
||||
<form id="formElem">
|
||||
<input type="file" name="file" accept="image/*">
|
||||
<input type="submit">
|
||||
</form>
|
||||
<script>
|
||||
formElem.onsubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
let res = await fetch('/post', {
|
||||
method: 'POST',
|
||||
body: new FormData(formElem)
|
||||
});
|
||||
console.log(await res.text());
|
||||
};
|
||||
</script>
|
||||
)";
|
||||
|
||||
int main(void) {
|
||||
Server svr;
|
||||
|
||||
svr.Get("/", [](const Request & /*req*/, Response &res) {
|
||||
res.set_content(html, "text/html");
|
||||
});
|
||||
|
||||
svr.Post("/post", [](const Request & req, Response &res) {
|
||||
auto file = req.get_file_value("file");
|
||||
cout << "file: " << file.offset << ":" << file.length << ":" << file.filename << endl;
|
||||
|
||||
ofstream ofs(file.filename, ios::binary);
|
||||
ofs << req.body.substr(file.offset, file.length);
|
||||
|
||||
res.set_content("done", "text/plain");
|
||||
});
|
||||
|
||||
svr.listen("localhost", 1234);
|
||||
}
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
|
||||
#CXX = clang++
|
||||
CXXFLAGS = -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits
|
||||
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib -lssl -lcrypto
|
||||
OPENSSL_DIR = /usr/local/opt/openssl
|
||||
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
|
||||
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
||||
|
||||
all : test
|
||||
|
||||
@@ -54,6 +54,11 @@
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -19544,4 +19549,8 @@ bool StaticAssertTypeEq() {
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_H_
|
||||
|
||||
+592
-166
@@ -28,6 +28,8 @@ const string LONG_QUERY_URL = "/long-query-value?key=" + LONG_QUERY_VALUE;
|
||||
|
||||
const std::string JSON_DATA = "{\"hello\":\"world\"}";
|
||||
|
||||
const string LARGE_DATA = string(1024 * 1024 * 100, '@'); // 100MB
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST(StartupTest, WSAStartup) {
|
||||
WSADATA wsaData;
|
||||
@@ -95,28 +97,100 @@ TEST(GetHeaderValueTest, RegularValueInt) {
|
||||
|
||||
TEST(GetHeaderValueTest, Range) {
|
||||
{
|
||||
Headers headers = {make_range_header(1)};
|
||||
Headers headers = {make_range_header({{1, -1}})};
|
||||
auto val = detail::get_header_value(headers, "Range", 0, 0);
|
||||
EXPECT_STREQ("bytes=1-", val);
|
||||
}
|
||||
|
||||
{
|
||||
Headers headers = {make_range_header(1, 10)};
|
||||
Headers headers = {make_range_header({{-1, 1}})};
|
||||
auto val = detail::get_header_value(headers, "Range", 0, 0);
|
||||
EXPECT_STREQ("bytes=-1", val);
|
||||
}
|
||||
|
||||
{
|
||||
Headers headers = {make_range_header({{1, 10}})};
|
||||
auto val = detail::get_header_value(headers, "Range", 0, 0);
|
||||
EXPECT_STREQ("bytes=1-10", val);
|
||||
}
|
||||
|
||||
{
|
||||
Headers headers = {make_range_header(1, 10, 100)};
|
||||
Headers headers = {make_range_header({{1, 10}, {100, -1}})};
|
||||
auto val = detail::get_header_value(headers, "Range", 0, 0);
|
||||
EXPECT_STREQ("bytes=1-10, 100-", val);
|
||||
}
|
||||
|
||||
{
|
||||
Headers headers = {make_range_header(1, 10, 100, 200)};
|
||||
Headers headers = {make_range_header({{1, 10}, {100, 200}})};
|
||||
auto val = detail::get_header_value(headers, "Range", 0, 0);
|
||||
EXPECT_STREQ("bytes=1-10, 100-200", val);
|
||||
}
|
||||
|
||||
{
|
||||
Headers headers = {make_range_header({{0, 0}, {-1, 1}})};
|
||||
auto val = detail::get_header_value(headers, "Range", 0, 0);
|
||||
EXPECT_STREQ("bytes=0-0, -1", val);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ParseHeaderValueTest, Range) {
|
||||
{
|
||||
Ranges ranges;
|
||||
auto ret = detail::parse_range_header("bytes=1-", ranges);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(1u, ranges.size());
|
||||
EXPECT_EQ(1u, ranges[0].first);
|
||||
EXPECT_EQ(-1, ranges[0].second);
|
||||
}
|
||||
|
||||
{
|
||||
Ranges ranges;
|
||||
auto ret = detail::parse_range_header("bytes=-1", ranges);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(1u, ranges.size());
|
||||
EXPECT_EQ(-1, ranges[0].first);
|
||||
EXPECT_EQ(1u, ranges[0].second);
|
||||
}
|
||||
|
||||
{
|
||||
Ranges ranges;
|
||||
auto ret = detail::parse_range_header("bytes=1-10", ranges);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(1u, ranges.size());
|
||||
EXPECT_EQ(1u, ranges[0].first);
|
||||
EXPECT_EQ(10u, ranges[0].second);
|
||||
}
|
||||
|
||||
{
|
||||
Ranges ranges;
|
||||
auto ret = detail::parse_range_header("bytes=10-1", ranges);
|
||||
EXPECT_FALSE(ret);
|
||||
}
|
||||
|
||||
{
|
||||
Ranges ranges;
|
||||
auto ret = detail::parse_range_header("bytes=1-10, 100-", ranges);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(2u, ranges.size());
|
||||
EXPECT_EQ(1u, ranges[0].first);
|
||||
EXPECT_EQ(10u, ranges[0].second);
|
||||
EXPECT_EQ(100u, ranges[1].first);
|
||||
EXPECT_EQ(-1, ranges[1].second);
|
||||
}
|
||||
|
||||
{
|
||||
Ranges ranges;
|
||||
auto ret =
|
||||
detail::parse_range_header("bytes=1-10, 100-200, 300-400", ranges);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(3u, ranges.size());
|
||||
EXPECT_EQ(1u, ranges[0].first);
|
||||
EXPECT_EQ(10u, ranges[0].second);
|
||||
EXPECT_EQ(100u, ranges[1].first);
|
||||
EXPECT_EQ(200u, ranges[1].second);
|
||||
EXPECT_EQ(300u, ranges[2].first);
|
||||
EXPECT_EQ(400u, ranges[2].second);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ChunkedEncodingTest, FromHTTPWatch) {
|
||||
@@ -157,7 +231,42 @@ TEST(ChunkedEncodingTest, WithContentReceiver) {
|
||||
std::string body;
|
||||
auto res =
|
||||
cli.Get("/httpgallery/chunked/chunkedimage.aspx?0.4153841143030137",
|
||||
[&](const char *data, size_t len) { body.append(data, len); });
|
||||
[&](const char *data, size_t data_length) {
|
||||
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(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) {
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
|
||||
std::string out;
|
||||
@@ -188,7 +297,7 @@ TEST(RangeTest, FromHTTPBin) {
|
||||
}
|
||||
|
||||
{
|
||||
httplib::Headers headers = {httplib::make_range_header(1)};
|
||||
httplib::Headers headers = {httplib::make_range_header({{1, -1}})};
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(res->body, "bcdefghijklmnopqrstuvwxyzabcdef");
|
||||
@@ -196,16 +305,39 @@ TEST(RangeTest, FromHTTPBin) {
|
||||
}
|
||||
|
||||
{
|
||||
httplib::Headers headers = {httplib::make_range_header(1, 10)};
|
||||
httplib::Headers headers = {httplib::make_range_header({{1, 10}})};
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(res->body, "bcdefghijk");
|
||||
EXPECT_EQ(206, res->status);
|
||||
}
|
||||
|
||||
{
|
||||
httplib::Headers headers = {httplib::make_range_header({{0, 31}})};
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(res->body, "abcdefghijklmnopqrstuvwxyzabcdef");
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
{
|
||||
httplib::Headers headers = {httplib::make_range_header({{0, -1}})};
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(res->body, "abcdefghijklmnopqrstuvwxyzabcdef");
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
{
|
||||
httplib::Headers headers = {httplib::make_range_header({{0, 32}})};
|
||||
auto res = cli.Get("/range/32", headers);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(416, res->status);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConnectionErrorTest, InvalidHost) {
|
||||
auto host = "abcde.com";
|
||||
auto host = "-abcde.com";
|
||||
auto sec = 2;
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
@@ -264,8 +396,7 @@ TEST(CancelTest, NoCancel) {
|
||||
httplib::Client cli(host, port, sec);
|
||||
#endif
|
||||
|
||||
auto res =
|
||||
cli.Get("/range/32", [](uint64_t, uint64_t) { return true; });
|
||||
auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return true; });
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(res->body, "abcdefghijklmnopqrstuvwxyzabcdef");
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -283,8 +414,7 @@ TEST(CancelTest, WithCancelSmallPayload) {
|
||||
httplib::Client cli(host, port, sec);
|
||||
#endif
|
||||
|
||||
auto res =
|
||||
cli.Get("/range/32", [](uint64_t, uint64_t) { return false; });
|
||||
auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return false; });
|
||||
ASSERT_TRUE(res == nullptr);
|
||||
}
|
||||
|
||||
@@ -325,9 +455,9 @@ TEST(BaseAuthTest, FromHTTPWatch) {
|
||||
}
|
||||
|
||||
{
|
||||
auto res = cli.Get("/basic-auth/hello/world", {
|
||||
httplib::make_basic_authentication_header("hello", "world")
|
||||
});
|
||||
auto res =
|
||||
cli.Get("/basic-auth/hello/world",
|
||||
{httplib::make_basic_authentication_header("hello", "world")});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(res->body,
|
||||
"{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n");
|
||||
@@ -335,6 +465,88 @@ TEST(BaseAuthTest, FromHTTPWatch) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AbsoluteRedirectTest, Redirect) {
|
||||
auto host = "httpbin.org";
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
httplib::SSLClient cli(host);
|
||||
#else
|
||||
httplib::Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.follow_location(true);
|
||||
auto res = cli.Get("/absolute-redirect/3");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST(RedirectTest, Redirect) {
|
||||
auto host = "httpbin.org";
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
httplib::SSLClient cli(host);
|
||||
#else
|
||||
httplib::Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.follow_location(true);
|
||||
auto res = cli.Get("/redirect/3");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST(RelativeRedirectTest, Redirect) {
|
||||
auto host = "httpbin.org";
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
httplib::SSLClient cli(host);
|
||||
#else
|
||||
httplib::Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.follow_location(true);
|
||||
auto res = cli.Get("/relative-redirect/3");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST(TooManyRedirectTest, Redirect) {
|
||||
auto host = "httpbin.org";
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
httplib::SSLClient cli(host);
|
||||
#else
|
||||
httplib::Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.follow_location(true);
|
||||
auto res = cli.Get("/redirect/21");
|
||||
ASSERT_TRUE(res == nullptr);
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(YahooRedirectTest, Redirect) {
|
||||
httplib::Client cli("yahoo.com");
|
||||
|
||||
auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(301, res->status);
|
||||
|
||||
cli.follow_location(true);
|
||||
res = cli.Get("/");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
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");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(Server, BindAndListenSeparately) {
|
||||
Server svr;
|
||||
int port = svr.bind_to_any_port("localhost");
|
||||
@@ -402,28 +614,55 @@ protected:
|
||||
res.set_content(json, "appliation/json");
|
||||
res.status = 200;
|
||||
})
|
||||
.Get("/streamedchunked",
|
||||
.Get("/streamed-chunked",
|
||||
[&](const Request & /*req*/, Response &res) {
|
||||
res.content_producer = [](uint64_t offset) {
|
||||
if (offset < 3) return "a";
|
||||
if (offset < 6) return "b";
|
||||
return "";
|
||||
};
|
||||
res.set_chunked_content_provider(
|
||||
[](uint64_t /*offset*/, DataSink sink, Done done) {
|
||||
sink("123", 3);
|
||||
sink("456", 3);
|
||||
sink("789", 3);
|
||||
done();
|
||||
});
|
||||
})
|
||||
.Get("/streamed",
|
||||
[&](const Request & /*req*/, Response &res) {
|
||||
res.set_header("Content-Length", "6");
|
||||
res.content_producer = [](uint64_t offset) {
|
||||
if (offset < 3) return "a";
|
||||
if (offset < 6) return "b";
|
||||
return "";
|
||||
};
|
||||
res.set_content_provider(
|
||||
6, [](uint64_t offset, uint64_t /*length*/, DataSink sink) {
|
||||
sink(offset < 3 ? "a" : "b", 1);
|
||||
});
|
||||
})
|
||||
.Get("/streamed-with-range",
|
||||
[&](const Request & /*req*/, Response &res) {
|
||||
auto data = new std::string("abcdefg");
|
||||
res.set_content_provider(
|
||||
data->size(),
|
||||
[data](uint64_t offset, uint64_t length, DataSink sink) {
|
||||
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[static_cast<size_t>(offset)], out_len);
|
||||
},
|
||||
[data] { delete data; });
|
||||
})
|
||||
.Get("/streamed-cancel",
|
||||
[&](const Request & /*req*/, Response &res) {
|
||||
res.set_content_provider(
|
||||
size_t(-1),
|
||||
[](uint64_t /*offset*/, uint64_t /*length*/, DataSink sink) {
|
||||
std::string data = "data_chunk";
|
||||
sink(data.data(), data.size());
|
||||
});
|
||||
})
|
||||
.Get("/with-range",
|
||||
[&](const Request & /*req*/, Response &res) {
|
||||
res.set_content("abcdefg", "text/plain");
|
||||
})
|
||||
.Post("/chunked",
|
||||
[&](const Request &req, Response & /*res*/) {
|
||||
EXPECT_EQ(req.body, "dechunked post body");
|
||||
})
|
||||
.Post("/largechunked",
|
||||
.Post("/large-chunked",
|
||||
[&](const Request &req, Response & /*res*/) {
|
||||
std::string expected(6 * 30 * 1024u, 'a');
|
||||
EXPECT_EQ(req.body, expected);
|
||||
@@ -471,6 +710,11 @@ protected:
|
||||
EXPECT_EQ(req.body, "PUT");
|
||||
res.set_content(req.body, "text/plain");
|
||||
})
|
||||
.Put("/put-large",
|
||||
[&](const Request &req, Response &res) {
|
||||
EXPECT_EQ(req.body, LARGE_DATA);
|
||||
res.set_content(req.body, "text/plain");
|
||||
})
|
||||
.Patch("/patch",
|
||||
[&](const Request &req, Response &res) {
|
||||
EXPECT_EQ(req.body, "PATCH");
|
||||
@@ -507,6 +751,40 @@ protected:
|
||||
EXPECT_EQ(1u, req.get_header_value_count("Content-Length"));
|
||||
EXPECT_EQ("5", req.get_header_value("Content-Length"));
|
||||
})
|
||||
.Post("/content_receiver",
|
||||
[&](const Request & /*req*/, Response &res,
|
||||
const ContentReader &content_reader) {
|
||||
std::string body;
|
||||
content_reader([&](const char *data, size_t data_length) {
|
||||
EXPECT_EQ(data_length, 7);
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
EXPECT_EQ(body, "content");
|
||||
res.set_content(body, "text/plain");
|
||||
})
|
||||
.Put("/content_receiver",
|
||||
[&](const Request & /*req*/, Response &res,
|
||||
const ContentReader &content_reader) {
|
||||
std::string body;
|
||||
content_reader([&](const char *data, size_t data_length) {
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
EXPECT_EQ(body, "content");
|
||||
res.set_content(body, "text/plain");
|
||||
})
|
||||
.Patch("/content_receiver",
|
||||
[&](const Request & /*req*/, Response &res,
|
||||
const ContentReader &content_reader) {
|
||||
std::string body;
|
||||
content_reader([&](const char *data, size_t data_length) {
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
EXPECT_EQ(body, "content");
|
||||
res.set_content(body, "text/plain");
|
||||
})
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
.Get("/gzip",
|
||||
[&](const Request & /*req*/, Response &res) {
|
||||
@@ -579,7 +857,6 @@ TEST_F(ServerTest, GetMethod200) {
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ(1, res->get_header_value_count("Content-Type"));
|
||||
EXPECT_EQ("close", res->get_header_value("Connection"));
|
||||
EXPECT_EQ("Hello World!", res->body);
|
||||
}
|
||||
|
||||
@@ -737,85 +1014,29 @@ TEST_F(ServerTest, EmptyRequest) {
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, LongRequest) {
|
||||
auto res =
|
||||
cli_.Get("/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/__ok__");
|
||||
std::string request;
|
||||
for (size_t i = 0; i < 545; i++) {
|
||||
request += "/TooLongRequest";
|
||||
}
|
||||
request += "OK";
|
||||
|
||||
auto res = cli_.Get(request.c_str());
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(404, res->status);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, TooLongRequest) {
|
||||
auto res =
|
||||
cli_.Get("/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/"
|
||||
"TooLongRequest/TooLongRequest/TooLongRequest/__ng___");
|
||||
std::string request;
|
||||
for (size_t i = 0; i < 545; i++) {
|
||||
request += "/TooLongRequest";
|
||||
}
|
||||
request += "_NG";
|
||||
|
||||
auto res = cli_.Get(request.c_str());
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(404, res->status);
|
||||
EXPECT_EQ(414, res->status);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, LongHeader) {
|
||||
@@ -963,11 +1184,11 @@ TEST_F(ServerTest, EndWithPercentCharacterInQuery) {
|
||||
|
||||
TEST_F(ServerTest, MultipartFormData) {
|
||||
MultipartFormDataItems items = {
|
||||
{ "text1", "text default", "", "" },
|
||||
{ "text2", "aωb", "", "" },
|
||||
{ "file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain" },
|
||||
{ "file2", "{\n \"world\", true\n}\n", "world.json", "application/json" },
|
||||
{ "file3", "", "", "application/octet-stream" },
|
||||
{"text1", "text default", "", ""},
|
||||
{"text2", "aωb", "", ""},
|
||||
{"file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain"},
|
||||
{"file2", "{\n \"world\", true\n}\n", "world.json", "application/json"},
|
||||
{"file3", "", "", "application/octet-stream"},
|
||||
};
|
||||
|
||||
auto res = cli_.Post("/multipart", items);
|
||||
@@ -1013,25 +1234,119 @@ TEST_F(ServerTest, CaseInsensitiveTransferEncoding) {
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamed2) {
|
||||
auto res = cli_.Get("/streamed", {{make_range_header({{2, 3}})}});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(std::string("ab"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamed) {
|
||||
auto res = cli_.Get("/streamed");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("6", res->get_header_value("Content-Length"));
|
||||
EXPECT_TRUE(res->body == "aaabbb");
|
||||
EXPECT_EQ(std::string("aaabbb"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamedWithRange1) {
|
||||
auto res = cli_.Get("/streamed-with-range", {{make_range_header({{3, 5}})}});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("3", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(std::string("def"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamedWithRange2) {
|
||||
auto res = cli_.Get("/streamed-with-range", {{make_range_header({{1, -1}})}});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("6", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(std::string("bcdefg"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamedWithRangeMultipart) {
|
||||
auto res =
|
||||
cli_.Get("/streamed-with-range", {{make_range_header({{1, 2}, {4, 5}})}});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("269", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(false, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(269, res->body.size());
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamedEndless) {
|
||||
size_t offset = 0;
|
||||
auto res = cli_.Get("/streamed-cancel",
|
||||
[&](const char * /*data*/, uint64_t data_length) {
|
||||
if (offset < 100) {
|
||||
offset += data_length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
ASSERT_TRUE(res == nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetWithRange1) {
|
||||
auto res = cli_.Get("/with-range", {{make_range_header({{3, 5}})}});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("3", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(std::string("def"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetWithRange2) {
|
||||
auto res = cli_.Get("/with-range", {{make_range_header({{1, -1}})}});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("6", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(std::string("bcdefg"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetWithRange3) {
|
||||
auto res = cli_.Get("/with-range", {{make_range_header({{0, 0}})}});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("1", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(std::string("a"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetWithRange4) {
|
||||
auto res = cli_.Get("/with-range", {{make_range_header({{-1, 2}})}});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(std::string("fg"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetWithRangeMultipart) {
|
||||
auto res = cli_.Get("/with-range", {{make_range_header({{1, 2}, {4, 5}})}});
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("269", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(false, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(269, res->body.size());
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamedChunked) {
|
||||
auto res = cli_.Get("/streamedchunked");
|
||||
auto res = cli_.Get("/streamed-chunked");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_TRUE(res->body == "aaabbb");
|
||||
EXPECT_EQ(std::string("123456789"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, LargeChunkedPost) {
|
||||
Request req;
|
||||
req.method = "POST";
|
||||
req.path = "/largechunked";
|
||||
req.path = "/large-chunked";
|
||||
|
||||
std::string host_and_port;
|
||||
host_and_port += HOST;
|
||||
@@ -1084,6 +1399,42 @@ TEST_F(ServerTest, Put) {
|
||||
EXPECT_EQ("PUT", res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PutWithContentProvider) {
|
||||
auto res = cli_.Put(
|
||||
"/put", 3,
|
||||
[](size_t /*offset*/, size_t /*length*/, DataSink sink) {
|
||||
sink("PUT", 3);
|
||||
},
|
||||
"text/plain");
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("PUT", res->body);
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
TEST_F(ServerTest, PutWithContentProviderWithGzip) {
|
||||
auto res = cli_.Put(
|
||||
"/put", 3,
|
||||
[](size_t /*offset*/, size_t /*length*/, DataSink sink) {
|
||||
sink("PUT", 3);
|
||||
},
|
||||
"text/plain", true);
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("PUT", res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PutLargeFileWithGzip) {
|
||||
auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain", true);
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ(LARGE_DATA, res->body);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(ServerTest, Patch) {
|
||||
auto res = cli_.Patch("/patch", "PATCH", "text/plain");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
@@ -1119,15 +1470,89 @@ TEST_F(ServerTest, ArrayParam) {
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, NoMultipleHeaders) {
|
||||
Headers headers = {
|
||||
{ "Content-Length", "5" }
|
||||
};
|
||||
Headers headers = {{"Content-Length", "5"}};
|
||||
auto res = cli_.Post("/validate-no-multiple-headers", headers, "hello",
|
||||
"text/plain");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PostContentReceiver) {
|
||||
auto res = cli_.Post("/content_receiver", "content", "text/plain");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
ASSERT_EQ("content", res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PostContentReceiverGzip) {
|
||||
auto res = cli_.Post("/content_receiver", "content", "text/plain", true);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
ASSERT_EQ("content", res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PutContentReceiver) {
|
||||
auto res = cli_.Put("/content_receiver", "content", "text/plain");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
ASSERT_EQ("content", res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PatchContentReceiver) {
|
||||
auto res = cli_.Patch("/content_receiver", "content", "text/plain");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
ASSERT_EQ("content", res->body);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
std::vector<Request> requests;
|
||||
Get(requests, "/hi");
|
||||
Get(requests, "/hi");
|
||||
Get(requests, "/hi");
|
||||
Get(requests, "/not-exist");
|
||||
Post(requests, "/empty", "", "text/plain");
|
||||
|
||||
std::vector<Response> responses;
|
||||
auto ret = cli_.send(requests, responses);
|
||||
|
||||
ASSERT_TRUE(ret == true);
|
||||
ASSERT_TRUE(requests.size() == responses.size());
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
auto &res = responses[i];
|
||||
EXPECT_EQ(200, res.status);
|
||||
EXPECT_EQ("text/plain", res.get_header_value("Content-Type"));
|
||||
EXPECT_EQ("Hello World!", res.body);
|
||||
}
|
||||
|
||||
{
|
||||
auto &res = responses[3];
|
||||
EXPECT_EQ(404, res.status);
|
||||
}
|
||||
|
||||
{
|
||||
auto &res = responses[4];
|
||||
EXPECT_EQ(200, res.status);
|
||||
EXPECT_EQ("text/plain", res.get_header_value("Content-Type"));
|
||||
EXPECT_EQ("empty", res.body);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
TEST_F(ServerTest, Gzip) {
|
||||
Headers headers;
|
||||
@@ -1144,13 +1569,30 @@ TEST_F(ServerTest, Gzip) {
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GzipWithoutAcceptEncoding) {
|
||||
Headers headers;
|
||||
auto res = cli_.Get("/gzip", headers);
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("", res->get_header_value("Content-Encoding"));
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("100", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
|
||||
"7890123456789012345678901234567890",
|
||||
res->body);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GzipWithContentReceiver) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "gzip, deflate");
|
||||
std::string body;
|
||||
auto res = cli_.Get("/gzip", headers, [&](const char *data, size_t len) {
|
||||
body.append(data, len);
|
||||
});
|
||||
auto res =
|
||||
cli_.Get("/gzip", headers, [&](const char *data, uint64_t data_length) {
|
||||
EXPECT_EQ(data_length, 100);
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
|
||||
@@ -1162,6 +1604,26 @@ TEST_F(ServerTest, GzipWithContentReceiver) {
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GzipWithContentReceiverWithoutAcceptEncoding) {
|
||||
Headers headers;
|
||||
std::string body;
|
||||
auto res =
|
||||
cli_.Get("/gzip", headers, [&](const char *data, uint64_t data_length) {
|
||||
EXPECT_EQ(data_length, 100);
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ("", res->get_header_value("Content-Encoding"));
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("100", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
|
||||
"7890123456789012345678901234567890",
|
||||
body);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, NoGzip) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "gzip, deflate");
|
||||
@@ -1181,9 +1643,12 @@ TEST_F(ServerTest, NoGzipWithContentReceiver) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "gzip, deflate");
|
||||
std::string body;
|
||||
auto res = cli_.Get("/nogzip", headers, [&](const char *data, size_t len) {
|
||||
body.append(data, len);
|
||||
});
|
||||
auto res =
|
||||
cli_.Get("/nogzip", headers, [&](const char *data, uint64_t data_length) {
|
||||
EXPECT_EQ(data_length, 100);
|
||||
body.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(false, res->has_header("Content-Encoding"));
|
||||
@@ -1196,56 +1661,14 @@ TEST_F(ServerTest, NoGzipWithContentReceiver) {
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, MultipartFormDataGzip) {
|
||||
Request req;
|
||||
req.method = "POST";
|
||||
req.path = "/gzipmultipart";
|
||||
MultipartFormDataItems items = {
|
||||
{"key1", "test", "", ""},
|
||||
{"key2", "--abcdefg123", "", ""},
|
||||
};
|
||||
|
||||
std::string host_and_port;
|
||||
host_and_port += HOST;
|
||||
host_and_port += ":";
|
||||
host_and_port += std::to_string(PORT);
|
||||
auto res = cli_.Post("/gzipmultipart", items, true);
|
||||
|
||||
req.headers.emplace("Host", host_and_port.c_str());
|
||||
req.headers.emplace("Accept", "*/*");
|
||||
req.headers.emplace("User-Agent", "cpp-httplib/0.1");
|
||||
req.headers.emplace(
|
||||
"Content-Type",
|
||||
"multipart/form-data; boundary=------------------------fcba8368a9f48c0f");
|
||||
req.headers.emplace("Content-Encoding", "gzip");
|
||||
|
||||
// compressed_body generated by creating input.txt to this file:
|
||||
/*
|
||||
--------------------------fcba8368a9f48c0f
|
||||
Content-Disposition: form-data; name="key1"
|
||||
|
||||
test
|
||||
--------------------------fcba8368a9f48c0f
|
||||
Content-Disposition: form-data; name="key2"
|
||||
|
||||
--abcdefg123
|
||||
--------------------------fcba8368a9f48c0f--
|
||||
*/
|
||||
// then running unix2dos input.txt; gzip -9 -c input.txt | xxd -i.
|
||||
uint8_t compressed_body[] = {
|
||||
0x1f, 0x8b, 0x08, 0x08, 0x48, 0xf1, 0xd4, 0x5a, 0x02, 0x03, 0x69, 0x6e,
|
||||
0x70, 0x75, 0x74, 0x2e, 0x74, 0x78, 0x74, 0x00, 0xd3, 0xd5, 0xc5, 0x05,
|
||||
0xd2, 0x92, 0x93, 0x12, 0x2d, 0x8c, 0xcd, 0x2c, 0x12, 0x2d, 0xd3, 0x4c,
|
||||
0x2c, 0x92, 0x0d, 0xd2, 0x78, 0xb9, 0x9c, 0xf3, 0xf3, 0x4a, 0x52, 0xf3,
|
||||
0x4a, 0x74, 0x5d, 0x32, 0x8b, 0x0b, 0xf2, 0x8b, 0x33, 0x4b, 0x32, 0xf3,
|
||||
0xf3, 0xac, 0x14, 0xd2, 0xf2, 0x8b, 0x72, 0x75, 0x53, 0x12, 0x4b, 0x12,
|
||||
0xad, 0x15, 0xf2, 0x12, 0x73, 0x53, 0x6d, 0x95, 0xb2, 0x53, 0x2b, 0x0d,
|
||||
0x95, 0x78, 0xb9, 0x78, 0xb9, 0x4a, 0x52, 0x8b, 0x4b, 0x78, 0xb9, 0x74,
|
||||
0x69, 0x61, 0x81, 0x11, 0xd8, 0x02, 0x5d, 0xdd, 0xc4, 0xa4, 0xe4, 0x94,
|
||||
0xd4, 0xb4, 0x74, 0x43, 0x23, 0x63, 0x52, 0x2c, 0xd2, 0xd5, 0xe5, 0xe5,
|
||||
0x02, 0x00, 0xff, 0x0e, 0x72, 0xdf, 0xf8, 0x00, 0x00, 0x00};
|
||||
|
||||
req.body = std::string((char *)compressed_body,
|
||||
sizeof(compressed_body) / sizeof(compressed_body[0]));
|
||||
|
||||
auto res = std::make_shared<Response>();
|
||||
auto ret = cli_.send(req, *res);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
#endif
|
||||
@@ -1443,6 +1866,7 @@ TEST(SSLClientServerTest, ClientCertPresent) {
|
||||
});
|
||||
|
||||
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
|
||||
msleep(1);
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, 30, CLIENT_CERT_FILE,
|
||||
CLIENT_PRIVATE_KEY_FILE);
|
||||
@@ -1461,6 +1885,7 @@ TEST(SSLClientServerTest, ClientCertMissing) {
|
||||
svr.Get("/test", [&](const Request &, Response &) { ASSERT_TRUE(false); });
|
||||
|
||||
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
|
||||
msleep(1);
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, 30);
|
||||
auto res = cli.Get("/test");
|
||||
@@ -1481,6 +1906,7 @@ TEST(SSLClientServerTest, TrustDirOptional) {
|
||||
});
|
||||
|
||||
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
|
||||
msleep(1);
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, 30, CLIENT_CERT_FILE,
|
||||
CLIENT_PRIVATE_KEY_FILE);
|
||||
|
||||
+20
-4
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user