blob: e79a6a402a5cc3dc6881819b35bfcc0f0b80d08e [file] [log] [blame]
Vitaly Buka974647f2015-08-02 20:57:43 -07001// Copyright 2015 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 "buffet/webserv_client.h"
6
7#include <memory>
8#include <string>
9
10#include <libwebserv/protocol_handler.h>
11#include <libwebserv/request.h>
12#include <libwebserv/response.h>
13#include <libwebserv/server.h>
14
15#include "buffet/dbus_constants.h"
Alex Vakulenkob7a325c2015-09-21 10:57:17 -070016#include "buffet/socket_stream.h"
Vitaly Buka974647f2015-08-02 20:57:43 -070017
18namespace buffet {
19
20namespace {
21
Alex Vakulenkoe32375b2015-09-28 08:55:40 -070022using weave::provider::HttpServer;
23
24class RequestImpl : public HttpServer::Request {
Vitaly Buka974647f2015-08-02 20:57:43 -070025 public:
26 explicit RequestImpl(std::unique_ptr<libwebserv::Request> request)
27 : request_{std::move(request)} {}
28 ~RequestImpl() override {}
29
30 // HttpServer::Request implementation.
31 const std::string& GetPath() const override { return request_->GetPath(); }
Alex Vakulenkoe32375b2015-09-28 08:55:40 -070032
Vitaly Buka974647f2015-08-02 20:57:43 -070033 std::string GetFirstHeader(const std::string& name) const override {
34 return request_->GetFirstHeader(name);
35 }
Alex Vakulenkob7a325c2015-09-21 10:57:17 -070036
37 // TODO(avakulenko): Remove this method and rewrite all call sites in libweave
38 // to use GetDataStream() instead.
Vitaly Buka974647f2015-08-02 20:57:43 -070039 const std::vector<uint8_t>& GetData() const override {
Alex Vakulenko458e2c52015-09-25 13:23:43 -070040 if (request_data_)
Alex Vakulenkob7a325c2015-09-21 10:57:17 -070041 return *request_data_;
42
43 request_data_.reset(new std::vector<uint8_t>);
44 auto stream = request_->GetDataStream();
45 if (stream) {
46 if (stream->CanGetSize())
47 request_data_->reserve(stream->GetRemainingSize());
48 std::vector<uint8_t> buffer(16 * 1024); // 16K seems to be good enough.
49 size_t sz = 0;
50 while (stream->ReadBlocking(buffer.data(), buffer.size(), &sz, nullptr) &&
51 sz > 0) {
52 request_data_->insert(request_data_->end(),
53 buffer.data(), buffer.data() + sz);
54 }
55 }
56 return *request_data_;
57 }
58
59 std::unique_ptr<weave::Stream> GetDataStream() const override {
60 auto stream = std::unique_ptr<weave::Stream>{
61 new SocketStream{request_->GetDataStream()}};
62 return stream;
Vitaly Buka974647f2015-08-02 20:57:43 -070063 }
64
65 private:
66 std::unique_ptr<libwebserv::Request> request_;
Alex Vakulenkob7a325c2015-09-21 10:57:17 -070067 mutable std::unique_ptr<std::vector<uint8_t>> request_data_;
Vitaly Buka974647f2015-08-02 20:57:43 -070068
69 DISALLOW_COPY_AND_ASSIGN(RequestImpl);
70};
71
72} // namespace
73
74WebServClient::~WebServClient() {
75 web_server_->Disconnect();
76}
77
78void WebServClient::AddOnStateChangedCallback(
79 const OnStateChangedCallback& callback) {
80 on_state_changed_callbacks_.push_back(callback);
81 callback.Run(*this);
82}
83
84void WebServClient::AddRequestHandler(const std::string& path_prefix,
85 const OnRequestCallback& callback) {
86 web_server_->GetDefaultHttpHandler()->AddHandlerCallback(
87 path_prefix, "", base::Bind(&WebServClient::OnRequest,
88 weak_ptr_factory_.GetWeakPtr(), callback));
89 web_server_->GetDefaultHttpsHandler()->AddHandlerCallback(
90 path_prefix, "", base::Bind(&WebServClient::OnRequest,
91 weak_ptr_factory_.GetWeakPtr(), callback));
92}
93
94uint16_t WebServClient::GetHttpPort() const {
95 return http_port_;
96}
97
98uint16_t WebServClient::GetHttpsPort() const {
99 return https_port_;
100}
101
102const chromeos::Blob& WebServClient::GetHttpsCertificateFingerprint() const {
103 return certificate_;
104}
105
106WebServClient::WebServClient(
107 const scoped_refptr<dbus::Bus>& bus,
108 chromeos::dbus_utils::AsyncEventSequencer* sequencer) {
109 web_server_.reset(new libwebserv::Server);
110 web_server_->OnProtocolHandlerConnected(
111 base::Bind(&WebServClient::OnProtocolHandlerConnected,
112 weak_ptr_factory_.GetWeakPtr()));
113 web_server_->OnProtocolHandlerDisconnected(
114 base::Bind(&WebServClient::OnProtocolHandlerDisconnected,
115 weak_ptr_factory_.GetWeakPtr()));
116
Robert Gindacf92c662015-08-20 09:30:11 -0700117 web_server_->Connect(bus, buffet::dbus_constants::kServiceName,
Vitaly Buka974647f2015-08-02 20:57:43 -0700118 sequencer->GetHandler("Server::Connect failed.", true),
119 base::Bind(&base::DoNothing),
120 base::Bind(&base::DoNothing));
121}
122
123void WebServClient::OnRequest(const OnRequestCallback& callback,
124 std::unique_ptr<libwebserv::Request> request,
125 std::unique_ptr<libwebserv::Response> response) {
126 callback.Run(
127 RequestImpl{std::move(request)},
128 base::Bind(&WebServClient::OnResponse, weak_ptr_factory_.GetWeakPtr(),
129 base::Passed(&response)));
130}
131
132void WebServClient::OnResponse(std::unique_ptr<libwebserv::Response> response,
133 int status_code,
134 const std::string& data,
135 const std::string& mime_type) {
Alex Vakulenkob2fc6902015-09-23 14:36:25 -0700136 response->ReplyWithText(status_code, data, mime_type);
Vitaly Buka974647f2015-08-02 20:57:43 -0700137}
138
139void WebServClient::OnProtocolHandlerConnected(
140 libwebserv::ProtocolHandler* protocol_handler) {
141 if (protocol_handler->GetName() == libwebserv::ProtocolHandler::kHttp) {
142 http_port_ = *protocol_handler->GetPorts().begin();
143 } else if (protocol_handler->GetName() ==
144 libwebserv::ProtocolHandler::kHttps) {
145 https_port_ = *protocol_handler->GetPorts().begin();
146 certificate_ = protocol_handler->GetCertificateFingerprint();
147 }
148 for (const auto& cb : on_state_changed_callbacks_)
149 cb.Run(*this);
150}
151
152void WebServClient::OnProtocolHandlerDisconnected(
153 libwebserv::ProtocolHandler* protocol_handler) {
154 if (protocol_handler->GetName() == libwebserv::ProtocolHandler::kHttp) {
155 http_port_ = 0;
156 } else if (protocol_handler->GetName() ==
157 libwebserv::ProtocolHandler::kHttps) {
158 https_port_ = 0;
159 certificate_.clear();
160 }
161 for (const auto& cb : on_state_changed_callbacks_)
162 cb.Run(*this);
163}
164
165} // namespace buffet