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