Created
September 4, 2019 14:03
-
-
Save microcai/0050b7d001ff6647ecada86b96552278 to your computer and use it in GitHub Desktop.
HTTP/HTTPS beast wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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