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
diff --git a/libwebserv/connection.h b/libwebserv/connection.h
new file mode 100644
index 0000000..73bb816
--- /dev/null
+++ b/libwebserv/connection.h
@@ -0,0 +1,89 @@
+// 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.
+
+#ifndef WEBSERVER_LIBWEBSERV_CONNECTION_H_
+#define WEBSERVER_LIBWEBSERV_CONNECTION_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+#include <base/memory/scoped_ptr.h>
+#include <chromeos/errors/error.h>
+#include <libwebserv/export.h>
+
+struct MHD_Connection;
+struct MHD_PostProcessor;
+
+namespace base {
+class TaskRunner;
+}  // namespace base
+
+namespace libwebserv {
+
+class Request;
+class RequestHandlerInterface;
+class Response;
+class Server;
+
+// A wrapper class around low-level HTTP connection.
+class LIBWEBSERV_EXPORT Connection final : public base::RefCounted<Connection> {
+ public:
+  ~Connection();
+
+  // Factory creator method. Creates an instance of the connection and
+  // initializes some complex data members. This is safer and easier to
+  // report possible failures than reply on just the constructor.
+  static scoped_refptr<Connection> Create(Server* server,
+                                          const std::string& url,
+                                          const std::string& method,
+                                          MHD_Connection* connection,
+                                          RequestHandlerInterface* handler);
+
+ private:
+  LIBWEBSERV_PRIVATE Connection(
+      const scoped_refptr<base::TaskRunner>& task_runner,
+      MHD_Connection* connection,
+      RequestHandlerInterface* handler);
+
+  // Helper callback methods used by Server's ConnectionHandler to transfer
+  // request headers and data to the Connection's Request object.
+  LIBWEBSERV_PRIVATE bool BeginRequestData();
+  LIBWEBSERV_PRIVATE bool AddRequestData(const void* data, size_t size);
+  LIBWEBSERV_PRIVATE void EndRequestData();
+
+  // Callback for libmicrohttpd's PostProcessor.
+  LIBWEBSERV_PRIVATE bool ProcessPostData(const char* key,
+                                          const char* filename,
+                                          const char* content_type,
+                                          const char* transfer_encoding,
+                                          const char* data,
+                                          uint64_t off,
+                                          size_t size);
+
+  scoped_refptr<base::TaskRunner> task_runner_;
+  MHD_Connection* raw_connection_{nullptr};
+  RequestHandlerInterface* handler_{nullptr};
+  MHD_PostProcessor* post_processor_{nullptr};
+  scoped_ptr<Request> request_;
+  scoped_ptr<Response> response_;
+
+  enum class State { kIdle, kRequestSent, kResponseReceived, kDone };
+  State state_{State::kIdle};
+  int response_status_code_{0};
+  std::vector<uint8_t> response_data_;
+  std::multimap<std::string, std::string> response_headers_;
+
+  friend class ConnectionHelper;
+  friend class Request;
+  friend class Response;
+  friend class ServerHelper;
+  DISALLOW_COPY_AND_ASSIGN(Connection);
+};
+
+}  // namespace libwebserv
+
+#endif  // WEBSERVER_LIBWEBSERV_CONNECTION_H_
diff --git a/libwebserv/export.h b/libwebserv/export.h
new file mode 100644
index 0000000..f2c5394
--- /dev/null
+++ b/libwebserv/export.h
@@ -0,0 +1,13 @@
+// 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.
+
+#ifndef WEBSERVER_LIBWEBSERV_EXPORT_H_
+#define WEBSERVER_LIBWEBSERV_EXPORT_H_
+
+// See detailed explanation of the purpose of LIBWEBSERV_EXPORT in
+// chromeos/chromeos_export.h for similar attribute - CHROMEOS_EXPORT.
+#define LIBWEBSERV_EXPORT __attribute__((__visibility__("default")))
+#define LIBWEBSERV_PRIVATE __attribute__((__visibility__("hidden")))
+
+#endif  // WEBSERVER_LIBWEBSERV_EXPORT_H_
diff --git a/libwebserv/libwebserv.pc.in b/libwebserv/libwebserv.pc.in
new file mode 100644
index 0000000..537d6bc
--- /dev/null
+++ b/libwebserv/libwebserv.pc.in
@@ -0,0 +1,7 @@
+bslot=@BSLOT@
+
+Name: libwebserv
+Description: Web server interface library
+Version: ${bslot}
+Requires.private: @PRIVATE_PC@
+Libs: -lwebserv-${bslot}
diff --git a/libwebserv/libwebserv_testrunner.cc b/libwebserv/libwebserv_testrunner.cc
new file mode 100644
index 0000000..575f952
--- /dev/null
+++ b/libwebserv/libwebserv_testrunner.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 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 <base/at_exit.h>
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+  base::AtExitManager exit_manager;
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/libwebserv/preinstall.sh b/libwebserv/preinstall.sh
new file mode 100755
index 0000000..51ee83b
--- /dev/null
+++ b/libwebserv/preinstall.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+OUT=$1
+v=$2
+
+deps=$(<"${OUT}"/gen/libwebserv-${v}-deps.txt)
+sed \
+  -e "s/@BSLOT@/${v}/g" \
+  -e "s/@PRIVATE_PC@/${deps}/g" \
+  "libwebserv/libwebserv.pc.in" > "${OUT}/lib/libwebserv-${v}.pc"
diff --git a/libwebserv/request.cc b/libwebserv/request.cc
new file mode 100644
index 0000000..37ea1c1
--- /dev/null
+++ b/libwebserv/request.cc
@@ -0,0 +1,191 @@
+// 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/request.h>
+
+#include <libwebserv/connection.h>
+
+namespace libwebserv {
+
+FileInfo::FileInfo(const std::string& file_name,
+                   const std::string& content_type,
+                   const std::string& transfer_encoding)
+    : file_name_(file_name),
+      content_type_(content_type),
+      transfer_encoding_(transfer_encoding) {
+}
+
+const std::vector<uint8_t>& FileInfo::GetData() const {
+  return data_;
+}
+
+Request::Request(const std::string& url, const std::string& method)
+    : url_{url}, method_{method} {
+}
+
+Request::~Request() {
+}
+
+scoped_ptr<Request> Request::Create(const std::string& url,
+                                    const std::string& method) {
+  // Can't use make_shared here since Request::Request is private.
+  return scoped_ptr<Request>(new Request(url, method));
+}
+
+const std::vector<uint8_t>& Request::GetData() const {
+  return raw_data_;
+}
+
+bool Request::AddRawRequestData(const void* data, size_t size) {
+  const uint8_t* byte_data_ = static_cast<const uint8_t*>(data);
+  raw_data_.insert(raw_data_.end(), byte_data_, byte_data_ + size);
+  return true;
+}
+
+bool Request::AddPostFieldData(const char* key,
+                               const char* filename,
+                               const char* content_type,
+                               const char* transfer_encoding,
+                               const char* data,
+                               size_t size) {
+  if (filename) {
+    std::unique_ptr<FileInfo> file_info{
+        new FileInfo{filename, content_type ? content_type : "",
+                     transfer_encoding ? transfer_encoding : ""}};
+    file_info->data_.assign(data, data + size);
+    file_info_.emplace(key, std::move(file_info));
+    last_posted_data_was_file_ = true;
+    return true;
+  }
+  std::string value{data, size};
+  post_data_.emplace(key, value);
+  last_posted_data_was_file_ = false;
+  return true;
+}
+
+bool Request::AppendPostFieldData(const char* key,
+                                  const char* data,
+                                  size_t size) {
+  if (last_posted_data_was_file_) {
+    auto file_pair = file_info_.equal_range(key);
+    if (file_pair.first == file_info_.end())
+      return false;
+    FileInfo* file_info = file_pair.second->second.get();
+    file_info->data_.insert(file_info->data_.end(), data, data + size);
+    return true;
+  }
+
+  auto pair = post_data_.equal_range(key);
+  if (pair.first == post_data_.end())
+    return false;
+  --pair.second;  // Get the last form field with this name/key.
+  pair.second->second.append(data, size);
+  return true;
+}
+
+std::vector<PairOfStrings> Request::GetFormData() const {
+  auto data = GetFormDataGet();
+  auto post_data = GetFormDataPost();
+  data.insert(data.end(), post_data.begin(), post_data.end());
+  return data;
+}
+
+std::vector<PairOfStrings> Request::GetFormDataGet() const {
+  return std::vector<PairOfStrings>{get_data_.begin(), get_data_.end()};
+}
+
+std::vector<PairOfStrings> Request::GetFormDataPost() const {
+  return std::vector<PairOfStrings>{post_data_.begin(), post_data_.end()};
+}
+
+std::vector<std::pair<std::string, const FileInfo*>> Request::GetFiles() const {
+  std::vector<std::pair<std::string, const FileInfo*>> data;
+  data.reserve(file_info_.size());
+  for (const auto& pair : file_info_) {
+    data.emplace_back(pair.first, pair.second.get());
+  }
+  return data;
+}
+
+std::vector<std::string> Request::GetFormField(const std::string& name) const {
+  std::vector<std::string> data;
+  auto pair = get_data_.equal_range(name);
+  while (pair.first != pair.second) {
+    data.push_back(pair.first->second);
+    ++pair.first;
+  }
+  pair = post_data_.equal_range(name);
+  while (pair.first != pair.second) {
+    data.push_back(pair.first->second);
+    ++pair.first;
+  }
+  return data;
+}
+
+std::vector<std::string> Request::GetFormFieldPost(
+    const std::string& name) const {
+  std::vector<std::string> data;
+  auto pair = post_data_.equal_range(name);
+  while (pair.first != pair.second) {
+    data.push_back(pair.first->second);
+    ++pair.first;
+  }
+  return data;
+}
+
+std::vector<std::string> Request::GetFormFieldGet(
+    const std::string& name) const {
+  std::vector<std::string> data;
+  auto pair = get_data_.equal_range(name);
+  while (pair.first != pair.second) {
+    data.push_back(pair.first->second);
+    ++pair.first;
+  }
+  return data;
+}
+
+std::vector<const FileInfo*> Request::GetFileInfo(
+    const std::string& name) const {
+  std::vector<const FileInfo*> data;
+  auto pair = file_info_.equal_range(name);
+  while (pair.first != pair.second) {
+    data.push_back(pair.first->second.get());
+    ++pair.first;
+  }
+  return data;
+}
+
+std::vector<PairOfStrings> Request::GetHeaders() const {
+  return std::vector<PairOfStrings>{headers_.begin(), headers_.end()};
+}
+
+std::vector<std::string> Request::GetHeader(const std::string& name) const {
+  std::vector<std::string> data;
+  auto pair = headers_.equal_range(GetCanonicalHeaderName(name));
+  while (pair.first != pair.second) {
+    data.push_back(pair.first->second);
+    ++pair.first;
+  }
+  return data;
+}
+
+std::string Request::GetCanonicalHeaderName(const std::string& name) {
+  std::string canonical_name = name;
+  bool word_begin = true;
+  for (char& c : canonical_name) {
+    if (c == '-') {
+      word_begin = true;
+    } else {
+      if (word_begin) {
+        c = toupper(c);
+      } else {
+        c = tolower(c);
+      }
+      word_begin = false;
+    }
+  }
+  return canonical_name;
+}
+
+}  // namespace libwebserv
diff --git a/libwebserv/request.h b/libwebserv/request.h
new file mode 100644
index 0000000..6899b3d
--- /dev/null
+++ b/libwebserv/request.h
@@ -0,0 +1,146 @@
+// 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.
+
+#ifndef WEBSERVER_LIBWEBSERV_REQUEST_H_
+#define WEBSERVER_LIBWEBSERV_REQUEST_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+#include <base/memory/scoped_ptr.h>
+#include <libwebserv/export.h>
+
+struct MHD_Connection;
+
+namespace libwebserv {
+
+class Connection;
+using PairOfStrings = std::pair<std::string, std::string>;
+
+class LIBWEBSERV_EXPORT FileInfo final {
+ public:
+  FileInfo(const std::string& file_name,
+           const std::string& content_type,
+           const std::string& transfer_encoding);
+
+  const std::vector<uint8_t>& GetData() const;
+  const std::string& GetFileName() const { return file_name_; }
+  const std::string& GetContentType() const { return content_type_; }
+  const std::string& GetTransferEncoding() const { return transfer_encoding_; }
+
+ private:
+  std::string file_name_;
+  std::string content_type_;
+  std::string transfer_encoding_;
+  std::vector<uint8_t> data_;
+
+  friend class Request;
+  DISALLOW_COPY_AND_ASSIGN(FileInfo);
+};
+
+// A class that represents the HTTP request data.
+class LIBWEBSERV_EXPORT Request final {
+ public:
+  ~Request();
+
+  // Factory constructor method.
+  static scoped_ptr<Request> Create(const std::string& url,
+                                    const std::string& method);
+
+  // Gets the request body data stream. Note that the stream is available
+  // only for requests that provided data and if this data is not already
+  // pre-parsed by the server (e.g. "application/x-www-form-urlencoded" and
+  // "multipart/form-data"). If there is no request body, or the data has been
+  // pre-parsed by the server, the returned stream will be empty.
+  const std::vector<uint8_t>& GetData() const;
+
+  // Returns the request path (e.g. "/path/document").
+  const std::string& GetPath() const { return url_; }
+
+  // Returns the request method (e.g. "GET", "POST", etc).
+  const std::string& GetMethod() const { return method_; }
+
+  // Returns a list of key-value pairs that include values provided on the URL
+  // (e.g. "http://server.com/?foo=bar") and the non-file form fields in the
+  // POST data.
+  std::vector<PairOfStrings> GetFormData() const;
+
+  // Returns a list of key-value pairs for query parameters provided on the URL
+  // (e.g. "http://server.com/?foo=bar").
+  std::vector<PairOfStrings> GetFormDataGet() const;
+
+  // Returns a list of key-value pairs for the non-file form fields in the
+  // POST data.
+  std::vector<PairOfStrings> GetFormDataPost() const;
+
+  // Returns a list of file information records for all the file uploads in
+  // the POST request.
+  std::vector<std::pair<std::string, const FileInfo*>> GetFiles() const;
+
+  // Gets the values of form field with given |name|. This includes both
+  // values provided on the URL and as part of form data in POST request.
+  std::vector<std::string> GetFormField(const std::string& name) const;
+
+  // Gets the values of form field with given |name| for form data in POST
+  // request.
+  std::vector<std::string> GetFormFieldPost(const std::string& name) const;
+
+  // Gets the values of URL query parameters with given |name|.
+  std::vector<std::string> GetFormFieldGet(const std::string& name) const;
+
+  // Gets the file upload parameters for a file form field of given |name|.
+  std::vector<const FileInfo*> GetFileInfo(const std::string& name) const;
+
+  // Returns a list of key-value pairs for all the request headers.
+  std::vector<PairOfStrings> GetHeaders() const;
+
+  // Returns the value(s) of a request head of given |name|.
+  std::vector<std::string> GetHeader(const std::string& name) const;
+
+ private:
+  LIBWEBSERV_PRIVATE Request(const std::string& url, const std::string& method);
+
+  // Helper methods for processing request data coming from the raw HTTP
+  // connection.
+  // These methods parse the request headers and data so they can be accessed
+  // by request handlers later.
+  LIBWEBSERV_PRIVATE bool AddRawRequestData(const void* data, size_t size);
+  LIBWEBSERV_PRIVATE bool AddPostFieldData(const char* key,
+                                           const char* filename,
+                                           const char* content_type,
+                                           const char* transfer_encoding,
+                                           const char* data,
+                                           size_t size);
+  LIBWEBSERV_PRIVATE bool AppendPostFieldData(const char* key,
+                                              const char* data,
+                                              size_t size);
+  // Converts a request header name to canonical form (lowercase with uppercase
+  // first letter and each letter after a hyphen ('-')).
+  // "content-TYPE" will be converted to "Content-Type".
+  LIBWEBSERV_PRIVATE static std::string GetCanonicalHeaderName(
+      const std::string& name);
+
+  std::string url_;
+  std::string method_;
+  std::vector<uint8_t> raw_data_;
+  bool last_posted_data_was_file_{false};
+
+  std::multimap<std::string, std::string> post_data_;
+  std::multimap<std::string, std::string> get_data_;
+  std::multimap<std::string, std::unique_ptr<FileInfo>> file_info_;
+  std::multimap<std::string, std::string> headers_;
+
+  friend class Connection;
+  friend class RequestHelper;
+  DISALLOW_COPY_AND_ASSIGN(Request);
+};
+
+}  // namespace libwebserv
+
+#endif  // WEBSERVER_LIBWEBSERV_REQUEST_H_
diff --git a/libwebserv/request_handler_callback.cc b/libwebserv/request_handler_callback.cc
new file mode 100644
index 0000000..f5be1fb
--- /dev/null
+++ b/libwebserv/request_handler_callback.cc
@@ -0,0 +1,18 @@
+// 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/request_handler_callback.h>
+
+namespace libwebserv {
+
+RequestHandlerCallback::RequestHandlerCallback(
+    const base::Callback<HandlerSignature>& callback) : callback_(callback) {
+}
+
+void RequestHandlerCallback::HandleRequest(scoped_ptr<Request> request,
+                                           scoped_ptr<Response> response) {
+  callback_.Run(request.Pass(), response.Pass());
+}
+
+}  // namespace libwebserv
diff --git a/libwebserv/request_handler_callback.h b/libwebserv/request_handler_callback.h
new file mode 100644
index 0000000..1be1817
--- /dev/null
+++ b/libwebserv/request_handler_callback.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef WEBSERVER_LIBWEBSERV_REQUEST_HANDLER_CALLBACK_H_
+#define WEBSERVER_LIBWEBSERV_REQUEST_HANDLER_CALLBACK_H_
+
+#include <base/callback.h>
+#include <base/macros.h>
+#include <libwebserv/export.h>
+#include <libwebserv/request_handler_interface.h>
+
+namespace libwebserv {
+
+// A simple request handler that wraps a callback function.
+// Essentially, it redirects the RequestHandlerInterface::HandleRequest calls
+// to the provided callback.
+class LIBWEBSERV_EXPORT RequestHandlerCallback
+    : public RequestHandlerInterface {
+ public:
+  explicit RequestHandlerCallback(
+      const base::Callback<HandlerSignature>& callback);
+
+  void HandleRequest(scoped_ptr<Request> request,
+                     scoped_ptr<Response> response) override;
+
+ private:
+  base::Callback<HandlerSignature> callback_;
+  DISALLOW_COPY_AND_ASSIGN(RequestHandlerCallback);
+};
+
+}  // namespace libwebserv
+
+#endif  // WEBSERVER_LIBWEBSERV_REQUEST_HANDLER_CALLBACK_H_
diff --git a/libwebserv/request_handler_interface.h b/libwebserv/request_handler_interface.h
new file mode 100644
index 0000000..0b12126
--- /dev/null
+++ b/libwebserv/request_handler_interface.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef WEBSERVER_LIBWEBSERV_REQUEST_HANDLER_INTERFACE_H_
+#define WEBSERVER_LIBWEBSERV_REQUEST_HANDLER_INTERFACE_H_
+
+#include <base/memory/scoped_ptr.h>
+#include <libwebserv/request.h>
+#include <libwebserv/response.h>
+
+namespace libwebserv {
+
+// The base interface for HTTP request handlers. When registering a handler,
+// the RequestHandlerInterface is provided, and when a request comes in,
+// RequestHandlerInterface::HandleRequest() is called to process the data and
+// send response.
+class RequestHandlerInterface {
+ public:
+  using HandlerSignature = void(scoped_ptr<Request>, scoped_ptr<Response>);
+
+  virtual void HandleRequest(scoped_ptr<Request> request,
+                             scoped_ptr<Response> response) = 0;
+};
+
+}  // namespace libwebserv
+
+#endif  // WEBSERVER_LIBWEBSERV_REQUEST_HANDLER_INTERFACE_H_
diff --git a/libwebserv/response.cc b/libwebserv/response.cc
new file mode 100644
index 0000000..c54747f
--- /dev/null
+++ b/libwebserv/response.cc
@@ -0,0 +1,110 @@
+// 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/response.h>
+
+#include <algorithm>
+
+#include <base/json/json_writer.h>
+#include <base/logging.h>
+#include <base/values.h>
+#include <chromeos/http/http_request.h>
+#include <chromeos/mime_utils.h>
+#include <chromeos/strings/string_utils.h>
+#include <libwebserv/connection.h>
+#include <microhttpd.h>
+
+namespace libwebserv {
+
+Response::Response(const scoped_refptr<Connection>& connection)
+    : connection_(connection) {
+}
+
+Response::~Response() {
+  if (!reply_sent_) {
+    ReplyWithError(chromeos::http::status_code::InternalServerError,
+                   "Internal server error");
+  }
+}
+
+scoped_ptr<Response> Response::Create(
+    const scoped_refptr<Connection>& connection) {
+  return scoped_ptr<Response>(new Response(connection));
+}
+
+void Response::AddHeader(const std::string& header_name,
+                         const std::string& value) {
+  headers_.emplace(header_name, value);
+}
+
+void Response::AddHeaders(
+    const std::vector<std::pair<std::string, std::string>>& headers) {
+  headers_.insert(headers.begin(), headers.end());
+}
+
+void Response::Reply(int status_code,
+                     const void* data,
+                     size_t data_size,
+                     const std::string& mime_type) {
+  status_code_ = status_code;
+  const uint8_t* byte_ptr = static_cast<const uint8_t*>(data);
+  data_.assign(byte_ptr, byte_ptr + data_size);
+  AddHeader(chromeos::http::response_header::kContentType, mime_type);
+  SendResponse();
+}
+
+void Response::ReplyWithText(int status_code,
+                             const std::string& text,
+                             const std::string& mime_type) {
+  Reply(status_code, text.data(), text.size(), mime_type);
+}
+
+void Response::ReplyWithJson(int status_code, const base::Value* json) {
+  std::string text;
+  base::JSONWriter::WriteWithOptions(json,
+                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
+                                     &text);
+  std::string mime_type = chromeos::mime::AppendParameter(
+      chromeos::mime::application::kJson,
+      chromeos::mime::parameters::kCharset,
+      "utf-8");
+  ReplyWithText(status_code, text, mime_type);
+}
+
+void Response::ReplyWithJson(int status_code,
+                             const std::map<std::string, std::string>& json) {
+  base::DictionaryValue json_value;
+  for (const auto& pair : json) {
+    json_value.SetString(pair.first, pair.second);
+  }
+  ReplyWithJson(status_code, &json_value);
+}
+
+void Response::Redirect(int status_code, const std::string& redirect_url) {
+  AddHeader(chromeos::http::response_header::kLocation, redirect_url);
+  ReplyWithError(status_code, "");
+}
+
+void Response::ReplyWithError(int status_code, const std::string& error_text) {
+  status_code_ = status_code;
+  data_.assign(error_text.begin(), error_text.end());
+  SendResponse();
+}
+
+void Response::ReplyWithErrorNotFound() {
+  ReplyWithError(chromeos::http::status_code::NotFound, "Not Found");
+}
+
+void Response::SendResponse() {
+  CHECK(!reply_sent_) << "Response already sent";
+  reply_sent_ = true;
+  CHECK(connection_->state_ == Connection::State::kRequestSent)
+      << "Unexpected connection state";
+  connection_->response_status_code_ = status_code_;
+  connection_->response_data_ = std::move(data_);
+  connection_->response_headers_ = std::move(headers_);
+  connection_->state_ = Connection::State::kResponseReceived;
+}
+
+}  // namespace libwebserv
diff --git a/libwebserv/response.h b/libwebserv/response.h
new file mode 100644
index 0000000..05465e3
--- /dev/null
+++ b/libwebserv/response.h
@@ -0,0 +1,97 @@
+// 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.
+
+#ifndef WEBSERVER_LIBWEBSERV_RESPONSE_H_
+#define WEBSERVER_LIBWEBSERV_RESPONSE_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+#include <base/memory/scoped_ptr.h>
+#include <libwebserv/export.h>
+
+namespace base {
+class Value;
+}  // namespace base
+
+struct MHD_Connection;
+
+namespace libwebserv {
+
+class Connection;
+
+// Response class is a proxy for HTTP response used by the request handler
+// to provide response HTTP headers and data.
+class LIBWEBSERV_EXPORT Response
+    : public std::enable_shared_from_this<Response> {
+ public:
+  ~Response();
+
+  // Factory constructor method.
+  static scoped_ptr<Response> Create(
+      const scoped_refptr<Connection>& connection);
+
+  // Adds a single HTTP response header to the response.
+  void AddHeader(const std::string& header_name, const std::string& value);
+
+  // Adds number of HTTP response headers to the response.
+  void AddHeaders(
+      const std::vector<std::pair<std::string, std::string>>& headers);
+
+  // Generic reply method for sending arbitrary binary data response.
+  void Reply(int status_code,
+             const void* data,
+             size_t data_size,
+             const std::string& mime_type);
+
+  // Reply with text body.
+  void ReplyWithText(int status_code,
+                     const std::string& text,
+                     const std::string& mime_type);
+
+  // Reply with JSON object. The content type will be "application/json".
+  void ReplyWithJson(int status_code, const base::Value* json);
+
+  // Special form for JSON response for simple objects that have a flat
+  // list of key-value pairs of string type.
+  void ReplyWithJson(int status_code,
+                     const std::map<std::string, std::string>& json);
+
+  // Issue a redirect response, so the client browser loads a page at
+  // the URL specified in |redirect_url|. If this is not an external URL,
+  // it must be an absolute path starting at the root "/...".
+  void Redirect(int status_code, const std::string& redirect_url);
+
+  // Send a plain text response (with no Content-Type header).
+  // Usually used with error responses. |error_text| must be plain text.
+  void ReplyWithError(int status_code, const std::string& error_text);
+
+  // Send "404 Not Found" response.
+  void ReplyWithErrorNotFound();
+
+ private:
+  LIBWEBSERV_PRIVATE explicit Response(
+      const scoped_refptr<Connection>& connection);
+
+  LIBWEBSERV_PRIVATE void SendResponse();
+
+  scoped_refptr<Connection> connection_;
+  int status_code_{0};
+  std::vector<uint8_t> data_;
+  std::multimap<std::string, std::string> headers_;
+  bool reply_sent_{false};
+
+  friend class Connection;
+  friend class ResponseHelper;
+  DISALLOW_COPY_AND_ASSIGN(Response);
+};
+
+}  // namespace libwebserv
+
+#endif  // WEBSERVER_LIBWEBSERV_RESPONSE_H_
diff --git a/libwebserv/server.cc b/libwebserv/server.cc
new file mode 100644
index 0000000..196f178
--- /dev/null
+++ b/libwebserv/server.cc
@@ -0,0 +1,233 @@
+// 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/server.h>
+
+#include <limits>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/message_loop/message_loop_proxy.h>
+#include <libwebserv/connection.h>
+#include <libwebserv/request.h>
+#include <libwebserv/request_handler_callback.h>
+#include <libwebserv/request_handler_interface.h>
+#include <libwebserv/response.h>
+#include <microhttpd.h>
+
+namespace libwebserv {
+
+namespace {
+// Simple static request handler that just returns "404 Not Found" error.
+class PageNotFoundHandler : public RequestHandlerInterface {
+ public:
+  void HandleRequest(scoped_ptr<Request> request,
+                     scoped_ptr<Response> response) override {
+    response->ReplyWithErrorNotFound();
+  }
+};
+
+}  // anonymous namespace
+
+// Helper class to provide static callback methods to microhttpd library,
+// with the ability to access private methods of Server class.
+class ServerHelper {
+ public:
+  static int ConnectionHandler(void *cls,
+                               MHD_Connection* connection,
+                               const char* url,
+                               const char* method,
+                               const char* version,
+                               const char* upload_data,
+                               size_t* upload_data_size,
+                               void** con_cls) {
+    Server* server = reinterpret_cast<Server*>(cls);
+    if (nullptr == *con_cls) {
+      RequestHandlerInterface* handler = server->FindHandler(url, method);
+      if (!handler)
+        return MHD_NO;
+
+      auto server_connection =
+          Connection::Create(server, url, method, connection, handler);
+      if (!server_connection || !server_connection->BeginRequestData())
+        return MHD_NO;
+
+      *con_cls = server_connection.get();
+      server_connection->AddRef();
+    } else {
+      Connection* connection = reinterpret_cast<Connection*>(*con_cls);
+      if (*upload_data_size) {
+        if (!connection->AddRequestData(upload_data, *upload_data_size))
+          return MHD_NO;
+        *upload_data_size = 0;
+      } else {
+        connection->EndRequestData();
+      }
+    }
+    return MHD_YES;
+  }
+
+  static void RequestCompleted(void* cls,
+                               MHD_Connection* connection,
+                               void** con_cls,
+                               MHD_RequestTerminationCode toe) {
+    reinterpret_cast<Connection*>(*con_cls)->Release();
+    *con_cls = nullptr;
+  }
+};
+
+Server::Server() {}
+
+Server::~Server() {
+  Stop();
+}
+
+bool Server::Start(uint16_t port) {
+  return StartWithTLS(port, chromeos::SecureBlob{}, chromeos::Blob{});
+}
+
+bool Server::StartWithTLS(uint16_t port,
+                          const chromeos::SecureBlob& private_key,
+                          const chromeos::Blob& certificate) {
+  if (server_) {
+    LOG(ERROR) << "Web server is already running.";
+    return false;
+  }
+
+  // Either both keys and certificate must be specified or both muse be omitted.
+  CHECK_EQ(private_key.empty(), certificate.empty());
+
+  const bool use_tls = !private_key.empty();
+
+  task_runner_ = base::MessageLoopProxy::current();
+
+  LOG(INFO) << "Starting " << (use_tls ? "HTTPS" : "HTTP")
+            << " Server on port: " << port;
+  auto callback_addr =
+      reinterpret_cast<intptr_t>(&ServerHelper::RequestCompleted);
+  uint32_t flags = MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG;
+
+  std::vector<MHD_OptionItem> options{
+    {MHD_OPTION_CONNECTION_LIMIT, 10, nullptr},
+    {MHD_OPTION_CONNECTION_TIMEOUT, 60, nullptr},
+    {MHD_OPTION_NOTIFY_COMPLETED, callback_addr, nullptr},
+  };
+
+  // libmicrohttpd expects both the key and certificate to be a zero-terminated
+  // strings. Make sure they are terminated properly.
+  chromeos::SecureBlob private_key_copy = private_key;
+  chromeos::Blob certificate_copy = certificate;
+  if (use_tls) {
+    flags |= MHD_USE_SSL;
+    private_key_copy.push_back(0);
+    certificate_copy.push_back(0);
+    options.push_back(
+        MHD_OptionItem{MHD_OPTION_HTTPS_MEM_KEY, 0, private_key_copy.data()});
+    options.push_back(
+        MHD_OptionItem{MHD_OPTION_HTTPS_MEM_CERT, 0, certificate_copy.data()});
+  }
+
+  options.push_back(MHD_OptionItem{MHD_OPTION_END, 0, nullptr});
+
+  server_ = MHD_start_daemon(flags, port, nullptr, nullptr,
+                             &ServerHelper::ConnectionHandler, this,
+                             MHD_OPTION_ARRAY, options.data(), MHD_OPTION_END);
+  if (!server_) {
+    LOG(ERROR) << "Failed to start the web server on port " << port;
+    return false;
+  }
+  LOG(INFO) << "Server started";
+  return true;
+}
+
+bool Server::Stop() {
+  if (server_) {
+    LOG(INFO) << "Shutting down the web server...";
+    MHD_stop_daemon(server_);
+    server_ = nullptr;
+    LOG(INFO) << "Server shutdown complete";
+  }
+  return true;
+}
+
+int Server::AddHandler(const base::StringPiece& url,
+                       const base::StringPiece& method,
+                       std::unique_ptr<RequestHandlerInterface> handler) {
+  request_handlers_.emplace(++last_handler_id_,
+                            HandlerMapEntry{url.as_string(),
+                                            method.as_string(),
+                                            std::move(handler)});
+  return last_handler_id_;
+}
+
+int Server::AddHandlerCallback(
+    const base::StringPiece& url,
+    const base::StringPiece& method,
+    const base::Callback<RequestHandlerInterface::HandlerSignature>&
+        handler_callback) {
+  std::unique_ptr<RequestHandlerInterface> handler{
+      new RequestHandlerCallback{handler_callback}};
+  return AddHandler(url, method, std::move(handler));
+}
+
+bool Server::RemoveHandler(int handler_id) {
+  return (request_handlers_.erase(handler_id) > 0);
+}
+
+int Server::GetHandlerId(const base::StringPiece& url,
+                         const base::StringPiece& method) const {
+  for (const auto& pair : request_handlers_) {
+    if (pair.second.url == url && pair.second.method == method)
+      return pair.first;
+  }
+  return 0;
+}
+
+RequestHandlerInterface* Server::FindHandler(
+    const base::StringPiece& url,
+    const base::StringPiece& method) const {
+  static PageNotFoundHandler page_not_found_handler;
+
+  size_t score = std::numeric_limits<size_t>::max();
+  RequestHandlerInterface* handler = nullptr;
+  for (const auto& pair : request_handlers_) {
+    std::string handler_url = pair.second.url;
+    bool url_match = (handler_url == url);
+    bool method_match = (pair.second.method == method);
+
+    // Try exact match first. If everything matches, we have our handler.
+    if (url_match && method_match)
+      return pair.second.handler.get();
+
+    // Calculate the current handler's similarity score. The lower the score
+    // the better the match is...
+    size_t current_score = 0;
+    if (!url_match && !handler_url.empty() && handler_url.back() == '/') {
+      if (url.starts_with(handler_url)) {
+        url_match = true;
+        // Use the difference in URL length as URL match quality proxy.
+        // The longer URL, the more specific (better) match is.
+        // Multiply by 2 to allow for extra score point for matching the method.
+        current_score = (url.size() - handler_url.size()) * 2;
+      }
+    }
+
+    if (!method_match && pair.second.method.empty()) {
+      // If the handler didn't specify the method it handles, this means
+      // it doesn't care. However this isn't the exact match, so bump
+      // the score up one point.
+      method_match = true;
+      ++current_score;
+    }
+
+    if (url_match && method_match && current_score < score) {
+      score = current_score;
+      handler = pair.second.handler.get();
+    }
+  }
+
+  return handler ? handler : &page_not_found_handler;
+}
+
+}  // namespace libwebserv
diff --git a/libwebserv/server.h b/libwebserv/server.h
new file mode 100644
index 0000000..6221115
--- /dev/null
+++ b/libwebserv/server.h
@@ -0,0 +1,121 @@
+// 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.
+
+#ifndef WEBSERVER_LIBWEBSERV_SERVER_H_
+#define WEBSERVER_LIBWEBSERV_SERVER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include <base/callback_forward.h>
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+#include <base/strings/string_piece.h>
+#include <chromeos/secure_blob.h>
+#include <libwebserv/export.h>
+#include <libwebserv/request_handler_interface.h>
+
+struct MHD_Daemon;
+
+namespace base {
+class TaskRunner;
+}  // namespace base
+
+namespace libwebserv {
+
+// Top-level wrapper class around HTTP server and provides an interface to
+// the web server. It allows the users to start the server and
+// register request handlers.
+class LIBWEBSERV_EXPORT Server final {
+ public:
+  Server();
+  ~Server();
+
+  // Starts the server and makes it listen to HTTP requests on the given port.
+  //
+  // Note that a valid message loop must exist before calling Start.
+  bool Start(uint16_t port);
+
+  // Starts the server and makes it listen to HTTPS requests on the given port.
+  //
+  // Note that a valid message loop must exist before calling StartWithTLS.
+  bool StartWithTLS(uint16_t port,
+                    const chromeos::SecureBlob& private_key,
+                    const chromeos::Blob& certificate);
+
+  // Stops the server.
+  bool Stop();
+
+  // Adds a request handler for given |url|. If the |url| ends with a '/', this
+  // makes the handler respond to any URL beneath this path.
+  // Note that it is not possible to add a specific handler just for the root
+  // path "/". Doing so means "respond to any URL".
+  // |method| is optional request method verb, such as "GET" or "POST".
+  // If |method| is empty, the handler responds to any request verb.
+  // If there are more than one handler for a given request, the most specific
+  // match is chosen. For example, if there are the following handlers provided:
+  //    - A["/foo/",  ""]
+  //    - B["/foo/bar", "GET"]
+  //    - C["/foo/bar", ""]
+  // Here is what handlers are called when making certain requests:
+  //    - GET("/foo/bar")   => B[]
+  //    - POST("/foo/bar")  => C[]
+  //    - PUT("/foo/bar")   => C[]
+  //    - GET("/foo/baz")   => A[]
+  //    - GET("/foo")       => 404 Not Found
+  // This functions returns a handler ID which can be used later to remove
+  // the handler.
+  int AddHandler(const base::StringPiece& url,
+                 const base::StringPiece& method,
+                 std::unique_ptr<RequestHandlerInterface> handler);
+
+  // Similar to AddHandler() above but the handler is just a callback function.
+  int AddHandlerCallback(
+      const base::StringPiece& url,
+      const base::StringPiece& method,
+      const base::Callback<RequestHandlerInterface::HandlerSignature>&
+          handler_callback);
+
+  // Removes the handler with the specified |handler_id|.
+  // Returns false if the handler with the given ID is not found.
+  bool RemoveHandler(int handler_id);
+
+  // Finds the handler ID given the exact match criteria. Note that using
+  // this function could cause unexpected side effects if there are more than
+  // one handler registered for given URL/Method parameters.
+  // It is better to remember the handler ID from AddHandler() method and use
+  // that ID to remove the handler, instead of looking the handler up using
+  // URL/Method.
+  int GetHandlerId(const base::StringPiece& url,
+                   const base::StringPiece& method) const;
+
+  // Finds a handler for given URL/Method. This method does the criteria
+  // matching and not exact match performed by GetHandlerId. This is the method
+  // used to look up the handler for incoming HTTP requests.
+  RequestHandlerInterface* FindHandler(
+      const base::StringPiece& url,
+      const base::StringPiece& method) const;
+
+ private:
+  MHD_Daemon* server_ = nullptr;
+  scoped_refptr<base::TaskRunner> task_runner_;
+
+  struct LIBWEBSERV_PRIVATE HandlerMapEntry {
+    std::string url;
+    std::string method;
+    std::unique_ptr<RequestHandlerInterface> handler;
+  };
+
+  std::map<int, HandlerMapEntry> request_handlers_;
+  int last_handler_id_{0};
+
+  friend class ServerHelper;
+  friend class Connection;
+  DISALLOW_COPY_AND_ASSIGN(Server);
+};
+
+}  // namespace libwebserv
+
+#endif  // WEBSERVER_LIBWEBSERV_SERVER_H_