I\'m adding HTTPS support to code that does input and output using boost tcp::iostream (acting as an HTTP server).
I\'ve found examples (and have a working toy HTTPS
ssl::stream could be wrapped with boost::iostreams / bidirectional to mimic similar behaviours as tcp::iostream. flushing output before further reading seems cannot be avoided.
#include
#include
#include
#include
#include
#include
namespace bios = boost::iostreams;
namespace asio = boost::asio;
namespace ssl = boost::asio::ssl;
using std::string;
using boost::asio::ip::tcp;
using boost::system::system_error;
using boost::system::error_code;
int parse_url(const std::string &s,
std::string& proto, std::string& host, std::string& path)
{
std::smatch m;
bool found = regex_search(s, m, std::regex("^(http[s]?)://([^/]*)(.*)$"));
if (m.size() != 4)
return -1;
proto = m[1].str();
host = m[2].str();
path = m[3].str();
return 0;
}
void get_page(std::iostream& s, const string& host, const string& path)
{
s << "GET " << path << " HTTP/1.0\r\n"
<< "Host: " << host << "\r\n"
<< "Accept: */*\r\n"
<< "Connection: close\r\n\r\n" << std::flush;
std::cout << s.rdbuf() << std::endl;;
}
typedef ssl::stream ssl_socket;
class ssl_wrapper : public bios::device
{
ssl_socket& sock;
public:
typedef char char_type;
ssl_wrapper(ssl_socket& sock) : sock(sock) {}
std::streamsize read(char_type* s, std::streamsize n) {
error_code ec;
auto rc = asio::read(sock, asio::buffer(s,n), ec);
return rc;
}
std::streamsize write(const char_type* s, std::streamsize n) {
return asio::write(sock, asio::buffer(s,n));
}
};
int main(int argc, char* argv[])
{
std::string proto, host, path;
if (argc!= 2 || parse_url(argv[1], proto, host, path)!=0)
return EXIT_FAILURE;
try {
if (proto != "https") {
tcp::iostream s(host, proto);
s.expires_from_now(boost::posix_time::seconds(60));
get_page(s, host, path);
} else {
asio::io_service ios;
tcp::resolver resolver(ios);
tcp::resolver::query query(host, "https");
tcp::resolver::iterator endpoint_iterator =
resolver.resolve(query);
ssl::context ctx(ssl::context::sslv23);
ctx.set_default_verify_paths();
ssl_socket socket(ios, ctx);
asio::connect(socket.lowest_layer(), endpoint_iterator);
socket.set_verify_mode(ssl::verify_none);
socket.set_verify_callback(ssl::rfc2818_verification(host));
socket.handshake(ssl_socket::client);
bios::stream ss(socket);
get_page(ss, host, path);
}
} catch (const std::exception& e) {
std::cout << "Exception: " << e.what() << "\n";
}
}