Home | History | Annotate | Download | only in provider
      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