I'm trying to send a file with POST request but every time I get an empty body and absolutely no information about the file on the server side.
beast::http::request<beast::http::file_body> req;
req.method(beast::http::verb::post);
req.target(target);
req.set(beast::http::field::host, host);
req.set(beast::http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.body().open(inputFilePath.c_str(), beast::file_mode::scan, ec);
write(_stream, req);
From what I see this opens a file and uses write_some
to send a data. The number of bytes written is non-null... but where is it writing them to if the body on the server side is absolutely empty?
Multipart uploads are not a feature of Beast.
You can look at some inspiration here, though: https://github.com/boostorg/beast/pull/2381, e.g. example/http/client/sync/http_client_sync_post.cpp
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
using tcp = net::ip::tcp; // from <boost/asio/ip/tcp.hpp>
auto multi_part_post(std::filesystem::path fileName)
{
#define MULTI_PART_BOUNDARY \
"AaB03x" // This is the boundary to limit the start/end of a
// part. It may be any string. More info on the RFC
// 2388
// (https://datatracker.ietf.org/doc/html/rfc2388)
#define CRLF \
"\r\n" // Line ends must be CRLF
// https://datatracker.ietf.org/doc/html/rfc7231#section-3.1.1.4
http::request<http::string_body> req{
http::verb::post, "/post", 11};
req.set(http::field::host, "httpbin.org");
req.set(http::field::user_agent, "stackoverflow/sehe");
req.set(
http::field::content_type,
"multipart/form-data; boundary=" MULTI_PART_BOUNDARY);
// Prepare the multipart/form-data message
std::ostringstream payload;
payload
<< "--" MULTI_PART_BOUNDARY CRLF //
<< R"(Content-Disposition: form-data; name="comment")" //
<< CRLF CRLF "Multipart POST demo" CRLF << //
"--" MULTI_PART_BOUNDARY CRLF //
<< R"(Content-Disposition: form-data; name="files"; filename=)" //
<< fileName.filename() << CRLF //
<< "Content-Type: application/octet-stream" CRLF CRLF //
<< std::ifstream(fileName, std::ios::binary).rdbuf() //
<< CRLF << //
"--" MULTI_PART_BOUNDARY << "--" CRLF; //
// Allow Beast to set headers depending on HTTP version, verb and
// body
req.body() = std::move(payload).str();
req.prepare_payload();
return req;
#undef MULTI_PART_BOUNDARY
#undef CRLF
}
int main() {
auto req = multi_part_post("test.cpp");
std::cout << "Sending " << req << std::endl;
{ // will not work on COLIRU
net::io_context ioc;
beast::tcp_stream stream(ioc);
stream.connect(tcp::resolver(ioc).resolve("httpbin.org", "http"));
write(stream, req);
http::response<http::string_body> res;
beast::flat_buffer buffer;
read(stream, buffer, res);
std::cout << res << std::endl;
}
}