blob: f165849a9bf53dc2487aea500cbdca206167af04 [file] [log] [blame]
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "buffet/webserv_client.h"
#include <memory>
#include <string>
#include <libwebserv/protocol_handler.h>
#include <libwebserv/request.h>
#include <libwebserv/response.h>
#include <libwebserv/server.h>
#include "buffet/dbus_constants.h"
#include "buffet/socket_stream.h"
namespace buffet {
namespace {
class RequestImpl : public weave::HttpServer::Request {
public:
explicit RequestImpl(std::unique_ptr<libwebserv::Request> request)
: request_{std::move(request)} {}
~RequestImpl() override {}
// HttpServer::Request implementation.
const std::string& GetPath() const override { return request_->GetPath(); }
std::string GetFirstHeader(const std::string& name) const override {
return request_->GetFirstHeader(name);
}
// TODO(avakulenko): Remove this method and rewrite all call sites in libweave
// to use GetDataStream() instead.
const std::vector<uint8_t>& GetData() const override {
if (request_data_)
return *request_data_;
request_data_.reset(new std::vector<uint8_t>);
auto stream = request_->GetDataStream();
if (stream) {
if (stream->CanGetSize())
request_data_->reserve(stream->GetRemainingSize());
std::vector<uint8_t> buffer(16 * 1024); // 16K seems to be good enough.
size_t sz = 0;
while (stream->ReadBlocking(buffer.data(), buffer.size(), &sz, nullptr) &&
sz > 0) {
request_data_->insert(request_data_->end(),
buffer.data(), buffer.data() + sz);
}
}
return *request_data_;
}
std::unique_ptr<weave::Stream> GetDataStream() const override {
auto stream = std::unique_ptr<weave::Stream>{
new SocketStream{request_->GetDataStream()}};
return stream;
}
private:
std::unique_ptr<libwebserv::Request> request_;
mutable std::unique_ptr<std::vector<uint8_t>> request_data_;
DISALLOW_COPY_AND_ASSIGN(RequestImpl);
};
} // namespace
WebServClient::~WebServClient() {
web_server_->Disconnect();
}
void WebServClient::AddOnStateChangedCallback(
const OnStateChangedCallback& callback) {
on_state_changed_callbacks_.push_back(callback);
callback.Run(*this);
}
void WebServClient::AddRequestHandler(const std::string& path_prefix,
const OnRequestCallback& callback) {
web_server_->GetDefaultHttpHandler()->AddHandlerCallback(
path_prefix, "", base::Bind(&WebServClient::OnRequest,
weak_ptr_factory_.GetWeakPtr(), callback));
web_server_->GetDefaultHttpsHandler()->AddHandlerCallback(
path_prefix, "", base::Bind(&WebServClient::OnRequest,
weak_ptr_factory_.GetWeakPtr(), callback));
}
uint16_t WebServClient::GetHttpPort() const {
return http_port_;
}
uint16_t WebServClient::GetHttpsPort() const {
return https_port_;
}
const chromeos::Blob& WebServClient::GetHttpsCertificateFingerprint() const {
return certificate_;
}
WebServClient::WebServClient(
const scoped_refptr<dbus::Bus>& bus,
chromeos::dbus_utils::AsyncEventSequencer* sequencer) {
web_server_.reset(new libwebserv::Server);
web_server_->OnProtocolHandlerConnected(
base::Bind(&WebServClient::OnProtocolHandlerConnected,
weak_ptr_factory_.GetWeakPtr()));
web_server_->OnProtocolHandlerDisconnected(
base::Bind(&WebServClient::OnProtocolHandlerDisconnected,
weak_ptr_factory_.GetWeakPtr()));
web_server_->Connect(bus, buffet::dbus_constants::kServiceName,
sequencer->GetHandler("Server::Connect failed.", true),
base::Bind(&base::DoNothing),
base::Bind(&base::DoNothing));
}
void WebServClient::OnRequest(const OnRequestCallback& callback,
std::unique_ptr<libwebserv::Request> request,
std::unique_ptr<libwebserv::Response> response) {
callback.Run(
RequestImpl{std::move(request)},
base::Bind(&WebServClient::OnResponse, weak_ptr_factory_.GetWeakPtr(),
base::Passed(&response)));
}
void WebServClient::OnResponse(std::unique_ptr<libwebserv::Response> response,
int status_code,
const std::string& data,
const std::string& mime_type) {
response->ReplyWithText(status_code, data, mime_type);
}
void WebServClient::OnProtocolHandlerConnected(
libwebserv::ProtocolHandler* protocol_handler) {
if (protocol_handler->GetName() == libwebserv::ProtocolHandler::kHttp) {
http_port_ = *protocol_handler->GetPorts().begin();
} else if (protocol_handler->GetName() ==
libwebserv::ProtocolHandler::kHttps) {
https_port_ = *protocol_handler->GetPorts().begin();
certificate_ = protocol_handler->GetCertificateFingerprint();
}
for (const auto& cb : on_state_changed_callbacks_)
cb.Run(*this);
}
void WebServClient::OnProtocolHandlerDisconnected(
libwebserv::ProtocolHandler* protocol_handler) {
if (protocol_handler->GetName() == libwebserv::ProtocolHandler::kHttp) {
http_port_ = 0;
} else if (protocol_handler->GetName() ==
libwebserv::ProtocolHandler::kHttps) {
https_port_ = 0;
certificate_.clear();
}
for (const auto& cb : on_state_changed_callbacks_)
cb.Run(*this);
}
} // namespace buffet