blob: 7897c7610a50c0c72123f7453eadf8e21bd172b3 [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>
21
22#include "libwebserv/org.chromium.WebServer.RequestHandler.h"
Daniel Eratf719c982015-08-14 17:33:16 -060023#include "libwebserv/request.h"
24#include "libwebserv/request_handler_callback.h"
25#include "libwebserv/response.h"
26#include "libwebserv/server.h"
Alex Vakulenko31a63792015-02-03 12:44:57 -080027#include "webservd/dbus-proxies.h"
Alex Vakulenko31a63792015-02-03 12:44:57 -080028
29namespace libwebserv {
30
31namespace {
32
33// A dummy callback for async D-Bus errors.
34void IgnoreError(chromeos::Error* error) {}
35
36} // anonymous namespace
37
38const char ProtocolHandler::kHttp[] = "http";
39const char ProtocolHandler::kHttps[] = "https";
40
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080041ProtocolHandler::ProtocolHandler(const std::string& name, Server* server)
42 : name_{name}, server_{server} {
43}
Alex Vakulenko31a63792015-02-03 12:44:57 -080044
45ProtocolHandler::~ProtocolHandler() {
46 // Remove any existing handlers, so the web server knows that we don't
47 // need them anymore.
48
49 // We need to get a copy of the map keys since removing the handlers will
50 // modify the map in the middle of the loop and that's not a good thing.
51 auto handler_ids = chromeos::GetMapKeys(request_handlers_);
52 for (int handler_id : handler_ids) {
53 RemoveHandler(handler_id);
54 }
55}
56
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080057std::string ProtocolHandler::GetName() const {
58 return name_;
Alex Vakulenko31a63792015-02-03 12:44:57 -080059}
60
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080061std::set<uint16_t> ProtocolHandler::GetPorts() const {
62 std::set<uint16_t> ports;
63 for (const auto& pair : proxies_)
64 ports.insert(pair.second->port());
65 return ports;
Alex Vakulenko31a63792015-02-03 12:44:57 -080066}
67
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080068std::set<std::string> ProtocolHandler::GetProtocols() const {
69 std::set<std::string> protocols;
70 for (const auto& pair : proxies_)
71 protocols.insert(pair.second->protocol());
72 return protocols;
Alex Vakulenko31a63792015-02-03 12:44:57 -080073}
74
75chromeos::Blob ProtocolHandler::GetCertificateFingerprint() const {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080076 chromeos::Blob fingerprint;
77 for (const auto& pair : proxies_) {
78 fingerprint = pair.second->certificate_fingerprint();
79 if (!fingerprint.empty())
80 break;
81 }
82 return fingerprint;
Alex Vakulenko31a63792015-02-03 12:44:57 -080083}
84
85int ProtocolHandler::AddHandler(
86 const std::string& url,
87 const std::string& method,
88 std::unique_ptr<RequestHandlerInterface> handler) {
Alex Vakulenko3d8c9122015-03-13 13:54:00 -070089 request_handlers_.emplace(
90 ++last_handler_id_,
91 HandlerMapEntry{url, method,
92 std::map<ProtocolHandlerProxy*, std::string>{},
93 std::move(handler)});
94 // For each instance of remote protocol handler object sharing the same name,
95 // add the request handler.
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080096 for (const auto& pair : proxies_) {
97 pair.second->AddRequestHandlerAsync(
Alex Vakulenko31a63792015-02-03 12:44:57 -080098 url,
99 method,
100 server_->service_name_,
101 base::Bind(&ProtocolHandler::AddHandlerSuccess,
102 weak_ptr_factory_.GetWeakPtr(),
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700103 last_handler_id_,
104 pair.second),
Alex Vakulenko31a63792015-02-03 12:44:57 -0800105 base::Bind(&ProtocolHandler::AddHandlerError,
106 weak_ptr_factory_.GetWeakPtr(),
107 last_handler_id_));
108 }
109 return last_handler_id_;
110}
111
112int ProtocolHandler::AddHandlerCallback(
113 const std::string& url,
114 const std::string& method,
115 const base::Callback<RequestHandlerInterface::HandlerSignature>&
116 handler_callback) {
117 std::unique_ptr<RequestHandlerInterface> handler{
118 new RequestHandlerCallback{handler_callback}};
119 return AddHandler(url, method, std::move(handler));
120}
121
122bool ProtocolHandler::RemoveHandler(int handler_id) {
123 auto p = request_handlers_.find(handler_id);
124 if (p == request_handlers_.end())
125 return false;
126
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700127 for (const auto& pair : p->second.remote_handler_ids) {
128 pair.first->RemoveRequestHandlerAsync(
129 pair.second,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800130 base::Bind(&base::DoNothing),
131 base::Bind(&IgnoreError));
132 }
133
134 request_handlers_.erase(p);
135 return true;
136}
137
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800138void ProtocolHandler::Connect(ProtocolHandlerProxy* proxy) {
139 proxies_.emplace(proxy->GetObjectPath(), proxy);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800140 for (const auto& pair : request_handlers_) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800141 proxy->AddRequestHandlerAsync(
Alex Vakulenko31a63792015-02-03 12:44:57 -0800142 pair.second.url,
143 pair.second.method,
144 server_->service_name_,
145 base::Bind(&ProtocolHandler::AddHandlerSuccess,
146 weak_ptr_factory_.GetWeakPtr(),
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700147 pair.first,
148 proxy),
Alex Vakulenko31a63792015-02-03 12:44:57 -0800149 base::Bind(&ProtocolHandler::AddHandlerError,
150 weak_ptr_factory_.GetWeakPtr(),
151 pair.first));
152 }
153}
154
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800155void ProtocolHandler::Disconnect(const dbus::ObjectPath& object_path) {
156 proxies_.erase(object_path);
157 if (proxies_.empty())
158 remote_handler_id_map_.clear();
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700159 for (auto& pair : request_handlers_)
160 pair.second.remote_handler_ids.clear();
Alex Vakulenko31a63792015-02-03 12:44:57 -0800161}
162
163void ProtocolHandler::AddHandlerSuccess(int handler_id,
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700164 ProtocolHandlerProxy* proxy,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800165 const std::string& remote_handler_id) {
166 auto p = request_handlers_.find(handler_id);
167 CHECK(p != request_handlers_.end());
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700168 p->second.remote_handler_ids.emplace(proxy, remote_handler_id);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800169
170 remote_handler_id_map_.emplace(remote_handler_id, handler_id);
171}
172
173void ProtocolHandler::AddHandlerError(int handler_id, chromeos::Error* error) {
174 // Nothing to do at the moment.
175}
176
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800177bool ProtocolHandler::ProcessRequest(const std::string& protocol_handler_id,
178 const std::string& remote_handler_id,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800179 const std::string& request_id,
180 std::unique_ptr<Request> request,
181 chromeos::ErrorPtr* error) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800182 request_id_map_.emplace(request_id, protocol_handler_id);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800183 auto id_iter = remote_handler_id_map_.find(remote_handler_id);
184 if (id_iter == remote_handler_id_map_.end()) {
185 chromeos::Error::AddToPrintf(error, FROM_HERE,
186 chromeos::errors::dbus::kDomain,
187 DBUS_ERROR_FAILED,
188 "Unknown request handler '%s'",
189 remote_handler_id.c_str());
190 return false;
191 }
192 auto handler_iter = request_handlers_.find(id_iter->second);
193 if (handler_iter == request_handlers_.end()) {
194 chromeos::Error::AddToPrintf(error, FROM_HERE,
195 chromeos::errors::dbus::kDomain,
196 DBUS_ERROR_FAILED,
197 "Handler # %d is no longer available",
198 id_iter->second);
199 return false;
200 }
201 handler_iter->second.handler->HandleRequest(
Alex Vakulenko83e66cd2015-04-24 14:51:58 -0700202 std::move(request),
203 std::unique_ptr<Response>{new Response{this, request_id}});
Alex Vakulenko31a63792015-02-03 12:44:57 -0800204 return true;
205}
206
207void ProtocolHandler::CompleteRequest(
208 const std::string& request_id,
209 int status_code,
210 const std::multimap<std::string, std::string>& headers,
211 const std::vector<uint8_t>& data) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800212 ProtocolHandlerProxy* proxy = GetRequestProtocolHandlerProxy(request_id);
213 if (!proxy)
Alex Vakulenko31a63792015-02-03 12:44:57 -0800214 return;
Alex Vakulenko31a63792015-02-03 12:44:57 -0800215
216 std::vector<std::tuple<std::string, std::string>> header_list;
217 header_list.reserve(headers.size());
218 for (const auto& pair : headers)
219 header_list.emplace_back(pair.first, pair.second);
220
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800221 proxy->CompleteRequestAsync(request_id, status_code, header_list, data,
222 base::Bind(&base::DoNothing),
223 base::Bind([](chromeos::Error*) {}));
Alex Vakulenko31a63792015-02-03 12:44:57 -0800224}
225
226void ProtocolHandler::GetFileData(
227 const std::string& request_id,
228 int file_id,
229 const base::Callback<void(const std::vector<uint8_t>&)>& success_callback,
230 const base::Callback<void(chromeos::Error*)>& error_callback) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800231 ProtocolHandlerProxy* proxy = GetRequestProtocolHandlerProxy(request_id);
232 CHECK(proxy);
233
234 proxy->GetRequestFileDataAsync(
Alex Vakulenko31a63792015-02-03 12:44:57 -0800235 request_id, file_id, success_callback, error_callback);
236}
237
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800238ProtocolHandler::ProtocolHandlerProxy*
239ProtocolHandler::GetRequestProtocolHandlerProxy(
240 const std::string& request_id) const {
241 auto iter = request_id_map_.find(request_id);
242 if (iter == request_id_map_.end()) {
243 LOG(ERROR) << "Can't find pending request with ID " << request_id;
244 return nullptr;
245 }
246 std::string handler_id = iter->second;
247 auto find_proxy_by_id = [handler_id](decltype(*proxies_.begin()) pair) {
248 return pair.second->id() == handler_id;
249 };
250 auto proxy_iter = std::find_if(proxies_.begin(), proxies_.end(),
251 find_proxy_by_id);
252 if (proxy_iter == proxies_.end()) {
253 LOG(WARNING) << "Completing a request after the handler proxy is removed";
254 return nullptr;
255 }
256 return proxy_iter->second;
257}
258
Alex Vakulenko31a63792015-02-03 12:44:57 -0800259
260} // namespace libwebserv