blob: 53514bebff38d172109584a7060eef95da81d357 [file] [log] [blame]
Alex Vakulenko31a63792015-02-03 12:44:57 -08001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Daniel Eratf719c982015-08-14 17:33:16 -06005#include "libwebserv/protocol_handler.h"
Alex Vakulenko31a63792015-02-03 12:44:57 -08006
7#include <tuple>
8
9#include <base/logging.h>
10#include <chromeos/map_utils.h>
11
12#include "libwebserv/org.chromium.WebServer.RequestHandler.h"
Daniel Eratf719c982015-08-14 17:33:16 -060013#include "libwebserv/request.h"
14#include "libwebserv/request_handler_callback.h"
15#include "libwebserv/response.h"
16#include "libwebserv/server.h"
Alex Vakulenko31a63792015-02-03 12:44:57 -080017#include "webservd/dbus-proxies.h"
Alex Vakulenko31a63792015-02-03 12:44:57 -080018
19namespace libwebserv {
20
21namespace {
22
23// A dummy callback for async D-Bus errors.
24void IgnoreError(chromeos::Error* error) {}
25
26} // anonymous namespace
27
28const char ProtocolHandler::kHttp[] = "http";
29const char ProtocolHandler::kHttps[] = "https";
30
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080031ProtocolHandler::ProtocolHandler(const std::string& name, Server* server)
32 : name_{name}, server_{server} {
33}
Alex Vakulenko31a63792015-02-03 12:44:57 -080034
35ProtocolHandler::~ProtocolHandler() {
36 // Remove any existing handlers, so the web server knows that we don't
37 // need them anymore.
38
39 // We need to get a copy of the map keys since removing the handlers will
40 // modify the map in the middle of the loop and that's not a good thing.
41 auto handler_ids = chromeos::GetMapKeys(request_handlers_);
42 for (int handler_id : handler_ids) {
43 RemoveHandler(handler_id);
44 }
45}
46
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080047std::string ProtocolHandler::GetName() const {
48 return name_;
Alex Vakulenko31a63792015-02-03 12:44:57 -080049}
50
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080051std::set<uint16_t> ProtocolHandler::GetPorts() const {
52 std::set<uint16_t> ports;
53 for (const auto& pair : proxies_)
54 ports.insert(pair.second->port());
55 return ports;
Alex Vakulenko31a63792015-02-03 12:44:57 -080056}
57
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080058std::set<std::string> ProtocolHandler::GetProtocols() const {
59 std::set<std::string> protocols;
60 for (const auto& pair : proxies_)
61 protocols.insert(pair.second->protocol());
62 return protocols;
Alex Vakulenko31a63792015-02-03 12:44:57 -080063}
64
65chromeos::Blob ProtocolHandler::GetCertificateFingerprint() const {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080066 chromeos::Blob fingerprint;
67 for (const auto& pair : proxies_) {
68 fingerprint = pair.second->certificate_fingerprint();
69 if (!fingerprint.empty())
70 break;
71 }
72 return fingerprint;
Alex Vakulenko31a63792015-02-03 12:44:57 -080073}
74
75int ProtocolHandler::AddHandler(
76 const std::string& url,
77 const std::string& method,
78 std::unique_ptr<RequestHandlerInterface> handler) {
Alex Vakulenko3d8c9122015-03-13 13:54:00 -070079 request_handlers_.emplace(
80 ++last_handler_id_,
81 HandlerMapEntry{url, method,
82 std::map<ProtocolHandlerProxy*, std::string>{},
83 std::move(handler)});
84 // For each instance of remote protocol handler object sharing the same name,
85 // add the request handler.
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080086 for (const auto& pair : proxies_) {
87 pair.second->AddRequestHandlerAsync(
Alex Vakulenko31a63792015-02-03 12:44:57 -080088 url,
89 method,
90 server_->service_name_,
91 base::Bind(&ProtocolHandler::AddHandlerSuccess,
92 weak_ptr_factory_.GetWeakPtr(),
Alex Vakulenko3d8c9122015-03-13 13:54:00 -070093 last_handler_id_,
94 pair.second),
Alex Vakulenko31a63792015-02-03 12:44:57 -080095 base::Bind(&ProtocolHandler::AddHandlerError,
96 weak_ptr_factory_.GetWeakPtr(),
97 last_handler_id_));
98 }
99 return last_handler_id_;
100}
101
102int ProtocolHandler::AddHandlerCallback(
103 const std::string& url,
104 const std::string& method,
105 const base::Callback<RequestHandlerInterface::HandlerSignature>&
106 handler_callback) {
107 std::unique_ptr<RequestHandlerInterface> handler{
108 new RequestHandlerCallback{handler_callback}};
109 return AddHandler(url, method, std::move(handler));
110}
111
112bool ProtocolHandler::RemoveHandler(int handler_id) {
113 auto p = request_handlers_.find(handler_id);
114 if (p == request_handlers_.end())
115 return false;
116
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700117 for (const auto& pair : p->second.remote_handler_ids) {
118 pair.first->RemoveRequestHandlerAsync(
119 pair.second,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800120 base::Bind(&base::DoNothing),
121 base::Bind(&IgnoreError));
122 }
123
124 request_handlers_.erase(p);
125 return true;
126}
127
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800128void ProtocolHandler::Connect(ProtocolHandlerProxy* proxy) {
129 proxies_.emplace(proxy->GetObjectPath(), proxy);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800130 for (const auto& pair : request_handlers_) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800131 proxy->AddRequestHandlerAsync(
Alex Vakulenko31a63792015-02-03 12:44:57 -0800132 pair.second.url,
133 pair.second.method,
134 server_->service_name_,
135 base::Bind(&ProtocolHandler::AddHandlerSuccess,
136 weak_ptr_factory_.GetWeakPtr(),
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700137 pair.first,
138 proxy),
Alex Vakulenko31a63792015-02-03 12:44:57 -0800139 base::Bind(&ProtocolHandler::AddHandlerError,
140 weak_ptr_factory_.GetWeakPtr(),
141 pair.first));
142 }
143}
144
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800145void ProtocolHandler::Disconnect(const dbus::ObjectPath& object_path) {
146 proxies_.erase(object_path);
147 if (proxies_.empty())
148 remote_handler_id_map_.clear();
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700149 for (auto& pair : request_handlers_)
150 pair.second.remote_handler_ids.clear();
Alex Vakulenko31a63792015-02-03 12:44:57 -0800151}
152
153void ProtocolHandler::AddHandlerSuccess(int handler_id,
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700154 ProtocolHandlerProxy* proxy,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800155 const std::string& remote_handler_id) {
156 auto p = request_handlers_.find(handler_id);
157 CHECK(p != request_handlers_.end());
Alex Vakulenko3d8c9122015-03-13 13:54:00 -0700158 p->second.remote_handler_ids.emplace(proxy, remote_handler_id);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800159
160 remote_handler_id_map_.emplace(remote_handler_id, handler_id);
161}
162
163void ProtocolHandler::AddHandlerError(int handler_id, chromeos::Error* error) {
164 // Nothing to do at the moment.
165}
166
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800167bool ProtocolHandler::ProcessRequest(const std::string& protocol_handler_id,
168 const std::string& remote_handler_id,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800169 const std::string& request_id,
170 std::unique_ptr<Request> request,
171 chromeos::ErrorPtr* error) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800172 request_id_map_.emplace(request_id, protocol_handler_id);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800173 auto id_iter = remote_handler_id_map_.find(remote_handler_id);
174 if (id_iter == remote_handler_id_map_.end()) {
175 chromeos::Error::AddToPrintf(error, FROM_HERE,
176 chromeos::errors::dbus::kDomain,
177 DBUS_ERROR_FAILED,
178 "Unknown request handler '%s'",
179 remote_handler_id.c_str());
180 return false;
181 }
182 auto handler_iter = request_handlers_.find(id_iter->second);
183 if (handler_iter == request_handlers_.end()) {
184 chromeos::Error::AddToPrintf(error, FROM_HERE,
185 chromeos::errors::dbus::kDomain,
186 DBUS_ERROR_FAILED,
187 "Handler # %d is no longer available",
188 id_iter->second);
189 return false;
190 }
191 handler_iter->second.handler->HandleRequest(
Alex Vakulenko83e66cd2015-04-24 14:51:58 -0700192 std::move(request),
193 std::unique_ptr<Response>{new Response{this, request_id}});
Alex Vakulenko31a63792015-02-03 12:44:57 -0800194 return true;
195}
196
197void ProtocolHandler::CompleteRequest(
198 const std::string& request_id,
199 int status_code,
200 const std::multimap<std::string, std::string>& headers,
201 const std::vector<uint8_t>& data) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800202 ProtocolHandlerProxy* proxy = GetRequestProtocolHandlerProxy(request_id);
203 if (!proxy)
Alex Vakulenko31a63792015-02-03 12:44:57 -0800204 return;
Alex Vakulenko31a63792015-02-03 12:44:57 -0800205
206 std::vector<std::tuple<std::string, std::string>> header_list;
207 header_list.reserve(headers.size());
208 for (const auto& pair : headers)
209 header_list.emplace_back(pair.first, pair.second);
210
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800211 proxy->CompleteRequestAsync(request_id, status_code, header_list, data,
212 base::Bind(&base::DoNothing),
213 base::Bind([](chromeos::Error*) {}));
Alex Vakulenko31a63792015-02-03 12:44:57 -0800214}
215
216void ProtocolHandler::GetFileData(
217 const std::string& request_id,
218 int file_id,
219 const base::Callback<void(const std::vector<uint8_t>&)>& success_callback,
220 const base::Callback<void(chromeos::Error*)>& error_callback) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800221 ProtocolHandlerProxy* proxy = GetRequestProtocolHandlerProxy(request_id);
222 CHECK(proxy);
223
224 proxy->GetRequestFileDataAsync(
Alex Vakulenko31a63792015-02-03 12:44:57 -0800225 request_id, file_id, success_callback, error_callback);
226}
227
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800228ProtocolHandler::ProtocolHandlerProxy*
229ProtocolHandler::GetRequestProtocolHandlerProxy(
230 const std::string& request_id) const {
231 auto iter = request_id_map_.find(request_id);
232 if (iter == request_id_map_.end()) {
233 LOG(ERROR) << "Can't find pending request with ID " << request_id;
234 return nullptr;
235 }
236 std::string handler_id = iter->second;
237 auto find_proxy_by_id = [handler_id](decltype(*proxies_.begin()) pair) {
238 return pair.second->id() == handler_id;
239 };
240 auto proxy_iter = std::find_if(proxies_.begin(), proxies_.end(),
241 find_proxy_by_id);
242 if (proxy_iter == proxies_.end()) {
243 LOG(WARNING) << "Completing a request after the handler proxy is removed";
244 return nullptr;
245 }
246 return proxy_iter->second;
247}
248
Alex Vakulenko31a63792015-02-03 12:44:57 -0800249
250} // namespace libwebserv