blob: ae9833e1a7e87b9a872156d4978872d69c7722ea [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>
12#include <openssl/err.h>
13
Johan Euphrosine3523fdd2015-10-14 20:46:05 -070014#include "examples/provider/event_task_runner.h"
Alex Vakulenko57fbee32015-09-21 11:04:46 -070015
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070016namespace weave {
17namespace examples {
18
19namespace {
20
21std::string GetSslError() {
22 char error[1000] = {};
23 ERR_error_string_n(ERR_get_error(), error, sizeof(error));
24 return error;
25}
26
27bufferevent* BuffetEventCallback(event_base* base, void* arg) {
28 SSL_CTX* ctx = static_cast<SSL_CTX*>(arg);
29 return bufferevent_openssl_socket_new(
30 base, -1, SSL_new(ctx), BUFFEREVENT_SSL_ACCEPTING, BEV_OPT_CLOSE_ON_FREE);
31}
32
33} // namespace
34
35class HttpServerImpl::RequestImpl : public Request {
36 public:
Vitaly Buka3264eca2015-12-15 21:00:45 -080037 RequestImpl(evhttp_request* req) {
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070038 req_.reset(req);
Vitaly Buka1a39c812015-10-08 21:20:58 -070039 uri_ = evhttp_request_get_evhttp_uri(req_.get());
Vitaly Buka533dd422015-10-09 18:57:51 -070040
41 data_.resize(evbuffer_get_length(req_->input_buffer));
42 evbuffer_remove(req_->input_buffer, &data_[0], data_.size());
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070043 }
44
45 ~RequestImpl() {}
46
Vitaly Buka1a39c812015-10-08 21:20:58 -070047 std::string GetPath() const override {
48 const char* path = evhttp_uri_get_path(uri_);
49 return path ? path : "";
50 }
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070051 std::string GetFirstHeader(const std::string& name) const override {
52 const char* header = evhttp_find_header(req_->input_headers, name.c_str());
53 if (!header)
54 return {};
55 return header;
56 }
Vitaly Buka533dd422015-10-09 18:57:51 -070057 std::string GetData() { return data_; }
Vitaly Buka5fe76092015-10-08 13:37:53 -070058
59 void SendReply(int status_code,
60 const std::string& data,
61 const std::string& mime_type) override {
62 std::unique_ptr<evbuffer, decltype(&evbuffer_free)> buf{evbuffer_new(),
63 &evbuffer_free};
64 evbuffer_add(buf.get(), data.data(), data.size());
65 evhttp_add_header(req_->output_headers, "Content-Type", mime_type.c_str());
66 evhttp_send_reply(req_.release(), status_code, "None", buf.get());
Alex Vakulenko57fbee32015-09-21 11:04:46 -070067 }
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070068
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070069 private:
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070070 std::unique_ptr<evhttp_request, decltype(&evhttp_cancel_request)> req_{
71 nullptr, &evhttp_cancel_request};
Vitaly Buka533dd422015-10-09 18:57:51 -070072 std::string data_;
Vitaly Buka1a39c812015-10-08 21:20:58 -070073 const evhttp_uri* uri_{nullptr};
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070074};
75
Alex Vakulenko57fbee32015-09-21 11:04:46 -070076HttpServerImpl::HttpServerImpl(EventTaskRunner* task_runner)
77 : task_runner_{task_runner} {
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070078 SSL_load_error_strings();
79 SSL_library_init();
80
81 ctx_.reset(SSL_CTX_new(TLSv1_2_server_method()));
82 SSL_CTX_set_options(ctx_.get(), SSL_OP_SINGLE_DH_USE |
83 SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_SSLv2);
84
85 ec_key_.reset(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
86 CHECK(ec_key_) << GetSslError();
87 CHECK_EQ(1, SSL_CTX_set_tmp_ecdh(ctx_.get(), ec_key_.get())) << GetSslError();
88
89 GenerateX509();
90 CHECK_EQ(1, SSL_CTX_use_PrivateKey(ctx_.get(), pkey_.get())) << GetSslError();
91 CHECK_EQ(1, SSL_CTX_use_certificate(ctx_.get(), x509_.get()))
92 << GetSslError();
93
94 CHECK_EQ(1, SSL_CTX_check_private_key(ctx_.get())) << GetSslError();
95
Alex Vakulenko57fbee32015-09-21 11:04:46 -070096 httpd_.reset(evhttp_new(task_runner_->GetEventBase()));
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070097 CHECK(httpd_);
Alex Vakulenko57fbee32015-09-21 11:04:46 -070098 httpsd_.reset(evhttp_new(task_runner_->GetEventBase()));
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070099 CHECK(httpsd_);
100
101 evhttp_set_bevcb(httpsd_.get(), BuffetEventCallback, ctx_.get());
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700102
103 CHECK_EQ(0, evhttp_bind_socket(httpd_.get(), "0.0.0.0", GetHttpPort()));
104 CHECK_EQ(0, evhttp_bind_socket(httpsd_.get(), "0.0.0.0", GetHttpsPort()));
105}
106
107void HttpServerImpl::GenerateX509() {
108 x509_.reset(X509_new());
109 CHECK(x509_) << GetSslError();
110
111 X509_set_version(x509_.get(), 2);
112
113 X509_gmtime_adj(X509_get_notBefore(x509_.get()), 0);
114 X509_gmtime_adj(X509_get_notAfter(x509_.get()),
115 base::TimeDelta::FromDays(365).InSeconds());
116
117 pkey_.reset(EVP_PKEY_new());
118 CHECK(pkey_) << GetSslError();
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);
123 CHECK(EVP_PKEY_assign_RSA(pkey_.get(), rsa)) << GetSslError();
124
125 X509_set_pubkey(x509_.get(), pkey_.get());
126
127 CHECK(X509_sign(x509_.get(), pkey_.get(), EVP_sha256())) << GetSslError();
128
129 cert_fingerprint_.resize(EVP_MD_size(EVP_sha256()));
130 uint32_t len = 0;
131 CHECK(X509_digest(x509_.get(), EVP_sha256(), cert_fingerprint_.data(), &len));
132 CHECK_EQ(len, cert_fingerprint_.size());
133}
134
135void HttpServerImpl::ProcessRequestCallback(evhttp_request* req, void* arg) {
136 static_cast<HttpServerImpl*>(arg)->ProcessRequest(req);
137}
138
139void HttpServerImpl::NotFound(evhttp_request* req) {
140 std::unique_ptr<evbuffer, decltype(&evbuffer_free)> buf{evbuffer_new(),
141 &evbuffer_free};
142 evbuffer_add_printf(buf.get(), "404 Not Found: %s\n",
143 evhttp_request_uri(req));
144 evhttp_send_reply(req, 404, "Not Found", buf.get());
145}
146
147void HttpServerImpl::ProcessRequest(evhttp_request* req) {
Vitaly Buka3264eca2015-12-15 21:00:45 -0800148 std::unique_ptr<RequestImpl> request{new RequestImpl{req}};
Vitaly Buka1a39c812015-10-08 21:20:58 -0700149 std::string path = request->GetPath();
150 auto it = handlers_.find(path);
151 if (it != handlers_.end()) {
152 return it->second.Run(std::move(request));
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700153 }
154 NotFound(req);
155}
Vitaly Buka1a39c812015-10-08 21:20:58 -0700156
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700157void HttpServerImpl::ProcessReply(std::shared_ptr<RequestImpl> request,
158 int status_code,
159 const std::string& data,
Johan Euphrosine1ca3c222015-10-15 20:43:42 -0700160 const std::string& mime_type) {}
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700161
Vitaly Buka1a39c812015-10-08 21:20:58 -0700162void HttpServerImpl::AddHttpRequestHandler(
163 const std::string& path,
164 const RequestHandlerCallback& callback) {
Vitaly Buka52d006a2015-11-21 17:14:51 -0800165 handlers_.insert(std::make_pair(path, callback));
Vitaly Buka1a39c812015-10-08 21:20:58 -0700166 evhttp_set_cb(httpd_.get(), path.c_str(), &ProcessRequestCallback, this);
167}
168
169void HttpServerImpl::AddHttpsRequestHandler(
170 const std::string& path,
171 const RequestHandlerCallback& callback) {
Vitaly Buka52d006a2015-11-21 17:14:51 -0800172 handlers_.insert(std::make_pair(path, callback));
Vitaly Buka1a39c812015-10-08 21:20:58 -0700173 evhttp_set_cb(httpsd_.get(), path.c_str(), &ProcessRequestCallback, this);
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700174}
175
176uint16_t HttpServerImpl::GetHttpPort() const {
177 return 7780;
178}
179
180uint16_t HttpServerImpl::GetHttpsPort() const {
181 return 7781;
182}
183
Alex Vakulenkoefee3a22015-11-17 15:08:38 -0800184base::TimeDelta HttpServerImpl::GetRequestTimeout() const {
185 return base::TimeDelta::Max();
186}
187
Vitaly Buka138aec42015-10-08 10:17:48 -0700188std::vector<uint8_t> HttpServerImpl::GetHttpsCertificateFingerprint() const {
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700189 return cert_fingerprint_;
190}
191
192} // namespace examples
193} // namespace weave