blob: 7224ceb8f06da25b08d863fd584ce0965260ae1a [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>
20#include <chromeos/map_utils.h>
Alex Vakulenko950687b2015-09-18 13:41:58 -070021#include <chromeos/streams/file_stream.h>
Alex Vakulenko67ec91b2015-09-24 16:36:56 -070022#include <chromeos/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"
Daniel Eratf719c982015-08-14 17:33:16 -060025#include "libwebserv/request.h"
26#include "libwebserv/request_handler_callback.h"
27#include "libwebserv/response.h"
28#include "libwebserv/server.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 Vakulenko330a10f2015-09-23 16:51:02 -070036void IgnoreDBusError(chromeos::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|.
40void WriteResponseData(chromeos::StreamPtr src_stream,
41 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 Vakulenko330a10f2015-09-23 16:51:02 -070044 chromeos::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.
48 auto on_success = [](chromeos::StreamPtr, chromeos::StreamPtr, uint64_t) {};
49 auto on_error = [](chromeos::StreamPtr, chromeos::StreamPtr,
50 const chromeos::Error*) {};
51 chromeos::stream_utils::CopyData(
52 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
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080061ProtocolHandler::ProtocolHandler(const std::string& name, Server* server)
62 : 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.
71 auto handler_ids = chromeos::GetMapKeys(request_handlers_);
72 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
95chromeos::Blob ProtocolHandler::GetCertificateFingerprint() const {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080096 chromeos::Blob fingerprint;
97 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,
112 std::map<ProtocolHandlerProxy*, std::string>{},
113 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 Vakulenko3d2d5632015-03-02 15:58:32 -0800158void ProtocolHandler::Connect(ProtocolHandlerProxy* proxy) {
159 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 Vakulenko3d8c9122015-03-13 13:54:00 -0700184 ProtocolHandlerProxy* 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
193void ProtocolHandler::AddHandlerError(int handler_id, chromeos::Error* error) {
194 // 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,
201 chromeos::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()) {
205 chromeos::Error::AddToPrintf(error, FROM_HERE,
206 chromeos::errors::dbus::kDomain,
207 DBUS_ERROR_FAILED,
208 "Unknown request handler '%s'",
209 remote_handler_id.c_str());
210 return false;
211 }
212 auto handler_iter = request_handlers_.find(id_iter->second);
213 if (handler_iter == request_handlers_.end()) {
214 chromeos::Error::AddToPrintf(error, FROM_HERE,
215 chromeos::errors::dbus::kDomain,
216 DBUS_ERROR_FAILED,
217 "Handler # %d is no longer available",
218 id_iter->second);
219 return false;
220 }
221 handler_iter->second.handler->HandleRequest(
Alex Vakulenko83e66cd2015-04-24 14:51:58 -0700222 std::move(request),
223 std::unique_ptr<Response>{new Response{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 Vakulenko330a10f2015-09-23 16:51:02 -0700231 chromeos::StreamPtr data_stream) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800232 ProtocolHandlerProxy* proxy = GetRequestProtocolHandlerProxy(request_id);
233 if (!proxy)
Alex Vakulenko31a63792015-02-03 12:44:57 -0800234 return;
Alex Vakulenko31a63792015-02-03 12:44:57 -0800235
236 std::vector<std::tuple<std::string, std::string>> header_list;
237 header_list.reserve(headers.size());
238 for (const auto& pair : headers)
239 header_list.emplace_back(pair.first, pair.second);
240
Alex Vakulenko330a10f2015-09-23 16:51:02 -0700241 int64_t data_size = -1;
242 if (data_stream->CanGetSize())
243 data_size = data_stream->GetRemainingSize();
244 proxy->CompleteRequestAsync(
245 request_id, status_code, header_list, data_size,
246 base::Bind(&WriteResponseData, base::Passed(&data_stream)),
247 base::Bind(&IgnoreDBusError));
Alex Vakulenko31a63792015-02-03 12:44:57 -0800248}
249
250void ProtocolHandler::GetFileData(
251 const std::string& request_id,
252 int file_id,
Alex Vakulenko950687b2015-09-18 13:41:58 -0700253 const base::Callback<void(chromeos::StreamPtr)>& success_callback,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800254 const base::Callback<void(chromeos::Error*)>& error_callback) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800255 ProtocolHandlerProxy* proxy = GetRequestProtocolHandlerProxy(request_id);
256 CHECK(proxy);
257
Alex Vakulenko950687b2015-09-18 13:41:58 -0700258 // Store the success/error callback in a shared object so it can be referenced
259 // by the two wrapper callbacks. Since the original callbacks MAY contain
260 // move-only types, copying the base::Callback object is generally unsafe and
261 // may destroy the source object of the copy (despite the fact that it is
262 // constant). So, here we move both callbacks to |Callbacks| structure and
263 // use a shared pointer to it in both success and error callback wrappers.
264 struct Callbacks {
265 base::Callback<void(chromeos::StreamPtr)> on_success;
266 base::Callback<void(chromeos::Error*)> on_error;
267 };
268 auto callbacks = std::make_shared<Callbacks>();
269 callbacks->on_success = success_callback;
270 callbacks->on_error = error_callback;
271
272 auto on_success = [callbacks](const dbus::FileDescriptor& fd) {
273 chromeos::ErrorPtr error;
274 // Unfortunately there is no way to take ownership of the file descriptor
275 // since |fd| is a const reference, so duplicate the descriptor.
276 int dupfd = dup(fd.value());
277 auto stream = chromeos::FileStream::FromFileDescriptor(dupfd, true, &error);
278 if (!stream)
279 return callbacks->on_error.Run(error.get());
280 callbacks->on_success.Run(std::move(stream));
281 };
282 auto on_error = [callbacks](chromeos::Error* error) {
283 callbacks->on_error.Run(error);
284 };
285
286 proxy->GetRequestFileDataAsync(request_id, file_id, base::Bind(on_success),
287 base::Bind(on_error));
Alex Vakulenko31a63792015-02-03 12:44:57 -0800288}
289
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800290ProtocolHandler::ProtocolHandlerProxy*
291ProtocolHandler::GetRequestProtocolHandlerProxy(
292 const std::string& request_id) const {
293 auto iter = request_id_map_.find(request_id);
294 if (iter == request_id_map_.end()) {
295 LOG(ERROR) << "Can't find pending request with ID " << request_id;
296 return nullptr;
297 }
298 std::string handler_id = iter->second;
299 auto find_proxy_by_id = [handler_id](decltype(*proxies_.begin()) pair) {
300 return pair.second->id() == handler_id;
301 };
302 auto proxy_iter = std::find_if(proxies_.begin(), proxies_.end(),
303 find_proxy_by_id);
304 if (proxy_iter == proxies_.end()) {
305 LOG(WARNING) << "Completing a request after the handler proxy is removed";
306 return nullptr;
307 }
308 return proxy_iter->second;
309}
310
Alex Vakulenko31a63792015-02-03 12:44:57 -0800311
312} // namespace libwebserv