I'm developing a local client-server application in C++. Client requires to Server a binary file to be sent, through a POST request. Based on the code available on this repository https://github.com/eidheim/Simple-Web-Server I've implemented my own test version:
#include "server_https.hpp"
#include "client_https.hpp"
#include <future>
// Added for the json-example
#define BOOST_SPIRIT_THREADSAFE
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
// Added for the default_resource example
#include "crypto.hpp"
#include <algorithm>
#include <boost/filesystem.hpp>
#include <fstream>
#include <vector>
#include <sys/stat.h>
using namespace std;
// Added for the json-example:
using namespace boost::property_tree;
using HttpsServer = SimpleWeb::Server<SimpleWeb::HTTPS>;
using HttpsClient = SimpleWeb::Client<SimpleWeb::HTTPS>;
typedef unsigned char BYTE;
std::vector<BYTE> readFile(const char* filename){
// open the file:
std::streampos fileSize;
std::ifstream file(filename, std::ios::binary);
if ( !file )
std::cout << std::strerror(errno) << '\n';
// get its size:
file.seekg(0, std::ios::end);
fileSize = file.tellg();
file.seekg(0, std::ios::beg);
// read the data:
std::vector<BYTE> fileData(fileSize);
file.read((char*) &fileData[0], fileSize);
return fileData;
}
int main() {
HttpsServer server("/cert/CA/localhost/localhost.crt", "/cert/CA/localhost/localhost.key");
server.config.port = 8080;
server.resource["^/file$"]["POST"] = [](std::shared_ptr<HttpsServer::Response> response, std::shared_ptr<HttpsServer::Request> request) {
auto binaryFile = readFile("../source/Directory.zip");
stringstream stream;
stream << "HTTP/1.1 200 OK\r\n" << "Content-Length: " << binaryFile.size()*sizeof(BYTE) << "\r\n\r\n" << "Content: ";
stream.write( (char*) &binaryFile[0], sizeof(BYTE)*binaryFile.size() );
response->write(stream);
};
promise<unsigned short> server_port;
thread server_thread([&server, &server_port]() {
server.start([&server_port](unsigned short port) {
server_port.set_value(port);
});
});
cout << "Server listening on port " << server_port.get_future().get() << endl<< endl;
{
string json_string = "{\"zipFile\": \"SimpleZipFile\"}";
HttpsClient client("localhost:8080", false);
try {
cout << "Example POST request to https://localhost:8080/file" << endl;
auto r2 = client.request("POST", "/file", json_string);
cout << "Post request correcly done" << endl << endl;
std::string payload = r2->content.string();
std::size_t found = payload.find("Content: ");
payload.erase(0,found+9);
std::ofstream destFile;
destFile.open("../destination/Directory.zip", std::ios::out | std::ios::binary);
if ( !destFile )
std::cout << std::strerror(errno) << '\n';
destFile.write( payload.c_str(), payload.size() );
destFile.close();
}
catch(const SimpleWeb::system_error &e) {
cerr << "Client request error: " << e.what() << endl;
}
}
server_thread.join();
}
Everything works fine, but actually I would like to change this code to allowing data transfer with Chunked transfer encoding.
I understand theoretically how Chunked transfer encoding work, but It's not clear how implementing it. Server has to sent an unknown number of chunks to client, but when response->write(chunck)
is invoked just the first chunck would be transmitted and server will end the post request handling.
How can I send multiple chuncks?