mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 40db42108f | |||
| 24bb1387d6 | |||
| d0bd4afb0b | |||
| 78ea786abd | |||
| 9cac2c9ceb | |||
| 0cff3245df | |||
| 0e3925db3f | |||
| c9a13d214b | |||
| 0954af2d4c | |||
| 7c1c952f5a | |||
| a6edfc730a | |||
| c1264bfedc | |||
| 90a5b6ceb0 | |||
| eb240ad2e5 | |||
| 88c961f37e | |||
| b952376968 | |||
| 5dd605d3a2 | |||
| 9c0c98b1ed | |||
| 615867322d | |||
| 02d3cd5909 | |||
| 47e5af15ea | |||
| a5c239c174 | |||
| c2afc5ca44 | |||
| cee062d4c9 | |||
| b21dc8cbe0 | |||
| e1133a2dcb | |||
| e273fec93c | |||
| 95d0b073bd | |||
| 9c7d841b37 |
@@ -32,7 +32,7 @@ jobs:
|
||||
run: cd test && make -f Makefile.fuzz_test
|
||||
- name: setup msbuild on windows
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: warrenbuckley/Setup-MSBuild@v1
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
- name: make-windows
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
|
||||
@@ -5,7 +5,7 @@ cpp-httplib
|
||||
|
||||
A C++11 single-file header-only cross platform HTTP/HTTPS library.
|
||||
|
||||
It's extremely easy to setup. Just include **httplib.h** file in your code!
|
||||
It's extremely easy to setup. Just include the **httplib.h** file in your code!
|
||||
|
||||
NOTE: This is a 'blocking' HTTP library. If you are looking for a 'non-blocking' library, this is not the one that you want.
|
||||
|
||||
@@ -120,24 +120,50 @@ svr.set_file_extension_and_mimetype_mapping("hh", "text/x-h");
|
||||
|
||||
The followings are built-in mappings:
|
||||
|
||||
| Extension | MIME Type |
|
||||
| :-------- | :--------------------- |
|
||||
| txt | text/plain |
|
||||
| html, htm | text/html |
|
||||
| css | text/css |
|
||||
| jpeg, jpg | image/jpg |
|
||||
| png | image/png |
|
||||
| gif | image/gif |
|
||||
| svg | image/svg+xml |
|
||||
| ico | image/x-icon |
|
||||
| json | application/json |
|
||||
| pdf | application/pdf |
|
||||
| js | application/javascript |
|
||||
| wasm | application/wasm |
|
||||
| xml | application/xml |
|
||||
| xhtml | application/xhtml+xml |
|
||||
| Extension | MIME Type |
|
||||
| :--------- | :-------------------------- |
|
||||
| css | text/css |
|
||||
| csv | text/csv |
|
||||
| txt | text/plain |
|
||||
| vtt | text/vtt |
|
||||
| html, htm | text/html |
|
||||
| apng | image/apng |
|
||||
| avif | image/avif |
|
||||
| bmp | image/bmp |
|
||||
| gif | image/gif |
|
||||
| png | image/png |
|
||||
| svg | image/svg+xml |
|
||||
| webp | image/webp |
|
||||
| ico | image/x-icon |
|
||||
| tif | image/tiff |
|
||||
| tiff | image/tiff |
|
||||
| jpeg, jpg | image/jpeg |
|
||||
| mp4 | video/mp4 |
|
||||
| mpeg | video/mpeg |
|
||||
| webm | video/webm |
|
||||
| mp3 | audio/mp3 |
|
||||
| mpga | audio/mpeg |
|
||||
| weba | audio/webm |
|
||||
| wav | audio/wave |
|
||||
| otf | font/otf |
|
||||
| ttf | font/ttf |
|
||||
| woff | font/woff |
|
||||
| woff2 | font/woff2 |
|
||||
| 7z | application/x-7z-compressed |
|
||||
| atom | application/atom+xml |
|
||||
| pdf | application/pdf |
|
||||
| mjs, js | application/javascript |
|
||||
| json | application/json |
|
||||
| rss | application/rss+xml |
|
||||
| tar | application/x-tar |
|
||||
| xhtml, xht | application/xhtml+xml |
|
||||
| xslt | application/xslt+xml |
|
||||
| xml | application/xml |
|
||||
| gz | application/gzip |
|
||||
| zip | application/zip |
|
||||
| wasm | application/wasm |
|
||||
|
||||
NOTE: These the static file server methods are not thread safe.
|
||||
NOTE: These static file server methods are not thread-safe.
|
||||
|
||||
### Logging
|
||||
|
||||
@@ -171,7 +197,7 @@ svr.Post("/multipart", [&](const auto& req, auto& res) {
|
||||
});
|
||||
```
|
||||
|
||||
### Receive content with Content receiver
|
||||
### Receive content with a content receiver
|
||||
|
||||
```cpp
|
||||
svr.Post("/content_receiver",
|
||||
@@ -198,7 +224,7 @@ svr.Post("/content_receiver",
|
||||
});
|
||||
```
|
||||
|
||||
### Send content with Content provider
|
||||
### Send content with the content provider
|
||||
|
||||
```cpp
|
||||
const size_t DATA_CHUNK_SIZE = 4;
|
||||
@@ -255,7 +281,7 @@ svr.Get("/chunked", [&](const Request& req, Response& res) {
|
||||
|
||||
### 'Expect: 100-continue' handler
|
||||
|
||||
As default, the server sends `100 Continue` response for `Expect: 100-continue` header.
|
||||
By default, the server sends a `100 Continue` response for an `Expect: 100-continue` header.
|
||||
|
||||
```cpp
|
||||
// Send a '417 Expectation Failed' response.
|
||||
@@ -275,6 +301,7 @@ svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
|
||||
|
||||
```cpp
|
||||
svr.set_keep_alive_max_count(2); // Default is 5
|
||||
svr.set_keep_alive_timeout(10); // Default is 5
|
||||
```
|
||||
|
||||
### Timeout
|
||||
@@ -285,7 +312,7 @@ svr.set_write_timeout(5, 0); // 5 seconds
|
||||
svr.set_idle_interval(0, 100000); // 100 milliseconds
|
||||
```
|
||||
|
||||
### Set maximum payload length for reading request body
|
||||
### Set maximum payload length for reading a request body
|
||||
|
||||
```c++
|
||||
svr.set_payload_max_length(1024 * 1024 * 512); // 512MB
|
||||
@@ -470,7 +497,7 @@ cli.set_read_timeout(5, 0); // 5 seconds
|
||||
cli.set_write_timeout(5, 0); // 5 seconds
|
||||
```
|
||||
|
||||
### Receive content with Content receiver
|
||||
### Receive content with a content receiver
|
||||
|
||||
```c++
|
||||
std::string body;
|
||||
@@ -497,12 +524,12 @@ auto res = cli.Get(
|
||||
});
|
||||
```
|
||||
|
||||
### Send content with Content provider
|
||||
### Send content with a content provider
|
||||
|
||||
```cpp
|
||||
std::string body = ...;
|
||||
|
||||
auto res = cli_.Post(
|
||||
auto res = cli.Post(
|
||||
"/stream", body.size(),
|
||||
[](size_t offset, size_t length, DataSink &sink) {
|
||||
sink.write(body.data() + offset, length);
|
||||
@@ -511,6 +538,21 @@ auto res = cli_.Post(
|
||||
"text/plain");
|
||||
```
|
||||
|
||||
### Chunked transfer encoding
|
||||
|
||||
```cpp
|
||||
auto res = cli.Post(
|
||||
"/stream",
|
||||
[](size_t offset, DataSink &sink) {
|
||||
sink.os << "chunked data 1";
|
||||
sink.os << "chunked data 2";
|
||||
sink.os << "chunked data 3";
|
||||
sink.done();
|
||||
return true; // return 'false' if you want to cancel the request.
|
||||
},
|
||||
"text/plain");
|
||||
```
|
||||
|
||||
### With Progress Callback
|
||||
|
||||
```cpp
|
||||
@@ -605,7 +647,7 @@ res = cli.Get("/");
|
||||
res->status; // 200
|
||||
```
|
||||
|
||||
### Use a specitic network interface
|
||||
### Use a specific network interface
|
||||
|
||||
NOTE: This feature is not available on Windows, yet.
|
||||
|
||||
@@ -630,10 +672,16 @@ cli.set_ca_cert_path("./ca-bundle.crt");
|
||||
cli.enable_server_certificate_verification(true);
|
||||
```
|
||||
|
||||
Note: When using SSL, it seems impossible to avoid SIGPIPE in all cases, since on some operating systems, SIGPIPE
|
||||
can only be suppressed on a per-message basis, but there is no way to make the OpenSSL library do so for its
|
||||
internal communications. If your program needs to avoid being terminated on SIGPIPE, the only fully general way might
|
||||
be to set up a signal handler for SIGPIPE to handle or ignore it yourself.
|
||||
|
||||
|
||||
Compression
|
||||
-----------
|
||||
|
||||
The server can applie compression to the following MIME type contents:
|
||||
The server can apply compression to the following MIME type contents:
|
||||
|
||||
* all text types except text/event-stream
|
||||
* image/svg+xml
|
||||
@@ -697,7 +745,7 @@ Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32
|
||||
#include <httplib.h>
|
||||
```
|
||||
|
||||
Note: Cygwin on Windows is not supported.
|
||||
Note: Windows 8 or lower and Cygwin on Windows are not supported.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
#include <memory>
|
||||
#include <httplib.h>
|
||||
#include <memory>
|
||||
|
||||
class FuzzedStream : public httplib::Stream {
|
||||
public:
|
||||
FuzzedStream(const uint8_t* data, size_t size)
|
||||
public:
|
||||
FuzzedStream(const uint8_t *data, size_t size)
|
||||
: data_(data), size_(size), read_pos_(0) {}
|
||||
|
||||
ssize_t read(char* ptr, size_t size) override {
|
||||
if (size + read_pos_ > size_) {
|
||||
size = size_ - read_pos_;
|
||||
}
|
||||
ssize_t read(char *ptr, size_t size) override {
|
||||
if (size + read_pos_ > size_) { size = size_ - read_pos_; }
|
||||
memcpy(ptr, data_ + read_pos_, size);
|
||||
read_pos_ += size;
|
||||
return size;
|
||||
return static_cast<ssize_t>(size);
|
||||
}
|
||||
|
||||
ssize_t write(const char* ptr, size_t size) override {
|
||||
ssize_t write(const char *ptr, size_t size) override {
|
||||
response_.append(ptr, size);
|
||||
return static_cast<int>(size);
|
||||
}
|
||||
|
||||
int write(const char* ptr) { return write(ptr, strlen(ptr)); }
|
||||
ssize_t write(const char *ptr) { return write(ptr, strlen(ptr)); }
|
||||
|
||||
int write(const std::string& s) { return write(s.data(), s.size()); }
|
||||
ssize_t write(const std::string &s) { return write(s.data(), s.size()); }
|
||||
|
||||
std::string get_remote_addr() const { return ""; }
|
||||
|
||||
@@ -35,16 +33,18 @@ class FuzzedStream : public httplib::Stream {
|
||||
port = 8080;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t* data_;
|
||||
socket_t socket() const override { return 0; }
|
||||
|
||||
private:
|
||||
const uint8_t *data_;
|
||||
size_t size_;
|
||||
size_t read_pos_;
|
||||
std::string response_;
|
||||
};
|
||||
|
||||
class FuzzableServer : public httplib::Server {
|
||||
public:
|
||||
void ProcessFuzzedRequest(FuzzedStream& stream) {
|
||||
public:
|
||||
void ProcessFuzzedRequest(FuzzedStream &stream) {
|
||||
bool connection_close = false;
|
||||
process_request(stream, /*last_connection=*/false, connection_close,
|
||||
nullptr);
|
||||
@@ -53,36 +53,36 @@ class FuzzableServer : public httplib::Server {
|
||||
|
||||
static FuzzableServer g_server;
|
||||
|
||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
|
||||
extern "C" int LLVMFuzzerInitialize(int * /*argc*/, char *** /*argv*/) {
|
||||
g_server.Get(R"(.*)",
|
||||
[&](const httplib::Request& req, httplib::Response& res) {
|
||||
[&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||
res.set_content("response content", "text/plain");
|
||||
});
|
||||
g_server.Post(R"(.*)",
|
||||
[&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||
res.set_content("response content", "text/plain");
|
||||
});
|
||||
g_server.Post(R"(.*)",
|
||||
[&](const httplib::Request& req, httplib::Response& res) {
|
||||
g_server.Put(R"(.*)",
|
||||
[&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||
res.set_content("response content", "text/plain");
|
||||
});
|
||||
g_server.Patch(R"(.*)",
|
||||
[&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||
res.set_content("response content", "text/plain");
|
||||
});
|
||||
g_server.Put(R"(.*)",
|
||||
[&](const httplib::Request& req, httplib::Response& res) {
|
||||
res.set_content("response content", "text/plain");
|
||||
});
|
||||
g_server.Patch(R"(.*)",
|
||||
[&](const httplib::Request& req, httplib::Response& res) {
|
||||
res.set_content("response content", "text/plain");
|
||||
});
|
||||
g_server.Delete(R"(.*)",
|
||||
[&](const httplib::Request& req, httplib::Response& res) {
|
||||
res.set_content("response content", "text/plain");
|
||||
});
|
||||
g_server.Options(R"(.*)",
|
||||
[&](const httplib::Request& req, httplib::Response& res) {
|
||||
res.set_content("response content", "text/plain");
|
||||
});
|
||||
g_server.Delete(
|
||||
R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||
res.set_content("response content", "text/plain");
|
||||
});
|
||||
g_server.Options(
|
||||
R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||
res.set_content("response content", "text/plain");
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
FuzzedStream stream{data, size};
|
||||
g_server.ProcessFuzzedRequest(stream);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +42,9 @@
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion"
|
||||
#elif __GNUC__
|
||||
#pragma gcc diagnostic push
|
||||
#pragma gcc diagnostic ignored "-Wsign-conversion"
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#endif
|
||||
|
||||
// The following lines pull in the real gtest *.cc files.
|
||||
@@ -9127,5 +9128,5 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
|
||||
#if __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#elif __GNUC__
|
||||
#pragma gcc diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
+7
-6
@@ -63,8 +63,9 @@
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wsign-compare"
|
||||
#elif __GNUC__
|
||||
#pragma gcc diagnostic push
|
||||
#pragma gcc diagnostic ignored "-Wsign-compare"
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#endif
|
||||
|
||||
// Copyright 2005, Google Inc.
|
||||
@@ -18353,8 +18354,8 @@ AssertionResult CmpHelperEQ(const char* expected_expression,
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wsign-compare"
|
||||
#elif __GNUC__
|
||||
#pragma gcc diagnostic push
|
||||
#pragma gcc diagnostic ignored "-Wsign-compare"
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#endif
|
||||
|
||||
if (expected == actual) {
|
||||
@@ -18366,7 +18367,7 @@ AssertionResult CmpHelperEQ(const char* expected_expression,
|
||||
#elif __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#elif __GNUC__
|
||||
#pragma gcc diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
return EqFailure(expected_expression,
|
||||
@@ -19564,7 +19565,7 @@ bool StaticAssertTypeEq() {
|
||||
#if __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#elif __GNUC__
|
||||
#pragma gcc diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_H_
|
||||
|
||||
+128
-11
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
@@ -45,6 +46,18 @@ TEST(StartupTest, WSAStartup) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(EncodeQueryParamTest, ParseUnescapedChararactersTest){
|
||||
string unescapedCharacters = "-_.!~*'()";
|
||||
|
||||
EXPECT_EQ(detail::encode_query_param(unescapedCharacters), "-_.!~*'()");
|
||||
}
|
||||
|
||||
TEST(EncodeQueryParamTest, ParseReservedCharactersTest){
|
||||
string reservedCharacters = ";,/?:@&=+$";
|
||||
|
||||
EXPECT_EQ(detail::encode_query_param(reservedCharacters), "%3B%2C%2F%3F%3A%40%26%3D%2B%24");
|
||||
}
|
||||
|
||||
TEST(TrimTests, TrimStringTests) {
|
||||
EXPECT_EQ("abc", detail::trim_copy("abc"));
|
||||
EXPECT_EQ("abc", detail::trim_copy(" abc "));
|
||||
@@ -778,6 +791,7 @@ TEST(YahooRedirectTest, Redirect) {
|
||||
res = cli.Get("/");
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("https://yahoo.com/", res->location);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -928,6 +942,31 @@ TEST(ErrorHandlerTest, ContentLength) {
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
}
|
||||
|
||||
TEST(InvalidFormatTest, StatusCode) {
|
||||
Server svr;
|
||||
|
||||
svr.Get("/hi", [](const Request & /*req*/, Response &res) {
|
||||
res.set_content("Hello World!\n", "text/plain");
|
||||
res.status = 9999; // Status should be a three-digit code...
|
||||
});
|
||||
|
||||
auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
|
||||
|
||||
// Give GET time to get a few messages.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
|
||||
auto res = cli.Get("/hi");
|
||||
ASSERT_FALSE(res);
|
||||
}
|
||||
|
||||
svr.stop();
|
||||
thread.join();
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
}
|
||||
|
||||
class ServerTest : public ::testing::Test {
|
||||
protected:
|
||||
ServerTest()
|
||||
@@ -1434,6 +1473,7 @@ TEST_F(ServerTest, GetMethod302Redirect) {
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("Hello World!", res->body);
|
||||
EXPECT_EQ("/hi", res->location);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetMethod404) {
|
||||
@@ -1662,6 +1702,7 @@ TEST_F(ServerTest, PostMethod303Redirect) {
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("redirected.", res->body);
|
||||
EXPECT_EQ("/2", res->location);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, UserDefinedMIMETypeMapping) {
|
||||
@@ -1672,6 +1713,16 @@ TEST_F(ServerTest, UserDefinedMIMETypeMapping) {
|
||||
EXPECT_EQ("abcde", res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, StaticFileRange) {
|
||||
auto res = cli_.Get("/dir/test.abcde", {{make_range_header({{2, 3}})}});
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(std::string("cd"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, InvalidBaseDirMount) {
|
||||
EXPECT_EQ(false, svr_.set_mount_point("invalid_mount_point", "./www3"));
|
||||
}
|
||||
@@ -1755,7 +1806,8 @@ TEST_F(ServerTest, LongHeader) {
|
||||
"@@@@@@@@@@@@@@@@");
|
||||
|
||||
auto res = std::make_shared<Response>();
|
||||
auto ret = cli_.send(req, *res);
|
||||
auto error = Error::Success;
|
||||
auto ret = cli_.send(req, *res, error);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -1815,7 +1867,8 @@ TEST_F(ServerTest, TooLongHeader) {
|
||||
"@@@@@@@@@@@@@@@@@");
|
||||
|
||||
auto res = std::make_shared<Response>();
|
||||
auto ret = cli_.send(req, *res);
|
||||
auto error = Error::Success;
|
||||
auto ret = cli_.send(req, *res, error);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -1904,7 +1957,8 @@ TEST_F(ServerTest, CaseInsensitiveTransferEncoding) {
|
||||
req.body = "4\r\ndech\r\nf\r\nunked post body\r\n0\r\n\r\n";
|
||||
|
||||
auto res = std::make_shared<Response>();
|
||||
auto ret = cli_.send(req, *res);
|
||||
auto error = Error::Success;
|
||||
auto ret = cli_.send(req, *res, error);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -2121,7 +2175,8 @@ TEST_F(ServerTest, LargeChunkedPost) {
|
||||
req.body = chunk + chunk + chunk + chunk + chunk + chunk + "0\r\n\r\n";
|
||||
|
||||
auto res = std::make_shared<Response>();
|
||||
auto ret = cli_.send(req, *res);
|
||||
auto error = Error::Success;
|
||||
auto ret = cli_.send(req, *res, error);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -2217,6 +2272,31 @@ TEST_F(ServerTest, PostWithContentProviderAbort) {
|
||||
EXPECT_EQ(Error::Canceled, res.error());
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PutWithContentProviderWithoutLength) {
|
||||
auto res = cli_.Put(
|
||||
"/put",
|
||||
[](size_t /*offset*/, DataSink &sink) {
|
||||
EXPECT_TRUE(sink.is_writable());
|
||||
sink.os << "PUT";
|
||||
sink.done();
|
||||
return true;
|
||||
},
|
||||
"text/plain");
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("PUT", res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PostWithContentProviderWithoutLengthAbort) {
|
||||
auto res = cli_.Post(
|
||||
"/post", [](size_t /*offset*/, DataSink & /*sink*/) { return false; },
|
||||
"text/plain");
|
||||
|
||||
ASSERT_TRUE(!res);
|
||||
EXPECT_EQ(Error::Canceled, res.error());
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
TEST_F(ServerTest, PutWithContentProviderWithGzip) {
|
||||
cli_.set_compress(true);
|
||||
@@ -2247,6 +2327,33 @@ TEST_F(ServerTest, PostWithContentProviderWithGzipAbort) {
|
||||
EXPECT_EQ(Error::Canceled, res.error());
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PutWithContentProviderWithoutLengthWithGzip) {
|
||||
cli_.set_compress(true);
|
||||
auto res = cli_.Put(
|
||||
"/put",
|
||||
[](size_t /*offset*/, DataSink &sink) {
|
||||
EXPECT_TRUE(sink.is_writable());
|
||||
sink.os << "PUT";
|
||||
sink.done();
|
||||
return true;
|
||||
},
|
||||
"text/plain");
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("PUT", res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PostWithContentProviderWithoutLengthWithGzipAbort) {
|
||||
cli_.set_compress(true);
|
||||
auto res = cli_.Post(
|
||||
"/post", [](size_t /*offset*/, DataSink & /*sink*/) { return false; },
|
||||
"text/plain");
|
||||
|
||||
ASSERT_TRUE(!res);
|
||||
EXPECT_EQ(Error::Canceled, res.error());
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PutLargeFileWithGzip) {
|
||||
cli_.set_compress(true);
|
||||
auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain");
|
||||
@@ -2334,7 +2441,7 @@ TEST(GzipDecompressor, ChunkedDecompression) {
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
TEST_F(ServerTest, GetStreamedChunkedWithBrotli) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "brotli");
|
||||
headers.emplace("Accept-Encoding", "br");
|
||||
|
||||
auto res = cli_.Get("/streamed-chunked", headers);
|
||||
ASSERT_TRUE(res);
|
||||
@@ -2344,7 +2451,7 @@ TEST_F(ServerTest, GetStreamedChunkedWithBrotli) {
|
||||
|
||||
TEST_F(ServerTest, GetStreamedChunkedWithBrotli2) {
|
||||
Headers headers;
|
||||
headers.emplace("Accept-Encoding", "brotli");
|
||||
headers.emplace("Accept-Encoding", "br");
|
||||
|
||||
auto res = cli_.Get("/streamed-chunked2", headers);
|
||||
ASSERT_TRUE(res);
|
||||
@@ -2495,7 +2602,8 @@ TEST_F(ServerTest, HTTP2Magic) {
|
||||
req.body = "SM";
|
||||
|
||||
auto res = std::make_shared<Response>();
|
||||
auto ret = cli_.send(req, *res);
|
||||
auto error = Error::Success;
|
||||
auto ret = cli_.send(req, *res, error);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
EXPECT_EQ(400, res->status);
|
||||
@@ -2693,7 +2801,7 @@ TEST_F(ServerTest, Brotli) {
|
||||
auto res = cli_.Get("/compress", headers);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ("brotli", res->get_header_value("Content-Encoding"));
|
||||
EXPECT_EQ("br", res->get_header_value("Content-Encoding"));
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("19", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ("123456789012345678901234567890123456789012345678901234567890123456"
|
||||
@@ -2706,7 +2814,7 @@ TEST_F(ServerTest, Brotli) {
|
||||
// Sends a raw request to a server listening at HOST:PORT.
|
||||
static bool send_request(time_t read_timeout_sec, const std::string &req,
|
||||
std::string *resp = nullptr) {
|
||||
Error error = Error::Success;
|
||||
auto error = Error::Success;
|
||||
|
||||
auto client_sock =
|
||||
detail::create_client_socket(HOST, PORT, false, nullptr,
|
||||
@@ -2896,6 +3004,12 @@ TEST(ServerRequestParsingTest, InvalidHeaderTextWithExtraCR) {
|
||||
"Content-Type: text/plain\r\n\r");
|
||||
}
|
||||
|
||||
TEST(ServerRequestParsingTest, InvalidSpaceInURL) {
|
||||
std::string out;
|
||||
test_raw_request("GET /h i HTTP/1.1\r\n\r\n", &out);
|
||||
EXPECT_EQ("HTTP/1.1 400 Bad Request", out.substr(0, 24));
|
||||
}
|
||||
|
||||
TEST(ServerStopTest, StopServerWithChunkedTransmission) {
|
||||
Server svr;
|
||||
|
||||
@@ -3586,6 +3700,7 @@ TEST(YahooRedirectTest2, SimpleInterface) {
|
||||
res = cli.Get("/");
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("https://yahoo.com/", res->location);
|
||||
}
|
||||
|
||||
TEST(YahooRedirectTest3, SimpleInterface) {
|
||||
@@ -3599,6 +3714,7 @@ TEST(YahooRedirectTest3, SimpleInterface) {
|
||||
res = cli.Get("/");
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("https://www.yahoo.com/", res->location);
|
||||
}
|
||||
|
||||
TEST(YahooRedirectTest3, NewResultInterface) {
|
||||
@@ -3622,13 +3738,14 @@ TEST(YahooRedirectTest3, NewResultInterface) {
|
||||
EXPECT_EQ(200, res.value().status);
|
||||
EXPECT_EQ(200, (*res).status);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("https://www.yahoo.com/", res->location);
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
TEST(DecodeWithChunkedEncoding, BrotliEncoding) {
|
||||
Client cli("https://cdnjs.cloudflare.com");
|
||||
auto res = cli.Get("/ajax/libs/jquery/3.5.1/jquery.js",
|
||||
{{"Accept-Encoding", "brotli"}});
|
||||
auto res =
|
||||
cli.Get("/ajax/libs/jquery/3.5.1/jquery.js", {{"Accept-Encoding", "br"}});
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
|
||||
Reference in New Issue
Block a user