blob: 9a10acf8281ee7ed46afd3533d700621e8489f5c [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
5#include "webserver/libwebserv/protocol_handler.h"
6
7#include <tuple>
8
9#include <base/logging.h>
10#include <chromeos/map_utils.h>
11
12#include "libwebserv/org.chromium.WebServer.RequestHandler.h"
13#include "webservd/dbus-proxies.h"
14#include "webserver/libwebserv/request.h"
15#include "webserver/libwebserv/request_handler_callback.h"
16#include "webserver/libwebserv/response.h"
17#include "webserver/libwebserv/server.h"
18
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
31ProtocolHandler::ProtocolHandler(const std::string& id, Server* server)
32 : id_{id}, server_{server} {}
33
34ProtocolHandler::~ProtocolHandler() {
35 // Remove any existing handlers, so the web server knows that we don't
36 // need them anymore.
37
38 // We need to get a copy of the map keys since removing the handlers will
39 // modify the map in the middle of the loop and that's not a good thing.
40 auto handler_ids = chromeos::GetMapKeys(request_handlers_);
41 for (int handler_id : handler_ids) {
42 RemoveHandler(handler_id);
43 }
44}
45
46std::string ProtocolHandler::GetID() const {
47 return id_;
48}
49
50uint16_t ProtocolHandler::GetPort() const {
51 CHECK(IsConnected());
52 return proxy_->port();
53}
54
55std::string ProtocolHandler::GetProtocol() const {
56 CHECK(IsConnected());
57 return proxy_->protocol();
58}
59
60chromeos::Blob ProtocolHandler::GetCertificateFingerprint() const {
61 CHECK(IsConnected());
62 return proxy_->certificate_fingerprint();
63}
64
65int ProtocolHandler::AddHandler(
66 const std::string& url,
67 const std::string& method,
68 std::unique_ptr<RequestHandlerInterface> handler) {
69 request_handlers_.emplace(++last_handler_id_,
70 HandlerMapEntry{url, method, std::string{},
71 std::move(handler)});
72 if (proxy_) {
73 proxy_->AddRequestHandlerAsync(
74 url,
75 method,
76 server_->service_name_,
77 base::Bind(&ProtocolHandler::AddHandlerSuccess,
78 weak_ptr_factory_.GetWeakPtr(),
79 last_handler_id_),
80 base::Bind(&ProtocolHandler::AddHandlerError,
81 weak_ptr_factory_.GetWeakPtr(),
82 last_handler_id_));
83 }
84 return last_handler_id_;
85}
86
87int ProtocolHandler::AddHandlerCallback(
88 const std::string& url,
89 const std::string& method,
90 const base::Callback<RequestHandlerInterface::HandlerSignature>&
91 handler_callback) {
92 std::unique_ptr<RequestHandlerInterface> handler{
93 new RequestHandlerCallback{handler_callback}};
94 return AddHandler(url, method, std::move(handler));
95}
96
97bool ProtocolHandler::RemoveHandler(int handler_id) {
98 auto p = request_handlers_.find(handler_id);
99 if (p == request_handlers_.end())
100 return false;
101
102 if (proxy_) {
103 proxy_->RemoveRequestHandlerAsync(
104 p->second.remote_handler_id,
105 base::Bind(&base::DoNothing),
106 base::Bind(&IgnoreError));
107 }
108
109 request_handlers_.erase(p);
110 return true;
111}
112
113void ProtocolHandler::Connect(
114 org::chromium::WebServer::ProtocolHandlerProxy* proxy) {
115 proxy_ = proxy;
116 for (const auto& pair : request_handlers_) {
117 proxy_->AddRequestHandlerAsync(
118 pair.second.url,
119 pair.second.method,
120 server_->service_name_,
121 base::Bind(&ProtocolHandler::AddHandlerSuccess,
122 weak_ptr_factory_.GetWeakPtr(),
123 pair.first),
124 base::Bind(&ProtocolHandler::AddHandlerError,
125 weak_ptr_factory_.GetWeakPtr(),
126 pair.first));
127 }
128}
129
130void ProtocolHandler::Disconnect() {
131 proxy_ = nullptr;
132 remote_handler_id_map_.clear();
133}
134
135void ProtocolHandler::AddHandlerSuccess(int handler_id,
136 const std::string& remote_handler_id) {
137 auto p = request_handlers_.find(handler_id);
138 CHECK(p != request_handlers_.end());
139 p->second.remote_handler_id = remote_handler_id;
140
141 remote_handler_id_map_.emplace(remote_handler_id, handler_id);
142}
143
144void ProtocolHandler::AddHandlerError(int handler_id, chromeos::Error* error) {
145 // Nothing to do at the moment.
146}
147
148bool ProtocolHandler::ProcessRequest(const std::string& remote_handler_id,
149 const std::string& request_id,
150 std::unique_ptr<Request> request,
151 chromeos::ErrorPtr* error) {
152 auto id_iter = remote_handler_id_map_.find(remote_handler_id);
153 if (id_iter == remote_handler_id_map_.end()) {
154 chromeos::Error::AddToPrintf(error, FROM_HERE,
155 chromeos::errors::dbus::kDomain,
156 DBUS_ERROR_FAILED,
157 "Unknown request handler '%s'",
158 remote_handler_id.c_str());
159 return false;
160 }
161 auto handler_iter = request_handlers_.find(id_iter->second);
162 if (handler_iter == request_handlers_.end()) {
163 chromeos::Error::AddToPrintf(error, FROM_HERE,
164 chromeos::errors::dbus::kDomain,
165 DBUS_ERROR_FAILED,
166 "Handler # %d is no longer available",
167 id_iter->second);
168 return false;
169 }
170 handler_iter->second.handler->HandleRequest(
171 scoped_ptr<Request>(request.release()),
172 scoped_ptr<Response>(new Response{this, request_id}));
173 return true;
174}
175
176void ProtocolHandler::CompleteRequest(
177 const std::string& request_id,
178 int status_code,
179 const std::multimap<std::string, std::string>& headers,
180 const std::vector<uint8_t>& data) {
181 if (!proxy_) {
182 LOG(WARNING) << "Completing a request after the handler proxy is removed";
183 return;
184 }
185
186 std::vector<std::tuple<std::string, std::string>> header_list;
187 header_list.reserve(headers.size());
188 for (const auto& pair : headers)
189 header_list.emplace_back(pair.first, pair.second);
190
191 proxy_->CompleteRequestAsync(request_id, status_code, header_list, data,
192 base::Bind(&base::DoNothing),
193 base::Bind([](chromeos::Error*) {}));
194}
195
196void ProtocolHandler::GetFileData(
197 const std::string& request_id,
198 int file_id,
199 const base::Callback<void(const std::vector<uint8_t>&)>& success_callback,
200 const base::Callback<void(chromeos::Error*)>& error_callback) {
201 CHECK(proxy_);
202 proxy_->GetRequestFileDataAsync(
203 request_id, file_id, success_callback, error_callback);
204}
205
206
207} // namespace libwebserv