blob: 3d64d15b49919686935986920695ea0cc3d3564d [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Vitaly Buka17b0a8a2015-08-31 19:12:35 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Johan Euphrosine3523fdd2015-10-14 20:46:05 -07005#include "examples/provider/event_http_server.h"
Vitaly Buka17b0a8a2015-08-31 19:12:35 -07006
7#include <vector>
8
9#include <base/bind.h>
10#include <base/time/time.h>
11#include <event2/bufferevent_ssl.h>
Jacob Marble33135582016-01-28 10:29:23 -080012#include <evhtp.h>
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070013#include <openssl/err.h>
14
Johan Euphrosine3523fdd2015-10-14 20:46:05 -070015#include "examples/provider/event_task_runner.h"
Alex Vakulenko57fbee32015-09-21 11:04:46 -070016
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070017namespace weave {
18namespace examples {
19
20namespace {
21
22std::string GetSslError() {
23 char error[1000] = {};
24 ERR_error_string_n(ERR_get_error(), error, sizeof(error));
25 return error;
26}
27
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070028} // namespace
29
30class HttpServerImpl::RequestImpl : public Request {
31 public:
Jacob Marble33135582016-01-28 10:29:23 -080032 RequestImpl(EventPtr<evhtp_request_t> req) : req_(std::move(req)) {
David Paulb18bead2016-02-29 15:42:38 -070033 evbuf_t* input_buffer = req_.get()->buffer_in;
Jacob Marble33135582016-01-28 10:29:23 -080034 data_.resize(evbuffer_get_length(input_buffer));
35 evbuffer_remove(input_buffer, &data_[0], data_.size());
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070036 }
37
38 ~RequestImpl() {}
39
Jacob Marble70712802016-02-05 13:28:15 -080040 std::string GetPath() const override { return req_->uri->path->full; }
Jacob Marble33135582016-01-28 10:29:23 -080041
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070042 std::string GetFirstHeader(const std::string& name) const override {
Jacob Marble33135582016-01-28 10:29:23 -080043 const char* header = evhtp_header_find(req_->headers_in, name.c_str());
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070044 if (!header)
45 return {};
46 return header;
47 }
Jacob Marble33135582016-01-28 10:29:23 -080048
Vitaly Buka533dd422015-10-09 18:57:51 -070049 std::string GetData() { return data_; }
Vitaly Buka5fe76092015-10-08 13:37:53 -070050
51 void SendReply(int status_code,
52 const std::string& data,
53 const std::string& mime_type) override {
Jacob Marble33135582016-01-28 10:29:23 -080054 EventPtr<evbuffer> buf{evbuffer_new()};
Vitaly Buka5fe76092015-10-08 13:37:53 -070055 evbuffer_add(buf.get(), data.data(), data.size());
Jacob Marble33135582016-01-28 10:29:23 -080056 evhtp_header_key_add(req_->headers_out, "Content-Type", 0);
57 evhtp_header_val_add(req_->headers_out, mime_type.c_str(), 1);
David Paulb18bead2016-02-29 15:42:38 -070058 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 Marble33135582016-01-28 10:29:23 -080061 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 Vakulenko57fbee32015-09-21 11:04:46 -070064 }
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070065
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070066 private:
Jacob Marble33135582016-01-28 10:29:23 -080067 EventPtr<evhtp_request_t> req_;
Vitaly Buka533dd422015-10-09 18:57:51 -070068 std::string data_;
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070069};
70
Alex Vakulenko57fbee32015-09-21 11:04:46 -070071HttpServerImpl::HttpServerImpl(EventTaskRunner* task_runner)
72 : task_runner_{task_runner} {
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070073 SSL_load_error_strings();
74 SSL_library_init();
75
Jacob Marble33135582016-01-28 10:29:23 -080076 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 Buka17b0a8a2015-08-31 19:12:35 -070081
Jacob Marble33135582016-01-28 10:29:23 -080082 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 Buka17b0a8a2015-08-31 19:12:35 -070086
Jacob Marble33135582016-01-28 10:29:23 -080087 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 Buka17b0a8a2015-08-31 19:12:35 -070095
Jacob Marble33135582016-01-28 10:29:23 -080096 CHECK_EQ(1, SSL_CTX_check_private_key(ctx.get())) << GetSslError();
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070097
Jacob Marble33135582016-01-28 10:29:23 -080098 httpd_.reset(evhtp_new(task_runner_->GetEventBase(), nullptr));
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070099 CHECK(httpd_);
Jacob Marble33135582016-01-28 10:29:23 -0800100 httpsd_.reset(evhtp_new(task_runner_->GetEventBase(), nullptr));
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700101 CHECK(httpsd_);
102
Jacob Marble33135582016-01-28 10:29:23 -0800103 httpsd_.get()->ssl_ctx = ctx.release();
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700104
Jacob Marble33135582016-01-28 10:29:23 -0800105 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 Buka17b0a8a2015-08-31 19:12:35 -0700107}
108
Jacob Marble33135582016-01-28 10:29:23 -0800109void HttpServerImpl::GenerateX509(X509* x509, EVP_PKEY* pkey) {
110 CHECK(x509) << GetSslError();
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700111
Jacob Marble33135582016-01-28 10:29:23 -0800112 X509_set_version(x509, 2);
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700113
Jacob Marble33135582016-01-28 10:29:23 -0800114 X509_gmtime_adj(X509_get_notBefore(x509), 0);
115 X509_gmtime_adj(X509_get_notAfter(x509),
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700116 base::TimeDelta::FromDays(365).InSeconds());
117
Jacob Marble33135582016-01-28 10:29:23 -0800118 CHECK(pkey) << GetSslError();
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700119 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 Marble33135582016-01-28 10:29:23 -0800123 CHECK(EVP_PKEY_assign_RSA(pkey, rsa)) << GetSslError();
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700124
Jacob Marble33135582016-01-28 10:29:23 -0800125 X509_set_pubkey(x509, pkey);
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700126
Jacob Marble33135582016-01-28 10:29:23 -0800127 CHECK(X509_sign(x509, pkey, EVP_sha256())) << GetSslError();
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700128
129 cert_fingerprint_.resize(EVP_MD_size(EVP_sha256()));
130 uint32_t len = 0;
Jacob Marble33135582016-01-28 10:29:23 -0800131 CHECK(X509_digest(x509, EVP_sha256(), cert_fingerprint_.data(), &len));
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700132 CHECK_EQ(len, cert_fingerprint_.size());
133}
134
Jacob Marble33135582016-01-28 10:29:23 -0800135void HttpServerImpl::NotFound(evhtp_request_t* req) {
136 EventPtr<evbuffer> buf{evbuffer_new()};
Jacob Marble70712802016-02-05 13:28:15 -0800137 evbuffer_add_printf(buf.get(), "404 Not Found: %s\n", req->uri->path->full);
Jacob Marble33135582016-01-28 10:29:23 -0800138 evhtp_send_reply_start(req, 404);
139 evhtp_send_reply_body(req, buf.get());
140 evhtp_send_reply_end(req);
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700141}
142
Jacob Marble33135582016-01-28 10:29:23 -0800143void HttpServerImpl::ProcessRequest(evhtp_request_t* req) {
144 std::unique_ptr<RequestImpl> request{new RequestImpl{EventPtr<evhtp_request_t>{req}}};
Vitaly Buka1a39c812015-10-08 21:20:58 -0700145 std::string path = request->GetPath();
Vitaly Buka978e7122016-03-04 17:32:23 -0800146 auto it = handlers_.find(std::make_pair(path, req->htp));
Vitaly Buka1a39c812015-10-08 21:20:58 -0700147 if (it != handlers_.end()) {
148 return it->second.Run(std::move(request));
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700149 }
150 NotFound(req);
151}
Vitaly Buka1a39c812015-10-08 21:20:58 -0700152
Jacob Marble33135582016-01-28 10:29:23 -0800153void HttpServerImpl::ProcessRequestCallback(evhtp_request_t* req, void* arg) {
154 static_cast<HttpServerImpl*>(arg)->ProcessRequest(req);
155}
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700156
Vitaly Buka1a39c812015-10-08 21:20:58 -0700157void HttpServerImpl::AddHttpRequestHandler(
158 const std::string& path,
159 const RequestHandlerCallback& callback) {
Vitaly Buka978e7122016-03-04 17:32:23 -0800160 handlers_[std::make_pair(path, httpd_.get())] = callback;
Jacob Marble33135582016-01-28 10:29:23 -0800161 evhtp_set_cb(httpd_.get(), path.c_str(), &ProcessRequestCallback, this);
Vitaly Buka1a39c812015-10-08 21:20:58 -0700162}
163
164void HttpServerImpl::AddHttpsRequestHandler(
165 const std::string& path,
166 const RequestHandlerCallback& callback) {
Vitaly Buka978e7122016-03-04 17:32:23 -0800167 handlers_[std::make_pair(path, httpsd_.get())] = callback;
Jacob Marble33135582016-01-28 10:29:23 -0800168 evhtp_set_cb(httpsd_.get(), path.c_str(), &ProcessRequestCallback, this);
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700169}
170
Vitaly Buka978e7122016-03-04 17:32:23 -0800171void 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
176void 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 Marble33135582016-01-28 10:29:23 -0800181void HttpServerImpl::ProcessReply(std::shared_ptr<RequestImpl> request,
182 int status_code,
183 const std::string& data,
184 const std::string& mime_type) {}
185
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700186uint16_t HttpServerImpl::GetHttpPort() const {
187 return 7780;
188}
189
190uint16_t HttpServerImpl::GetHttpsPort() const {
191 return 7781;
192}
193
Alex Vakulenkoefee3a22015-11-17 15:08:38 -0800194base::TimeDelta HttpServerImpl::GetRequestTimeout() const {
195 return base::TimeDelta::Max();
196}
197
Vitaly Buka138aec42015-10-08 10:17:48 -0700198std::vector<uint8_t> HttpServerImpl::GetHttpsCertificateFingerprint() const {
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700199 return cert_fingerprint_;
200}
201
202} // namespace examples
203} // namespace weave