webserver: Moved platform2/libwebserv to platform2/webserver
Cleaned up the code structure a bit inside the web server directory
to reflect the current layout of functionality:
- Renamed the top-level director from libwebserv to webserver
- Moved the client library code to sub-directory of libwebserv to
be on the same level as the web server daemon (webservd).
- Updated the source code to reflect the new include paths.
BUG=brillo:10
TEST=FEATURES=test emerge-storm webserver privetd ap-daemons
CQ-DEPEND=CL:245755,CL:*195317
Change-Id: Idb8d665b6e0c15b5ee0219ff72327045a7084363
Reviewed-on: https://chromium-review.googlesource.com/245736
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/libwebserv/connection.cc b/libwebserv/connection.cc
new file mode 100644
index 0000000..4e1ae8f
--- /dev/null
+++ b/libwebserv/connection.cc
@@ -0,0 +1,158 @@
+// Copyright 2014 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 <libwebserv/connection.h>
+
+#include <algorithm>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/logging.h>
+#include <base/task_runner.h>
+#include <chromeos/http/http_request.h>
+#include <libwebserv/request.h>
+#include <libwebserv/request_handler_interface.h>
+#include <libwebserv/response.h>
+#include <libwebserv/server.h>
+#include <microhttpd.h>
+
+namespace libwebserv {
+
+// Helper class to provide static callback methods to microhttpd library,
+// with the ability to access private methods of Connection class.
+class ConnectionHelper {
+ public:
+ static int PostDataIterator(void* cls,
+ MHD_ValueKind kind,
+ const char* key,
+ const char* filename,
+ const char* content_type,
+ const char* transfer_encoding,
+ const char* data,
+ uint64_t off,
+ size_t size) {
+ Connection* server_connection = reinterpret_cast<Connection*>(cls);
+ if (!server_connection->ProcessPostData(
+ key, filename, content_type, transfer_encoding, data, off, size)) {
+ return MHD_NO;
+ }
+ return MHD_YES;
+ }
+};
+
+// Helper class to provide static callback methods to microhttpd library,
+// with the ability to access private methods of Request class.
+class RequestHelper {
+ public:
+ static int ValueCallback(void* cls,
+ MHD_ValueKind kind,
+ const char* key,
+ const char* value) {
+ auto self = reinterpret_cast<Request*>(cls);
+ std::string data;
+ if (value)
+ data = value;
+ if (kind == MHD_HEADER_KIND) {
+ self->headers_.emplace(Request::GetCanonicalHeaderName(key), data);
+ } else if (kind == MHD_COOKIE_KIND) {
+ // TODO(avakulenko): add support for cookies...
+ } else if (kind == MHD_POSTDATA_KIND) {
+ self->post_data_.emplace(key, data);
+ } else if (kind == MHD_GET_ARGUMENT_KIND) {
+ self->get_data_.emplace(key, data);
+ }
+ return MHD_YES;
+ }
+};
+
+Connection::Connection(const scoped_refptr<base::TaskRunner>& task_runner,
+ MHD_Connection* connection,
+ RequestHandlerInterface* handler)
+ : task_runner_(task_runner),
+ raw_connection_(connection),
+ handler_(handler) {
+}
+
+Connection::~Connection() {
+ if (post_processor_)
+ MHD_destroy_post_processor(post_processor_);
+}
+
+scoped_refptr<Connection> Connection::Create(Server* server,
+ const std::string& url,
+ const std::string& method,
+ MHD_Connection* connection,
+ RequestHandlerInterface* handler) {
+ scoped_refptr<Connection> result(
+ new Connection(server->task_runner_, connection, handler));
+ VLOG(1) << "Incoming HTTP connection (" << result.get() << ")."
+ << " Method='" << method << "', URL='" << url << "'";
+ result->post_processor_ = MHD_create_post_processor(
+ connection, 1024, &ConnectionHelper::PostDataIterator, result.get());
+ result->request_ = Request::Create(url, method);
+ result->response_ = Response::Create(result);
+ return result;
+}
+
+bool Connection::BeginRequestData() {
+ MHD_get_connection_values(raw_connection_, MHD_HEADER_KIND,
+ &RequestHelper::ValueCallback, request_.get());
+ MHD_get_connection_values(raw_connection_, MHD_COOKIE_KIND,
+ &RequestHelper::ValueCallback, request_.get());
+ MHD_get_connection_values(raw_connection_, MHD_POSTDATA_KIND,
+ &RequestHelper::ValueCallback, request_.get());
+ MHD_get_connection_values(raw_connection_, MHD_GET_ARGUMENT_KIND,
+ &RequestHelper::ValueCallback, request_.get());
+ return true;
+}
+
+bool Connection::AddRequestData(const void* data, size_t size) {
+ if (!post_processor_)
+ return request_->AddRawRequestData(data, size);
+ return MHD_post_process(post_processor_,
+ static_cast<const char*>(data), size) == MHD_YES;
+}
+
+void Connection::EndRequestData() {
+ if (state_ == State::kIdle) {
+ state_ = State::kRequestSent;
+ // libmicrohttpd calls handlers on its own thread.
+ // Redirect this to the main IO thread of the server.
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&RequestHandlerInterface::HandleRequest,
+ base::Unretained(handler_), base::Passed(&request_),
+ base::Passed(&response_)));
+ } else if (state_ == State::kResponseReceived) {
+ VLOG(1) << "Sending HTTP response for connection (" << this
+ << "): " << response_status_code_
+ << ", data size = " << response_data_.size();
+ MHD_Response* resp = MHD_create_response_from_buffer(
+ response_data_.size(), response_data_.data(), MHD_RESPMEM_PERSISTENT);
+ for (const auto& pair : response_headers_) {
+ MHD_add_response_header(resp, pair.first.c_str(), pair.second.c_str());
+ }
+ CHECK_EQ(MHD_YES,
+ MHD_queue_response(raw_connection_, response_status_code_, resp))
+ << "Failed to queue response";
+ MHD_destroy_response(resp); // |resp| is ref-counted.
+ state_ = State::kDone;
+ }
+}
+
+bool Connection::ProcessPostData(const char* key,
+ const char* filename,
+ const char* content_type,
+ const char* transfer_encoding,
+ const char* data,
+ uint64_t off,
+ size_t size) {
+ if (off == 0)
+ return request_->AddPostFieldData(key, filename, content_type,
+ transfer_encoding, data, size);
+ return request_->AppendPostFieldData(key, data, size);
+}
+
+} // namespace libwebserv