mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-25 12:14:41 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba685dbe48 | ||
|
|
49c4c2f9c1 | ||
|
|
58909f5917 | ||
|
|
5982b5c360 | ||
|
|
eb1fe5b191 | ||
|
|
5e01587ed6 | ||
|
|
5935d9fa59 | ||
|
|
5bb4c12c6b | ||
|
|
85637844c9 | ||
|
|
d043b18097 | ||
|
|
31bb13abd2 | ||
|
|
8728db7477 | ||
|
|
1c50ac3667 | ||
|
|
cf386f97fd | ||
|
|
b2203bb05a | ||
|
|
f5b806d995 | ||
|
|
3895210f19 |
No files matched your search
-14
@@ -1,14 +0,0 @@
|
|||||||
# Environment
|
|
||||||
language: cpp
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
- osx
|
|
||||||
|
|
||||||
# Compiler selection
|
|
||||||
compiler:
|
|
||||||
- clang
|
|
||||||
|
|
||||||
# Build/test steps
|
|
||||||
script:
|
|
||||||
- cd ${TRAVIS_BUILD_DIR}/test
|
|
||||||
- make all
|
|
||||||
@@ -2,7 +2,6 @@ cpp-httplib
|
|||||||
===========
|
===========
|
||||||
|
|
||||||
[](https://github.com/yhirose/cpp-httplib/actions)
|
[](https://github.com/yhirose/cpp-httplib/actions)
|
||||||
[](https://travis-ci.org/yhirose/cpp-httplib)
|
|
||||||
[](https://ci.appveyor.com/project/yhirose/cpp-httplib)
|
[](https://ci.appveyor.com/project/yhirose/cpp-httplib)
|
||||||
|
|
||||||
A C++11 single-file header-only cross platform HTTP/HTTPS library.
|
A C++11 single-file header-only cross platform HTTP/HTTPS library.
|
||||||
@@ -172,14 +171,14 @@ svr.Post("/content_receiver",
|
|||||||
### Send content with Content provider
|
### Send content with Content provider
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const uint64_t DATA_CHUNK_SIZE = 4;
|
const size_t DATA_CHUNK_SIZE = 4;
|
||||||
|
|
||||||
svr.Get("/stream", [&](const Request &req, Response &res) {
|
svr.Get("/stream", [&](const Request &req, Response &res) {
|
||||||
auto data = new std::string("abcdefg");
|
auto data = new std::string("abcdefg");
|
||||||
|
|
||||||
res.set_content_provider(
|
res.set_content_provider(
|
||||||
data->size(), // Content length
|
data->size(), // Content length
|
||||||
[data](uint64_t offset, uint64_t length, DataSink &sink) {
|
[data](size_t offset, size_t length, DataSink &sink) {
|
||||||
const auto &d = *data;
|
const auto &d = *data;
|
||||||
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
|
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
|
||||||
},
|
},
|
||||||
@@ -192,7 +191,7 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
|
|||||||
```cpp
|
```cpp
|
||||||
svr.Get("/chunked", [&](const Request& req, Response& res) {
|
svr.Get("/chunked", [&](const Request& req, Response& res) {
|
||||||
res.set_chunked_content_provider(
|
res.set_chunked_content_provider(
|
||||||
[](uint64_t offset, DataSink &sink) {
|
[](size_t offset, DataSink &sink) {
|
||||||
sink.write("123", 3);
|
sink.write("123", 3);
|
||||||
sink.write("345", 3);
|
sink.write("345", 3);
|
||||||
sink.write("789", 3);
|
sink.write("789", 3);
|
||||||
@@ -291,7 +290,7 @@ auto res = cli.Get("/hi", headers);
|
|||||||
std::string body;
|
std::string body;
|
||||||
|
|
||||||
auto res = cli.Get("/large-data",
|
auto res = cli.Get("/large-data",
|
||||||
[&](const char *data, uint64_t data_length) {
|
[&](const char *data, size_t data_length) {
|
||||||
body.append(data, data_length);
|
body.append(data, data_length);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -437,6 +436,15 @@ Get(requests, "/get-request2");
|
|||||||
Post(requests, "/post-request1", "text", "text/plain");
|
Post(requests, "/post-request1", "text", "text/plain");
|
||||||
Post(requests, "/post-request2", "text", "text/plain");
|
Post(requests, "/post-request2", "text", "text/plain");
|
||||||
|
|
||||||
|
const size_t DATA_CHUNK_SIZE = 4;
|
||||||
|
std::string data("abcdefg");
|
||||||
|
Post(requests, "/post-request-with-content-provider",
|
||||||
|
data.size(),
|
||||||
|
[&](size_t offset, size_t length, DataSink &sink){
|
||||||
|
sink.write(&data[offset], std::min(length, DATA_CHUNK_SIZE));
|
||||||
|
},
|
||||||
|
"text/plain");
|
||||||
|
|
||||||
std::vector<Response> responses;
|
std::vector<Response> responses;
|
||||||
if (cli.send(requests, responses)) {
|
if (cli.send(requests, responses)) {
|
||||||
for (const auto& res: responses) {
|
for (const auto& res: responses) {
|
||||||
|
|||||||
@@ -50,7 +50,9 @@
|
|||||||
|
|
||||||
#ifndef CPPHTTPLIB_THREAD_POOL_COUNT
|
#ifndef CPPHTTPLIB_THREAD_POOL_COUNT
|
||||||
#define CPPHTTPLIB_THREAD_POOL_COUNT \
|
#define CPPHTTPLIB_THREAD_POOL_COUNT \
|
||||||
((std::max)(8u, std::thread::hardware_concurrency() - 1))
|
((std::max)(8u, std::thread::hardware_concurrency() > 0 \
|
||||||
|
? std::thread::hardware_concurrency() - 1 \
|
||||||
|
: 0))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -275,6 +277,7 @@ struct Request {
|
|||||||
|
|
||||||
// for client
|
// for client
|
||||||
size_t redirect_count = CPPHTTPLIB_REDIRECT_MAX_COUNT;
|
size_t redirect_count = CPPHTTPLIB_REDIRECT_MAX_COUNT;
|
||||||
|
size_t authorization_count = 1;
|
||||||
ResponseHandler response_handler;
|
ResponseHandler response_handler;
|
||||||
ContentReceiver content_receiver;
|
ContentReceiver content_receiver;
|
||||||
Progress progress;
|
Progress progress;
|
||||||
@@ -855,6 +858,21 @@ inline void Post(std::vector<Request> &requests, const char *path,
|
|||||||
Post(requests, path, Headers(), body, content_type);
|
Post(requests, path, Headers(), body, content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Post(std::vector<Request> &requests, const char *path,
|
||||||
|
size_t content_length, ContentProvider content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
Request req;
|
||||||
|
req.method = "POST";
|
||||||
|
req.headers = Headers();
|
||||||
|
req.path = path;
|
||||||
|
req.content_length = content_length;
|
||||||
|
req.content_provider = content_provider;
|
||||||
|
|
||||||
|
if (content_type) { req.headers.emplace("Content-Type", content_type); }
|
||||||
|
|
||||||
|
requests.emplace_back(std::move(req));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
class SSLServer : public Server {
|
class SSLServer : public Server {
|
||||||
public:
|
public:
|
||||||
@@ -1198,20 +1216,18 @@ inline int close_socket(socket_t sock) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T> inline ssize_t handle_EINTR(T fn) {
|
||||||
inline ssize_t handle_EINTR(T fn) {
|
|
||||||
ssize_t res = false;
|
ssize_t res = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
res = fn();
|
res = fn();
|
||||||
if (res < 0 && errno == EINTR) {
|
if (res < 0 && errno == EINTR) { continue; }
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HANDLE_EINTR(method, ...) (handle_EINTR([&]() { return method(__VA_ARGS__); }))
|
#define HANDLE_EINTR(method, ...) \
|
||||||
|
(handle_EINTR([&]() { return method(__VA_ARGS__); }))
|
||||||
|
|
||||||
inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) {
|
inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) {
|
||||||
#ifdef CPPHTTPLIB_USE_POLL
|
#ifdef CPPHTTPLIB_USE_POLL
|
||||||
@@ -1231,7 +1247,8 @@ inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) {
|
|||||||
tv.tv_sec = static_cast<long>(sec);
|
tv.tv_sec = static_cast<long>(sec);
|
||||||
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
|
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
|
||||||
|
|
||||||
return HANDLE_EINTR(select, static_cast<int>(sock + 1), &fds, nullptr, nullptr, &tv);
|
return HANDLE_EINTR(select, static_cast<int>(sock + 1), &fds, nullptr,
|
||||||
|
nullptr, &tv);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1253,7 +1270,8 @@ inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) {
|
|||||||
tv.tv_sec = static_cast<long>(sec);
|
tv.tv_sec = static_cast<long>(sec);
|
||||||
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
|
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
|
||||||
|
|
||||||
return HANDLE_EINTR(select, static_cast<int>(sock + 1), nullptr, &fds, nullptr, &tv);
|
return HANDLE_EINTR(select, static_cast<int>(sock + 1), nullptr, &fds,
|
||||||
|
nullptr, &tv);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1270,7 +1288,7 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
|
|||||||
int error = 0;
|
int error = 0;
|
||||||
socklen_t len = sizeof(error);
|
socklen_t len = sizeof(error);
|
||||||
auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
|
auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
|
||||||
reinterpret_cast<char *>(&error), &len);
|
reinterpret_cast<char *>(&error), &len);
|
||||||
return res >= 0 && !error;
|
return res >= 0 && !error;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -1286,7 +1304,8 @@ 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_sec = static_cast<long>(sec);
|
||||||
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
|
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
|
||||||
|
|
||||||
if (HANDLE_EINTR(select, static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv) > 0 &&
|
if (HANDLE_EINTR(select, static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse,
|
||||||
|
&tv) > 0 &&
|
||||||
(FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
|
(FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
|
||||||
int error = 0;
|
int error = 0;
|
||||||
socklen_t len = sizeof(error);
|
socklen_t len = sizeof(error);
|
||||||
@@ -1469,11 +1488,18 @@ socket_t create_socket(const char *host, int port, Fn fn,
|
|||||||
int yes = 1;
|
int yes = 1;
|
||||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&yes),
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&yes),
|
||||||
sizeof(yes));
|
sizeof(yes));
|
||||||
|
|
||||||
#ifdef SO_REUSEPORT
|
#ifdef SO_REUSEPORT
|
||||||
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, reinterpret_cast<char *>(&yes),
|
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, reinterpret_cast<char *>(&yes),
|
||||||
sizeof(yes));
|
sizeof(yes));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (rp->ai_family == AF_INET6) {
|
||||||
|
int no = 0;
|
||||||
|
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char *>(&no),
|
||||||
|
sizeof(no));
|
||||||
|
}
|
||||||
|
|
||||||
// bind or connect
|
// bind or connect
|
||||||
if (fn(sock, *rp)) {
|
if (fn(sock, *rp)) {
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
@@ -2057,7 +2083,9 @@ inline ssize_t write_content(Stream &strm, ContentProvider content_provider,
|
|||||||
written_length = strm.write(d, l);
|
written_length = strm.write(d, l);
|
||||||
};
|
};
|
||||||
data_sink.done = [&](void) { written_length = -1; };
|
data_sink.done = [&](void) { written_length = -1; };
|
||||||
data_sink.is_writable = [&](void) { return strm.is_writable(); };
|
data_sink.is_writable = [&](void) {
|
||||||
|
return strm.is_writable() && written_length >= 0;
|
||||||
|
};
|
||||||
|
|
||||||
content_provider(offset, end_offset - offset, data_sink);
|
content_provider(offset, end_offset - offset, data_sink);
|
||||||
if (written_length < 0) { return written_length; }
|
if (written_length < 0) { return written_length; }
|
||||||
@@ -2088,7 +2116,9 @@ inline ssize_t write_content_chunked(Stream &strm,
|
|||||||
data_available = false;
|
data_available = false;
|
||||||
written_length = strm.write("0\r\n\r\n");
|
written_length = strm.write("0\r\n\r\n");
|
||||||
};
|
};
|
||||||
data_sink.is_writable = [&](void) { return strm.is_writable(); };
|
data_sink.is_writable = [&](void) {
|
||||||
|
return strm.is_writable() && written_length >= 0;
|
||||||
|
};
|
||||||
|
|
||||||
content_provider(offset, 0, data_sink);
|
content_provider(offset, 0, data_sink);
|
||||||
|
|
||||||
@@ -2710,10 +2740,11 @@ inline std::pair<std::string, std::string> make_digest_authentication_header(
|
|||||||
":" + qop + ":" + H(A2));
|
":" + qop + ":" + H(A2));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto field = "Digest username=\"hello\", realm=\"" + auth.at("realm") +
|
auto field = "Digest username=\"" + username + "\", realm=\"" +
|
||||||
"\", nonce=\"" + auth.at("nonce") + "\", uri=\"" + req.path +
|
auth.at("realm") + "\", nonce=\"" + auth.at("nonce") +
|
||||||
"\", algorithm=" + algo + ", qop=" + qop + ", nc=\"" + nc +
|
"\", uri=\"" + req.path + "\", algorithm=" + algo +
|
||||||
"\", cnonce=\"" + cnonce + "\", response=\"" + response + "\"";
|
", qop=" + qop + ", nc=\"" + nc + "\", cnonce=\"" + cnonce +
|
||||||
|
"\", response=\"" + response + "\"";
|
||||||
|
|
||||||
auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
|
auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
|
||||||
return std::make_pair(key, field);
|
return std::make_pair(key, field);
|
||||||
@@ -3866,7 +3897,8 @@ inline bool Client::handle_request(Stream &strm, const Request &req,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
if (res.status == 401 || res.status == 407) {
|
if ((res.status == 401 || res.status == 407) &&
|
||||||
|
req.authorization_count == 1) {
|
||||||
auto is_proxy = res.status == 407;
|
auto is_proxy = res.status == 407;
|
||||||
const auto &username =
|
const auto &username =
|
||||||
is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
|
is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
|
||||||
@@ -3877,10 +3909,12 @@ inline bool Client::handle_request(Stream &strm, const Request &req,
|
|||||||
std::map<std::string, std::string> auth;
|
std::map<std::string, std::string> auth;
|
||||||
if (parse_www_authenticate(res, auth, is_proxy)) {
|
if (parse_www_authenticate(res, auth, is_proxy)) {
|
||||||
Request new_req = req;
|
Request new_req = req;
|
||||||
auto key = is_proxy ? "Proxy-Authorization" : "WWW-Authorization";
|
new_req.authorization_count += 1;
|
||||||
|
auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
|
||||||
new_req.headers.erase(key);
|
new_req.headers.erase(key);
|
||||||
new_req.headers.insert(make_digest_authentication_header(
|
new_req.headers.insert(make_digest_authentication_header(
|
||||||
req, auth, 1, random_string(10), username, password, is_proxy));
|
req, auth, new_req.authorization_count, random_string(10), username,
|
||||||
|
password, is_proxy));
|
||||||
|
|
||||||
Response new_res;
|
Response new_res;
|
||||||
|
|
||||||
@@ -5122,4 +5156,3 @@ namespace detail {
|
|||||||
} // namespace httplib
|
} // namespace httplib
|
||||||
|
|
||||||
#endif // CPPHTTPLIB_HTTPLIB_H
|
#endif // CPPHTTPLIB_HTTPLIB_H
|
||||||
|
|
||||||
+56
-13
@@ -563,15 +563,17 @@ TEST(DigestAuthTest, FromHTTPWatch) {
|
|||||||
for (auto path : paths) {
|
for (auto path : paths) {
|
||||||
auto res = cli.Get(path.c_str());
|
auto res = cli.Get(path.c_str());
|
||||||
ASSERT_TRUE(res != nullptr);
|
ASSERT_TRUE(res != nullptr);
|
||||||
EXPECT_EQ(400, res->status);
|
EXPECT_EQ(401, res->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
cli.set_digest_auth("bad", "world");
|
// NOTE: Until httpbin.org fixes issue #46, the following test is commented
|
||||||
for (auto path : paths) {
|
// out. Plese see https://httpbin.org/digest-auth/auth/hello/world
|
||||||
auto res = cli.Get(path.c_str());
|
// cli.set_digest_auth("bad", "world");
|
||||||
ASSERT_TRUE(res != nullptr);
|
// for (auto path : paths) {
|
||||||
EXPECT_EQ(400, res->status);
|
// auto res = cli.Get(path.c_str());
|
||||||
}
|
// ASSERT_TRUE(res != nullptr);
|
||||||
|
// EXPECT_EQ(400, res->status);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -724,6 +726,39 @@ TEST(RedirectToDifferentPort, Redirect) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TEST(Server, BindDualStack) {
|
||||||
|
Server svr;
|
||||||
|
|
||||||
|
svr.Get("/1", [&](const Request & /*req*/, Response &res) {
|
||||||
|
res.set_content("Hello World!", "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
auto thread = std::thread([&]() { svr.listen("::", PORT); });
|
||||||
|
|
||||||
|
// Give GET time to get a few messages.
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
|
||||||
|
{
|
||||||
|
Client cli("127.0.0.1", PORT);
|
||||||
|
|
||||||
|
auto res = cli.Get("/1");
|
||||||
|
ASSERT_TRUE(res != nullptr);
|
||||||
|
EXPECT_EQ(200, res->status);
|
||||||
|
EXPECT_EQ(res->body, "Hello World!");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Client cli("::1", PORT);
|
||||||
|
|
||||||
|
auto res = cli.Get("/1");
|
||||||
|
ASSERT_TRUE(res != nullptr);
|
||||||
|
EXPECT_EQ(200, res->status);
|
||||||
|
EXPECT_EQ(res->body, "Hello World!");
|
||||||
|
}
|
||||||
|
svr.stop();
|
||||||
|
thread.join();
|
||||||
|
ASSERT_FALSE(svr.is_running());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Server, BindAndListenSeparately) {
|
TEST(Server, BindAndListenSeparately) {
|
||||||
Server svr;
|
Server svr;
|
||||||
int port = svr.bind_to_any_port("0.0.0.0");
|
int port = svr.bind_to_any_port("0.0.0.0");
|
||||||
@@ -1749,9 +1784,8 @@ TEST_F(ServerTest, GetStreamedEndless) {
|
|||||||
|
|
||||||
TEST_F(ServerTest, ClientStop) {
|
TEST_F(ServerTest, ClientStop) {
|
||||||
thread t = thread([&]() {
|
thread t = thread([&]() {
|
||||||
auto res =
|
auto res = cli_.Get("/streamed-cancel",
|
||||||
cli_.Get("/streamed-cancel",
|
[&](const char *, uint64_t) { return true; });
|
||||||
[&](const char *, uint64_t) { return true; });
|
|
||||||
ASSERT_TRUE(res == nullptr);
|
ASSERT_TRUE(res == nullptr);
|
||||||
});
|
});
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
@@ -2056,6 +2090,9 @@ TEST_F(ServerTest, KeepAlive) {
|
|||||||
Get(requests, "/hi");
|
Get(requests, "/hi");
|
||||||
Get(requests, "/not-exist");
|
Get(requests, "/not-exist");
|
||||||
Post(requests, "/empty", "", "text/plain");
|
Post(requests, "/empty", "", "text/plain");
|
||||||
|
Post(
|
||||||
|
requests, "/empty", 0, [&](size_t, size_t, httplib::DataSink &) {},
|
||||||
|
"text/plain");
|
||||||
|
|
||||||
std::vector<Response> responses;
|
std::vector<Response> responses;
|
||||||
auto ret = cli_.send(requests, responses);
|
auto ret = cli_.send(requests, responses);
|
||||||
@@ -2075,8 +2112,8 @@ TEST_F(ServerTest, KeepAlive) {
|
|||||||
EXPECT_EQ(404, res.status);
|
EXPECT_EQ(404, res.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
for (size_t i = 4; i < 6; i++) {
|
||||||
auto &res = responses[4];
|
auto &res = responses[i];
|
||||||
EXPECT_EQ(200, res.status);
|
EXPECT_EQ(200, res.status);
|
||||||
EXPECT_EQ("text/plain", res.get_header_value("Content-Type"));
|
EXPECT_EQ("text/plain", res.get_header_value("Content-Type"));
|
||||||
EXPECT_EQ("empty", res.body);
|
EXPECT_EQ("empty", res.body);
|
||||||
@@ -2341,7 +2378,8 @@ TEST(ServerRequestParsingTest, ExcessiveWhitespaceInUnparseableHeaderLine) {
|
|||||||
// began.
|
// began.
|
||||||
// The crash occurs with libc++ but not libstdc++.
|
// The crash occurs with libc++ but not libstdc++.
|
||||||
test_raw_request("GET /hi HTTP/1.1\r\n"
|
test_raw_request("GET /hi HTTP/1.1\r\n"
|
||||||
"a:" + std::string(2000, ' ') + '\r' + std::string(20, 'z') +
|
"a:" +
|
||||||
|
std::string(2000, ' ') + '\r' + std::string(20, 'z') +
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"\r\n");
|
"\r\n");
|
||||||
}
|
}
|
||||||
@@ -2386,6 +2424,11 @@ TEST(ServerRequestParsingTest, ChunkLengthTooHighInRequest) {
|
|||||||
EXPECT_EQ("HTTP/1.1 400 Bad Request", out.substr(0, 24));
|
EXPECT_EQ("HTTP/1.1 400 Bad Request", out.substr(0, 24));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ServerRequestParsingTest, InvalidHeaderTextWithExtraCR) {
|
||||||
|
test_raw_request("GET /hi HTTP/1.1\r\n"
|
||||||
|
"Content-Type: text/plain\r\n\r");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ServerStopTest, StopServerWithChunkedTransmission) {
|
TEST(ServerStopTest, StopServerWithChunkedTransmission) {
|
||||||
Server svr;
|
Server svr;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user