blob: 8c50d4769b25c16ba366ba39732c7f3ca12d4605 [file] [log] [blame]
Daniel Erat35f65872015-08-17 20:59:29 -06001// 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.
Alex Vakulenko31a63792015-02-03 12:44:57 -080014
Daniel Eratf719c982015-08-14 17:33:16 -060015#include "libwebserv/protocol_handler.h"
Alex Vakulenko31a63792015-02-03 12:44:57 -080016
17#include <tuple>
18
19#include <base/logging.h>
Alex Vakulenko75d6da22015-10-13 10:01:34 -070020#include <brillo/map_utils.h>
21#include <brillo/streams/file_stream.h>
22#include <brillo/streams/stream_utils.h>
Alex Vakulenko31a63792015-02-03 12:44:57 -080023
Christopher Wiley34bc9df2015-08-19 15:03:47 -070024#include "dbus_bindings/org.chromium.WebServer.RequestHandler.h"
Christopher Wiley6a460fe2015-12-15 11:29:57 -080025#include "libwebserv/dbus_server.h"
Daniel Eratf719c982015-08-14 17:33:16 -060026#include "libwebserv/request.h"
27#include "libwebserv/request_handler_callback.h"
Christopher Book692fdfd2015-11-24 08:53:31 -050028#include "libwebserv/response_impl.h"
Alex Vakulenko31a63792015-02-03 12:44:57 -080029#include "webservd/dbus-proxies.h"
Alex Vakulenko31a63792015-02-03 12:44:57 -080030
31namespace libwebserv {
32
33namespace {
34
Alex Vakulenko67ec91b2015-09-24 16:36:56 -070035// Dummy callback for async D-Bus errors.
Alex Vakulenko75d6da22015-10-13 10:01:34 -070036void IgnoreDBusError(brillo::Error* error) {}
Alex Vakulenko330a10f2015-09-23 16:51:02 -070037
38// Copies the data from |src_stream| to the destination stream represented
39// by a file descriptor |fd|.
Alex Vakulenko75d6da22015-10-13 10:01:34 -070040void WriteResponseData(brillo::StreamPtr src_stream,
Alex Vakulenko330a10f2015-09-23 16:51:02 -070041 const dbus::FileDescriptor& fd) {
Alex Vakulenko330a10f2015-09-23 16:51:02 -070042 int dupfd = dup(fd.value());
Alex Vakulenko67ec91b2015-09-24 16:36:56 -070043 auto dest_stream =
Alex Vakulenko75d6da22015-10-13 10:01:34 -070044 brillo::FileStream::FromFileDescriptor(dupfd, true, nullptr);
Alex Vakulenko67ec91b2015-09-24 16:36:56 -070045 CHECK(dest_stream);
46 // Dummy callbacks for success/error of data-copy operation. We ignore both
47 // notifications here.
Alex Vakulenko75d6da22015-10-13 10:01:34 -070048 auto on_success = [](brillo::StreamPtr, brillo::StreamPtr, uint64_t) {};
49 auto on_error = [](brillo::StreamPtr, brillo::StreamPtr,
50 const brillo::Error*) {};
51 brillo::stream_utils::CopyData(
Alex Vakulenko67ec91b2015-09-24 16:36:56 -070052 std::move(src_stream), std::move(dest_stream), base::Bind(on_success),
53 base::Bind(on_error));
Alex Vakulenko330a10f2015-09-23 16:51:02 -070054}
Alex Vakulenko31a63792015-02-03 12:44:57 -080055
56} // anonymous namespace
57
58const char ProtocolHandler::kHttp[] = "http";
59const char ProtocolHandler::kHttps[] = "https";
60
Christopher Wiley6a460fe2015-12-15 11:29:57 -080061ProtocolHandler::ProtocolHandler(const std::string& name, DBusServer* server)
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080062 : name_{name}, server_{server} {
63}
Alex Vakulenko31a63792015-02-03 12:44:57 -080064
65ProtocolHandler::~ProtocolHandler() {
66 // Remove any existing handlers, so the web server knows that we don't
67 // need them anymore.
68
69 // We need to get a copy of the map keys since removing the handlers will
70 // modify the map in the middle of the loop and that's not a good thing.
Alex Vakulenko75d6da22015-10-13 10:01:34 -070071 auto handler_ids = brillo::GetMapKeys(request_handlers_);
Alex Vakulenko31a63792015-02-03 12:44:57 -080072 for (int handler_id : handler_ids) {
73 RemoveHandler(handler_id);
74 }
75}
76
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080077std::string ProtocolHandler::GetName() const {
78 return name_;
Alex Vakulenko31a63792015-02-03 12:44:57 -080079}
80
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080081std::set<uint16_t> ProtocolHandler::GetPorts() const {
82 std::set<uint16_t> ports;
83 for (const auto& pair : proxies_)
84 ports.insert(pair.second->port());
85 return ports;
Alex Vakulenko31a63792015-02-03 12:44:57 -080086}
87
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080088std::set<std::string> ProtocolHandler::GetProtocols() const {
89 std::set<std::string> protocols;
90 for (const auto& pair : proxies_)
91 protocols.insert(pair.second->protocol());
92 return protocols;
Alex Vakulenko31a63792015-02-03 12:44:57 -080093}
94
Alex Vakulenko75d6da22015-10-13 10:01:34 -070095brillo::Blob ProtocolHandler::GetCertificateFingerprint() const {
96 brillo::Blob fingerprint;
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080097 for (const auto& pair : proxies_) {
98 fingerprint = pair.second->certificate_fingerprint();
99 if (!fingerprint.empty())
100 break;
101 }
102 return fingerprint;
Alex Vakulenko31a63792015-02-03 12:44:57 -0800103}
104
105int ProtocolHandler::AddHandler(
106 const std::string& url,
107 const std::string& method,
108 std::unique_ptr<RequestHandlerInterface> handler) {
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700109 request_handlers_.emplace(
110 ++last_handler_id_,
111 HandlerMapEntry{url, method,
Alex Vakulenko53eea372015-12-08 17:12:58 -0800112 std::map<ProtocolHandlerProxyInterface*, std::string>{},
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700113 std::move(handler)});
114 // For each instance of remote protocol handler object sharing the same name,
115 // add the request handler.
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800116 for (const auto& pair : proxies_) {
117 pair.second->AddRequestHandlerAsync(
Alex Vakulenko31a63792015-02-03 12:44:57 -0800118 url,
119 method,
120 server_->service_name_,
121 base::Bind(&ProtocolHandler::AddHandlerSuccess,
122 weak_ptr_factory_.GetWeakPtr(),
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700123 last_handler_id_,
124 pair.second),
Alex Vakulenko31a63792015-02-03 12:44:57 -0800125 base::Bind(&ProtocolHandler::AddHandlerError,
126 weak_ptr_factory_.GetWeakPtr(),
127 last_handler_id_));
128 }
129 return last_handler_id_;
130}
131
132int ProtocolHandler::AddHandlerCallback(
133 const std::string& url,
134 const std::string& method,
135 const base::Callback<RequestHandlerInterface::HandlerSignature>&
136 handler_callback) {
137 std::unique_ptr<RequestHandlerInterface> handler{
138 new RequestHandlerCallback{handler_callback}};
139 return AddHandler(url, method, std::move(handler));
140}
141
142bool ProtocolHandler::RemoveHandler(int handler_id) {
143 auto p = request_handlers_.find(handler_id);
144 if (p == request_handlers_.end())
145 return false;
146
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700147 for (const auto& pair : p->second.remote_handler_ids) {
148 pair.first->RemoveRequestHandlerAsync(
149 pair.second,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800150 base::Bind(&base::DoNothing),
Alex Vakulenko330a10f2015-09-23 16:51:02 -0700151 base::Bind(&IgnoreDBusError));
Alex Vakulenko31a63792015-02-03 12:44:57 -0800152 }
153
154 request_handlers_.erase(p);
155 return true;
156}
157
Alex Vakulenko53eea372015-12-08 17:12:58 -0800158void ProtocolHandler::Connect(ProtocolHandlerProxyInterface* proxy) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800159 proxies_.emplace(proxy->GetObjectPath(), proxy);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800160 for (const auto& pair : request_handlers_) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800161 proxy->AddRequestHandlerAsync(
Alex Vakulenko31a63792015-02-03 12:44:57 -0800162 pair.second.url,
163 pair.second.method,
164 server_->service_name_,
165 base::Bind(&ProtocolHandler::AddHandlerSuccess,
166 weak_ptr_factory_.GetWeakPtr(),
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700167 pair.first,
168 proxy),
Alex Vakulenko31a63792015-02-03 12:44:57 -0800169 base::Bind(&ProtocolHandler::AddHandlerError,
170 weak_ptr_factory_.GetWeakPtr(),
171 pair.first));
172 }
173}
174
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800175void ProtocolHandler::Disconnect(const dbus::ObjectPath& object_path) {
176 proxies_.erase(object_path);
177 if (proxies_.empty())
178 remote_handler_id_map_.clear();
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700179 for (auto& pair : request_handlers_)
180 pair.second.remote_handler_ids.clear();
Alex Vakulenko31a63792015-02-03 12:44:57 -0800181}
182
183void ProtocolHandler::AddHandlerSuccess(int handler_id,
Alex Vakulenko53eea372015-12-08 17:12:58 -0800184 ProtocolHandlerProxyInterface* proxy,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800185 const std::string& remote_handler_id) {
186 auto p = request_handlers_.find(handler_id);
187 CHECK(p != request_handlers_.end());
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700188 p->second.remote_handler_ids.emplace(proxy, remote_handler_id);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800189
190 remote_handler_id_map_.emplace(remote_handler_id, handler_id);
191}
192
Alex Vakulenko75d6da22015-10-13 10:01:34 -0700193void ProtocolHandler::AddHandlerError(int handler_id, brillo::Error* error) {
Alex Vakulenko31a63792015-02-03 12:44:57 -0800194 // Nothing to do at the moment.
195}
196
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800197bool ProtocolHandler::ProcessRequest(const std::string& protocol_handler_id,
198 const std::string& remote_handler_id,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800199 const std::string& request_id,
200 std::unique_ptr<Request> request,
Alex Vakulenko75d6da22015-10-13 10:01:34 -0700201 brillo::ErrorPtr* error) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800202 request_id_map_.emplace(request_id, protocol_handler_id);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800203 auto id_iter = remote_handler_id_map_.find(remote_handler_id);
204 if (id_iter == remote_handler_id_map_.end()) {
Alex Vakulenko75d6da22015-10-13 10:01:34 -0700205 brillo::Error::AddToPrintf(error, FROM_HERE,
206 brillo::errors::dbus::kDomain,
207 DBUS_ERROR_FAILED,
208 "Unknown request handler '%s'",
209 remote_handler_id.c_str());
Alex Vakulenko31a63792015-02-03 12:44:57 -0800210 return false;
211 }
212 auto handler_iter = request_handlers_.find(id_iter->second);
213 if (handler_iter == request_handlers_.end()) {
Alex Vakulenko75d6da22015-10-13 10:01:34 -0700214 brillo::Error::AddToPrintf(error, FROM_HERE,
215 brillo::errors::dbus::kDomain,
216 DBUS_ERROR_FAILED,
217 "Handler # %d is no longer available",
218 id_iter->second);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800219 return false;
220 }
221 handler_iter->second.handler->HandleRequest(
Alex Vakulenko83e66cd2015-04-24 14:51:58 -0700222 std::move(request),
Christopher Book692fdfd2015-11-24 08:53:31 -0500223 std::unique_ptr<Response>{new ResponseImpl{this, request_id}});
Alex Vakulenko31a63792015-02-03 12:44:57 -0800224 return true;
225}
226
227void ProtocolHandler::CompleteRequest(
228 const std::string& request_id,
229 int status_code,
230 const std::multimap<std::string, std::string>& headers,
Alex Vakulenko75d6da22015-10-13 10:01:34 -0700231 brillo::StreamPtr data_stream) {
Alex Vakulenko53eea372015-12-08 17:12:58 -0800232 ProtocolHandlerProxyInterface* proxy =
233 GetRequestProtocolHandlerProxy(request_id);
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800234 if (!proxy)
Alex Vakulenko31a63792015-02-03 12:44:57 -0800235 return;
Alex Vakulenko31a63792015-02-03 12:44:57 -0800236
237 std::vector<std::tuple<std::string, std::string>> header_list;
238 header_list.reserve(headers.size());
239 for (const auto& pair : headers)
240 header_list.emplace_back(pair.first, pair.second);
241
Alex Vakulenko330a10f2015-09-23 16:51:02 -0700242 int64_t data_size = -1;
243 if (data_stream->CanGetSize())
244 data_size = data_stream->GetRemainingSize();
245 proxy->CompleteRequestAsync(
246 request_id, status_code, header_list, data_size,
247 base::Bind(&WriteResponseData, base::Passed(&data_stream)),
248 base::Bind(&IgnoreDBusError));
Alex Vakulenko31a63792015-02-03 12:44:57 -0800249}
250
251void ProtocolHandler::GetFileData(
252 const std::string& request_id,
253 int file_id,
Alex Vakulenko75d6da22015-10-13 10:01:34 -0700254 const base::Callback<void(brillo::StreamPtr)>& success_callback,
255 const base::Callback<void(brillo::Error*)>& error_callback) {
Alex Vakulenko53eea372015-12-08 17:12:58 -0800256 ProtocolHandlerProxyInterface* proxy =
257 GetRequestProtocolHandlerProxy(request_id);
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800258 CHECK(proxy);
259
Alex Vakulenko950687b2015-09-18 13:41:58 -0700260 // Store the success/error callback in a shared object so it can be referenced
261 // by the two wrapper callbacks. Since the original callbacks MAY contain
262 // move-only types, copying the base::Callback object is generally unsafe and
263 // may destroy the source object of the copy (despite the fact that it is
264 // constant). So, here we move both callbacks to |Callbacks| structure and
265 // use a shared pointer to it in both success and error callback wrappers.
266 struct Callbacks {
Alex Vakulenko75d6da22015-10-13 10:01:34 -0700267 base::Callback<void(brillo::StreamPtr)> on_success;
268 base::Callback<void(brillo::Error*)> on_error;
Alex Vakulenko950687b2015-09-18 13:41:58 -0700269 };
270 auto callbacks = std::make_shared<Callbacks>();
271 callbacks->on_success = success_callback;
272 callbacks->on_error = error_callback;
273
274 auto on_success = [callbacks](const dbus::FileDescriptor& fd) {
Alex Vakulenko75d6da22015-10-13 10:01:34 -0700275 brillo::ErrorPtr error;
Alex Vakulenko950687b2015-09-18 13:41:58 -0700276 // Unfortunately there is no way to take ownership of the file descriptor
277 // since |fd| is a const reference, so duplicate the descriptor.
278 int dupfd = dup(fd.value());
Alex Vakulenko75d6da22015-10-13 10:01:34 -0700279 auto stream = brillo::FileStream::FromFileDescriptor(dupfd, true, &error);
Alex Vakulenko950687b2015-09-18 13:41:58 -0700280 if (!stream)
281 return callbacks->on_error.Run(error.get());
282 callbacks->on_success.Run(std::move(stream));
283 };
Alex Vakulenko75d6da22015-10-13 10:01:34 -0700284 auto on_error = [callbacks](brillo::Error* error) {
Alex Vakulenko950687b2015-09-18 13:41:58 -0700285 callbacks->on_error.Run(error);
286 };
287
288 proxy->GetRequestFileDataAsync(request_id, file_id, base::Bind(on_success),
289 base::Bind(on_error));
Alex Vakulenko31a63792015-02-03 12:44:57 -0800290}
291
Alex Vakulenko53eea372015-12-08 17:12:58 -0800292ProtocolHandler::ProtocolHandlerProxyInterface*
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800293ProtocolHandler::GetRequestProtocolHandlerProxy(
294 const std::string& request_id) const {
295 auto iter = request_id_map_.find(request_id);
296 if (iter == request_id_map_.end()) {
297 LOG(ERROR) << "Can't find pending request with ID " << request_id;
298 return nullptr;
299 }
300 std::string handler_id = iter->second;
301 auto find_proxy_by_id = [handler_id](decltype(*proxies_.begin()) pair) {
302 return pair.second->id() == handler_id;
303 };
304 auto proxy_iter = std::find_if(proxies_.begin(), proxies_.end(),
305 find_proxy_by_id);
306 if (proxy_iter == proxies_.end()) {
307 LOG(WARNING) << "Completing a request after the handler proxy is removed";
308 return nullptr;
309 }
310 return proxy_iter->second;
311}
312
Alex Vakulenko31a63792015-02-03 12:44:57 -0800313
314} // namespace libwebserv