mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-15 10:39:37 +00:00
Add make_file_body
This commit is contained in:
1 parent
b4d16a582d
commit
c53d93d145
3 files changed
+76
-1
No files matched your search
@@ -989,7 +989,7 @@ httplib::UploadFormDataItems items = {
|
|||||||
auto res = cli.Post("/multipart", items);
|
auto res = cli.Post("/multipart", items);
|
||||||
```
|
```
|
||||||
|
|
||||||
To upload files from disk without loading them entirely into memory, use `make_file_provider`. The file is read and sent in chunks with a correct `Content-Length` header.
|
To upload files from disk without loading them entirely into memory, use `make_file_provider`. The file is sent with chunked transfer encoding.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
httplib::FormDataProviderItems providers = {
|
httplib::FormDataProviderItems providers = {
|
||||||
@@ -1000,6 +1000,15 @@ httplib::FormDataProviderItems providers = {
|
|||||||
auto res = cli.Post("/upload", {}, {}, providers);
|
auto res = cli.Post("/upload", {}, {}, providers);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### POST with a file body
|
||||||
|
|
||||||
|
To POST a file as a raw binary body with `Content-Length`, use `make_file_body`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto [size, provider] = httplib::make_file_body("/path/to/data.bin");
|
||||||
|
auto res = cli.Post("/upload", size, provider, "application/octet-stream");
|
||||||
|
```
|
||||||
|
|
||||||
### PUT
|
### PUT
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
|
|||||||
@@ -1042,6 +1042,32 @@ make_file_provider(const std::string &name, const std::string &filepath,
|
|||||||
return fdp;
|
return fdp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::pair<size_t, ContentProvider>
|
||||||
|
make_file_body(const std::string &filepath) {
|
||||||
|
std::ifstream f(filepath, std::ios::binary | std::ios::ate);
|
||||||
|
if (!f) { return {0, ContentProvider{}}; }
|
||||||
|
auto size = static_cast<size_t>(f.tellg());
|
||||||
|
|
||||||
|
ContentProvider provider = [filepath](size_t offset, size_t length,
|
||||||
|
DataSink &sink) -> bool {
|
||||||
|
std::ifstream f(filepath, std::ios::binary);
|
||||||
|
if (!f) { return false; }
|
||||||
|
f.seekg(static_cast<std::streamoff>(offset));
|
||||||
|
if (!f.good()) { return false; }
|
||||||
|
char buf[8192];
|
||||||
|
while (length > 0) {
|
||||||
|
auto to_read = (std::min)(sizeof(buf), length);
|
||||||
|
f.read(buf, static_cast<std::streamsize>(to_read));
|
||||||
|
auto n = static_cast<size_t>(f.gcount());
|
||||||
|
if (n == 0) { break; }
|
||||||
|
if (!sink.write(buf, n)) { return false; }
|
||||||
|
length -= n;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return {size, std::move(provider)};
|
||||||
|
}
|
||||||
|
|
||||||
using ContentReceiverWithProgress = std::function<bool(
|
using ContentReceiverWithProgress = std::function<bool(
|
||||||
const char *data, size_t data_length, size_t offset, size_t total_length)>;
|
const char *data, size_t data_length, size_t offset, size_t total_length)>;
|
||||||
|
|
||||||
|
|||||||
@@ -11821,6 +11821,46 @@ TEST(MultipartFormDataTest, MakeFileProvider) {
|
|||||||
EXPECT_EQ(StatusCode::OK_200, res->status);
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(MakeFileBodyTest, Basic) {
|
||||||
|
const std::string file_content(4096, 'Z');
|
||||||
|
const std::string tmp_path = "/tmp/httplib_test_make_file_body.bin";
|
||||||
|
{
|
||||||
|
std::ofstream ofs(tmp_path, std::ios::binary);
|
||||||
|
ofs.write(file_content.data(),
|
||||||
|
static_cast<std::streamsize>(file_content.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto handled = false;
|
||||||
|
|
||||||
|
Server svr;
|
||||||
|
svr.Post("/upload", [&](const Request &req, Response &res) {
|
||||||
|
EXPECT_EQ(file_content, req.body);
|
||||||
|
handled = true;
|
||||||
|
res.status = StatusCode::OK_200;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto port = svr.bind_to_any_port(HOST);
|
||||||
|
auto t = thread([&] { svr.listen_after_bind(); });
|
||||||
|
auto se = detail::scope_exit([&] {
|
||||||
|
svr.stop();
|
||||||
|
t.join();
|
||||||
|
ASSERT_FALSE(svr.is_running());
|
||||||
|
ASSERT_TRUE(handled);
|
||||||
|
std::remove(tmp_path.c_str());
|
||||||
|
});
|
||||||
|
|
||||||
|
svr.wait_until_ready();
|
||||||
|
|
||||||
|
auto fb = make_file_body(tmp_path);
|
||||||
|
ASSERT_GT(fb.first, 0u);
|
||||||
|
|
||||||
|
Client cli(HOST, port);
|
||||||
|
auto res =
|
||||||
|
cli.Post("/upload", fb.first, fb.second, "application/octet-stream");
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(TaskQueueTest, IncreaseAtomicInteger) {
|
TEST(TaskQueueTest, IncreaseAtomicInteger) {
|
||||||
static constexpr unsigned int number_of_tasks{1000000};
|
static constexpr unsigned int number_of_tasks{1000000};
|
||||||
std::atomic_uint count{0};
|
std::atomic_uint count{0};
|
||||||
|
|||||||
Reference in new issue
Block a user