blob: 622785b2bbc88361a41bd58f202c2a4d5f63d3ea [file] [log] [blame]
// Copyright 2015 The Weave 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 <string>
#include <vector>
#include <base/callback.h>
#include <base/time/time.h>
#include <weave/stream.h>
namespace weave {
namespace provider {
// This interface should be implemented by the user of libweave and
// provided during device creation in Device::Create(...)
// libweave will use this interface to handle HTTP / HTTPS requests for Privet
// APIs.
// This interface consist of 2 parts that need to be implemented by the
// libweave user: HttpServer and HttpServer::Request. HttpServer provides
// interface to control webserver, and is used to initialize Device object.
// Request provides an abstraction for a specific HTTP request and may be a
// short-lived object.
// Implementation of AddHttpsRequestHandler(...) method should follow the
// same guidelines as implementation of AddHttpRequestHandler(...) with the
// only difference, it is for HTTPS connection (not HTTP).
// Implementation of GetHttpPort() method should return port number on
// which HTTP server will be listening. Normally it is port 80, but this
// allows implementer to choose different port if necessary and tell it to
// libweave.
// Implementation of GetHttpsPort() should follow the same guidelines as
// GetHttpPort(). Default HTTPS port is 443, but could be changed and
// communicated to libweave using this method.
// Implementation of GetHttpsCertificateFingerprint() method should
// compute fingerprint of the certificate that HTTPS web server will be using.
// Method of computing fingerprint is the following:
// fingerprint = SHA256 ( DER certificate )
// You can see example implementation in HttpServerImpl::GenerateX509()
// in libweave/examples/provider/
// Implementation of AddHttpRequestHandler(...) method should add path
// to the list of the exposed entry points for the webserver and store
// path and callback pair somewhere. Once webserver receives an HTTP request,
// it should check if there is a libweave-registered handler corresponding to
// the path in the request. If there is one, implementation should invoke
// the callback associated with this path. If there is no callback associated
// with request path, webserver should return HTTP status code 404.
// For example, let's say local IP is "" and libweave called
// AddHttpRequestHandler("/privet/info", InfoHandlerCallback);
// If webserver receives "" request, HttpServer
// implementation must invoke InfoHandlerCallback.
// If webserver receives "" request, it must
// return HTTP status code 404 response.
// As everywhere else, invoking callbacks have some limitations:
// - callback should not be called before AddHttpRequestHandler() returns
// - callback should be called on the same thread
// Once HttpServer implementation invokes a registered callback, it should
// provide the Request interface implementation to access a request data.
// Implementation of GetPath() method should return path of the HTTP
// request. For example, "/privet/info".
// Implementation of the GetFirstHeader(...) method should return the first
// header in the request matching name parameter of this method.
// For example, GetFirstHeader("Content-Length") may return "3495".
// Implementation of GetData() method should return full request data
// in a binary format wrapped into std::string object.
// Implementation of the SendReply(...) method should send request response
// message with specified parameters:
// status_code - standard HTTP status code, for example 200 to indicate
// successful response.
// data - binary data of the response body wrapped into std::string object.
// mime_type - MIME type of the response, that should be transferred into
// "Content-Type" HTTP header.
// Implementation of the SendReply(...) method may also add other standard
// HTTP headers, like "Content-Length" or "Transfer-Encoding" depending on
// capabilities of the server and client which made this request.
// In case a device has multiple networking interfaces, the device developer
// needs to make a decision where local APIs (Privet) are necessary and where
// they are not needed. For example, it may not make sense to expose local
// APIs on any external-facing network interface (cellular or WAN).
// In some cases, there might be more then one network interface where local
// APIs makes sense. For example, a device may have both WiFi and Ethernet
// connections. In such case, webserver should start on both interfaces
// simultaneously, and allow requests from both interfaces to be handled by
// libweave.
// From libweave perspective, it always looks like there is only one network
// interface. It is the job of HttpServer implementation to hide network
// complexity from libweave and to bring webserver up on the same port on all
// interfaces.
class HttpServer {
class Request {
virtual ~Request() = default;
virtual std::string GetPath() const = 0;
virtual std::string GetFirstHeader(const std::string& name) const = 0;
virtual std::string GetData() = 0;
virtual void SendReply(int status_code,
const std::string& data,
const std::string& mime_type) = 0;
// Callback type for AddRequestHandler.
using RequestHandlerCallback =
base::Callback<void(std::unique_ptr<Request> request)>;
// Adds callback called on new http/https requests with the given path.
virtual void AddHttpRequestHandler(
const std::string& path,
const RequestHandlerCallback& callback) = 0;
virtual void AddHttpsRequestHandler(
const std::string& path,
const RequestHandlerCallback& callback) = 0;
virtual uint16_t GetHttpPort() const = 0;
virtual uint16_t GetHttpsPort() const = 0;
virtual std::vector<uint8_t> GetHttpsCertificateFingerprint() const = 0;
// Specifies request timeout, after which the web server automatically aborts
// requests. Should return base::TimeDelta::Max() if there is no timeout.
virtual base::TimeDelta GetRequestTimeout() const = 0;
virtual ~HttpServer() = default;
} // namespace provider
} // namespace weave