Merge remote-tracking branch 'weave/master' into 'weave/aosp-master'

919a8a9 Remove crypto type "None"
3313558 Replace bleeding-edge libevent with libevhtp.
c3d7714 Make default Makefile target "all".
d9e3061 Add libevent-dev to README.
ebfa60b Add a unit tests for deleting CloudCommandProxy along with CommandInstance
c920bb2 Fix memory leak when removing CommandInstance from CommandQueue
329ad80 Rename CommandQueue::DelayedRemove into RemoveLater()
6a1ba84 Changed meaning of some SSID flags
98d1fee Periodicly clean up command queue and remove old processed commands

Change-Id: If63cb3d9a34d405df06ab958c609bb46668737bc
diff --git a/.gitignore b/.gitignore
index a256906..86c649b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,6 @@
 /out/
 /third_party/include
 /third_party/lib
+/third_party/libevhtp
+/third_party/googletest
 gomacc.lock
diff --git a/Makefile b/Makefile
index de69f40..df27b58 100644
--- a/Makefile
+++ b/Makefile
@@ -88,7 +88,6 @@
 
 weave_obj_files := $(WEAVE_SRC_FILES:%.cc=out/$(BUILD_MODE)/%.o)
 
-# TODO(jacobmarble): There are too many gtest/gmock deps in non-test targets. Fix.
 $(weave_obj_files) : out/$(BUILD_MODE)/%.o : %.cc
 	mkdir -p $(dir $@)
 	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
@@ -102,7 +101,8 @@
 clean :
 	rm -rf out
 
-cleanall : clean clean-gtest clean-libevent
+cleanall : clean clean-gtest clean-libevhtp
 
 .PHONY : clean cleanall all
+.DEFAULT_GOAL := all
 
diff --git a/README.md b/README.md
index fc042b7..211033c 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,20 @@
 
 ```
 sudo apt-get update
-sudo apt-get install autoconf automake binutils g++ hostapd libavahi-client-dev libcurl4-openssl-dev libexpat1-dev libnl-3-dev libnl-route-3-dev libssl-dev libtool
+sudo apt-get install \
+  autoconf \
+  automake \
+  binutils \
+  g++ \
+  hostapd \
+  libavahi-client-dev \
+  libcurl4-openssl-dev \
+  libevent-dev \
+  libexpat1-dev \
+  libnl-3-dev \
+  libnl-route-3-dev \
+  libssl-dev \
+  libtool
 ```
 
 # Prerequisites
@@ -72,7 +85,8 @@
   - hostapd
   - libavahi-client-dev
   - libcurl4-openssl-dev
-  - libevent 2.1.x-alpha (included; see third_party/get_libevent.sh)
+  - libevent 2.0.x
+  - libevhtp (included; see third_party/get_libevhtp.sh)
 
 
 # Compiling
@@ -80,19 +94,18 @@
 The `make --jobs/-j` flag is encouraged, to speed up build time. For example
 
 ```
-make all -j
+make -j
 ```
 
+which happens to be the same as
+
+```
+make all -j
+````
+
 ### Build library
 
 ```
