Skip to content

Instantly share code, notes, and snippets.

@microcai
Created September 4, 2019 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save microcai/0050b7d001ff6647ecada86b96552278 to your computer and use it in GitHub Desktop.
Save microcai/0050b7d001ff6647ecada86b96552278 to your computer and use it in GitHub Desktop.
HTTP/HTTPS beast wrapper
#include <iostream>
#include <optional>
#include <variant>
#include <boost/beast.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/asio/ssl/rfc2818_verification.hpp>
#include "easyhttp/easyhttp.hpp"
#include "./url_parser.hpp"
const char globaltrust_root[] = "-----BEGIN CERTIFICATE-----\n\
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n\
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n\
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n\
MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n\
YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n\
aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n\
jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n\
xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n\
1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n\
snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n\
U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n\
9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n\
BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n\
AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n\
yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n\
38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n\
AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n\
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n\
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n\
-----END CERTIFICATE-----\n\
";
const char globaltrust_c2[] = "-----BEGIN CERTIFICATE-----\n\
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G\n\
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp\n\
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1\n\
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG\n\
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n\
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL\n\
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8\n\
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq\n\
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\n\
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa\n\
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB\n\
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH\n\
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n\n\
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG\n\
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs\n\
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO\n\
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS\n\
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\n\
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7\n\
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n\
-----END CERTIFICATE-----\n\
";
const char globaltrust_c3[] = "-----BEGIN CERTIFICATE-----\n\
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n\
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n\
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n\
MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n\
YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n\
aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n\
jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n\
xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n\
1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n\
snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n\
U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n\
9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n\
BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n\
AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n\
yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n\
38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n\
AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n\
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n\
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n\
-----END CERTIFICATE-----\n\
";
const char server_cert[]= "-----BEGIN CERTIFICATE-----\n\
MIIGCTCCBPGgAwIBAgIMerD5hF8IkKUtKgHaMA0GCSqGSIb3DQEBCwUAMGAxCzAJ\n\
BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTYwNAYDVQQDEy1H\n\
bG9iYWxTaWduIERvbWFpbiBWYWxpZGF0aW9uIENBIC0gU0hBMjU2IC0gRzIwHhcN\n\
MTgxMTIzMDIwNjQ3WhcNMTkxMTI0MDIwNjQ3WjA9MSEwHwYDVQQLExhEb21haW4g\n\
Q29udHJvbCBWYWxpZGF0ZWQxGDAWBgNVBAMMDyouY2hhaW5zcGF5LmNvbTCCASIw\n\
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCboRPl07CqeKJ7gb9UZWJbdVW/\n\
SgrOfbEGYRleHoOkJtzn5oN4u8VpzzHEFLeO6scx/AwEKnjDLmfWjDaeVWs0XI4R\n\
jDZ/dshI6fjF+wR7I+hwWdh6OOi5qon/2d7VFpaFdN61Tv6vC7/WW5j9Fe/mxH4f\n\
2BT86/lpEdi86RPZO5DMCuOWg6xLUus5YlNci5YOk+luK40UV2k1c3MsH6RJ3Uin\n\
/S4Btk0kq/CCyFjhYLj7CAZP7Bq0Ada/8k0tWItCKZXkWKI4NyBDbJubSNz89Cqs\n\
sURDQETUppxSI4d6ip/+wPDW++SHprhksJZjZymBjLXkFFP+g/SObSrebQ8CAwEA\n\
AaOCAuQwggLgMA4GA1UdDwEB/wQEAwIFoDCBlAYIKwYBBQUHAQEEgYcwgYQwRwYI\n\
KwYBBQUHMAKGO2h0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dz\n\
ZG9tYWludmFsc2hhMmcycjEuY3J0MDkGCCsGAQUFBzABhi1odHRwOi8vb2NzcDIu\n\
Z2xvYmFsc2lnbi5jb20vZ3Nkb21haW52YWxzaGEyZzIwVgYDVR0gBE8wTTBBBgkr\n\
BgEEAaAyAQowNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5j\n\
b20vcmVwb3NpdG9yeS8wCAYGZ4EMAQIBMAkGA1UdEwQCMAAwQwYDVR0fBDwwOjA4\n\
oDagNIYyaHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9ncy9nc2RvbWFpbnZhbHNo\n\
YTJnMi5jcmwwKQYDVR0RBCIwIIIPKi5jaGFpbnNwYXkuY29tgg1jaGFpbnNwYXku\n\
Y29tMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUhwq2\n\
p71fYpGcPzWZDgQYvDhmvGMwHwYDVR0jBBgwFoAU6k581IAt5RWBhiaMgm3AmKTP\n\
lw8wggEDBgorBgEEAdZ5AgQCBIH0BIHxAO8AdgBVgdTCFpA2AUrqC5tXPFPwwOQ4\n\
eHAlCBcvo6odBxPTDAAAAWc+UdF8AAAEAwBHMEUCID7VN9kcxPlGbqGfU0js4rxZ\n\
HTH4MjjNIy6ft5nhoDLLAiEAmVk20rGBAo1Mw7mLHTK4lKHV2stkvAwJN3KWzKRO\n\
xUAAdQC72d+8H4pxtZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAWc+UdWkAAAE\n\
AwBGMEQCIGYalmq+zhPjUxgA16mBSSWMSN/K4oXSNU8GUE3Fq9bbAiA6fH5Br54R\n\
7AVmxDAChN3aw3PZG8/Rin39FHJcQu5JmzANBgkqhkiG9w0BAQsFAAOCAQEApNPO\n\
h9dbkrVv0qoHoE199eaUhpkr1oS3a4xF/5hONdnGCoELWelyUkEst33JVuYC4qQw\n\
tvYhKEwNSM5Q3Oww9td6d2GPl6NihUvNgQ3ECSyu76GXEoEQ7kQktv3jNTf4oKq+\n\
nEEIKlwWKDOaXmpBg1RQa3zN/tJchIqJw+ilpPQTyNZ1kdbS3BSLJh43PhCLignv\n\
4bWlxIN1VBK3iS8tMpNEQuXdTA7j8Dq8tKj5ox7fQSabe2IUi7bc13jA2eM59Uhs\n\
gzRM+iNGlFoBV3jMni+Ezhb2XGgCBaxiCpzRrUTsK7cL6lc+1vdlQUGySn9nX1Dr\n\
VFpDKCB+1I2uDuyn6Q==\n\
-----END CERTIFICATE-----\n\
";
static const char * http_code_str(int http_code)
{
switch(http_code)
{
case 200:
return "OK";
case 404:
return "NOT FOUND";
default:
return ""; // TODO
}
}
easyhttp::error::http_error::http_error(int http_code)
: runtime_error(http_code_str(http_code))
, http_code(http_code)
{
}
#ifdef __ANDROID__
#include <android/log.h>
//定义TAG之后,我们可以在LogCat通过TAG过滤出NDK打印的日志
#define TAG "keystore-native"
// 定义info信息
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
// 定义debug信息
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
// 定义error信息
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
#else
#define LOGE(...) do { printf(__VA_ARGS__); printf("\n") ; } while(false)
#endif
static std::string common_http_req(easyhttp::URL url, boost::beast::http::request<boost::beast::http::string_body>& req_)
{
try
{
boost::asio::io_context io;
boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::sslv23);
ssl_ctx.add_certificate_authority(boost::asio::buffer(globaltrust_root));
ssl_ctx.add_certificate_authority(boost::asio::buffer(globaltrust_c2));
ssl_ctx.add_certificate_authority(boost::asio::buffer(globaltrust_c3));
ssl_ctx.add_certificate_authority(boost::asio::buffer(server_cert));
ssl_ctx.set_verify_callback(boost::asio::ssl::rfc2818_verification(url.get_host()));
ssl_ctx.set_verify_mode(boost::asio::ssl::verify_peer|boost::asio::ssl::verify_fail_if_no_peer_cert);
boost::asio::ip::tcp::resolver resolver_(io);
using tcp_socket = boost::asio::ip::tcp::socket;
using ssl_socket = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>;
tcp_socket* tcp_layer = nullptr;
std::optional<std::variant<tcp_socket, ssl_socket>> http_stream;
boost::beast::flat_buffer buffer_; // (Must persist between reads)
boost::beast::http::response<boost::beast::http::string_body> res_;
if (url.schema == "https") // use SSL here.
{
// inplace construct
http_stream.emplace(std::in_place_type<ssl_socket>, io, ssl_ctx);
ssl_socket& ssl_sock = std::get<1>(*http_stream);
// Let SSL have SNI capability
SSL_set_tlsext_host_name(ssl_sock.native_handle(), url.get_host().c_str());
tcp_layer = & ssl_sock.next_layer();
}
else
{
// inplace construct
http_stream.emplace(std::in_place_type<tcp_socket>, io);
tcp_layer = &(std::get<0>(*http_stream));
}
std::visit([&resolver_, &tcp_layer, &url](auto&& host)
{
using T = std::decay_t<decltype(host)>;
if constexpr (std::is_same_v<T, boost::asio::ip::address>)
{
tcp_layer->connect(boost::asio::ip::tcp::endpoint(host, (unsigned short)(url.port ? *url.port : ( url.schema == "https" ? 443 : 80))));
}
else
{
boost::asio::ip::tcp::resolver::results_type dns_result = resolver_.resolve(url.get_host(), std::to_string(url.port ? *url.port : ( url.schema == "https" ? 443 : 80)));
boost::asio::connect(*tcp_layer, dns_result.begin(), dns_result.end());
}
}, url.host);
if (url.schema == "https")
{
ssl_socket& ssl_stream = std::get<1>(*http_stream);
boost::system::error_code ec;
ssl_stream.handshake(boost::asio::ssl::stream_base::client, ec);
if (ec)
{
LOGE("ssl handshake failed: %s", ec.message().c_str());
return "";
}
}
// Send the HTTP request to the remote host
std::visit([&req_, &buffer_, &res_](auto && socket_)
{
boost::beast::http::write(socket_, req_);
boost::beast::http::read(socket_, buffer_, res_);
}, *http_stream);
return res_.body();
}
catch(std::runtime_error& e)
{
}
catch(std::exception& e)
{
}
return "";
}
std::string easyhttp::sync::get(std::string post_url)
{
// parse post_url to get host
auto url = parse_url(post_url);
boost::beast::http::request<boost::beast::http::string_body> req_;
req_.version(11);
req_.method(boost::beast::http::verb::get);
req_.target(url.get_target());
req_.set(boost::beast::http::field::host, url.get_host());
req_.set(boost::beast::http::field::user_agent, BOOST_BEAST_VERSION_STRING);
return common_http_req(url, req_);
}
std::string easyhttp::sync::post(std::string post_url, std::string post_content, std::string content_type)
{
// parse post_url to get host
auto url = parse_url(post_url);
boost::beast::http::request<boost::beast::http::string_body> req_;
req_.version(11);
req_.method(boost::beast::http::verb::post);
req_.target(url.get_target());
req_.set(boost::beast::http::field::host, url.get_host());
req_.set(boost::beast::http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req_.set(boost::beast::http::field::content_type, content_type);
req_.body() = post_content;
req_.prepare_payload();
return common_http_req(url, req_);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment