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
GetSslError()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:
RequestImpl(EventPtr<evhtp_request_t> req)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
~RequestImpl()39 ~RequestImpl() {}
40
GetPath() const41 std::string GetPath() const override { return req_->uri->path->full; }
42
GetFirstHeader(const std::string & name) const43 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
GetData()50 std::string GetData() { return data_; }
51
SendReply(int status_code,const std::string & data,const std::string & mime_type)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
HttpServerImpl(EventTaskRunner * task_runner)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
GenerateX509(X509 * x509,EVP_PKEY * pkey)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
NotFound(evhtp_request_t * req)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
ProcessRequest(evhtp_request_t * req)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
ProcessRequestCallback(evhtp_request_t * req,void * arg)151 void HttpServerImpl::ProcessRequestCallback(evhtp_request_t* req, void* arg) {
152 static_cast<HttpServerImpl*>(arg)->ProcessRequest(req);
153 }
154
AddHttpRequestHandler(const std::string & path,const RequestHandlerCallback & callback)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
AddHttpsRequestHandler(const std::string & path,const RequestHandlerCallback & callback)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
ProcessReply(std::shared_ptr<RequestImpl> request,int status_code,const std::string & data,const std::string & mime_type)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
GetHttpPort() const174 uint16_t HttpServerImpl::GetHttpPort() const {
175 return 7780;
176 }
177
GetHttpsPort() const178 uint16_t HttpServerImpl::GetHttpsPort() const {
179 return 7781;
180 }
181
GetRequestTimeout() const182 base::TimeDelta HttpServerImpl::GetRequestTimeout() const {
183 return base::TimeDelta::Max();
184 }
185
GetHttpsCertificateFingerprint() const186 std::vector<uint8_t> HttpServerImpl::GetHttpsCertificateFingerprint() const {
187 return cert_fingerprint_;
188 }
189
190 } // namespace examples
191 } // namespace weave
192