Compare commits

..

6 Commits

Author SHA1 Message Date
yhirose 5e6f973b99 Release v0.10.9 2022-07-08 17:40:05 -04:00
yhirose 7ed77b02ad Disable YouTubeNoSSLDigest 2022-07-08 17:40:05 -04:00
yhirose 127a64d5a0 Skip preamble and epilogue in multipart/form-data (Fix #1317) (#1320)
* fix: skip MIME preamble (#1317)

* Skip epilogue in multipart/form-data

Co-authored-by: Gavin1937 <71205842+Gavin1937@users.noreply.github.com>
2022-07-08 17:26:50 -04:00
yhirose caa31aafda Accept large data transfer over SSL (Fix #1261, Close #1312) 2022-07-02 07:50:33 -04:00
yhirose dae318495f Revert "Accept large data transfer over SSL (#1261)"
This reverts commit 307b729549.
2022-07-02 07:18:59 -04:00
Andrea Pappacoda 305a7abcb9 fix: update CPPHTTPLIB_VERSION to 0.10.8 (#1305) 2022-06-08 16:44:10 -04:00
3 changed files with 108 additions and 58 deletions
+55 -53
View File
@@ -8,7 +8,7 @@
#ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_VERSION "0.10.7"
#define CPPHTTPLIB_VERSION "0.10.9"
/*
* Configuration
@@ -193,7 +193,6 @@ using socket_t = int;
#endif
#endif //_WIN32
#include <cstring>
#include <algorithm>
#include <array>
#include <atomic>
@@ -201,6 +200,7 @@ using socket_t = int;
#include <cctype>
#include <climits>
#include <condition_variable>
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <fstream>
@@ -3794,6 +3794,7 @@ public:
switch (state_) {
case 0: { // Initial boundary
auto pattern = dash_ + boundary_ + crlf_;
buf_erase(buf_find(pattern));
if (pattern.size() > buf_size()) { return true; }
if (!buf_start_with(pattern)) { return false; }
buf_erase(pattern.size());
@@ -3887,17 +3888,13 @@ public:
if (buf_start_with(pattern)) {
buf_erase(pattern.size());
is_valid_ = true;
state_ = 5;
buf_erase(buf_size()); // Remove epilogue
} else {
return true;
}
}
break;
}
case 5: { // Done
is_valid_ = false;
return false;
}
}
}
@@ -5098,14 +5095,16 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
// Flush buffer
auto &data = bstrm.get_buffer();
strm.write(data.data(), data.size());
detail::write_data(strm, data.data(), data.size());
}
// Body
auto ret = true;
if (req.method != "HEAD") {
if (!res.body.empty()) {
if (!strm.write(res.body)) { ret = false; }
if (!detail::write_data(strm, res.body.data(), res.body.size())) {
ret = false;
}
} else if (res.content_provider_) {
if (write_content_with_provider(strm, req, res, boundary, content_type)) {
res.content_provider_success_ = true;
@@ -6322,7 +6321,8 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
auto last = offset + data_len == content_length;
auto ret = compressor.compress(
data, data_len, last, [&](const char *compressed_data, size_t compressed_data_len) {
data, data_len, last,
[&](const char *compressed_data, size_t compressed_data_len) {
req.body.append(compressed_data, compressed_data_len);
return true;
});
@@ -7228,63 +7228,65 @@ inline bool SSLSocketStream::is_writable() const {
}
inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
size_t readbytes = 0;
if (SSL_pending(ssl_) > 0) {
auto ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
if (ret == 1) { return static_cast<ssize_t>(readbytes); }
if (SSL_get_error(ssl_, ret) == SSL_ERROR_ZERO_RETURN) { return 0; }
return -1;
}
if (!is_readable()) { return -1; }
auto ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
if (ret == 1) { return static_cast<ssize_t>(readbytes); }
auto err = SSL_get_error(ssl_, ret);
int n = 1000;
return SSL_read(ssl_, ptr, static_cast<int>(size));
} else if (is_readable()) {
auto ret = SSL_read(ssl_, ptr, static_cast<int>(size));
if (ret < 0) {
auto err = SSL_get_error(ssl_, ret);
int n = 1000;
#ifdef _WIN32
while (--n >= 0 &&
(err == SSL_ERROR_WANT_READ ||
(err == SSL_ERROR_SYSCALL && WSAGetLastError() == WSAETIMEDOUT))) {
while (--n >= 0 && (err == SSL_ERROR_WANT_READ ||
(err == SSL_ERROR_SYSCALL &&
WSAGetLastError() == WSAETIMEDOUT))) {
#else
while (--n >= 0 && err == SSL_ERROR_WANT_READ) {
while (--n >= 0 && err == SSL_ERROR_WANT_READ) {
#endif
if (SSL_pending(ssl_) > 0) {
ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
if (ret == 1) { return static_cast<ssize_t>(readbytes); }
if (SSL_get_error(ssl_, ret) == SSL_ERROR_ZERO_RETURN) { return 0; }
return -1;
if (SSL_pending(ssl_) > 0) {
return SSL_read(ssl_, ptr, static_cast<int>(size));
} else if (is_readable()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
ret = SSL_read(ssl_, ptr, static_cast<int>(size));
if (ret >= 0) { return ret; }
err = SSL_get_error(ssl_, ret);
} else {
return -1;
}
}
}
if (!is_readable()) { return -1; }
std::this_thread::sleep_for(std::chrono::milliseconds(1));
ret = SSL_read_ex(ssl_, ptr, size, &readbytes);
if (ret == 1) { return static_cast<ssize_t>(readbytes); }
err = SSL_get_error(ssl_, ret);
return ret;
}
if (err == SSL_ERROR_ZERO_RETURN) { return 0; }
return -1;
}
inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
if (!is_writable()) { return -1; }
size_t written = 0;
auto ret = SSL_write_ex(ssl_, ptr, size, &written);
if (ret == 1) { return static_cast<ssize_t>(written); }
auto err = SSL_get_error(ssl_, ret);
int n = 1000;
if (is_writable()) {
auto handle_size = static_cast<int>(
std::min<size_t>(size, std::numeric_limits<int>::max()));
auto ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
if (ret < 0) {
auto err = SSL_get_error(ssl_, ret);
int n = 1000;
#ifdef _WIN32
while (--n >= 0 &&
(err == SSL_ERROR_WANT_WRITE ||
(err == SSL_ERROR_SYSCALL && WSAGetLastError() == WSAETIMEDOUT))) {
while (--n >= 0 && (err == SSL_ERROR_WANT_WRITE ||
(err == SSL_ERROR_SYSCALL &&
WSAGetLastError() == WSAETIMEDOUT))) {
#else
while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
#endif
if (!is_writable()) { return -1; }
std::this_thread::sleep_for(std::chrono::milliseconds(1));
ret = SSL_write_ex(ssl_, ptr, size, &written);
if (ret == 1) { return static_cast<ssize_t>(written); }
err = SSL_get_error(ssl_, ret);
if (is_writable()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
if (ret >= 0) { return ret; }
err = SSL_get_error(ssl_, ret);
} else {
return -1;
}
}
}
return ret;
}
if (err == SSL_ERROR_ZERO_RETURN) { return 0; }
return -1;
}
+52 -4
View File
@@ -3015,8 +3015,10 @@ TEST(GzipDecompressor, ChunkedDecompression) {
httplib::detail::gzip_compressor compressor;
bool result = compressor.compress(
data.data(), data.size(),
/*last=*/true, [&](const char *compressed_data_chunk, size_t compressed_data_size) {
compressed_data.insert(compressed_data.size(), compressed_data_chunk, compressed_data_size);
/*last=*/true,
[&](const char *compressed_data_chunk, size_t compressed_data_size) {
compressed_data.insert(compressed_data.size(), compressed_data_chunk,
compressed_data_size);
return true;
});
ASSERT_TRUE(result);
@@ -3035,8 +3037,11 @@ TEST(GzipDecompressor, ChunkedDecompression) {
std::min(compressed_data.size() - chunk_begin, chunk_size);
bool result = decompressor.decompress(
compressed_data.data() + chunk_begin, current_chunk_size,
[&](const char *decompressed_data_chunk, size_t decompressed_data_chunk_size) {
decompressed_data.insert(decompressed_data.size(), decompressed_data_chunk, decompressed_data_chunk_size);
[&](const char *decompressed_data_chunk,
size_t decompressed_data_chunk_size) {
decompressed_data.insert(decompressed_data.size(),
decompressed_data_chunk,
decompressed_data_chunk_size);
return true;
});
ASSERT_TRUE(result);
@@ -4974,5 +4979,48 @@ TEST(MultipartFormDataTest, LargeData) {
svr.stop();
t.join();
}
TEST(MultipartFormDataTest, WithPreamble) {
Server svr;
svr.Post("/post", [&](const Request &req, Response &res) {
res.set_content("ok", "text/plain");
});
thread t = thread([&] { svr.listen(HOST, PORT); });
while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
const std::string body =
"This is the preamble. It is to be ignored, though it\r\n"
"is a handy place for composition agents to include an\r\n"
"explanatory note to non-MIME conformant readers.\r\n"
"\r\n"
"\r\n"
"--simple boundary\r\n"
"Content-Disposition: form-data; name=\"field1\"\r\n"
"\r\n"
"value1\r\n"
"--simple boundary\r\n"
"Content-Disposition: form-data; name=\"field2\"; "
"filename=\"example.txt\"\r\n"
"\r\n"
"value2\r\n"
"--simple boundary--\r\n"
"This is the epilogue. It is also to be ignored.\r\n";
std::string content_type =
R"(multipart/form-data; boundary="simple boundary")";
Client cli(HOST, PORT);
auto res = cli.Post("/post", body, content_type.c_str());
ASSERT_TRUE(res);
EXPECT_EQ(200, res->status);
svr.stop();
t.join();
}
#endif
+1 -1
View File
@@ -82,7 +82,7 @@ TEST(RedirectTest, YouTubeNoSSLBasic) {
RedirectProxyText(cli, "/", true);
}
TEST(RedirectTest, YouTubeNoSSLDigest) {
TEST(RedirectTest, DISABLED_YouTubeNoSSLDigest) {
Client cli("youtube.com");
RedirectProxyText(cli, "/", false);
}