Fixes #33
This commit is contained in:
parent
99204ec73d
commit
ef7f4692a4
3 changed files with 97 additions and 63 deletions
144
client_http.hpp
144
client_http.hpp
|
|
@ -2,6 +2,7 @@
|
||||||
#define CLIENT_HTTP_HPP
|
#define CLIENT_HTTP_HPP
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/utility/string_ref.hpp>
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
@ -26,11 +27,38 @@ namespace SimpleWeb {
|
||||||
|
|
||||||
Response(): content(&content_buffer) {};
|
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>()) {
|
const std::map<std::string, std::string>& header=std::map<std::string, std::string>()) {
|
||||||
std::stringstream empty_ss;
|
std::string corrected_path=path;
|
||||||
return request(request_type, path, empty_ss, header);
|
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,
|
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";
|
write_stream << h.first << ": " << h.second << "\r\n";
|
||||||
}
|
}
|
||||||
if(content_length>0)
|
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";
|
write_stream << "\r\n";
|
||||||
if(content_length>0)
|
if(content_length>0)
|
||||||
write_stream << content.rdbuf();
|
write_stream << content.rdbuf();
|
||||||
|
|
||||||
std::shared_ptr<Response> response(new Response());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
connect();
|
connect();
|
||||||
|
|
||||||
boost::asio::write(*socket, write_buffer);
|
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) {
|
catch(const std::exception& e) {
|
||||||
socket_error=true;
|
socket_error=true;
|
||||||
throw std::invalid_argument(e.what());
|
throw std::invalid_argument(e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return request_read();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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>
|
template<class socket_type>
|
||||||
|
|
|
||||||
|
|
@ -145,13 +145,11 @@ int main() {
|
||||||
auto r1=client.request("GET", "/match/123");
|
auto r1=client.request("GET", "/match/123");
|
||||||
cout << r1->content.rdbuf() << endl;
|
cout << r1->content.rdbuf() << endl;
|
||||||
|
|
||||||
string json="{\"firstName\": \"John\",\"lastName\": \"Smith\",\"age\": 25}";
|
string json_string="{\"firstName\": \"John\",\"lastName\": \"Smith\",\"age\": 25}";
|
||||||
stringstream ss(json);
|
auto r2=client.request("POST", "/string", json_string);
|
||||||
auto r2=client.request("POST", "/string", ss);
|
|
||||||
cout << r2->content.rdbuf() << endl;
|
cout << r2->content.rdbuf() << endl;
|
||||||
|
|
||||||
ss.str(json);
|
auto r3=client.request("POST", "/json", json_string);
|
||||||
auto r3=client.request("POST", "/json", ss);
|
|
||||||
cout << r3->content.rdbuf() << endl;
|
cout << r3->content.rdbuf() << endl;
|
||||||
|
|
||||||
server_thread.join();
|
server_thread.join();
|
||||||
|
|
|
||||||
|
|
@ -146,13 +146,11 @@ int main() {
|
||||||
auto r1=client.request("GET", "/match/123");
|
auto r1=client.request("GET", "/match/123");
|
||||||
cout << r1->content.rdbuf() << endl;
|
cout << r1->content.rdbuf() << endl;
|
||||||
|
|
||||||
string json="{\"firstName\": \"John\",\"lastName\": \"Smith\",\"age\": 25}";
|
string json_string="{\"firstName\": \"John\",\"lastName\": \"Smith\",\"age\": 25}";
|
||||||
stringstream ss(json);
|
auto r2=client.request("POST", "/string", json_string);
|
||||||
auto r2=client.request("POST", "/string", ss);
|
|
||||||
cout << r2->content.rdbuf() << endl;
|
cout << r2->content.rdbuf() << endl;
|
||||||
|
|
||||||
ss.str(json);
|
auto r3=client.request("POST", "/json", json_string);
|
||||||
auto r3=client.request("POST", "/json", ss);
|
|
||||||
cout << r3->content.rdbuf() << endl;
|
cout << r3->content.rdbuf() << endl;
|
||||||
|
|
||||||
server_thread.join();
|
server_thread.join();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue