Vitaly Buka | 4615e0d | 2015-10-14 15:35:12 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Weave Authors. All rights reserved. |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Johan Euphrosine | 3523fdd | 2015-10-14 20:46:05 -0700 | [diff] [blame] | 5 | #include "examples/provider/event_http_server.h" |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 6 | |
| 7 | #include <vector> |
| 8 | |
| 9 | #include <base/bind.h> |
| 10 | #include <base/time/time.h> |
| 11 | #include <event2/bufferevent_ssl.h> |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 12 | #include <evhtp.h> |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 13 | #include <openssl/err.h> |
| 14 | |
Johan Euphrosine | 3523fdd | 2015-10-14 20:46:05 -0700 | [diff] [blame] | 15 | #include "examples/provider/event_task_runner.h" |
Alex Vakulenko | 57fbee3 | 2015-09-21 11:04:46 -0700 | [diff] [blame] | 16 | |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 17 | namespace weave { |
| 18 | namespace examples { |
| 19 | |
| 20 | namespace { |
| 21 | |
| 22 | std::string GetSslError() { |
| 23 | char error[1000] = {}; |
| 24 | ERR_error_string_n(ERR_get_error(), error, sizeof(error)); |
| 25 | return error; |
| 26 | } |
| 27 | |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 28 | } // namespace |
| 29 | |
| 30 | class HttpServerImpl::RequestImpl : public Request { |
| 31 | public: |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 32 | RequestImpl(EventPtr<evhtp_request_t> req) : req_(std::move(req)) { |
David Paul | b18bead | 2016-02-29 15:42:38 -0700 | [diff] [blame] | 33 | evbuf_t* input_buffer = req_.get()->buffer_in; |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 34 | data_.resize(evbuffer_get_length(input_buffer)); |
| 35 | evbuffer_remove(input_buffer, &data_[0], data_.size()); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 36 | } |
| 37 | |
| 38 | ~RequestImpl() {} |
| 39 | |
Jacob Marble | 7071280 | 2016-02-05 13:28:15 -0800 | [diff] [blame] | 40 | std::string GetPath() const override { return req_->uri->path->full; } |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 41 | |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 42 | std::string GetFirstHeader(const std::string& name) const override { |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 43 | const char* header = evhtp_header_find(req_->headers_in, name.c_str()); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 44 | if (!header) |
| 45 | return {}; |
| 46 | return header; |
| 47 | } |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 48 | |
Vitaly Buka | 533dd42 | 2015-10-09 18:57:51 -0700 | [diff] [blame] | 49 | std::string GetData() { return data_; } |
Vitaly Buka | 5fe7609 | 2015-10-08 13:37:53 -0700 | [diff] [blame] | 50 | |
| 51 | void SendReply(int status_code, |
| 52 | const std::string& data, |
| 53 | const std::string& mime_type) override { |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 54 | EventPtr<evbuffer> buf{evbuffer_new()}; |
Vitaly Buka | 5fe7609 | 2015-10-08 13:37:53 -0700 | [diff] [blame] | 55 | evbuffer_add(buf.get(), data.data(), data.size()); |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 56 | evhtp_header_key_add(req_->headers_out, "Content-Type", 0); |
| 57 | evhtp_header_val_add(req_->headers_out, mime_type.c_str(), 1); |
David Paul | b18bead | 2016-02-29 15:42:38 -0700 | [diff] [blame] | 58 | evhtp_header_key_add(req_->headers_out, "Content-Length", 0); |
| 59 | std::string content_length = std::to_string(evbuffer_get_length(buf.get())); |
| 60 | evhtp_header_val_add(req_->headers_out, content_length.c_str(), 1); |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 61 | evhtp_send_reply_start(req_.get(), status_code); |
| 62 | evhtp_send_reply_body(req_.get(), buf.get()); |
| 63 | evhtp_send_reply_end(req_.get()); |
Alex Vakulenko | 57fbee3 | 2015-09-21 11:04:46 -0700 | [diff] [blame] | 64 | } |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 65 | |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 66 | private: |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 67 | EventPtr<evhtp_request_t> req_; |
Vitaly Buka | 533dd42 | 2015-10-09 18:57:51 -0700 | [diff] [blame] | 68 | std::string data_; |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 69 | }; |
| 70 | |
Alex Vakulenko | 57fbee3 | 2015-09-21 11:04:46 -0700 | [diff] [blame] | 71 | HttpServerImpl::HttpServerImpl(EventTaskRunner* task_runner) |
| 72 | : task_runner_{task_runner} { |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 73 | SSL_load_error_strings(); |
| 74 | SSL_library_init(); |
| 75 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 76 | std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)> ctx{ |
| 77 | SSL_CTX_new(TLSv1_2_server_method()), &SSL_CTX_free}; |
| 78 | CHECK(ctx); |
| 79 | SSL_CTX_set_options(ctx.get(), SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | |
| 80 | SSL_OP_NO_SSLv2); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 81 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 82 | std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> ec_key{ |
| 83 | EC_KEY_new_by_curve_name(NID_X9_62_prime256v1), &EC_KEY_free}; |
| 84 | CHECK(ec_key) << GetSslError(); |
| 85 | CHECK_EQ(1, SSL_CTX_set_tmp_ecdh(ctx.get(), ec_key.get())) << GetSslError(); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 86 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 87 | std::unique_ptr<X509, decltype(&X509_free)> x509{X509_new(), &X509_free}; |
| 88 | CHECK(x509); |
| 89 | std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> pkey{EVP_PKEY_new(), |
| 90 | &EVP_PKEY_free}; |
| 91 | CHECK(pkey); |
| 92 | GenerateX509(x509.get(), pkey.get()); |
| 93 | CHECK_EQ(1, SSL_CTX_use_PrivateKey(ctx.get(), pkey.get())) << GetSslError(); |
| 94 | CHECK_EQ(1, SSL_CTX_use_certificate(ctx.get(), x509.get())) << GetSslError(); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 95 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 96 | CHECK_EQ(1, SSL_CTX_check_private_key(ctx.get())) << GetSslError(); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 97 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 98 | httpd_.reset(evhtp_new(task_runner_->GetEventBase(), nullptr)); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 99 | CHECK(httpd_); |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 100 | httpsd_.reset(evhtp_new(task_runner_->GetEventBase(), nullptr)); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 101 | CHECK(httpsd_); |
| 102 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 103 | httpsd_.get()->ssl_ctx = ctx.release(); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 104 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 105 | CHECK_EQ(0, evhtp_bind_socket(httpd_.get(), "0.0.0.0", GetHttpPort(), -1)); |
| 106 | CHECK_EQ(0, evhtp_bind_socket(httpsd_.get(), "0.0.0.0", GetHttpsPort(), -1)); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 107 | } |
| 108 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 109 | void HttpServerImpl::GenerateX509(X509* x509, EVP_PKEY* pkey) { |
| 110 | CHECK(x509) << GetSslError(); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 111 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 112 | X509_set_version(x509, 2); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 113 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 114 | X509_gmtime_adj(X509_get_notBefore(x509), 0); |
| 115 | X509_gmtime_adj(X509_get_notAfter(x509), |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 116 | base::TimeDelta::FromDays(365).InSeconds()); |
| 117 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 118 | CHECK(pkey) << GetSslError(); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 119 | std::unique_ptr<BIGNUM, decltype(&BN_free)> big_num(BN_new(), &BN_free); |
| 120 | CHECK(BN_set_word(big_num.get(), 65537)) << GetSslError(); |
| 121 | auto rsa = RSA_new(); |
| 122 | RSA_generate_key_ex(rsa, 2048, big_num.get(), nullptr); |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 123 | CHECK(EVP_PKEY_assign_RSA(pkey, rsa)) << GetSslError(); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 124 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 125 | X509_set_pubkey(x509, pkey); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 126 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 127 | CHECK(X509_sign(x509, pkey, EVP_sha256())) << GetSslError(); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 128 | |
| 129 | cert_fingerprint_.resize(EVP_MD_size(EVP_sha256())); |
| 130 | uint32_t len = 0; |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 131 | CHECK(X509_digest(x509, EVP_sha256(), cert_fingerprint_.data(), &len)); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 132 | CHECK_EQ(len, cert_fingerprint_.size()); |
| 133 | } |
| 134 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 135 | void HttpServerImpl::NotFound(evhtp_request_t* req) { |
| 136 | EventPtr<evbuffer> buf{evbuffer_new()}; |
Jacob Marble | 7071280 | 2016-02-05 13:28:15 -0800 | [diff] [blame] | 137 | evbuffer_add_printf(buf.get(), "404 Not Found: %s\n", req->uri->path->full); |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 138 | evhtp_send_reply_start(req, 404); |
| 139 | evhtp_send_reply_body(req, buf.get()); |
| 140 | evhtp_send_reply_end(req); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 141 | } |
| 142 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 143 | void HttpServerImpl::ProcessRequest(evhtp_request_t* req) { |
| 144 | std::unique_ptr<RequestImpl> request{new RequestImpl{EventPtr<evhtp_request_t>{req}}}; |
Vitaly Buka | 1a39c81 | 2015-10-08 21:20:58 -0700 | [diff] [blame] | 145 | std::string path = request->GetPath(); |
Vitaly Buka | 978e712 | 2016-03-04 17:32:23 -0800 | [diff] [blame] | 146 | auto it = handlers_.find(std::make_pair(path, req->htp)); |
Vitaly Buka | 1a39c81 | 2015-10-08 21:20:58 -0700 | [diff] [blame] | 147 | if (it != handlers_.end()) { |
| 148 | return it->second.Run(std::move(request)); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 149 | } |
| 150 | NotFound(req); |
| 151 | } |
Vitaly Buka | 1a39c81 | 2015-10-08 21:20:58 -0700 | [diff] [blame] | 152 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 153 | void HttpServerImpl::ProcessRequestCallback(evhtp_request_t* req, void* arg) { |
| 154 | static_cast<HttpServerImpl*>(arg)->ProcessRequest(req); |
| 155 | } |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 156 | |
Vitaly Buka | 1a39c81 | 2015-10-08 21:20:58 -0700 | [diff] [blame] | 157 | void HttpServerImpl::AddHttpRequestHandler( |
| 158 | const std::string& path, |
| 159 | const RequestHandlerCallback& callback) { |
Vitaly Buka | 978e712 | 2016-03-04 17:32:23 -0800 | [diff] [blame] | 160 | handlers_[std::make_pair(path, httpd_.get())] = callback; |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 161 | evhtp_set_cb(httpd_.get(), path.c_str(), &ProcessRequestCallback, this); |
Vitaly Buka | 1a39c81 | 2015-10-08 21:20:58 -0700 | [diff] [blame] | 162 | } |
| 163 | |
| 164 | void HttpServerImpl::AddHttpsRequestHandler( |
| 165 | const std::string& path, |
| 166 | const RequestHandlerCallback& callback) { |
Vitaly Buka | 978e712 | 2016-03-04 17:32:23 -0800 | [diff] [blame] | 167 | handlers_[std::make_pair(path, httpsd_.get())] = callback; |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 168 | evhtp_set_cb(httpsd_.get(), path.c_str(), &ProcessRequestCallback, this); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 169 | } |
| 170 | |
Vitaly Buka | 978e712 | 2016-03-04 17:32:23 -0800 | [diff] [blame] | 171 | void HttpServerImpl::RemoveHttpRequestHandler(const std::string& path) { |
| 172 | handlers_.erase(std::make_pair(path, httpd_.get())); |
| 173 | evhtp_set_cb(httpd_.get(), path.c_str(), nullptr, nullptr); |
| 174 | } |
| 175 | |
| 176 | void HttpServerImpl::RemoveHttpsRequestHandler(const std::string& path) { |
| 177 | handlers_.erase(std::make_pair(path, httpsd_.get())); |
| 178 | evhtp_set_cb(httpsd_.get(), path.c_str(), nullptr, nullptr); |
| 179 | } |
| 180 | |
Jacob Marble | 3313558 | 2016-01-28 10:29:23 -0800 | [diff] [blame] | 181 | void HttpServerImpl::ProcessReply(std::shared_ptr<RequestImpl> request, |
| 182 | int status_code, |
| 183 | const std::string& data, |
| 184 | const std::string& mime_type) {} |
| 185 | |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 186 | uint16_t HttpServerImpl::GetHttpPort() const { |
| 187 | return 7780; |
| 188 | } |
| 189 | |
| 190 | uint16_t HttpServerImpl::GetHttpsPort() const { |
| 191 | return 7781; |
| 192 | } |
| 193 | |
Alex Vakulenko | efee3a2 | 2015-11-17 15:08:38 -0800 | [diff] [blame] | 194 | base::TimeDelta HttpServerImpl::GetRequestTimeout() const { |
| 195 | return base::TimeDelta::Max(); |
| 196 | } |
| 197 | |
Vitaly Buka | 138aec4 | 2015-10-08 10:17:48 -0700 | [diff] [blame] | 198 | std::vector<uint8_t> HttpServerImpl::GetHttpsCertificateFingerprint() const { |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 199 | return cert_fingerprint_; |
| 200 | } |
| 201 | |
| 202 | } // namespace examples |
| 203 | } // namespace weave |