1 // Copyright 2015 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "buffet/webserv_client.h"
16 
17 #include <memory>
18 #include <string>
19 
20 #include <libwebserv/protocol_handler.h>
21 #include <libwebserv/request.h>
22 #include <libwebserv/response.h>
23 #include <libwebserv/server.h>
24 
25 #include "buffet/dbus_constants.h"
26 #include "buffet/socket_stream.h"
27 
28 namespace buffet {
29 
30 namespace {
31 
32 using weave::provider::HttpServer;
33 
34 class RequestImpl : public HttpServer::Request {
35  public:
RequestImpl(std::unique_ptr<libwebserv::Request> request,std::unique_ptr<libwebserv::Response> response)36   explicit RequestImpl(std::unique_ptr<libwebserv::Request> request,
37                        std::unique_ptr<libwebserv::Response> response)
38       : request_{std::move(request)}, response_{std::move(response)} {}
~RequestImpl()39   ~RequestImpl() override {}
40 
41   // HttpServer::Request implementation.
GetPath() const42   std::string GetPath() const override { return request_->GetPath(); }
43 
GetFirstHeader(const std::string & name) const44   std::string GetFirstHeader(const std::string& name) const override {
45     return request_->GetFirstHeader(name);
46   }
47 
48   // TODO(avakulenko): Remove this method and rewrite all call sites in libweave
49   // to use GetDataStream() instead.
GetData()50   std::string GetData() override {
51     if (request_data_)
52       return *request_data_;
53 
54     request_data_.reset(new std::string);
55     auto stream = request_->GetDataStream();
56     if (stream) {
57       if (stream->CanGetSize())
58         request_data_->reserve(stream->GetRemainingSize());
59       std::vector<char> buffer(16 * 1024);  // 16K seems to be good enough.
60       size_t sz = 0;
61       while (stream->ReadBlocking(buffer.data(), buffer.size(), &sz, nullptr) &&
62              sz > 0) {
63         request_data_->append(buffer.data(), buffer.data() + sz);
64       }
65     }
66     return *request_data_;
67   }
68 
SendReply(int status_code,const std::string & data,const std::string & mime_type)69   void SendReply(int status_code,
70                  const std::string& data,
71                  const std::string& mime_type) override {
72     response_->ReplyWithText(status_code, data, mime_type);
73   }
74 
GetDataStream() const75   std::unique_ptr<weave::Stream> GetDataStream() const {
76     auto stream = std::unique_ptr<weave::Stream>{
77         new SocketStream{request_->GetDataStream()}};
78     return stream;
79   }
80 
81  private:
82   std::unique_ptr<libwebserv::Request> request_;
83   std::unique_ptr<libwebserv::Response> response_;
84   mutable std::unique_ptr<std::string> request_data_;
85 
86   DISALLOW_COPY_AND_ASSIGN(RequestImpl);
87 };
88 
89 }  // namespace
90 
WebServClient(const scoped_refptr<dbus::Bus> & bus,brillo::dbus_utils::AsyncEventSequencer * sequencer,const base::Closure & server_available_callback)91 WebServClient::WebServClient(
92     const scoped_refptr<dbus::Bus>& bus,
93     brillo::dbus_utils::AsyncEventSequencer* sequencer,
94     const base::Closure& server_available_callback)
95     : server_available_callback_{server_available_callback} {
96   web_server_ = libwebserv::Server::ConnectToServerViaDBus(
97       bus, buffet::dbus_constants::kServiceName,
98       sequencer->GetHandler("Server::Connect failed.", true),
99       base::Bind(&base::DoNothing),
100       base::Bind(&base::DoNothing));
101   web_server_->OnProtocolHandlerConnected(
102       base::Bind(&WebServClient::OnProtocolHandlerConnected,
103                  weak_ptr_factory_.GetWeakPtr()));
104   web_server_->OnProtocolHandlerDisconnected(
105       base::Bind(&WebServClient::OnProtocolHandlerDisconnected,
106                  weak_ptr_factory_.GetWeakPtr()));
107 }
108 
~WebServClient()109 WebServClient::~WebServClient() {}
110 
AddHttpRequestHandler(const std::string & path,const RequestHandlerCallback & callback)111 void WebServClient::AddHttpRequestHandler(
112     const std::string& path,
113     const RequestHandlerCallback& callback) {
114   web_server_->GetDefaultHttpHandler()->AddHandlerCallback(
115       path, "", base::Bind(&WebServClient::OnRequest,
116                            weak_ptr_factory_.GetWeakPtr(), callback));
117 }
118 
AddHttpsRequestHandler(const std::string & path,const RequestHandlerCallback & callback)119 void WebServClient::AddHttpsRequestHandler(
120     const std::string& path,
121     const RequestHandlerCallback& callback) {
122   web_server_->GetDefaultHttpsHandler()->AddHandlerCallback(
123       path, "", base::Bind(&WebServClient::OnRequest,
124                            weak_ptr_factory_.GetWeakPtr(), callback));
125 }
126 
GetHttpPort() const127 uint16_t WebServClient::GetHttpPort() const {
128   return http_port_;
129 }
130 
GetHttpsPort() const131 uint16_t WebServClient::GetHttpsPort() const {
132   return https_port_;
133 }
134 
GetRequestTimeout() const135 base::TimeDelta WebServClient::GetRequestTimeout() const {
136   return web_server_->GetDefaultRequestTimeout();
137 }
138 
GetHttpsCertificateFingerprint() const139 brillo::Blob WebServClient::GetHttpsCertificateFingerprint() const {
140   return certificate_;
141 }
142 
OnRequest(const RequestHandlerCallback & callback,std::unique_ptr<libwebserv::Request> request,std::unique_ptr<libwebserv::Response> response)143 void WebServClient::OnRequest(const RequestHandlerCallback& callback,
144                               std::unique_ptr<libwebserv::Request> request,
145                               std::unique_ptr<libwebserv::Response> response) {
146   std::unique_ptr<Request> weave_request{
147       new RequestImpl{std::move(request), std::move(response)}};
148   callback.Run(std::move(weave_request));
149 }
150 
OnProtocolHandlerConnected(libwebserv::ProtocolHandler * protocol_handler)151 void WebServClient::OnProtocolHandlerConnected(
152     libwebserv::ProtocolHandler* protocol_handler) {
153   if (protocol_handler->GetName() == libwebserv::ProtocolHandler::kHttp) {
154     http_port_ = *protocol_handler->GetPorts().begin();
155   } else if (protocol_handler->GetName() ==
156              libwebserv::ProtocolHandler::kHttps) {
157     https_port_ = *protocol_handler->GetPorts().begin();
158     certificate_ = protocol_handler->GetCertificateFingerprint();
159   }
160   if (https_port_ && https_port_)
161     server_available_callback_.Run();
162 }
163 
OnProtocolHandlerDisconnected(libwebserv::ProtocolHandler * protocol_handler)164 void WebServClient::OnProtocolHandlerDisconnected(
165     libwebserv::ProtocolHandler* protocol_handler) {
166   if (protocol_handler->GetName() == libwebserv::ProtocolHandler::kHttp) {
167     http_port_ = 0;
168   } else if (protocol_handler->GetName() ==
169              libwebserv::ProtocolHandler::kHttps) {
170     https_port_ = 0;
171     certificate_.clear();
172   }
173 }
174 
175 }  // namespace buffet
176