-make
-
-```
-
-or
-
-```
 make out/Debug/libweave.so
 ```
 
diff --git a/examples/daemon/common/daemon.h b/examples/daemon/common/daemon.h
index 6dc021d..985c5e5 100644
--- a/examples/daemon/common/daemon.h
+++ b/examples/daemon/common/daemon.h
@@ -20,7 +20,6 @@
  public:
   struct Options {
     bool force_bootstrapping_{false};
-    bool disable_security_{false};
     bool disable_privet_{false};
     std::string registration_ticket_;
     std::string model_id_{"AAAAA"};
@@ -31,7 +30,6 @@
                  << "\t-h,--help                    Show this help message\n"
                  << "\t--v=LEVEL                    Logging level\n"
                  << "\t-b,--bootstrapping           Force WiFi bootstrapping\n"
-                 << "\t-d,--disable_security        Disable privet security\n"
                  << "\t--registration_ticket=TICKET Register device with the "
                     "given ticket\n"
                  << "\t--disable_privet             Disable local privet\n";
@@ -44,8 +42,6 @@
           return false;
         } else if (arg == "-b" || arg == "--bootstrapping") {
           force_bootstrapping_ = true;
-        } else if (arg == "-d" || arg == "--disable_security") {
-          disable_security_ = true;
         } else if (arg == "--disable_privet") {
           disable_privet_ = true;
         } else if (arg.find("--registration_ticket") != std::string::npos) {
@@ -71,8 +67,7 @@
   Daemon(const Options& opts)
       : task_runner_{new weave::examples::EventTaskRunner},
         config_store_{
-            new weave::examples::FileConfigStore(opts.disable_security_,
-                                                 opts.model_id_,
+            new weave::examples::FileConfigStore(opts.model_id_,
                                                  task_runner_.get())},
         http_client_{new weave::examples::CurlHttpClient(task_runner_.get())},
         network_{new weave::examples::EventNetworkImpl(task_runner_.get())},
diff --git a/examples/examples.mk b/examples/examples.mk
index 06266a3..f1e92b6 100644
--- a/examples/examples.mk
+++ b/examples/examples.mk
@@ -7,7 +7,7 @@
 
 examples_provider_obj_files := $(EXAMPLES_PROVIDER_SRC_FILES:%.cc=out/$(BUILD_MODE)/%.o)
 
-$(examples_provider_obj_files) : out/$(BUILD_MODE)/%.o : %.cc third_party/include/event2/event.h
+$(examples_provider_obj_files) : out/$(BUILD_MODE)/%.o : %.cc third_party/include/evhtp.h
 	mkdir -p $(dir $@)
 	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
@@ -15,7 +15,7 @@
 	rm -f $@
 	$(AR) crsT $@ $^
 
-out/$(BUILD_MODE)/examples/daemon/%.o : examples/daemon/%.cc third_party/include/event2/event.h
+out/$(BUILD_MODE)/examples/daemon/%.o : examples/daemon/%.cc third_party/include/evhtp.h
 	mkdir -p $(dir $@)
 	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
@@ -32,22 +32,22 @@
 	-lssl \
 	-lcrypto
 
-out/$(BUILD_MODE)/weave_daemon_ledflasher : out/$(BUILD_MODE)/examples/daemon/ledflasher/ledflasher.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_ledflasher : out/$(BUILD_MODE)/examples/daemon/ledflasher/ledflasher.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so third_party/lib/libevhtp.a
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
-out/$(BUILD_MODE)/weave_daemon_light : out/$(BUILD_MODE)/examples/daemon/light/light.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_light : out/$(BUILD_MODE)/examples/daemon/light/light.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so third_party/lib/libevhtp.a
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
-out/$(BUILD_MODE)/weave_daemon_lock : out/$(BUILD_MODE)/examples/daemon/lock/lock.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_lock : out/$(BUILD_MODE)/examples/daemon/lock/lock.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so third_party/lib/libevhtp.a
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
-out/$(BUILD_MODE)/weave_daemon_oven : out/$(BUILD_MODE)/examples/daemon/oven/oven.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_oven : out/$(BUILD_MODE)/examples/daemon/oven/oven.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so third_party/lib/libevhtp.a
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
-out/$(BUILD_MODE)/weave_daemon_sample : out/$(BUILD_MODE)/examples/daemon/sample/sample.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_sample : out/$(BUILD_MODE)/examples/daemon/sample/sample.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so third_party/lib/libevhtp.a
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
-out/$(BUILD_MODE)/weave_daemon_speaker : out/$(BUILD_MODE)/examples/daemon/speaker/speaker.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_speaker : out/$(BUILD_MODE)/examples/daemon/speaker/speaker.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so third_party/lib/libevhtp.a
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
 all-examples : out/$(BUILD_MODE)/weave_daemon_ledflasher out/$(BUILD_MODE)/weave_daemon_light out/$(BUILD_MODE)/weave_daemon_lock out/$(BUILD_MODE)/weave_daemon_oven out/$(BUILD_MODE)/weave_daemon_sample out/$(BUILD_MODE)/weave_daemon_speaker
diff --git a/examples/provider/event_deleter.h b/examples/provider/event_deleter.h
index 078c326..9bb53f4 100644
--- a/examples/provider/event_deleter.h
+++ b/examples/provider/event_deleter.h
@@ -7,9 +7,10 @@
 
 #include <memory>
 
-#include <third_party/include/event2/event.h>
-#include <third_party/include/event2/event_struct.h>
-#include <third_party/include/event2/http.h>
+#include <evhtp.h>
+#include <event2/event.h>
+#include <event2/event_struct.h>
+#include <openssl/ssl.h>
 
 namespace weave {
 namespace examples {
@@ -18,9 +19,19 @@
 // so we can use one unique_ptr definition for all of them
 class EventDeleter {
  public:
-  void operator()(evhttp_uri* http_uri) { evhttp_uri_free(http_uri); }
-  void operator()(evhttp_connection* conn) { evhttp_connection_free(conn); }
-  void operator()(evhttp_request* req) { evhttp_request_free(req); }
+  void operator()(evbuffer* buf) { evbuffer_free(buf); }
+  void operator()(evhtp_t* evhtp) {
+    if (evhtp->ssl_ctx) {
+      // Work around a double-free bug in recent versions of libevhtp.
+      // https://github.com/ellzey/libevhtp/pull/208
+      SSL_CTX_free(evhtp->ssl_ctx);
+      evhtp->ssl_ctx = nullptr;
+    }
+    evhtp_unbind_socket(evhtp);
+    evhtp_free(evhtp);
+  }
+  void operator()(evhtp_connection_t* conn) { evhtp_connection_free(conn); }
+  void operator()(evhtp_request_t* req) { evhtp_request_free(req); }
   void operator()(event_base* base) { event_base_free(base); }
   void operator()(event* ev) {
     event_del(ev);
diff --git a/examples/provider/event_http_server.cc b/examples/provider/event_http_server.cc
index ae9833e..1bf58f6 100644
--- a/examples/provider/event_http_server.cc
+++ b/examples/provider/event_http_server.cc
@@ -9,6 +9,7 @@
 #include <base/bind.h>
 #include <base/time/time.h>
 #include <event2/bufferevent_ssl.h>
+#include <evhtp.h>
 #include <openssl/err.h>
 
 #include "examples/provider/event_task_runner.h"
@@ -24,53 +25,45 @@
   return error;
 }
 
-bufferevent* BuffetEventCallback(event_base* base, void* arg) {
-  SSL_CTX* ctx = static_cast<SSL_CTX*>(arg);
-  return bufferevent_openssl_socket_new(
-      base, -1, SSL_new(ctx), BUFFEREVENT_SSL_ACCEPTING, BEV_OPT_CLOSE_ON_FREE);
-}
-
 }  // namespace
 
 class HttpServerImpl::RequestImpl : public Request {
  public:
-  RequestImpl(evhttp_request* req) {
-    req_.reset(req);
-    uri_ = evhttp_request_get_evhttp_uri(req_.get());
-
-    data_.resize(evbuffer_get_length(req_->input_buffer));
-    evbuffer_remove(req_->input_buffer, &data_[0], data_.size());
+  RequestImpl(EventPtr<evhtp_request_t> req) : req_(std::move(req)) {
+    evbuf_t* input_buffer =
+        bufferevent_get_input(evhtp_request_get_bev(req_.get()));
+    data_.resize(evbuffer_get_length(input_buffer));
+    evbuffer_remove(input_buffer, &data_[0], data_.size());
   }
 
   ~RequestImpl() {}
 
-  std::string GetPath() const override {
-    const char* path = evhttp_uri_get_path(uri_);
-    return path ? path : "";
-  }
+  std::string GetPath() const override { return req_->uri->path->path; }
+
   std::string GetFirstHeader(const std::string& name) const override {
-    const char* header = evhttp_find_header(req_->input_headers, name.c_str());
+    const char* header = evhtp_header_find(req_->headers_in, name.c_str());
     if (!header)
       return {};
     return header;
   }
+
   std::string GetData() { return data_; }
 
   void SendReply(int status_code,
                  const std::string& data,
                  const std::string& mime_type) override {
-    std::unique_ptr<evbuffer, decltype(&evbuffer_free)> buf{evbuffer_new(),
-                                                            &evbuffer_free};
+    EventPtr<evbuffer> buf{evbuffer_new()};
     evbuffer_add(buf.get(), data.data(), data.size());
-    evhttp_add_header(req_->output_headers, "Content-Type", mime_type.c_str());
-    evhttp_send_reply(req_.release(), status_code, "None", buf.get());
+    evhtp_header_key_add(req_->headers_out, "Content-Type", 0);
+    evhtp_header_val_add(req_->headers_out, mime_type.c_str(), 1);
+    evhtp_send_reply_start(req_.get(), status_code);
+    evhtp_send_reply_body(req_.get(), buf.get());
+    evhtp_send_reply_end(req_.get());
   }
 
  private:
-  std::unique_ptr<evhttp_request, decltype(&evhttp_cancel_request)> req_{
-      nullptr, &evhttp_cancel_request};
+  EventPtr<evhtp_request_t> req_;
   std::string data_;
-  const evhttp_uri* uri_{nullptr};
 };
 
 HttpServerImpl::HttpServerImpl(EventTaskRunner* task_runner)
@@ -78,74 +71,75 @@
   SSL_load_error_strings();
   SSL_library_init();
 
-  ctx_.reset(SSL_CTX_new(TLSv1_2_server_method()));
-  SSL_CTX_set_options(ctx_.get(), SSL_OP_SINGLE_DH_USE |
-                                      SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_SSLv2);
+  std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)> ctx{
+      SSL_CTX_new(TLSv1_2_server_method()), &SSL_CTX_free};
+  CHECK(ctx);
+  SSL_CTX_set_options(ctx.get(), SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE |
+                                     SSL_OP_NO_SSLv2);
 
-  ec_key_.reset(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
-  CHECK(ec_key_) << GetSslError();
-  CHECK_EQ(1, SSL_CTX_set_tmp_ecdh(ctx_.get(), ec_key_.get())) << GetSslError();
+  std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> ec_key{
+      EC_KEY_new_by_curve_name(NID_X9_62_prime256v1), &EC_KEY_free};
+  CHECK(ec_key) << GetSslError();
+  CHECK_EQ(1, SSL_CTX_set_tmp_ecdh(ctx.get(), ec_key.get())) << GetSslError();
 
-  GenerateX509();
-  CHECK_EQ(1, SSL_CTX_use_PrivateKey(ctx_.get(), pkey_.get())) << GetSslError();
-  CHECK_EQ(1, SSL_CTX_use_certificate(ctx_.get(), x509_.get()))
-      << GetSslError();
+  std::unique_ptr<X509, decltype(&X509_free)> x509{X509_new(), &X509_free};
+  CHECK(x509);
+  std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> pkey{EVP_PKEY_new(),
+                                                           &EVP_PKEY_free};
+  CHECK(pkey);
+  GenerateX509(x509.get(), pkey.get());
+  CHECK_EQ(1, SSL_CTX_use_PrivateKey(ctx.get(), pkey.get())) << GetSslError();
+  CHECK_EQ(1, SSL_CTX_use_certificate(ctx.get(), x509.get())) << GetSslError();
 
-  CHECK_EQ(1, SSL_CTX_check_private_key(ctx_.get())) << GetSslError();
+  CHECK_EQ(1, SSL_CTX_check_private_key(ctx.get())) << GetSslError();
 
-  httpd_.reset(evhttp_new(task_runner_->GetEventBase()));
+  httpd_.reset(evhtp_new(task_runner_->GetEventBase(), nullptr));
   CHECK(httpd_);
-  httpsd_.reset(evhttp_new(task_runner_->GetEventBase()));
+  httpsd_.reset(evhtp_new(task_runner_->GetEventBase(), nullptr));
   CHECK(httpsd_);
 
-  evhttp_set_bevcb(httpsd_.get(), BuffetEventCallback, ctx_.get());
+  httpsd_.get()->ssl_ctx = ctx.release();
 
-  CHECK_EQ(0, evhttp_bind_socket(httpd_.get(), "0.0.0.0", GetHttpPort()));
-  CHECK_EQ(0, evhttp_bind_socket(httpsd_.get(), "0.0.0.0", GetHttpsPort()));
+  CHECK_EQ(0, evhtp_bind_socket(httpd_.get(), "0.0.0.0", GetHttpPort(), -1));
+  CHECK_EQ(0, evhtp_bind_socket(httpsd_.get(), "0.0.0.0", GetHttpsPort(), -1));
 }
 
-void HttpServerImpl::GenerateX509() {
-  x509_.reset(X509_new());
-  CHECK(x509_) << GetSslError();
+void HttpServerImpl::GenerateX509(X509* x509, EVP_PKEY* pkey) {
+  CHECK(x509) << GetSslError();
 
-  X509_set_version(x509_.get(), 2);
+  X509_set_version(x509, 2);
 
-  X509_gmtime_adj(X509_get_notBefore(x509_.get()), 0);
-  X509_gmtime_adj(X509_get_notAfter(x509_.get()),
+  X509_gmtime_adj(X509_get_notBefore(x509), 0);
+  X509_gmtime_adj(X509_get_notAfter(x509),
                   base::TimeDelta::FromDays(365).InSeconds());
 
-  pkey_.reset(EVP_PKEY_new());
-  CHECK(pkey_) << GetSslError();
+  CHECK(pkey) << GetSslError();
   std::unique_ptr<BIGNUM, decltype(&BN_free)> big_num(BN_new(), &BN_free);
   CHECK(BN_set_word(big_num.get(), 65537)) << GetSslError();
   auto rsa = RSA_new();
   RSA_generate_key_ex(rsa, 2048, big_num.get(), nullptr);
-  CHECK(EVP_PKEY_assign_RSA(pkey_.get(), rsa)) << GetSslError();
+  CHECK(EVP_PKEY_assign_RSA(pkey, rsa)) << GetSslError();
 
-  X509_set_pubkey(x509_.get(), pkey_.get());
+  X509_set_pubkey(x509, pkey);
 
-  CHECK(X509_sign(x509_.get(), pkey_.get(), EVP_sha256())) << GetSslError();
+  CHECK(X509_sign(x509, pkey, EVP_sha256())) << GetSslError();
 
   cert_fingerprint_.resize(EVP_MD_size(EVP_sha256()));
   uint32_t len = 0;
-  CHECK(X509_digest(x509_.get(), EVP_sha256(), cert_fingerprint_.data(), &len));
+  CHECK(X509_digest(x509, EVP_sha256(), cert_fingerprint_.data(), &len));
   CHECK_EQ(len, cert_fingerprint_.size());
 }
 
-void HttpServerImpl::ProcessRequestCallback(evhttp_request* req, void* arg) {
-  static_cast<HttpServerImpl*>(arg)->ProcessRequest(req);
+void HttpServerImpl::NotFound(evhtp_request_t* req) {
+  EventPtr<evbuffer> buf{evbuffer_new()};
+  evbuffer_add_printf(buf.get(), "404 Not Found: %s\n", req->uri->path->path);
+  evhtp_send_reply_start(req, 404);
+  evhtp_send_reply_body(req, buf.get());
+  evhtp_send_reply_end(req);
 }
 
-void HttpServerImpl::NotFound(evhttp_request* req) {
-  std::unique_ptr<evbuffer, decltype(&evbuffer_free)> buf{evbuffer_new(),
-                                                          &evbuffer_free};
-  evbuffer_add_printf(buf.get(), "404 Not Found: %s\n",
-                      evhttp_request_uri(req));
-  evhttp_send_reply(req, 404, "Not Found", buf.get());
-}
-
-void HttpServerImpl::ProcessRequest(evhttp_request* req) {
-  std::unique_ptr<RequestImpl> request{new RequestImpl{req}};
+void HttpServerImpl::ProcessRequest(evhtp_request_t* req) {
+  std::unique_ptr<RequestImpl> request{new RequestImpl{EventPtr<evhtp_request_t>{req}}};
   std::string path = request->GetPath();
   auto it = handlers_.find(path);
   if (it != handlers_.end()) {
@@ -154,25 +148,29 @@
   NotFound(req);
 }
 
-void HttpServerImpl::ProcessReply(std::shared_ptr<RequestImpl> request,
-                                  int status_code,
-                                  const std::string& data,
-                                  const std::string& mime_type) {}
+void HttpServerImpl::ProcessRequestCallback(evhtp_request_t* req, void* arg) {
+  static_cast<HttpServerImpl*>(arg)->ProcessRequest(req);
+}
 
 void HttpServerImpl::AddHttpRequestHandler(
     const std::string& path,
     const RequestHandlerCallback& callback) {
   handlers_.insert(std::make_pair(path, callback));
-  evhttp_set_cb(httpd_.get(), path.c_str(), &ProcessRequestCallback, this);
+  evhtp_set_cb(httpd_.get(), path.c_str(), &ProcessRequestCallback, this);
 }
 
 void HttpServerImpl::AddHttpsRequestHandler(
     const std::string& path,
     const RequestHandlerCallback& callback) {
   handlers_.insert(std::make_pair(path, callback));
-  evhttp_set_cb(httpsd_.get(), path.c_str(), &ProcessRequestCallback, this);
+  evhtp_set_cb(httpsd_.get(), path.c_str(), &ProcessRequestCallback, this);
 }
 
+void HttpServerImpl::ProcessReply(std::shared_ptr<RequestImpl> request,
+                                  int status_code,
+                                  const std::string& data,
+                                  const std::string& mime_type) {}
+
 uint16_t HttpServerImpl::GetHttpPort() const {
   return 7780;
 }
diff --git a/examples/provider/event_http_server.h b/examples/provider/event_http_server.h
index 950e536..8bb5dd9 100644
--- a/examples/provider/event_http_server.h
+++ b/examples/provider/event_http_server.h
@@ -5,8 +5,7 @@
 #ifndef LIBWEAVE_EXAMPLES_PROVIDER_EVENT_HTTP_SERVER_H_
 #define LIBWEAVE_EXAMPLES_PROVIDER_EVENT_HTTP_SERVER_H_
 
-#include <event2/http.h>
-#include <evhttp.h>
+#include <evhtp.h>
 #include <openssl/ssl.h>
 
 #include <map>
@@ -16,12 +15,14 @@
 #include <base/memory/weak_ptr.h>
 #include <weave/provider/http_server.h>
 
+#include "examples/provider/event_deleter.h"
+
 namespace weave {
 namespace examples {
 
 class EventTaskRunner;
 
-// HTTP/HTTPS server implemented with libevent.
+// HTTP/HTTPS server implemented with libevhtp.
 class HttpServerImpl : public provider::HttpServer {
  public:
   class RequestImpl;
@@ -38,32 +39,21 @@
   std::vector<uint8_t> GetHttpsCertificateFingerprint() const override;
 
  private:
-  void GenerateX509();
-  static void ProcessRequestCallback(evhttp_request* req, void* arg);
-  void ProcessRequest(evhttp_request* req);
+  void GenerateX509(X509* x509, EVP_PKEY* pkey);
+  static void ProcessRequestCallback(evhtp_request_t* req, void* arg);
+  void ProcessRequest(evhtp_request_t* req);
   void ProcessReply(std::shared_ptr<RequestImpl> request,
                     int status_code,
                     const std::string& data,
                     const std::string& mime_type);
-  void NotFound(evhttp_request* req);
+  void NotFound(evhtp_request_t* req);
 
   std::map<std::string, RequestHandlerCallback> handlers_;
 
-  std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> ec_key_{nullptr,
-                                                          &EC_KEY_free};
-
-  std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> pkey_{nullptr,
-                                                            &EVP_PKEY_free};
-
-  std::unique_ptr<X509, decltype(&X509_free)> x509_{nullptr, &X509_free};
-
-  std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)> ctx_{nullptr,
-                                                         &SSL_CTX_free};
   std::vector<uint8_t> cert_fingerprint_;
   EventTaskRunner* task_runner_{nullptr};
-  std::unique_ptr<evhttp, decltype(&evhttp_free)> httpd_{nullptr, &evhttp_free};
-  std::unique_ptr<evhttp, decltype(&evhttp_free)> httpsd_{nullptr,
-                                                          &evhttp_free};
+  EventPtr<evhtp_t> httpd_;
+  EventPtr<evhtp_t> httpsd_;
 
   base::WeakPtrFactory<HttpServerImpl> weak_ptr_factory_{this};
 };
diff --git a/examples/provider/event_task_runner.cc b/examples/provider/event_task_runner.cc
index 1d94612..a86ffff 100644
--- a/examples/provider/event_task_runner.cc
+++ b/examples/provider/event_task_runner.cc
@@ -31,7 +31,9 @@
   int16_t flags = EV_PERSIST | EV_ET;
   flags |= (what & kReadable) ? EV_READ : 0;
   flags |= (what & kWriteable) ? EV_WRITE : 0;
+#if LIBEVENT_VERSION_NUMBER >= 0x02010400
   flags |= (what & kClosed) ? EV_CLOSED : 0;
+#endif
   event* ioevent = event_new(base_.get(), fd, flags, FdEventHandler, this);
   EventPtr<event> ioeventPtr{ioevent};
   fd_task_map_.insert(
@@ -53,7 +55,9 @@
   sigfillset(&sa.sa_mask);
   sigaction(SIGINT, &sa, nullptr);
 
-  event_base_loop(g_event_base, EVLOOP_NO_EXIT_ON_EMPTY);
+  do {
+    event_base_loop(g_event_base, EVLOOP_ONCE);
+  } while (!event_base_got_exit(g_event_base));
   g_event_base = nullptr;
 }
 
diff --git a/examples/provider/file_config_store.cc b/examples/provider/file_config_store.cc
index 31efaa7..a6c2e60 100644
--- a/examples/provider/file_config_store.cc
+++ b/examples/provider/file_config_store.cc
@@ -19,11 +19,9 @@
 
 const char kSettingsDir[] = "/var/lib/weave/";
 
-FileConfigStore::FileConfigStore(bool disable_security,
-                                 const std::string& model_id,
+FileConfigStore::FileConfigStore(const std::string& model_id,
                                  provider::TaskRunner* task_runner)
-    : disable_security_{disable_security},
-      model_id_{model_id},
+    : model_id_{model_id},
       task_runner_{task_runner} {}
 
 std::string FileConfigStore::GetPath(const std::string& name) const {
@@ -61,7 +59,6 @@
   settings->client_secret = "LS_iPYo_WIOE0m2VnLdduhnx";
   settings->api_key = "AIzaSyACK3oZtmIylUKXiTMqkZqfuRiCgQmQSAQ";
 
-  settings->disable_security = disable_security_;
   return true;
 }
 
diff --git a/examples/provider/file_config_store.h b/examples/provider/file_config_store.h
index e7398d1..337e82a 100644
--- a/examples/provider/file_config_store.h
+++ b/examples/provider/file_config_store.h
@@ -17,8 +17,7 @@
 
 class FileConfigStore : public provider::ConfigStore {
  public:
-  FileConfigStore(bool disable_security,
-                  const std::string& model_id,
+  FileConfigStore(const std::string& model_id,
                   provider::TaskRunner* task_runner);
 
   bool LoadDefaults(Settings* settings) override;
@@ -31,7 +30,6 @@
 
  private:
   std::string GetPath(const std::string& name) const;
-  const bool disable_security_;
   const std::string model_id_;
   provider::TaskRunner* task_runner_{nullptr};
 };
diff --git a/examples/provider/wifi_manager.h b/examples/provider/wifi_manager.h
index 2bfc5ca..72f54df 100644
--- a/examples/provider/wifi_manager.h
+++ b/examples/provider/wifi_manager.h
@@ -35,6 +35,8 @@
                const DoneCallback& callback) override;
   void StartAccessPoint(const std::string& ssid) override;
   void StopAccessPoint() override;
+  bool IsWifi24Supported() const override {return true;};
+  bool IsWifi50Supported() const override {return false;};
 
   static bool HasWifiCapability();
 
diff --git a/include/weave/provider/test/fake_task_runner.h b/include/weave/provider/test/fake_task_runner.h
index bb79455..4080072 100644
--- a/include/weave/provider/test/fake_task_runner.h
+++ b/include/weave/provider/test/fake_task_runner.h
@@ -31,6 +31,7 @@
   void Run(size_t number_of_iterations = 1000);
   void Break();
   base::Clock* GetClock();
+  size_t GetTaskQueueSize() const;
 
  private:
   void SaveTask(const tracked_objects::Location& from_here,
diff --git a/include/weave/provider/test/mock_wifi.h b/include/weave/provider/test/mock_wifi.h
index 9fbe10f..7ede55e 100644
--- a/include/weave/provider/test/mock_wifi.h
+++ b/include/weave/provider/test/mock_wifi.h
@@ -23,6 +23,8 @@
                     const DoneCallback&));
   MOCK_METHOD1(StartAccessPoint, void(const std::string&));
   MOCK_METHOD0(StopAccessPoint, void());
+  MOCK_CONST_METHOD0(IsWifi24Supported, bool());
+  MOCK_CONST_METHOD0(IsWifi50Supported, bool());
 };
 
 }  // namespace test
diff --git a/include/weave/provider/wifi.h b/include/weave/provider/wifi.h
index 48ac651..9c7cfca 100644
--- a/include/weave/provider/wifi.h
+++ b/include/weave/provider/wifi.h
@@ -28,6 +28,9 @@
   // Stops WiFi access point.
   virtual void StopAccessPoint() = 0;
 
+  virtual bool IsWifi24Supported() const = 0;
+  virtual bool IsWifi50Supported() const = 0;
+
  protected:
   virtual ~Wifi() {}
 };
diff --git a/include/weave/settings.h b/include/weave/settings.h
index eeb3f93..741fff2 100644
--- a/include/weave/settings.h
+++ b/include/weave/settings.h
@@ -71,7 +71,6 @@
   // Internal options to tweak some library functionality. External code should
   // avoid using them.
   bool wifi_auto_setup_enabled{true};
-  bool disable_security{false};
   std::string test_privet_ssid;
 };
 
diff --git a/src/base_api_handler_unittest.cc b/src/base_api_handler_unittest.cc
index 8b0f0b2..2a202d1 100644
--- a/src/base_api_handler_unittest.cc
+++ b/src/base_api_handler_unittest.cc
@@ -8,6 +8,7 @@
 #include <base/time/default_clock.h>
 #include <base/values.h>
 #include <gtest/gtest.h>
+#include <weave/provider/test/fake_task_runner.h>
 #include <weave/provider/test/mock_config_store.h>
 #include <weave/provider/test/mock_http_client.h>
 #include <weave/test/mock_device.h>
@@ -93,7 +94,8 @@
   Config config_{&config_store_};
   StrictMock<provider::test::MockHttpClient> http_client_;
   std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
-  ComponentManagerImpl component_manager_;
+  StrictMock<provider::test::FakeTaskRunner> task_runner_;
+  ComponentManagerImpl component_manager_{&task_runner_};
   std::unique_ptr<BaseApiHandler> handler_;
   StrictMock<test::MockDevice> device_;
 };
diff --git a/src/commands/cloud_command_proxy.h b/src/commands/cloud_command_proxy.h
index 13f4654..80efd70 100644
--- a/src/commands/cloud_command_proxy.h
+++ b/src/commands/cloud_command_proxy.h
@@ -29,7 +29,7 @@
 }
 
 // Command proxy which publishes command updates to the cloud.
-class CloudCommandProxy final : public CommandInstance::Observer {
+class CloudCommandProxy : public CommandInstance::Observer {
  public:
   CloudCommandProxy(CommandInstance* command_instance,
                     CloudCommandUpdateInterface* cloud_command_updater,
diff --git a/src/commands/cloud_command_proxy_unittest.cc b/src/commands/cloud_command_proxy_unittest.cc
index 013769d..0de67fe 100644
--- a/src/commands/cloud_command_proxy_unittest.cc
+++ b/src/commands/cloud_command_proxy_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <queue>
 
+#include <base/bind.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <weave/provider/test/fake_task_runner.h>
@@ -16,6 +17,7 @@
 #include "src/mock_component_manager.h"
 
 using testing::_;
+using testing::AnyNumber;
 using testing::DoAll;
 using testing::Invoke;
 using testing::Return;
@@ -62,6 +64,27 @@
   base::Time creation_time_;
 };
 
+class CloudCommandProxyWrapper : public CloudCommandProxy {
+ public:
+  CloudCommandProxyWrapper(CommandInstance* command_instance,
+                           CloudCommandUpdateInterface* cloud_command_updater,
+                           ComponentManager* component_manager,
+                           std::unique_ptr<BackoffEntry> backoff_entry,
+                           provider::TaskRunner* task_runner,
+                           const base::Closure& destruct_callback)
+      : CloudCommandProxy{command_instance, cloud_command_updater,
+                          component_manager, std::move(backoff_entry),
+                          task_runner},
+        destruct_callback_{destruct_callback} {}
+
+  ~CloudCommandProxyWrapper() {
+    destruct_callback_.Run();
+  }
+
+ private:
+  base::Closure destruct_callback_;
+};
+
 class CloudCommandProxyTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -100,15 +123,21 @@
         new TestBackoffEntry{&policy, task_runner_.GetClock()}};
 
     // Finally construct the CloudCommandProxy we are going to test here.
-    std::unique_ptr<CloudCommandProxy> proxy{new CloudCommandProxy{
+    std::unique_ptr<CloudCommandProxy> proxy{new CloudCommandProxyWrapper{
         command_instance_.get(), &cloud_updater_, &component_manager_,
-        std::move(backoff), &task_runner_}};
+        std::move(backoff), &task_runner_,
+        base::Bind(&CloudCommandProxyTest::OnProxyDestroyed,
+                   base::Unretained(this))}};
     // CloudCommandProxy::CloudCommandProxy() subscribe itself to weave::Command
     // notifications. When weave::Command is being destroyed it sends
     // ::OnCommandDestroyed() and CloudCommandProxy deletes itself.
     proxy.release();
+
+    EXPECT_CALL(*this, OnProxyDestroyed()).Times(AnyNumber());
   }
 
+  MOCK_METHOD0(OnProxyDestroyed, void());
+
   ComponentManager::UpdateID current_state_update_id_{0};
   base::CallbackList<void(ComponentManager::UpdateID)> callbacks_;
   testing::StrictMock<MockCloudCommandUpdateInterface> cloud_updater_;
@@ -120,6 +149,14 @@
 
 }  // anonymous namespace
 
+TEST_F(CloudCommandProxyTest, EnsureDestroyed) {
+  EXPECT_CALL(*this, OnProxyDestroyed()).Times(1);
+  command_instance_.reset();
+  // Verify that CloudCommandProxy has been destroyed already and not at some
+  // point during the destruction of CloudCommandProxyTest class.
+  testing::Mock::VerifyAndClearExpectations(this);
+}
+
 TEST_F(CloudCommandProxyTest, ImmediateUpdate) {
   const char expected[] = "{'state':'done'}";
   EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expected), _));
diff --git a/src/commands/command_instance.cc b/src/commands/command_instance.cc
index fc9b0e7..590bbb1 100644
--- a/src/commands/command_instance.cc
+++ b/src/commands/command_instance.cc
@@ -284,7 +284,7 @@
 
 void CommandInstance::RemoveFromQueue() {
   if (queue_)
-    queue_->DelayedRemove(GetID());
+    queue_->RemoveLater(GetID());
 }
 
 }  // namespace weave
diff --git a/src/commands/command_instance.h b/src/commands/command_instance.h
index b1028d0..febe5c5 100644
--- a/src/commands/command_instance.h
+++ b/src/commands/command_instance.h
@@ -89,10 +89,7 @@
 
   // Sets the pointer to queue this command is part of.
   void AttachToQueue(CommandQueue* queue) { queue_ = queue; }
-  void DetachFromQueue() {
-    observers_.Clear();
-    queue_ = nullptr;
-  }
+  void DetachFromQueue() { queue_ = nullptr; }
 
  private:
   // Helper function to update the command status.
diff --git a/src/commands/command_queue.cc b/src/commands/command_queue.cc
index 134dc1c..f0d2228 100644
--- a/src/commands/command_queue.cc
+++ b/src/commands/command_queue.cc
@@ -18,6 +18,10 @@
 }
 }
 
+CommandQueue::CommandQueue(provider::TaskRunner* task_runner,
+                           base::Clock* clock)
+    : task_runner_{task_runner}, clock_{clock} {}
+
 void CommandQueue::AddCommandAddedCallback(const CommandCallback& callback) {
   on_command_added_.push_back(callback);
   // Send all pre-existed commands.
@@ -84,18 +88,19 @@
     it_handler->second.Run(pair.first->second);
   else if (!default_command_callback_.is_null())
     default_command_callback_.Run(pair.first->second);
-
-  Cleanup();
 }
 
-void CommandQueue::DelayedRemove(const std::string& id) {
+void CommandQueue::RemoveLater(const std::string& id) {
   auto p = map_.find(id);
   if (p == map_.end())
     return;
-  remove_queue_.push(std::make_pair(
-      base::Time::Now() + base::TimeDelta::FromMinutes(kRemoveCommandDelayMin),
-      id));
-  Cleanup();
+  auto remove_delay = base::TimeDelta::FromMinutes(kRemoveCommandDelayMin);
+  remove_queue_.push(std::make_pair(clock_->Now() + remove_delay, id));
+  if (remove_queue_.size() == 1) {
+    // The queue was empty, this is the first command to be removed, schedule
+    // a clean-up task.
+    ScheduleCleanup(remove_delay);
+  }
 }
 
 bool CommandQueue::Remove(const std::string& id) {
@@ -110,19 +115,26 @@
   return true;
 }
 
-void CommandQueue::Cleanup() {
-  while (!remove_queue_.empty() && remove_queue_.front().first < Now()) {
-    Remove(remove_queue_.front().second);
+void CommandQueue::Cleanup(const base::Time& cutoff_time) {
+  while (!remove_queue_.empty() && remove_queue_.top().first <= cutoff_time) {
+    Remove(remove_queue_.top().second);
     remove_queue_.pop();
   }
 }
 
-void CommandQueue::SetNowForTest(base::Time now) {
-  test_now_ = now;
+void CommandQueue::ScheduleCleanup(base::TimeDelta delay) {
+  task_runner_->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&CommandQueue::PerformScheduledCleanup,
+                 weak_ptr_factory_.GetWeakPtr()),
+      delay);
 }
 
-base::Time CommandQueue::Now() const {
-  return test_now_.is_null() ? base::Time::Now() : test_now_;
+void CommandQueue::PerformScheduledCleanup() {
+  base::Time now = clock_->Now();
+  Cleanup(now);
+  if (!remove_queue_.empty())
+    ScheduleCleanup(remove_queue_.top().first - now);
 }
 
 CommandInstance* CommandQueue::Find(const std::string& id) const {
diff --git a/src/commands/command_queue.h b/src/commands/command_queue.h
index 0f0a18b..a092c12 100644
--- a/src/commands/command_queue.h
+++ b/src/commands/command_queue.h
@@ -14,8 +14,10 @@
 
 #include <base/callback.h>
 #include <base/macros.h>
+#include <base/time/default_clock.h>
 #include <base/time/time.h>
 #include <weave/device.h>
+#include <weave/provider/task_runner.h>
 
 #include "src/commands/command_instance.h"
 
@@ -23,7 +25,7 @@
 
 class CommandQueue final {
  public:
-  CommandQueue() = default;
+  CommandQueue(provider::TaskRunner* task_runner, base::Clock* clock);
 
   // TODO: Remove AddCommandAddedCallback and AddCommandRemovedCallback.
   using CommandCallback = base::Callback<void(Command* command)>;
@@ -51,7 +53,7 @@
 
   // Selects command identified by |id| ready for removal. Command will actually
   // be removed after some time.
-  void DelayedRemove(const std::string& id);
+  void RemoveLater(const std::string& id);
 
   // Finds a command instance in the queue by the instance |id|. Returns
   // nullptr if the command with the given |id| is not found. The returned
@@ -64,23 +66,29 @@
   // Removes a command identified by |id| from the queue.
   bool Remove(const std::string& id);
 
-  // Removes old commands selected with DelayedRemove.
-  void Cleanup();
+  // Removes old commands scheduled by RemoveLater() to be deleted after
+  // |cutoff_time|.
+  void Cleanup(const base::Time& cutoff_time);
 
-  // Overrides CommandQueue::Now() for tests.
-  void SetNowForTest(base::Time now);
+  // Schedule a cleanup task to be run after the specified |delay|.
+  void ScheduleCleanup(base::TimeDelta delay);
 
-  // Returns current time.
-  base::Time Now() const;
+  // Perform removal of scheduled commands (by calling Cleanup()) and scheduling
+  // another cleanup task if the removal queue is still not empty.
+  void PerformScheduledCleanup();
 
-  // Overridden value to be returned from Now().
-  base::Time test_now_;
+  provider::TaskRunner* task_runner_{nullptr};
+  base::Clock* clock_{nullptr};
 
   // ID-to-CommandInstance map.
   std::map<std::string, std::shared_ptr<CommandInstance>> map_;
 
-  // Queue of commands to be removed.
-  std::queue<std::pair<base::Time, std::string>> remove_queue_;
+  // Queue of commands to be removed, keeps them sorted by the timestamp
+  // (earliest first). This is done to tolerate system clock changes.
+  template <typename T>
+  using InversePriorityQueue =
+      std::priority_queue<T, std::vector<T>, std::greater<T>>;
+  InversePriorityQueue<std::pair<base::Time, std::string>> remove_queue_;
 
   using CallbackList = std::vector<CommandCallback>;
   CallbackList on_command_added_;
@@ -88,6 +96,9 @@
   std::map<std::string, Device::CommandHandlerCallback> command_callbacks_;
   Device::CommandHandlerCallback default_command_callback_;
 
+  // WeakPtr factory for controlling the lifetime of command queue cleanup
+  // tasks.
+  base::WeakPtrFactory<CommandQueue> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(CommandQueue);
 };
 
diff --git a/src/commands/command_queue_unittest.cc b/src/commands/command_queue_unittest.cc
index b4c5938..1e2e0ac 100644
--- a/src/commands/command_queue_unittest.cc
+++ b/src/commands/command_queue_unittest.cc
@@ -10,12 +10,18 @@
 
 #include <base/bind.h>
 #include <base/memory/weak_ptr.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <weave/provider/test/fake_task_runner.h>
 
+#include "src/bind_lambda.h"
 #include "src/string_utils.h"
 
 namespace weave {
 
+using testing::Return;
+using testing::StrictMock;
+
 class CommandQueueTest : public testing::Test {
  public:
   std::unique_ptr<CommandInstance> CreateDummyCommandInstance(
@@ -30,11 +36,15 @@
   bool Remove(const std::string& id) { return queue_.Remove(id); }
 
   void Cleanup(const base::TimeDelta& interval) {
-    queue_.SetNowForTest(base::Time::Now() + interval);
-    return queue_.Cleanup();
+    return queue_.Cleanup(task_runner_.GetClock()->Now() + interval);
   }
 
-  CommandQueue queue_;
+  std::string GetFirstCommandToBeRemoved() const {
+    return queue_.remove_queue_.top().second;
+  }
+
+  StrictMock<provider::test::FakeTaskRunner> task_runner_;
+  CommandQueue queue_{&task_runner_, task_runner_.GetClock()};
 };
 
 // Keeps track of commands being added to and removed from the queue_.
@@ -105,12 +115,12 @@
   EXPECT_TRUE(queue_.IsEmpty());
 }
 
-TEST_F(CommandQueueTest, DelayedRemove) {
+TEST_F(CommandQueueTest, RemoveLater) {
   const std::string id1 = "id1";
   queue_.Add(CreateDummyCommandInstance("base.reboot", id1));
   EXPECT_EQ(1u, queue_.GetCount());
 
-  queue_.DelayedRemove(id1);
+  queue_.RemoveLater(id1);
   EXPECT_EQ(1u, queue_.GetCount());
 
   Cleanup(base::TimeDelta::FromMinutes(1));
@@ -120,6 +130,46 @@
   EXPECT_EQ(0u, queue_.GetCount());
 }
 
+TEST_F(CommandQueueTest, RemoveLaterOnCleanupTask) {
+  const std::string id1 = "id1";
+  queue_.Add(CreateDummyCommandInstance("base.reboot", id1));
+  EXPECT_EQ(1u, queue_.GetCount());
+
+  queue_.RemoveLater(id1);
+  EXPECT_EQ(1u, queue_.GetCount());
+  ASSERT_EQ(1u, task_runner_.GetTaskQueueSize());
+
+  task_runner_.RunOnce();
+
+  EXPECT_EQ(0u, queue_.GetCount());
+  EXPECT_EQ(0u, task_runner_.GetTaskQueueSize());
+}
+
+TEST_F(CommandQueueTest, CleanupMultipleCommands) {
+  const std::string id1 = "id1";
+  const std::string id2 = "id2";
+
+  queue_.Add(CreateDummyCommandInstance("base.reboot", id1));
+  queue_.Add(CreateDummyCommandInstance("base.reboot", id2));
+  auto remove_task = [this](const std::string& id) { queue_.RemoveLater(id); };
+  remove_task(id1);
+  task_runner_.PostDelayedTask(FROM_HERE, base::Bind(remove_task, id2),
+                               base::TimeDelta::FromSeconds(10));
+  EXPECT_EQ(2u, queue_.GetCount());
+  ASSERT_EQ(2u, task_runner_.GetTaskQueueSize());
+  task_runner_.RunOnce();  // Executes "remove_task(id2) @ T+10s".
+  ASSERT_EQ(2u, queue_.GetCount());
+  ASSERT_EQ(1u, task_runner_.GetTaskQueueSize());
+  EXPECT_EQ(id1, GetFirstCommandToBeRemoved());
+  task_runner_.RunOnce();  // Should remove task "id1" from queue.
+  ASSERT_EQ(1u, queue_.GetCount());
+  ASSERT_EQ(1u, task_runner_.GetTaskQueueSize());
+  EXPECT_EQ(id2, GetFirstCommandToBeRemoved());
+  task_runner_.RunOnce();  // Should remove task "id2" from queue.
+  EXPECT_EQ(0u, queue_.GetCount());
+  EXPECT_EQ(0u, task_runner_.GetTaskQueueSize());
+}
+
 TEST_F(CommandQueueTest, Dispatch) {
   FakeDispatcher dispatch(&queue_);
   const std::string id1 = "id1";
diff --git a/src/component_manager_impl.cc b/src/component_manager_impl.cc
index 550775d..dec4a48 100644
--- a/src/component_manager_impl.cc
+++ b/src/component_manager_impl.cc
@@ -31,8 +31,10 @@
 LIBWEAVE_EXPORT EnumToStringMap<UserRole>::EnumToStringMap()
     : EnumToStringMap(kMap) {}
 
-ComponentManagerImpl::ComponentManagerImpl(base::Clock* clock)
-    : clock_{clock ? clock : &default_clock_} {}
+ComponentManagerImpl::ComponentManagerImpl(provider::TaskRunner* task_runner,
+                                           base::Clock* clock)
+    : clock_{clock ? clock : &default_clock_},
+      command_queue_{task_runner, clock_} {}
 
 ComponentManagerImpl::~ComponentManagerImpl() {}
 
diff --git a/src/component_manager_impl.h b/src/component_manager_impl.h
index 8c4ad16..f3c5451 100644
--- a/src/component_manager_impl.h
+++ b/src/component_manager_impl.h
@@ -15,7 +15,8 @@
 
 class ComponentManagerImpl final : public ComponentManager {
  public:
-  explicit ComponentManagerImpl(base::Clock* clock = nullptr);
+  explicit ComponentManagerImpl(provider::TaskRunner* task_runner,
+                                base::Clock* clock = nullptr);
   ~ComponentManagerImpl() override;
 
   // Loads trait definition schema.
diff --git a/src/component_manager_unittest.cc b/src/component_manager_unittest.cc
index 63fedac..97dc00d 100644
--- a/src/component_manager_unittest.cc
+++ b/src/component_manager_unittest.cc
@@ -7,6 +7,7 @@
 #include <map>
 
 #include <gtest/gtest.h>
+#include <weave/provider/test/fake_task_runner.h>
 #include <weave/test/unittest_utils.h>
 
 #include "src/bind_lambda.h"
@@ -90,8 +91,9 @@
                                       {"t5", "t6"}, nullptr));
   }
 
+  StrictMock<provider::test::FakeTaskRunner> task_runner_;
   StrictMock<test::MockClock> clock_;
-  ComponentManagerImpl manager_{&clock_};
+  ComponentManagerImpl manager_{&task_runner_, &clock_};
 };
 
 }  // anonymous namespace
diff --git a/src/config_unittest.cc b/src/config_unittest.cc
index fbb558a..4b0e5b4 100644
--- a/src/config_unittest.cc
+++ b/src/config_unittest.cc
@@ -68,7 +68,6 @@
   EXPECT_FALSE(GetSettings().device_id.empty());
   EXPECT_EQ("", GetSettings().firmware_version);
   EXPECT_TRUE(GetSettings().wifi_auto_setup_enabled);
-  EXPECT_FALSE(GetSettings().disable_security);
   EXPECT_EQ("", GetSettings().test_privet_ssid);
   EXPECT_EQ(std::set<PairingType>{PairingType::kPinCode},
             GetSettings().pairing_modes);
@@ -164,8 +163,6 @@
   EXPECT_EQ("state_device_id", GetSettings().device_id);
   EXPECT_EQ(GetDefaultSettings().wifi_auto_setup_enabled,
             GetSettings().wifi_auto_setup_enabled);
-  EXPECT_EQ(GetDefaultSettings().disable_security,
-            GetSettings().disable_security);
   EXPECT_EQ(GetDefaultSettings().test_privet_ssid,
             GetSettings().test_privet_ssid);
   EXPECT_EQ(GetDefaultSettings().pairing_modes, GetSettings().pairing_modes);
diff --git a/src/device_manager.cc b/src/device_manager.cc
index 04d7a6b..097f854 100644
--- a/src/device_manager.cc
+++ b/src/device_manager.cc
@@ -29,7 +29,7 @@
                              provider::Wifi* wifi,
                              provider::Bluetooth* bluetooth)
     : config_{new Config{config_store}},
-      component_manager_{new ComponentManagerImpl} {
+      component_manager_{new ComponentManagerImpl{task_runner}} {
   if (http_server) {
     auth_manager_.reset(new privet::AuthManager(
         config_.get(), http_server->GetHttpsCertificateFingerprint()));
diff --git a/src/device_registration_info_unittest.cc b/src/device_registration_info_unittest.cc
index cd11ac9..7908c8b 100644
--- a/src/device_registration_info_unittest.cc
+++ b/src/device_registration_info_unittest.cc
@@ -208,7 +208,7 @@
       {},
       &clock_};
   std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
-  ComponentManagerImpl component_manager_;
+  ComponentManagerImpl component_manager_{&task_runner_};
 };
 
 TEST_F(DeviceRegistrationInfoTest, GetServiceURL) {
diff --git a/src/privet/privet_manager.cc b/src/privet/privet_manager.cc
index edc7907..9c717ce 100644
--- a/src/privet/privet_manager.cc
+++ b/src/privet/privet_manager.cc
@@ -53,8 +53,6 @@
   CHECK(auth_manager);
   CHECK(device);
 
-  disable_security_ = device->GetSettings().disable_security;
-
   device_ = DeviceDelegate::CreateDefault(
       task_runner_, http_server->GetHttpPort(), http_server->GetHttpsPort(),
       http_server->GetRequestTimeout());
@@ -129,9 +127,6 @@
     const std::shared_ptr<provider::HttpServer::Request>& request,
     const std::string& data) {
   std::string auth_header = request->GetFirstHeader(http::kAuthorization);
-  if (auth_header.empty() && disable_security_)
-    auth_header = "Privet anonymous";
-
   base::DictionaryValue empty;
   auto value = base::JSONReader::Read(data);
   const base::DictionaryValue* dictionary = &empty;
diff --git a/src/privet/privet_manager.h b/src/privet/privet_manager.h
index 371d843..06eb89a 100644
--- a/src/privet/privet_manager.h
+++ b/src/privet/privet_manager.h
@@ -79,7 +79,6 @@
   void OnChanged();
   void OnConnectivityChanged();
 
-  bool disable_security_{false};
   provider::TaskRunner* task_runner_{nullptr};
   std::unique_ptr<CloudDelegate> cloud_;
   std::unique_ptr<DeviceDelegate> device_;
diff --git a/src/privet/privet_types.cc b/src/privet/privet_types.cc
index dd291b3..9e50f94 100644
--- a/src/privet/privet_types.cc
+++ b/src/privet/privet_types.cc
@@ -52,7 +52,6 @@
 };
 
 const EnumToStringMap<CryptoType>::Map kCryptoTypeMap[] = {
-    {CryptoType::kNone, "none"},
     {CryptoType::kSpake_p224, "p224_spake2"},
 };
 
diff --git a/src/privet/privet_types.h b/src/privet/privet_types.h
index c738865..49c4522 100644
--- a/src/privet/privet_types.h
+++ b/src/privet/privet_types.h
@@ -15,7 +15,6 @@
 namespace privet {
 
 enum class CryptoType {
-  kNone,
   kSpake_p224,
 };
 
diff --git a/src/privet/security_manager.cc b/src/privet/security_manager.cc
index 358876d..0f00699 100644
--- a/src/privet/security_manager.cc
+++ b/src/privet/security_manager.cc
@@ -67,25 +67,6 @@
   crypto::P224EncryptedKeyExchange spake_;
 };
 
-class UnsecureKeyExchanger : public SecurityManager::KeyExchanger {
- public:
-  explicit UnsecureKeyExchanger(const std::string& password)
-      : password_(password) {}
-  ~UnsecureKeyExchanger() override = default;
-
-  // SecurityManager::KeyExchanger methods.
-  const std::string& GetMessage() override { return password_; }
-
-  bool ProcessMessage(const std::string& message, ErrorPtr* error) override {
-    return true;
-  }
-
-  const std::string& GetKey() const override { return password_; }
-
- private:
-  std::string password_;
-};
-
 }  // namespace
 
 SecurityManager::SecurityManager(const Config* config,
@@ -218,8 +199,6 @@
 
 std::set<CryptoType> SecurityManager::GetCryptoTypes() const {
   std::set<CryptoType> result{CryptoType::kSpake_p224};
-  if (GetSettings().disable_security)
-    result.insert(CryptoType::kNone);
   return result;
 }
 
@@ -259,8 +238,6 @@
 
 bool SecurityManager::IsValidPairingCode(
     const std::vector<uint8_t>& auth_code) const {
-  if (GetSettings().disable_security)
-    return true;
   for (const auto& session : confirmed_sessions_) {
     const std::string& key = session.second->GetKey();
     const std::string& id = session.first;
@@ -309,11 +286,6 @@
     case CryptoType::kSpake_p224:
       spake.reset(new Spakep224Exchanger(code));
       break;
-    case CryptoType::kNone:
-      if (GetSettings().disable_security) {
-        spake.reset(new UnsecureKeyExchanger(code));
-        break;
-      }
     // Fall through...
     default:
       return Error::AddTo(error, FROM_HERE, errors::kInvalidParams,
@@ -428,9 +400,6 @@
 }
 
 bool SecurityManager::CheckIfPairingAllowed(ErrorPtr* error) {
-  if (GetSettings().disable_security)
-    return true;
-
   if (block_pairing_until_ > auth_manager_->Now()) {
     return Error::AddTo(error, FROM_HERE, errors::kDeviceBusy,
                         "Too many pairing attempts");
diff --git a/src/privet/wifi_bootstrap_manager.cc b/src/privet/wifi_bootstrap_manager.cc
index 566da80..ce2016a 100644
--- a/src/privet/wifi_bootstrap_manager.cc
+++ b/src/privet/wifi_bootstrap_manager.cc
@@ -204,8 +204,12 @@
 }
 
 std::set<WifiType> WifiBootstrapManager::GetTypes() const {
-  // TODO(wiley) This should do some system work to figure this out.
-  return {WifiType::kWifi24};
+  std::set<WifiType> result;
+  if (wifi_->IsWifi24Supported())
+    result.insert(WifiType::kWifi24);
+  if (wifi_->IsWifi50Supported())
+    result.insert(WifiType::kWifi50);
+  return result;
 }
 
 void WifiBootstrapManager::OnConnectDone(const std::string& ssid,
@@ -255,9 +259,15 @@
 
 void WifiBootstrapManager::UpdateConnectionState() {
   connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
-
   Network::State service_state{network_->GetConnectionState()};
   VLOG(3) << "New network state: " << EnumToString(service_state);
+
+  // TODO: Make it true wifi state, currently it's rather online state.
+  if (service_state != Network::State::kOnline &&
+      config_->GetSettings().last_configured_ssid.empty()) {
+    return;
+  }
+
   switch (service_state) {
     case Network::State::kOffline:
       connection_state_ = ConnectionState{ConnectionState::kOffline};
diff --git a/src/privet/wifi_ssid_generator.cc b/src/privet/wifi_ssid_generator.cc
index 697e5d8..4ad1602 100644
--- a/src/privet/wifi_ssid_generator.cc
+++ b/src/privet/wifi_ssid_generator.cc
@@ -52,20 +52,27 @@
 }
 
 std::string WifiSsidGenerator::GenerateFlags() const {
-  return GenerateFlagsInternal(false);
+  return GenerateFlagsInternal();
 }
 
-std::string WifiSsidGenerator::GenerateFlagsInternal(bool for_ssid) const {
+std::string WifiSsidGenerator::GenerateFlagsInternal() const {
   std::bitset<6> flags1;
   // Device needs WiFi configuration.
   flags1[0] = wifi_ && IsSetupNeeded(wifi_->GetConnectionState());
+
   // Device needs GCD registration.
   flags1[1] = IsSetupNeeded(gcd_->GetConnectionState());
 
   std::bitset<6> flags2;
 
-  // Device is discoverable over WiFi.
-  flags2[0] = for_ssid || (wifi_ && !wifi_->GetHostedSsid().empty());
+  if (wifi_) {
+    std::set<WifiType> types = wifi_->GetTypes();
+    // Device supports 2.4Ghz WiFi networks.
+    flags2[0] = types.find(WifiType::kWifi24) != types.end();
+
+    // Device supports 5.0Ghz WiFi networks.
+    flags2[1] = types.find(WifiType::kWifi50) != types.end();
+  }
 
   std::string result{2, base64chars[0]};
   result[0] = base64chars[flags1.to_ulong()];
@@ -82,7 +89,7 @@
 
   std::string result =
       base::StringPrintf(kSsidFormat, name.c_str(), idx.c_str(),
-                         model_id.c_str(), GenerateFlagsInternal(true).c_str());
+                         model_id.c_str(), GenerateFlagsInternal().c_str());
   CHECK_EQ(result[result.size() - 11], '.');
   return result;
 }
diff --git a/src/privet/wifi_ssid_generator.h b/src/privet/wifi_ssid_generator.h
index 2b86f28..1197e73 100644
--- a/src/privet/wifi_ssid_generator.h
+++ b/src/privet/wifi_ssid_generator.h
@@ -30,7 +30,7 @@
 
   // Sets object to use |n| instead of random number for SSID generation.
   void SetRandomForTests(int n);
-  std::string GenerateFlagsInternal(bool for_ssid) const;
+  std::string GenerateFlagsInternal() const;
 
   const CloudDelegate* gcd_{nullptr};
   const WifiDelegate* wifi_{nullptr};
diff --git a/src/privet/wifi_ssid_generator_unittest.cc b/src/privet/wifi_ssid_generator_unittest.cc
index 10680c8..406576d 100644
--- a/src/privet/wifi_ssid_generator_unittest.cc
+++ b/src/privet/wifi_ssid_generator_unittest.cc
@@ -22,26 +22,10 @@
   WifiSsidGenerator ssid_generator_{&gcd_, &wifi_};
 };
 
-TEST_F(WifiSsidGeneratorTest, GenerateFlagsNoHostedAp) {
-  EXPECT_EQ(ssid_generator_.GenerateFlags().size(), 2u);
+TEST_F(WifiSsidGeneratorTest, GenerateFlagsWithWifi24) {
+  EXPECT_CALL(wifi_, GetTypes())
+      .WillRepeatedly(Return(std::set<WifiType>{WifiType::kWifi24}));
 
-  wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
-  gcd_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
-  EXPECT_EQ("DA", ssid_generator_.GenerateFlags());
-
-  wifi_.connection_state_ = ConnectionState{ConnectionState::kOnline};
-  EXPECT_EQ("CA", ssid_generator_.GenerateFlags());
-
-  gcd_.connection_state_ = ConnectionState{ConnectionState::kOffline};
-  EXPECT_EQ("AA", ssid_generator_.GenerateFlags());
-
-  wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
-  EXPECT_EQ("BA", ssid_generator_.GenerateFlags());
-}
-
-TEST_F(WifiSsidGeneratorTest, GenerateFlagsWithHostedAp) {
-  EXPECT_CALL(wifi_, GetHostedSsid())
-      .WillRepeatedly(Return(ssid_generator_.GenerateSsid()));
   EXPECT_EQ(ssid_generator_.GenerateFlags().size(), 2u);
 
   wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
@@ -58,6 +42,26 @@
   EXPECT_EQ("BB", ssid_generator_.GenerateFlags());
 }
 
+TEST_F(WifiSsidGeneratorTest, GenerateFlagsWithWifi50) {
+  EXPECT_CALL(wifi_, GetTypes())
+      .WillRepeatedly(Return(std::set<WifiType>{WifiType::kWifi50}));
+
+  EXPECT_EQ(ssid_generator_.GenerateFlags().size(), 2u);
+
+  wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
+  gcd_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
+  EXPECT_EQ("DC", ssid_generator_.GenerateFlags());
+
+  wifi_.connection_state_ = ConnectionState{ConnectionState::kOnline};
+  EXPECT_EQ("CC", ssid_generator_.GenerateFlags());
+
+  gcd_.connection_state_ = ConnectionState{ConnectionState::kOffline};
+  EXPECT_EQ("AC", ssid_generator_.GenerateFlags());
+
+  wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
+  EXPECT_EQ("BC", ssid_generator_.GenerateFlags());
+}
+
 TEST_F(WifiSsidGeneratorTest, GenerateSsid31orLess) {
   EXPECT_LE(ssid_generator_.GenerateSsid().size(), 31u);
 }
diff --git a/src/test/fake_task_runner.cc b/src/test/fake_task_runner.cc
index 88e078b..68d5e32 100644
--- a/src/test/fake_task_runner.cc
+++ b/src/test/fake_task_runner.cc
@@ -52,6 +52,10 @@
   queue_.emplace(std::make_pair(test_clock_->Now() + delay, ++counter_), task);
 }
 
+size_t FakeTaskRunner::GetTaskQueueSize() const {
+  return queue_.size();
+}
+
 }  // namespace test
 }  // namespace provider
 }  // namespace weave
diff --git a/src/weave_unittest.cc b/src/weave_unittest.cc
index ebc66cd..b300f57 100644
--- a/src/weave_unittest.cc
+++ b/src/weave_unittest.cc
@@ -181,7 +181,10 @@
 
 class WeaveTest : public ::testing::Test {
  protected:
-  void SetUp() override {}
+  void SetUp() override {
+    EXPECT_CALL(wifi_, IsWifi24Supported()).WillRepeatedly(Return(true));
+    EXPECT_CALL(wifi_, IsWifi50Supported()).WillRepeatedly(Return(false));
+  }
 
   template <class UrlMatcher>
   void ExpectRequest(HttpClient::Method method,
diff --git a/third_party/get_libevent.sh b/third_party/get_libevent.sh
deleted file mode 100755
index 9985bc0..0000000
--- a/third_party/get_libevent.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-# Copyright 2015 The Weave Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Make libevent.
-# Example uses libevent to implement HTTPS server. This capability is
-# available only in version 2.1.x-alpha. Step could be replaced with apt-get
-# in future.
-cd $(dirname "$0")
-THIRD_PARTY=$(pwd)
-
-mkdir -p include lib
-
-rm -rf $THIRD_PARTY/libevent
-git clone https://github.com/libevent/libevent.git || exit 1
-cd libevent || exit 1
-
-./autogen.sh || exit 1
-./configure --disable-shared || exit 1
-make || exit 1
-if [ -z "$DISABLE_LIBEVENT_TEST" ]; then
-  echo -e "\n\nTesting libevent...\nCan take several minutes.\n"
-  make verify || exit 1
-fi
-cp -rf include/*.h include/event2 $THIRD_PARTY/include/ || exit 1
-cp -f .libs/lib* $THIRD_PARTY/lib/ || exit 1
-
-rm -rf $THIRD_PARTY/libevent
diff --git a/third_party/get_libevhtp.sh b/third_party/get_libevhtp.sh
new file mode 100755
index 0000000..c270813
--- /dev/null
+++ b/third_party/get_libevhtp.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2016 The Weave Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Make libevhtp.
+# Example uses libevhtp to implement HTTPS server. This step could be
+# replaced with apt-get in future (Debian jessie, Ubuntu vivid).
+cd $(dirname "$0")
+THIRD_PARTY=$(pwd)
+
+mkdir -p include lib
+
+rm -rf $THIRD_PARTY/libevhtp
+curl -L https://github.com/ellzey/libevhtp/archive/1.2.10.tar.gz | tar xz || exit 1
+mv libevhtp-1.2.10 $THIRD_PARTY/libevhtp || exit 1
+cd $THIRD_PARTY/libevhtp || exit 1
+
+cmake -D EVHTP_DISABLE_REGEX:BOOL=ON . || exit 1
+make evhtp || exit 1
+
+cp -rf evhtp-config.h evhtp.h evthr/evthr.h htparse/htparse.h $THIRD_PARTY/include/ || exit 1
+cp -f libevhtp.a $THIRD_PARTY/lib/ || exit 1
+
+rm -rf $THIRD_PARTY/libevhtp
diff --git a/third_party/third_party.mk b/third_party/third_party.mk
index 8a11e2d..7f651a2 100644
--- a/third_party/third_party.mk
+++ b/third_party/third_party.mk
@@ -64,15 +64,15 @@
 	rm -rf third_party/googletest
 
 ###
-# libevent (third_party, downloaded on build)
+# libevhtp (third_party, downloaded on build)
 
-third_party/include/event2/event.h :
-	@echo Downloading and building libevent...
-	DISABLE_LIBEVENT_TEST=1 third_party/get_libevent.sh
-	@echo Finished downloading and building libevent.
+third_party/lib/libevhtp.a : third_party/include/evhtp.h
+third_party/include/evhtp.h :
+	@echo Downloading and building libevhtp...
+	third_party/get_libevhtp.sh
+	@echo Finished downloading and building libevhtp.
 
-clean-libevent :
-	rm -rf third_party/include/ev* third_party/include/event2
-	rm -rf third_party/lib/libevent*
-	rm -rf third_party/libevent
-
+clean-libevhtp :
+	rm -rf third_party/include/evhtp.h third_party/include/evhtp-config.h third_party/include/evthr.h third_party/include/htparse.h
+	rm -rf third_party/lib/libevhtp.a
+	rm -rf third_party/libevhtp