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