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 "libwebserv/dbus_protocol_handler.h" 16 17 #include <tuple> 18 19 #include <base/logging.h> 20 #include <brillo/map_utils.h> 21 #include <brillo/streams/file_stream.h> 22 #include <brillo/streams/stream_utils.h> 23 24 #include "dbus_bindings/org.chromium.WebServer.RequestHandler.h" 25 #include "libwebserv/dbus_server.h" 26 #include "libwebserv/protocol_handler.h" 27 #include "libwebserv/request.h" 28 #include "libwebserv/request_handler_callback.h" 29 #include "libwebserv/response_impl.h" 30 #include "webservd/dbus-proxies.h" 31 32 namespace libwebserv { 33 34 namespace { 35 36 // Dummy callback for async D-Bus errors. 37 void IgnoreDBusError(brillo::Error* /* error */) {} 38 39 // Copies the data from |src_stream| to the destination stream represented 40 // by a file descriptor |fd|. 41 void WriteResponseData(brillo::StreamPtr src_stream, 42 const dbus::FileDescriptor& fd) { 43 int dupfd = dup(fd.value()); 44 auto dest_stream = 45 brillo::FileStream::FromFileDescriptor(dupfd, true, nullptr); 46 CHECK(dest_stream); 47 // Dummy callbacks for success/error of data-copy operation. We ignore both 48 // notifications here. 49 auto on_success = [](brillo::StreamPtr, brillo::StreamPtr, uint64_t) {}; 50 auto on_error = [](brillo::StreamPtr, brillo::StreamPtr, 51 const brillo::Error*) {}; 52 brillo::stream_utils::CopyData( 53 std::move(src_stream), std::move(dest_stream), base::Bind(on_success), 54 base::Bind(on_error)); 55 } 56 57 } // anonymous namespace 58 59 DBusProtocolHandler::DBusProtocolHandler(const std::string& name, 60 DBusServer* server) 61 : name_{name}, server_{server} { 62 } 63 64 DBusProtocolHandler::~DBusProtocolHandler() { 65 // Remove any existing handlers, so the web server knows that we don't 66 // need them anymore. 67 68 // We need to get a copy of the map keys since removing the handlers will 69 // modify the map in the middle of the loop and that's not a good thing. 70 auto handler_ids = brillo::GetMapKeys(request_handlers_); 71 for (int handler_id : handler_ids) { 72 RemoveHandler(handler_id); 73 } 74 } 75 bool DBusProtocolHandler::IsConnected() const { 76 return !proxies_.empty(); 77 } 78 79 std::string DBusProtocolHandler::GetName() const { 80 return name_; 81 } 82 83 std::set<uint16_t> DBusProtocolHandler::GetPorts() const { 84 std::set<uint16_t> ports; 85 for (const auto& pair : proxies_) 86 ports.insert(pair.second->port()); 87 return ports; 88 } 89 90 std::set<std::string> DBusProtocolHandler::GetProtocols() const { 91 std::set<std::string> protocols; 92 for (const auto& pair : proxies_) 93 protocols.insert(pair.second->protocol()); 94 return protocols; 95 } 96 97 brillo::Blob DBusProtocolHandler::GetCertificateFingerprint() const { 98 brillo::Blob fingerprint; 99 for (const auto& pair : proxies_) { 100 fingerprint = pair.second->certificate_fingerprint(); 101 if (!fingerprint.empty()) 102 break; 103 } 104 return fingerprint; 105 } 106 107 int DBusProtocolHandler::AddHandler( 108 const std::string& url, 109 const std::string& method, 110 std::unique_ptr<RequestHandlerInterface> handler) { 111 request_handlers_.emplace( 112 ++last_handler_id_, 113 HandlerMapEntry{url, method, 114 std::map<ProtocolHandlerProxyInterface*, std::string>{}, 115 std::move(handler)}); 116 // For each instance of remote protocol handler object sharing the same name, 117 // add the request handler. 118 for (const auto& pair : proxies_) { 119 pair.second->AddRequestHandlerAsync( 120 url, 121 method, 122 server_->service_name_, 123 base::Bind(&DBusProtocolHandler::AddHandlerSuccess, 124 weak_ptr_factory_.GetWeakPtr(), 125 last_handler_id_, 126 pair.second), 127 base::Bind(&DBusProtocolHandler::AddHandlerError, 128 weak_ptr_factory_.GetWeakPtr(), 129 last_handler_id_)); 130 } 131 return last_handler_id_; 132 } 133 134 int DBusProtocolHandler::AddHandlerCallback( 135 const std::string& url, 136 const std::string& method, 137 const base::Callback<RequestHandlerInterface::HandlerSignature>& 138 handler_callback) { 139 std::unique_ptr<RequestHandlerInterface> handler{ 140 new RequestHandlerCallback{handler_callback}}; 141 return AddHandler(url, method, std::move(handler)); 142 } 143 144 bool DBusProtocolHandler::RemoveHandler(int handler_id) { 145 auto p = request_handlers_.find(handler_id); 146 if (p == request_handlers_.end()) 147 return false; 148 149 for (const auto& pair : p->second.remote_handler_ids) { 150 pair.first->RemoveRequestHandlerAsync( 151 pair.second, 152 base::Bind(&base::DoNothing), 153 base::Bind(&IgnoreDBusError)); 154 } 155 156 request_handlers_.erase(p); 157 return true; 158 } 159 160 void DBusProtocolHandler::Connect(ProtocolHandlerProxyInterface* proxy) { 161 proxies_.emplace(proxy->GetObjectPath(), proxy); 162 for (const auto& pair : request_handlers_) { 163 proxy->AddRequestHandlerAsync( 164 pair.second.url, 165 pair.second.method, 166 server_->service_name_, 167 base::Bind(&DBusProtocolHandler::AddHandlerSuccess, 168 weak_ptr_factory_.GetWeakPtr(), 169 pair.first, 170 proxy), 171 base::Bind(&DBusProtocolHandler::AddHandlerError, 172 weak_ptr_factory_.GetWeakPtr(), 173 pair.first)); 174 } 175 } 176 177 void DBusProtocolHandler::Disconnect(const dbus::ObjectPath& object_path) { 178 proxies_.erase(object_path); 179 if (proxies_.empty()) 180 remote_handler_id_map_.clear(); 181 for (auto& pair : request_handlers_) 182 pair.second.remote_handler_ids.clear(); 183 } 184 185 void DBusProtocolHandler::AddHandlerSuccess( 186 int handler_id, 187 ProtocolHandlerProxyInterface* proxy, 188 const std::string& remote_handler_id) { 189 auto p = request_handlers_.find(handler_id); 190 CHECK(p != request_handlers_.end()); 191 p->second.remote_handler_ids.emplace(proxy, remote_handler_id); 192 193 remote_handler_id_map_.emplace(remote_handler_id, handler_id); 194 } 195 196 void DBusProtocolHandler::AddHandlerError(int /* handler_id */, 197 brillo::Error* /* error */) { 198 // Nothing to do at the moment. 199 } 200 201 bool DBusProtocolHandler::ProcessRequest(const std::string& protocol_handler_id, 202 const std::string& remote_handler_id, 203 const std::string& request_id, 204 std::unique_ptr<Request> request, 205 brillo::ErrorPtr* error) { 206 request_id_map_.emplace(request_id, protocol_handler_id); 207 auto id_iter = remote_handler_id_map_.find(remote_handler_id); 208 if (id_iter == remote_handler_id_map_.end()) { 209 brillo::Error::AddToPrintf(error, FROM_HERE, 210 brillo::errors::dbus::kDomain, 211 DBUS_ERROR_FAILED, 212 "Unknown request handler '%s'", 213 remote_handler_id.c_str()); 214 return false; 215 } 216 auto handler_iter = request_handlers_.find(id_iter->second); 217 if (handler_iter == request_handlers_.end()) { 218 brillo::Error::AddToPrintf(error, FROM_HERE, 219 brillo::errors::dbus::kDomain, 220 DBUS_ERROR_FAILED, 221 "Handler # %d is no longer available", 222 id_iter->second); 223 return false; 224 } 225 handler_iter->second.handler->HandleRequest( 226 std::move(request), 227 std::unique_ptr<Response>{new ResponseImpl{this, request_id}}); 228 return true; 229 } 230 231 void DBusProtocolHandler::CompleteRequest( 232 const std::string& request_id, 233 int status_code, 234 const std::multimap<std::string, std::string>& headers, 235 brillo::StreamPtr data_stream) { 236 ProtocolHandlerProxyInterface* proxy = 237 GetRequestProtocolHandlerProxy(request_id); 238 if (!proxy) 239 return; 240 241 std::vector<std::tuple<std::string, std::string>> header_list; 242 header_list.reserve(headers.size()); 243 for (const auto& pair : headers) 244 header_list.emplace_back(pair.first, pair.second); 245 246 int64_t data_size = -1; 247 if (data_stream->CanGetSize()) 248 data_size = data_stream->GetRemainingSize(); 249 proxy->CompleteRequestAsync( 250 request_id, status_code, header_list, data_size, 251 base::Bind(&WriteResponseData, base::Passed(&data_stream)), 252 base::Bind(&IgnoreDBusError)); 253 } 254 255 void DBusProtocolHandler::GetFileData( 256 const std::string& request_id, 257 int file_id, 258 const base::Callback<void(brillo::StreamPtr)>& success_callback, 259 const base::Callback<void(brillo::Error*)>& error_callback) { 260 ProtocolHandlerProxyInterface* proxy = 261 GetRequestProtocolHandlerProxy(request_id); 262 CHECK(proxy); 263 264 // Store the success/error callback in a shared object so it can be referenced 265 // by the two wrapper callbacks. Since the original callbacks MAY contain 266 // move-only types, copying the base::Callback object is generally unsafe and 267 // may destroy the source object of the copy (despite the fact that it is 268 // constant). So, here we move both callbacks to |Callbacks| structure and 269 // use a shared pointer to it in both success and error callback wrappers. 270 struct Callbacks { 271 base::Callback<void(brillo::StreamPtr)> on_success; 272 base::Callback<void(brillo::Error*)> on_error; 273 }; 274 auto callbacks = std::make_shared<Callbacks>(); 275 callbacks->on_success = success_callback; 276 callbacks->on_error = error_callback; 277 278 auto on_success = [callbacks](const dbus::FileDescriptor& fd) { 279 brillo::ErrorPtr error; 280 // Unfortunately there is no way to take ownership of the file descriptor 281 // since |fd| is a const reference, so duplicate the descriptor. 282 int dupfd = dup(fd.value()); 283 auto stream = brillo::FileStream::FromFileDescriptor(dupfd, true, &error); 284 if (!stream) 285 return callbacks->on_error.Run(error.get()); 286 callbacks->on_success.Run(std::move(stream)); 287 }; 288 auto on_error = [callbacks](brillo::Error* error) { 289 callbacks->on_error.Run(error); 290 }; 291 292 proxy->GetRequestFileDataAsync(request_id, file_id, base::Bind(on_success), 293 base::Bind(on_error)); 294 } 295 296 DBusProtocolHandler::ProtocolHandlerProxyInterface* 297 DBusProtocolHandler::GetRequestProtocolHandlerProxy( 298 const std::string& request_id) const { 299 auto iter = request_id_map_.find(request_id); 300 if (iter == request_id_map_.end()) { 301 LOG(ERROR) << "Can't find pending request with ID " << request_id; 302 return nullptr; 303 } 304 std::string handler_id = iter->second; 305 auto find_proxy_by_id = [handler_id](decltype(*proxies_.begin()) pair) { 306 return pair.second->id() == handler_id; 307 }; 308 auto proxy_iter = std::find_if(proxies_.begin(), proxies_.end(), 309 find_proxy_by_id); 310 if (proxy_iter == proxies_.end()) { 311 LOG(WARNING) << "Completing a request after the handler proxy is removed"; 312 return nullptr; 313 } 314 return proxy_iter->second; 315 } 316 317 318 } // namespace libwebserv 319