libweave: Extracted interaction with libwebserv into WebServClient Class implements weave::HttpServer using libwebserv and it's going to be moved out of libweave. BUG=brillo:1252 TEST='FEATURES=test emerge-gizmo buffet' Change-Id: I069831d50e39478c281073a62ad81ef63f3065a6 Reviewed-on: https://chromium-review.googlesource.com/290141 Commit-Queue: Vitaly Buka <vitalybuka@chromium.org> Trybot-Ready: Vitaly Buka <vitalybuka@chromium.org> Tested-by: Vitaly Buka <vitalybuka@chromium.org> Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/buffet/buffet.gyp b/buffet/buffet.gyp index 1c619fa..c72b4d8 100644 --- a/buffet/buffet.gyp +++ b/buffet/buffet.gyp
@@ -67,7 +67,7 @@ '../libweave/src/privet/privet_types.cc', '../libweave/src/privet/publisher.cc', '../libweave/src/privet/security_manager.cc', - '../libweave/src/privet/privet_types.cc', + '../libweave/src/privet/webserv_client.cc', '../libweave/src/privet/wifi_bootstrap_manager.cc', '../libweave/src/privet/wifi_ssid_generator.cc', '../libweave/src/registration_status.cc',
diff --git a/libweave/include/weave/http_server.h b/libweave/include/weave/http_server.h new file mode 100644 index 0000000..db30252 --- /dev/null +++ b/libweave/include/weave/http_server.h
@@ -0,0 +1,54 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIBWEAVE_INCLUDE_WEAVE_HTTP_SERVER_H_ +#define LIBWEAVE_INCLUDE_WEAVE_HTTP_SERVER_H_ + +#include <string> +#include <vector> + +#include <chromeos/secure_blob.h> + +#include <base/callback.h> + +namespace weave { + +class HttpServer { + public: + class Request { + public: + virtual const std::string& GetPath() const = 0; + virtual std::string GetFirstHeader(const std::string& name) const = 0; + virtual const std::vector<uint8_t>& GetData() const = 0; + + protected: + virtual ~Request() = default; + }; + + using OnReplyCallback = base::Callback<void(int status_code, + const std::string& data, + const std::string& mime_type)>; + + using OnRequestCallback = + base::Callback<void(const Request& request, + const OnReplyCallback& callback)>; + + // Adds notification callback for server started/stopped serving requests. + virtual void AddOnStateChangedCallback(const base::Closure& callback) = 0; + + // Adds callback called on new http/https requests with the given path prefix. + virtual void AddRequestHandler(const std::string& path_prefix, + const OnRequestCallback& callback) = 0; + + virtual uint16_t GetHttpPort() const = 0; + virtual uint16_t GetHttpsPort() const = 0; + virtual const chromeos::Blob& GetHttpsCertificateFingerprint() const = 0; + + protected: + virtual ~HttpServer() = default; +}; + +} // namespace weave + +#endif // LIBWEAVE_INCLUDE_WEAVE_HTTP_SERVER_H_
diff --git a/libweave/src/privet/privet_manager.cc b/libweave/src/privet/privet_manager.cc index 32142f7..3e9f604 100644 --- a/libweave/src/privet/privet_manager.cc +++ b/libweave/src/privet/privet_manager.cc
@@ -11,6 +11,7 @@ #include <base/bind.h> #include <base/command_line.h> #include <base/json/json_reader.h> +#include <base/json/json_writer.h> #include <base/memory/weak_ptr.h> #include <base/scoped_observer.h> #include <base/strings/string_number_conversions.h> @@ -34,7 +35,9 @@ #include "libweave/src/privet/device_delegate.h" #include "libweave/src/privet/privet_handler.h" #include "libweave/src/privet/publisher.h" +#include "libweave/src/privet/webserv_client.h" #include "weave/network.h" +#include "weave/http_server.h" namespace weave { namespace privet { @@ -42,14 +45,6 @@ namespace { using chromeos::dbus_utils::AsyncEventSequencer; -using libwebserv::ProtocolHandler; -using libwebserv::Request; -using libwebserv::Response; - -std::string GetFirstHeader(const Request& request, const std::string& name) { - std::vector<std::string> headers = request.GetHeader(name); - return headers.empty() ? std::string() : headers.front(); -} } // namespace @@ -93,30 +88,16 @@ new PrivetHandler(cloud_.get(), device_.get(), security_.get(), wifi_bootstrap_manager_.get(), publisher_.get())); - web_server_.reset(new libwebserv::Server); - web_server_->OnProtocolHandlerConnected(base::Bind( - &Manager::OnProtocolHandlerConnected, weak_ptr_factory_.GetWeakPtr())); - web_server_->OnProtocolHandlerDisconnected(base::Bind( - &Manager::OnProtocolHandlerDisconnected, weak_ptr_factory_.GetWeakPtr())); - - web_server_->Connect(bus, buffet::kServiceName, - sequencer->GetHandler("Server::Connect failed.", true), - base::Bind(&base::DoNothing), - base::Bind(&base::DoNothing)); - - web_server_->GetDefaultHttpHandler()->AddHandlerCallback( - "/privet/", "", - base::Bind(&Manager::PrivetRequestHandler, base::Unretained(this))); - web_server_->GetDefaultHttpsHandler()->AddHandlerCallback( - "/privet/", "", - base::Bind(&Manager::PrivetRequestHandler, base::Unretained(this))); + web_server_.reset(new WebServClient{bus, sequencer}); + web_server_->AddOnStateChangedCallback(base::Bind( + &Manager::OnHttpServerStatusChanged, weak_ptr_factory_.GetWeakPtr())); + web_server_->AddRequestHandler("/privet/", + base::Bind(&Manager::PrivetRequestHandler, + weak_ptr_factory_.GetWeakPtr())); if (options.enable_ping) { - web_server_->GetDefaultHttpHandler()->AddHandlerCallback( - "/privet/ping", chromeos::http::request_type::kGet, - base::Bind(&Manager::HelloWorldHandler, base::Unretained(this))); - web_server_->GetDefaultHttpsHandler()->AddHandlerCallback( - "/privet/ping", chromeos::http::request_type::kGet, - base::Bind(&Manager::HelloWorldHandler, base::Unretained(this))); + web_server_->AddRequestHandler("/privet/ping", + base::Bind(&Manager::HelloWorldHandler, + weak_ptr_factory_.GetWeakPtr())); } } @@ -141,55 +122,55 @@ } void Manager::Shutdown() { - web_server_->Disconnect(); + web_server_.reset(); } void Manager::OnDeviceInfoChanged() { OnChanged(); } -void Manager::PrivetRequestHandler(std::unique_ptr<Request> request, - std::unique_ptr<Response> response) { +void Manager::PrivetRequestHandler( + const HttpServer::Request& request, + const HttpServer::OnReplyCallback& callback) { std::string auth_header = - GetFirstHeader(*request, chromeos::http::request_header::kAuthorization); + request.GetFirstHeader(chromeos::http::request_header::kAuthorization); if (auth_header.empty() && disable_security_) auth_header = "Privet anonymous"; - std::string data(request->GetData().begin(), request->GetData().end()); + std::string data(request.GetData().begin(), request.GetData().end()); VLOG(3) << "Input: " << data; base::DictionaryValue empty; std::unique_ptr<base::Value> value; - const base::DictionaryValue* dictionary = nullptr; + const base::DictionaryValue* dictionary = ∅ - if (data.empty()) { - dictionary = ∅ - } else { - std::string content_type = chromeos::mime::RemoveParameters( - GetFirstHeader(*request, chromeos::http::request_header::kContentType)); - if (content_type == chromeos::mime::application::kJson) { - value.reset(base::JSONReader::Read(data).release()); - if (value) - value->GetAsDictionary(&dictionary); - } + std::string content_type = chromeos::mime::RemoveParameters( + request.GetFirstHeader(chromeos::http::request_header::kContentType)); + if (content_type == chromeos::mime::application::kJson) { + value.reset(base::JSONReader::Read(data).release()); + if (value) + value->GetAsDictionary(&dictionary); } privet_handler_->HandleRequest( - request->GetPath(), auth_header, dictionary, - base::Bind(&Manager::PrivetResponseHandler, base::Unretained(this), - base::Passed(&response))); + request.GetPath(), auth_header, dictionary, + base::Bind(&Manager::PrivetResponseHandler, + weak_ptr_factory_.GetWeakPtr(), callback)); } -void Manager::PrivetResponseHandler(std::unique_ptr<Response> response, +void Manager::PrivetResponseHandler(const HttpServer::OnReplyCallback& callback, int status, const base::DictionaryValue& output) { VLOG(3) << "status: " << status << ", Output: " << output; - response->ReplyWithJson(status, &output); + std::string data; + base::JSONWriter::WriteWithOptions( + output, base::JSONWriter::OPTIONS_PRETTY_PRINT, &data); + callback.Run(status, data, chromeos::mime::application::kJson); } -void Manager::HelloWorldHandler(std::unique_ptr<Request> request, - std::unique_ptr<Response> response) { - response->ReplyWithText(chromeos::http::status_code::Ok, "Hello, world!", - chromeos::mime::text::kPlain); +void Manager::HelloWorldHandler(const HttpServer::Request& request, + const HttpServer::OnReplyCallback& callback) { + callback.Run(chromeos::http::status_code::Ok, "Hello, world!", + chromeos::mime::text::kPlain); } void Manager::OnChanged() { @@ -201,27 +182,15 @@ OnChanged(); } -void Manager::OnProtocolHandlerConnected(ProtocolHandler* protocol_handler) { - if (protocol_handler->GetName() == ProtocolHandler::kHttp) { - device_->SetHttpPort(*protocol_handler->GetPorts().begin()); +void Manager::OnHttpServerStatusChanged() { + if (device_->GetHttpEnpoint().first != web_server_->GetHttpPort()) { + device_->SetHttpPort(web_server_->GetHttpPort()); if (publisher_) publisher_->Update(); - } else if (protocol_handler->GetName() == ProtocolHandler::kHttps) { - device_->SetHttpsPort(*protocol_handler->GetPorts().begin()); - security_->SetCertificateFingerprint( - protocol_handler->GetCertificateFingerprint()); } -} - -void Manager::OnProtocolHandlerDisconnected(ProtocolHandler* protocol_handler) { - if (protocol_handler->GetName() == ProtocolHandler::kHttp) { - device_->SetHttpPort(0); - if (publisher_) - publisher_->Update(); - } else if (protocol_handler->GetName() == ProtocolHandler::kHttps) { - device_->SetHttpsPort(0); - security_->SetCertificateFingerprint({}); - } + device_->SetHttpsPort(web_server_->GetHttpsPort()); + security_->SetCertificateFingerprint( + web_server_->GetHttpsCertificateFingerprint()); } } // namespace privet
diff --git a/libweave/src/privet/privet_manager.h b/libweave/src/privet/privet_manager.h index bdcb298..29b803d 100644 --- a/libweave/src/privet/privet_manager.h +++ b/libweave/src/privet/privet_manager.h
@@ -17,6 +17,7 @@ #include "libweave/src/privet/security_manager.h" #include "libweave/src/privet/wifi_bootstrap_manager.h" #include "weave/device.h" +#include "weave/http_server.h" namespace chromeos { namespace dbus_utils { @@ -47,6 +48,7 @@ class PrivetHandler; class Publisher; class SecurityManager; +class WebServClient; class Manager : public Privet, public CloudDelegate::Observer { public: @@ -77,24 +79,20 @@ // CloudDelegate::Observer void OnDeviceInfoChanged() override; - void PrivetRequestHandler(std::unique_ptr<libwebserv::Request> request, - std::unique_ptr<libwebserv::Response> response); + void PrivetRequestHandler(const HttpServer::Request& request, + const HttpServer::OnReplyCallback& callback); - void PrivetResponseHandler(std::unique_ptr<libwebserv::Response> response, + void PrivetResponseHandler(const HttpServer::OnReplyCallback& callback, int status, const base::DictionaryValue& output); - void HelloWorldHandler(std::unique_ptr<libwebserv::Request> request, - std::unique_ptr<libwebserv::Response> response); + void HelloWorldHandler(const HttpServer::Request& request, + const HttpServer::OnReplyCallback& callback); void OnChanged(); void OnConnectivityChanged(bool online); - void OnProtocolHandlerConnected( - libwebserv::ProtocolHandler* protocol_handler); - - void OnProtocolHandlerDisconnected( - libwebserv::ProtocolHandler* protocol_handler); + void OnHttpServerStatusChanged(); bool disable_security_{false}; std::unique_ptr<CloudDelegate> cloud_; @@ -103,7 +101,8 @@ std::unique_ptr<WifiBootstrapManager> wifi_bootstrap_manager_; std::unique_ptr<Publisher> publisher_; std::unique_ptr<PrivetHandler> privet_handler_; - std::unique_ptr<libwebserv::Server> web_server_; + + std::unique_ptr<WebServClient> web_server_; ScopedObserver<CloudDelegate, CloudDelegate::Observer> cloud_observer_{this};
diff --git a/libweave/src/privet/webserv_client.cc b/libweave/src/privet/webserv_client.cc new file mode 100644 index 0000000..b8ba74d --- /dev/null +++ b/libweave/src/privet/webserv_client.cc
@@ -0,0 +1,136 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "libweave/src/privet/webserv_client.h" +// +#include <memory> +#include <string> + +#include <libwebserv/protocol_handler.h> +#include <libwebserv/request.h> +#include <libwebserv/response.h> +#include <libwebserv/server.h> + +#include "buffet/dbus_constants.h" + +namespace weave { +namespace privet { + +namespace { + +class RequestImpl : public HttpServer::Request { + public: + explicit RequestImpl(std::unique_ptr<libwebserv::Request> request) + : request_{std::move(request)} {} + ~RequestImpl() override {} + + // HttpServer::Request implementation. + const std::string& GetPath() const override { return request_->GetPath(); } + std::string GetFirstHeader(const std::string& name) const override { + return request_->GetFirstHeader(name); + } + const std::vector<uint8_t>& GetData() const override { + return request_->GetData(); + } + + private: + std::unique_ptr<libwebserv::Request> request_; + + DISALLOW_COPY_AND_ASSIGN(RequestImpl); +}; + +} // namespace + +WebServClient::~WebServClient() { + web_server_->Disconnect(); +} + +void WebServClient::AddOnStateChangedCallback(const base::Closure& callback) { + on_state_changed_callbacks_.push_back(callback); + callback.Run(); +} + +void WebServClient::AddRequestHandler(const std::string& path_prefix, + const OnRequestCallback& callback) { + web_server_->GetDefaultHttpHandler()->AddHandlerCallback( + path_prefix, "", base::Bind(&WebServClient::OnRequest, + weak_ptr_factory_.GetWeakPtr(), callback)); + web_server_->GetDefaultHttpsHandler()->AddHandlerCallback( + path_prefix, "", base::Bind(&WebServClient::OnRequest, + weak_ptr_factory_.GetWeakPtr(), callback)); +} + +uint16_t WebServClient::GetHttpPort() const { + return http_port_; +} + +uint16_t WebServClient::GetHttpsPort() const { + return https_port_; +} + +const chromeos::Blob& WebServClient::GetHttpsCertificateFingerprint() const { + return certificate_; +} + +WebServClient::WebServClient( + const scoped_refptr<dbus::Bus>& bus, + chromeos::dbus_utils::AsyncEventSequencer* sequencer) { + web_server_.reset(new libwebserv::Server); + web_server_->OnProtocolHandlerConnected( + base::Bind(&WebServClient::OnProtocolHandlerConnected, + weak_ptr_factory_.GetWeakPtr())); + web_server_->OnProtocolHandlerDisconnected( + base::Bind(&WebServClient::OnProtocolHandlerDisconnected, + weak_ptr_factory_.GetWeakPtr())); + + web_server_->Connect(bus, buffet::kServiceName, + sequencer->GetHandler("Server::Connect failed.", true), + base::Bind(&base::DoNothing), + base::Bind(&base::DoNothing)); +} + +void WebServClient::OnRequest(const OnRequestCallback& callback, + std::unique_ptr<libwebserv::Request> request, + std::unique_ptr<libwebserv::Response> response) { + callback.Run( + RequestImpl{std::move(request)}, + base::Bind(&WebServClient::OnResponse, weak_ptr_factory_.GetWeakPtr(), + base::Passed(&response))); +} + +void WebServClient::OnResponse(std::unique_ptr<libwebserv::Response> response, + int status_code, + const std::string& data, + const std::string& mime_type) { + response->Reply(status_code, data.data(), data.size(), mime_type); +} + +void WebServClient::OnProtocolHandlerConnected( + libwebserv::ProtocolHandler* protocol_handler) { + if (protocol_handler->GetName() == libwebserv::ProtocolHandler::kHttp) { + http_port_ = *protocol_handler->GetPorts().begin(); + } else if (protocol_handler->GetName() == + libwebserv::ProtocolHandler::kHttps) { + https_port_ = *protocol_handler->GetPorts().begin(); + certificate_ = protocol_handler->GetCertificateFingerprint(); + } + for (const auto& cb : on_state_changed_callbacks_) + cb.Run(); +} + +void WebServClient::OnProtocolHandlerDisconnected( + libwebserv::ProtocolHandler* protocol_handler) { + if (protocol_handler->GetName() == libwebserv::ProtocolHandler::kHttp) { + http_port_ = 0; + } else if (protocol_handler->GetName() == + libwebserv::ProtocolHandler::kHttps) { + https_port_ = 0; + certificate_.clear(); + } + for (const auto& cb : on_state_changed_callbacks_) + cb.Run(); +} + +} // namespace privet +} // namespace weave
diff --git a/libweave/src/privet/webserv_client.h b/libweave/src/privet/webserv_client.h new file mode 100644 index 0000000..43eb859 --- /dev/null +++ b/libweave/src/privet/webserv_client.h
@@ -0,0 +1,82 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIBWEAVE_SRC_PRIVET_WEBSERV_CLIENT_H_ +#define LIBWEAVE_SRC_PRIVET_WEBSERV_CLIENT_H_ + +#include <memory> +#include <string> +#include <vector> + +#include <base/memory/weak_ptr.h> + +#include "weave/http_server.h" + +namespace dbus { +class Bus; +} + +namespace chromeos { +namespace dbus_utils { +class AsyncEventSequencer; +} +} + +namespace libwebserv { +class ProtocolHandler; +class Request; +class Response; +class Server; +} + +namespace weave { +namespace privet { + +// Wrapper around libwebserv that implements HttpServer interface. +class WebServClient : public HttpServer { + public: + WebServClient(const scoped_refptr<dbus::Bus>& bus, + chromeos::dbus_utils::AsyncEventSequencer* sequencer); + ~WebServClient() override; + + // HttpServer implementation. + void AddOnStateChangedCallback(const base::Closure& callback) override; + void AddRequestHandler(const std::string& path_prefix, + const OnRequestCallback& callback) override; + uint16_t GetHttpPort() const override; + uint16_t GetHttpsPort() const override; + const chromeos::Blob& GetHttpsCertificateFingerprint() const override; + + private: + void OnRequest(const OnRequestCallback& callback, + std::unique_ptr<libwebserv::Request> request, + std::unique_ptr<libwebserv::Response> response); + + void OnResponse(std::unique_ptr<libwebserv::Response> response, + int status_code, + const std::string& data, + const std::string& mime_type); + + void OnProtocolHandlerConnected( + libwebserv::ProtocolHandler* protocol_handler); + + void OnProtocolHandlerDisconnected( + libwebserv::ProtocolHandler* protocol_handler); + + uint16_t http_port_{0}; + uint16_t https_port_{0}; + chromeos::Blob certificate_; + + std::vector<base::Closure> on_state_changed_callbacks_; + + std::unique_ptr<libwebserv::Server> web_server_; + + base::WeakPtrFactory<WebServClient> weak_ptr_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(WebServClient); +}; + +} // namespace privet +} // namespace weave + +#endif // LIBWEAVE_SRC_PRIVET_WEBSERV_CLIENT_H_