| // 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 "buffet/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" |
| #include "buffet/socket_stream.h" |
| |
| namespace buffet { |
| |
| namespace { |
| |
| class RequestImpl : public weave::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); |
| } |
| |
| // TODO(avakulenko): Remove this method and rewrite all call sites in libweave |
| // to use GetDataStream() instead. |
| const std::vector<uint8_t>& GetData() const override { |
| if (!request_data_) |
| return *request_data_; |
| |
| request_data_.reset(new std::vector<uint8_t>); |
| auto stream = request_->GetDataStream(); |
| if (stream) { |
| if (stream->CanGetSize()) |
| request_data_->reserve(stream->GetRemainingSize()); |
| std::vector<uint8_t> buffer(16 * 1024); // 16K seems to be good enough. |
| size_t sz = 0; |
| while (stream->ReadBlocking(buffer.data(), buffer.size(), &sz, nullptr) && |
| sz > 0) { |
| request_data_->insert(request_data_->end(), |
| buffer.data(), buffer.data() + sz); |
| } |
| } |
| return *request_data_; |
| } |
| |
| std::unique_ptr<weave::Stream> GetDataStream() const override { |
| auto stream = std::unique_ptr<weave::Stream>{ |
| new SocketStream{request_->GetDataStream()}}; |
| return stream; |
| } |
| |
| private: |
| std::unique_ptr<libwebserv::Request> request_; |
| mutable std::unique_ptr<std::vector<uint8_t>> request_data_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RequestImpl); |
| }; |
| |
| } // namespace |
| |
| WebServClient::~WebServClient() { |
| web_server_->Disconnect(); |
| } |
| |
| void WebServClient::AddOnStateChangedCallback( |
| const OnStateChangedCallback& callback) { |
| on_state_changed_callbacks_.push_back(callback); |
| callback.Run(*this); |
| } |
| |
| 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::dbus_constants::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(*this); |
| } |
| |
| 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(*this); |
| } |
| |
| } // namespace buffet |