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