This commit is contained in:
eidheim 2016-01-06 12:45:21 +01:00
commit ef7f4692a4
3 changed files with 97 additions and 63 deletions

View file

@ -2,6 +2,7 @@
#define CLIENT_HTTP_HPP
#include <boost/asio.hpp>
#include <boost/utility/string_ref.hpp>
#include <unordered_map>
#include <map>
@ -26,11 +27,38 @@ namespace SimpleWeb {
Response(): content(&content_buffer) {};
};
std::shared_ptr<Response> request(const std::string& request_type, const std::string& path="/",
std::shared_ptr<Response> request(const std::string& request_type, const std::string& path="/", boost::string_ref content="",
const std::map<std::string, std::string>& header=std::map<std::string, std::string>()) {
std::stringstream empty_ss;
return request(request_type, path, empty_ss, header);
std::string corrected_path=path;
if(corrected_path=="")
corrected_path="/";
boost::asio::streambuf write_buffer;
std::ostream write_stream(&write_buffer);
write_stream << request_type << " " << corrected_path << " HTTP/1.1\r\n";
write_stream << "Host: " << host << "\r\n";
for(auto& h: header) {
write_stream << h.first << ": " << h.second << "\r\n";
}
if(content.size()>0)
write_stream << "Content-Length: " << content.size() << "\r\n";
write_stream << "\r\n";
try {
connect();
boost::asio::write(*socket, write_buffer);
if(content.size()>0)
boost::asio::write(*socket, boost::asio::buffer(content.data(), content.size()));
}
catch(const std::exception& e) {
socket_error=true;
throw std::invalid_argument(e.what());
}
return request_read();
}
std::shared_ptr<Response> request(const std::string& request_type, const std::string& path, std::iostream& content,
@ -51,68 +79,22 @@ namespace SimpleWeb {
write_stream << h.first << ": " << h.second << "\r\n";
}
if(content_length>0)
write_stream << "Content-Length: " << std::to_string(content_length) << "\r\n";
write_stream << "Content-Length: " << content_length << "\r\n";
write_stream << "\r\n";
if(content_length>0)
write_stream << content.rdbuf();
std::shared_ptr<Response> response(new Response());
try {
connect();
boost::asio::write(*socket, write_buffer);
size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n\r\n");
size_t num_additional_bytes=response->content_buffer.size()-bytes_transferred;
parse_response_header(response, response->content);
if(response->header.count("Content-Length")>0) {
boost::asio::read(*socket, response->content_buffer,
boost::asio::transfer_exactly(stoull(response->header["Content-Length"])-num_additional_bytes));
}
else if(response->header.count("Transfer-Encoding")>0 && response->header["Transfer-Encoding"]=="chunked") {
boost::asio::streambuf streambuf;
std::ostream content(&streambuf);
size_t length;
std::string buffer;
do {
size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n");
std::string line;
getline(response->content, line);
bytes_transferred-=line.size()+1;
line.pop_back();
length=stoull(line, 0, 16);
size_t num_additional_bytes=response->content_buffer.size()-bytes_transferred;
if((2+length)>num_additional_bytes) {
boost::asio::read(*socket, response->content_buffer,
boost::asio::transfer_exactly(2+length-num_additional_bytes));
}
buffer.resize(length);
response->content.read(&buffer[0], length);
content.write(&buffer[0], length);
//Remove "\r\n"
response->content.get();
response->content.get();
} while(length>0);
std::ostream response_content_output_stream(&response->content_buffer);
response_content_output_stream << content.rdbuf();
}
}
catch(const std::exception& e) {
socket_error=true;
throw std::invalid_argument(e.what());
}
return response;
return request_read();
}
protected:
@ -168,6 +150,62 @@ namespace SimpleWeb {
}
}
}
std::shared_ptr<Response> request_read() {
std::shared_ptr<Response> response(new Response());
try {
size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n\r\n");
size_t num_additional_bytes=response->content_buffer.size()-bytes_transferred;
parse_response_header(response, response->content);
if(response->header.count("Content-Length")>0) {
boost::asio::read(*socket, response->content_buffer,
boost::asio::transfer_exactly(stoull(response->header["Content-Length"])-num_additional_bytes));
}
else if(response->header.count("Transfer-Encoding")>0 && response->header["Transfer-Encoding"]=="chunked") {
boost::asio::streambuf streambuf;
std::ostream content(&streambuf);
size_t length;
std::string buffer;
do {
size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n");
std::string line;
getline(response->content, line);
bytes_transferred-=line.size()+1;
line.pop_back();
length=stoull(line, 0, 16);
size_t num_additional_bytes=response->content_buffer.size()-bytes_transferred;
if((2+length)>num_additional_bytes) {
boost::asio::read(*socket, response->content_buffer,
boost::asio::transfer_exactly(2+length-num_additional_bytes));
}
buffer.resize(length);
response->content.read(&buffer[0], length);
content.write(&buffer[0], length);
//Remove "\r\n"
response->content.get();
response->content.get();
} while(length>0);
std::ostream response_content_output_stream(&response->content_buffer);
response_content_output_stream << content.rdbuf();
}
}
catch(const std::exception& e) {
socket_error=true;
throw std::invalid_argument(e.what());
}
return response;
}
};
template<class socket_type>

View file

@ -145,13 +145,11 @@ int main() {
auto r1=client.request("GET", "/match/123");
cout << r1->content.rdbuf() << endl;
string json="{\"firstName\": \"John\",\"lastName\": \"Smith\",\"age\": 25}";
stringstream ss(json);
auto r2=client.request("POST", "/string", ss);
string json_string="{\"firstName\": \"John\",\"lastName\": \"Smith\",\"age\": 25}";
auto r2=client.request("POST", "/string", json_string);
cout << r2->content.rdbuf() << endl;
ss.str(json);
auto r3=client.request("POST", "/json", ss);
auto r3=client.request("POST", "/json", json_string);
cout << r3->content.rdbuf() << endl;
server_thread.join();

View file

@ -146,13 +146,11 @@ int main() {
auto r1=client.request("GET", "/match/123");
cout << r1->content.rdbuf() << endl;
string json="{\"firstName\": \"John\",\"lastName\": \"Smith\",\"age\": 25}";
stringstream ss(json);
auto r2=client.request("POST", "/string", ss);
string json_string="{\"firstName\": \"John\",\"lastName\": \"Smith\",\"age\": 25}";
auto r2=client.request("POST", "/string", json_string);
cout << r2->content.rdbuf() << endl;
ss.str(json);
auto r3=client.request("POST", "/json", ss);
auto r3=client.request("POST", "/json", json_string);
cout << r3->content.rdbuf() << endl;
server_thread.join();