| // Copyright 2015 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #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 { |
| |
| using weave::provider::HttpServer; |
| |
| class RequestImpl : public HttpServer::Request { |
| public: |
| explicit RequestImpl(std::unique_ptr<libwebserv::Request> request, |
| std::unique_ptr<libwebserv::Response> response) |
| : request_{std::move(request)}, response_{std::move(response)} {} |
| ~RequestImpl() override {} |
| |
| // HttpServer::Request implementation. |
| 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. |
| std::string GetData() override { |
| if (request_data_) |
| return *request_data_; |
| |
| request_data_.reset(new std::string); |
| auto stream = request_->GetDataStream(); |
| if (stream) { |
| if (stream->CanGetSize()) |
| request_data_->reserve(stream->GetRemainingSize()); |
| std::vector<char> 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_->append(buffer.data(), buffer.data() + sz); |
| } |
| } |
| return *request_data_; |
| } |
| |
| void SendReply(int status_code, |
| const std::string& data, |
| const std::string& mime_type) override { |
| response_->ReplyWithText(status_code, data, mime_type); |
| } |
| |
| std::unique_ptr<weave::Stream> GetDataStream() const { |
| auto stream = std::unique_ptr<weave::Stream>{ |
| new SocketStream{request_->GetDataStream()}}; |
| return stream; |
| } |
| |
| private: |
| std::unique_ptr<libwebserv::Request> request_; |
| std::unique_ptr<libwebserv::Response> response_; |
| mutable std::unique_ptr<std::string> request_data_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RequestImpl); |
| }; |
| |
| } // namespace |
| |
| WebServClient::WebServClient( |
| const scoped_refptr<dbus::Bus>& bus, |
| brillo::dbus_utils::AsyncEventSequencer* sequencer, |
| const base::Closure& server_available_callback) |
| : server_available_callback_{server_available_callback} { |
| web_server_ = libwebserv::Server::ConnectToServerViaDBus( |
| bus, buffet::dbus_constants::kServiceName, |
| sequencer->GetHandler("Server::Connect failed.", true), |
| base::Bind(&base::DoNothing), |
| base::Bind(&base::DoNothing)); |
| web_server_->OnProtocolHandlerConnected( |
| base::Bind(&WebServClient::OnProtocolHandlerConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| web_server_->OnProtocolHandlerDisconnected( |
| base::Bind(&WebServClient::OnProtocolHandlerDisconnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| WebServClient::~WebServClient() {} |
| |
| void WebServClient::AddHttpRequestHandler( |
| const std::string& path, |
| const RequestHandlerCallback& callback) { |
| web_server_->GetDefaultHttpHandler()->AddHandlerCallback( |
| path, "", base::Bind(&WebServClient::OnRequest, |
| weak_ptr_factory_.GetWeakPtr(), callback)); |
| } |
| |
| void WebServClient::AddHttpsRequestHandler( |
| const std::string& path, |
| const RequestHandlerCallback& callback) { |
| web_server_->GetDefaultHttpsHandler()->AddHandlerCallback( |
| path, "", 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_; |
| } |
| |
| base::TimeDelta WebServClient::GetRequestTimeout() const { |
| return web_server_->GetDefaultRequestTimeout(); |
| } |
| |
| brillo::Blob WebServClient::GetHttpsCertificateFingerprint() const { |
| return certificate_; |
| } |
| |
| void WebServClient::OnRequest(const RequestHandlerCallback& callback, |
| std::unique_ptr<libwebserv::Request> request, |
| std::unique_ptr<libwebserv::Response> response) { |
| std::unique_ptr<Request> weave_request{ |
| new RequestImpl{std::move(request), std::move(response)}}; |
| callback.Run(std::move(weave_request)); |
| } |
| |
| 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(); |
| } |
| if (https_port_ && https_port_) |
| server_available_callback_.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(); |
| } |
| } |
| |
| } // namespace buffet |