blob: a15f7ab716baabb01dfe4aae7531dbab191103dc [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 Vakulenko039da312015-02-03 08:58:55 -080014
15#include <libwebserv/server.h>
16
Alex Vakulenko31a63792015-02-03 12:44:57 -080017#include <tuple>
Alex Vakulenko039da312015-02-03 08:58:55 -080018#include <vector>
19
Alex Vakulenko31a63792015-02-03 12:44:57 -080020#include <libwebserv/protocol_handler.h>
Alex Vakulenko039da312015-02-03 08:58:55 -080021#include <libwebserv/request.h>
Alex Vakulenko31a63792015-02-03 12:44:57 -080022
Christopher Wiley34bc9df2015-08-19 15:03:47 -070023#include "dbus_bindings/org.chromium.WebServer.RequestHandler.h"
Alex Vakulenko31a63792015-02-03 12:44:57 -080024#include "webservd/dbus-proxies.h"
Alex Vakulenko039da312015-02-03 08:58:55 -080025
26namespace libwebserv {
27
Alex Vakulenko31a63792015-02-03 12:44:57 -080028class Server::RequestHandler final
29 : public org::chromium::WebServer::RequestHandlerInterface {
Alex Vakulenko039da312015-02-03 08:58:55 -080030 public:
Alex Vakulenko31a63792015-02-03 12:44:57 -080031 explicit RequestHandler(Server* server) : server_{server} {}
32 bool ProcessRequest(
33 chromeos::ErrorPtr* error,
34 const std::tuple<std::string, std::string, std::string, std::string,
35 std::string>& in_request_info,
36 const std::vector<std::tuple<std::string, std::string>>& in_headers,
37 const std::vector<std::tuple<bool, std::string, std::string>>& in_params,
38 const std::vector<std::tuple<int32_t, std::string, std::string,
39 std::string, std::string>>& in_files,
Alex Vakulenko0f6413a2015-09-21 11:06:58 -070040 const dbus::FileDescriptor& in_body) override;
Alex Vakulenko31a63792015-02-03 12:44:57 -080041
42 private:
43 Server* server_{nullptr};
44 DISALLOW_COPY_AND_ASSIGN(RequestHandler);
Alex Vakulenko039da312015-02-03 08:58:55 -080045};
46
Alex Vakulenko31a63792015-02-03 12:44:57 -080047bool Server::RequestHandler::ProcessRequest(
48 chromeos::ErrorPtr* error,
49 const std::tuple<std::string, std::string, std::string, std::string,
50 std::string>& in_request_info,
51 const std::vector<std::tuple<std::string, std::string>>& in_headers,
52 const std::vector<std::tuple<bool, std::string, std::string>>& in_params,
Alex Vakulenko0f6413a2015-09-21 11:06:58 -070053 const std::vector<std::tuple<int32_t, std::string, std::string, std::string,
54 std::string>>& in_files,
55 const dbus::FileDescriptor& in_body) {
Alex Vakulenko31a63792015-02-03 12:44:57 -080056 std::string protocol_handler_id = std::get<0>(in_request_info);
57 std::string request_handler_id = std::get<1>(in_request_info);
58 std::string request_id = std::get<2>(in_request_info);
59 std::string url = std::get<3>(in_request_info);
60 std::string method = std::get<4>(in_request_info);
61 ProtocolHandler* protocol_handler =
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080062 server_->GetProtocolHandlerByID(protocol_handler_id);
Alex Vakulenko31a63792015-02-03 12:44:57 -080063 if (!protocol_handler) {
64 chromeos::Error::AddToPrintf(error, FROM_HERE,
65 chromeos::errors::dbus::kDomain,
66 DBUS_ERROR_FAILED,
67 "Unknown protocol handler '%s'",
68 protocol_handler_id.c_str());
69 return false;
70 }
71 std::unique_ptr<Request> request{new Request{protocol_handler, url, method}};
72 // Convert request data into format required by the Request object.
73 for (const auto& tuple : in_params) {
74 if (std::get<0>(tuple))
75 request->post_data_.emplace(std::get<1>(tuple), std::get<2>(tuple));
76 else
77 request->get_data_.emplace(std::get<1>(tuple), std::get<2>(tuple));
Alex Vakulenko039da312015-02-03 08:58:55 -080078 }
79
Alex Vakulenko31a63792015-02-03 12:44:57 -080080 for (const auto& tuple : in_headers)
81 request->headers_.emplace(std::get<0>(tuple), std::get<1>(tuple));
Alex Vakulenko039da312015-02-03 08:58:55 -080082
Alex Vakulenko31a63792015-02-03 12:44:57 -080083 for (const auto& tuple : in_files) {
84 request->file_info_.emplace(
85 std::get<1>(tuple), // field_name
86 std::unique_ptr<FileInfo>{new FileInfo{
87 protocol_handler,
88 std::get<0>(tuple), // file_id
89 request_id,
90 std::get<2>(tuple), // file_name
91 std::get<3>(tuple), // content_type
92 std::get<4>(tuple)}}); // transfer_encoding
93 }
94
Alex Vakulenko0f6413a2015-09-21 11:06:58 -070095 request->raw_data_fd_ = base::File(dup(in_body.value()));
96 CHECK(request->raw_data_fd_.IsValid());
Alex Vakulenko31a63792015-02-03 12:44:57 -080097
Alex Vakulenko3d2d5632015-03-02 15:58:32 -080098 return protocol_handler->ProcessRequest(protocol_handler_id,
99 request_handler_id,
Alex Vakulenko31a63792015-02-03 12:44:57 -0800100 request_id,
101 std::move(request),
102 error);
103}
104
105Server::Server()
106 : request_handler_{new RequestHandler{this}},
107 dbus_adaptor_{new org::chromium::WebServer::RequestHandlerAdaptor{
108 request_handler_.get()}} {}
Alex Vakulenko039da312015-02-03 08:58:55 -0800109
110Server::~Server() {
Alex Vakulenko039da312015-02-03 08:58:55 -0800111}
112
Alex Vakulenko31a63792015-02-03 12:44:57 -0800113void Server::Connect(
114 const scoped_refptr<dbus::Bus>& bus,
115 const std::string& service_name,
116 const chromeos::dbus_utils::AsyncEventSequencer::CompletionAction& cb,
117 const base::Closure& on_server_online,
118 const base::Closure& on_server_offline) {
119 service_name_ = service_name;
120 dbus_object_.reset(new chromeos::dbus_utils::DBusObject{
121 nullptr, bus, dbus_adaptor_->GetObjectPath()});
122 dbus_adaptor_->RegisterWithDBusObject(dbus_object_.get());
123 dbus_object_->RegisterAsync(cb);
124 on_server_online_ = on_server_online;
125 on_server_offline_ = on_server_offline;
Alex Vakulenko31a63792015-02-03 12:44:57 -0800126 object_manager_.reset(new org::chromium::WebServer::ObjectManagerProxy{bus});
127 object_manager_->SetServerAddedCallback(
128 base::Bind(&Server::Online, base::Unretained(this)));
129 object_manager_->SetServerRemovedCallback(
130 base::Bind(&Server::Offline, base::Unretained(this)));
131 object_manager_->SetProtocolHandlerAddedCallback(
132 base::Bind(&Server::ProtocolHandlerAdded, base::Unretained(this)));
133 object_manager_->SetProtocolHandlerRemovedCallback(
134 base::Bind(&Server::ProtocolHandlerRemoved, base::Unretained(this)));
Alex Vakulenko039da312015-02-03 08:58:55 -0800135}
136
Alex Vakulenko31a63792015-02-03 12:44:57 -0800137void Server::Disconnect() {
Alex Vakulenko31a63792015-02-03 12:44:57 -0800138 on_server_offline_.Reset();
139 on_server_online_.Reset();
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800140 protocol_handlers_ids_.clear();
141 protocol_handlers_names_.clear();
Alex Vakulenko77b4c2b2015-05-22 15:38:42 -0700142 // Release D-Bus object manager proxy after all the dependent maps are freed
143 // (e.g. |protocol_handlers_names_| contains pointers to ProtocolHandlerProxy,
144 // instances of which are owned by the D-Bus object manager).
145 object_manager_.reset();
146 dbus_object_.reset();
Alex Vakulenko31a63792015-02-03 12:44:57 -0800147}
148
149void Server::Online(org::chromium::WebServer::ServerProxy* server) {
Alex Vakulenkoa9352552015-02-17 12:49:59 -0800150 VLOG(1) << "Web server is on-line.";
Alex Vakulenko31a63792015-02-03 12:44:57 -0800151 proxy_ = server;
152 if (!on_server_online_.is_null())
153 on_server_online_.Run();
154}
155
156void Server::Offline(const dbus::ObjectPath& object_path) {
157 if (!on_server_offline_.is_null())
158 on_server_offline_.Run();
159 proxy_ = nullptr;
Alex Vakulenkoa9352552015-02-17 12:49:59 -0800160 VLOG(1) << "Web server is off-line.";
Alex Vakulenko31a63792015-02-03 12:44:57 -0800161}
162
163void Server::ProtocolHandlerAdded(
164 org::chromium::WebServer::ProtocolHandlerProxy* handler) {
Alex Vakulenkoa9352552015-02-17 12:49:59 -0800165 VLOG(1) << "Server-side protocol handler with ID '" << handler->id()
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800166 << "' is on-line (" << handler->name() << ")";
Alex Vakulenkoa9352552015-02-17 12:49:59 -0800167
Alex Vakulenko31a63792015-02-03 12:44:57 -0800168 protocol_handler_id_map_.emplace(handler->GetObjectPath(), handler->id());
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800169 ProtocolHandler* registered_handler = GetProtocolHandler(handler->name());
Alex Vakulenko31a63792015-02-03 12:44:57 -0800170 if (registered_handler) {
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800171 protocol_handlers_ids_.emplace(handler->id(), registered_handler);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800172 registered_handler->Connect(handler);
173 if (!on_protocol_handler_connected_.is_null())
174 on_protocol_handler_connected_.Run(registered_handler);
175 }
176}
177
178void Server::ProtocolHandlerRemoved(const dbus::ObjectPath& object_path) {
179 auto p = protocol_handler_id_map_.find(object_path);
180 if (p == protocol_handler_id_map_.end())
181 return;
182
Alex Vakulenkoa9352552015-02-17 12:49:59 -0800183 VLOG(1) << "Server-side protocol handler with ID '" << p->second
184 << "' is off-line.";
185
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800186 ProtocolHandler* registered_handler = GetProtocolHandlerByID(p->second);
Alex Vakulenko31a63792015-02-03 12:44:57 -0800187 if (registered_handler) {
188 if (!on_protocol_handler_disconnected_.is_null())
189 on_protocol_handler_disconnected_.Run(registered_handler);
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800190 registered_handler->Disconnect(object_path);
191 protocol_handlers_ids_.erase(p->second);
Alex Vakulenko039da312015-02-03 08:58:55 -0800192 }
193
Alex Vakulenko31a63792015-02-03 12:44:57 -0800194 protocol_handler_id_map_.erase(p);
Alex Vakulenko039da312015-02-03 08:58:55 -0800195}
196
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800197ProtocolHandler* Server::GetProtocolHandler(const std::string& name) {
198 auto p = protocol_handlers_names_.find(name);
199 if (p == protocol_handlers_names_.end()) {
Alex Vakulenkoa9352552015-02-17 12:49:59 -0800200 VLOG(1) << "Creating a client-side instance of web server's protocol "
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800201 << "handler with name '" << name << "'";
202 p = protocol_handlers_names_.emplace(
203 name,
204 std::unique_ptr<ProtocolHandler>{new ProtocolHandler{name, this}})
205 .first;
Alex Vakulenkoa9352552015-02-17 12:49:59 -0800206 }
207 return p->second.get();
Alex Vakulenko039da312015-02-03 08:58:55 -0800208}
209
Alex Vakulenkoa9352552015-02-17 12:49:59 -0800210ProtocolHandler* Server::GetDefaultHttpHandler() {
Alex Vakulenko31a63792015-02-03 12:44:57 -0800211 return GetProtocolHandler(ProtocolHandler::kHttp);
Alex Vakulenko039da312015-02-03 08:58:55 -0800212}
213
Alex Vakulenkoa9352552015-02-17 12:49:59 -0800214ProtocolHandler* Server::GetDefaultHttpsHandler() {
Alex Vakulenko31a63792015-02-03 12:44:57 -0800215 return GetProtocolHandler(ProtocolHandler::kHttps);
Alex Vakulenko039da312015-02-03 08:58:55 -0800216}
217
Alex Vakulenko3d2d5632015-03-02 15:58:32 -0800218ProtocolHandler* Server::GetProtocolHandlerByID(const std::string& id) const {
219 auto p = protocol_handlers_ids_.find(id);
220 if (p == protocol_handlers_ids_.end()) {
221 LOG(ERROR) << "Unable to locate protocol handler with ID '" << id << "'";
222 return nullptr;
223 }
224 return p->second;
225}
226
Alex Vakulenko31a63792015-02-03 12:44:57 -0800227void Server::OnProtocolHandlerConnected(
228 const base::Callback<void(ProtocolHandler*)>& callback) {
229 on_protocol_handler_connected_ = callback;
Alex Vakulenko039da312015-02-03 08:58:55 -0800230}
231
Alex Vakulenko31a63792015-02-03 12:44:57 -0800232void Server::OnProtocolHandlerDisconnected(
233 const base::Callback<void(ProtocolHandler*)>& callback) {
234 on_protocol_handler_disconnected_ = callback;
Alex Vakulenko039da312015-02-03 08:58:55 -0800235}
236
Alex Vakulenko039da312015-02-03 08:58:55 -0800237} // namespace libwebserv