1 // Copyright 2015 The Weave 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 #ifndef LIBWEAVE_INCLUDE_WEAVE_PROVIDER_HTTP_SERVER_H_
6 #define LIBWEAVE_INCLUDE_WEAVE_PROVIDER_HTTP_SERVER_H_
7 
8 #include <string>
9 #include <vector>
10 
11 #include <base/callback.h>
12 #include <base/time/time.h>
13 #include <weave/stream.h>
14 
15 namespace weave {
16 namespace provider {
17 
18 // This interface should be implemented by the user of libweave and
19 // provided during device creation in Device::Create(...)
20 // libweave will use this interface to handle HTTP / HTTPS requests for Privet
21 // APIs.
22 //
23 // This interface consist of 2 parts that need to be implemented by the
24 // libweave user: HttpServer and HttpServer::Request. HttpServer provides
25 // interface to control webserver, and is used to initialize Device object.
26 // Request provides an abstraction for a specific HTTP request and may be a
27 // short-lived object.
28 //
29 // Implementation of AddHttpsRequestHandler(...) method should follow the
30 // same guidelines as implementation of AddHttpRequestHandler(...) with the
31 // only difference, it is for HTTPS connection (not HTTP).
32 //
33 // Implementation of GetHttpPort() method should return port number on
34 // which HTTP server will be listening. Normally it is port 80, but this
35 // allows implementer to choose different port if necessary and tell it to
36 // libweave.
37 //
38 // Implementation of GetHttpsPort() should follow the same guidelines as
39 // GetHttpPort(). Default HTTPS port is 443, but could be changed and
40 // communicated to libweave using this method.
41 //
42 // Implementation of GetHttpsCertificateFingerprint() method should
43 // compute fingerprint of the certificate that HTTPS web server will be using.
44 // Method of computing fingerprint is the following:
45 //   fingerprint = SHA256 ( DER certificate )
46 // You can see example implementation in HttpServerImpl::GenerateX509()
47 // in libweave/examples/provider/event_http_server.cc
48 //
49 // Implementation of AddHttpRequestHandler(...) method should add path
50 // to the list of the exposed entry points for the webserver and store
51 // path and callback pair somewhere. Once webserver receives an HTTP request,
52 // it should check if there is a libweave-registered handler corresponding to
53 // the path in the request. If there is one, implementation should invoke
54 // the callback associated with this path. If there is no callback associated
55 // with request path, webserver should return HTTP status code 404.
56 //
57 // For example, let's say local IP is "192.168.0.1" and libweave called
58 //   AddHttpRequestHandler("/privet/info", InfoHandlerCallback);
59 // If webserver receives "http://192.168.0.1/privet/info" request, HttpServer
60 // implementation must invoke InfoHandlerCallback.
61 // If webserver receives "http://192.168.0.1/privet/auth" request, it must
62 // return HTTP status code 404 response.
63 //
64 // As everywhere else, invoking callbacks have some limitations:
65 //   - callback should not be called before AddHttpRequestHandler() returns
66 //   - callback should be called on the same thread
67 //
68 // Once HttpServer implementation invokes a registered callback, it should
69 // provide the Request interface implementation to access a request data.
70 //
71 // Implementation of GetPath() method should return path of the HTTP
72 // request. For example, "/privet/info".
73 //
74 // Implementation of the GetFirstHeader(...) method should return the first
75 // header in the request matching name parameter of this method.
76 // For example, GetFirstHeader("Content-Length") may return "3495".
77 //
78 // Implementation of GetData() method should return full request data
79 // in a binary format wrapped into std::string object.
80 //
81 // Implementation of the SendReply(...) method should send request response
82 // message with specified parameters:
83 //   status_code - standard HTTP status code, for example 200 to indicate
84 //     successful response.
85 //   data - binary data of the response body wrapped into std::string object.
86 //   mime_type - MIME type of the response, that should be transferred into
87 //     "Content-Type" HTTP header.
88 // Implementation of the SendReply(...) method may also add other standard
89 // HTTP headers, like "Content-Length" or "Transfer-Encoding" depending on
90 // capabilities of the server and client which made this request.
91 //
92 // In case a device has multiple networking interfaces, the device developer
93 // needs to make a decision where local APIs (Privet) are necessary and where
94 // they are not needed. For example, it may not make sense to expose local
95 // APIs on any external-facing network interface (cellular or WAN).
96 //
97 // In some cases, there might be more then one network interface where local
98 // APIs makes sense. For example, a device may have both WiFi and Ethernet
99 // connections. In such case, webserver should start on both interfaces
100 // simultaneously, and allow requests from both interfaces to be handled by
101 // libweave.
102 //
103 // From libweave perspective, it always looks like there is only one network
104 // interface. It is the job of HttpServer implementation to hide network
105 // complexity from libweave and to bring webserver up on the same port on all
106 // interfaces.
107 
108 class HttpServer {
109  public:
110   class Request {
111    public:
~Request()112     virtual ~Request() {}
113 
114     virtual std::string GetPath() const = 0;
115     virtual std::string GetFirstHeader(const std::string& name) const = 0;
116     virtual std::string GetData() = 0;
117 
118     virtual void SendReply(int status_code,
119                            const std::string& data,
120                            const std::string& mime_type) = 0;
121   };
122 
123   // Callback type for AddRequestHandler.
124   using RequestHandlerCallback =
125       base::Callback<void(std::unique_ptr<Request> request)>;
126 
127   // Adds callback called on new http/https requests with the given path.
128   virtual void AddHttpRequestHandler(
129       const std::string& path,
130       const RequestHandlerCallback& callback) = 0;
131   virtual void AddHttpsRequestHandler(
132       const std::string& path,
133       const RequestHandlerCallback& callback) = 0;
134 
135   virtual uint16_t GetHttpPort() const = 0;
136   virtual uint16_t GetHttpsPort() const = 0;
137   virtual std::vector<uint8_t> GetHttpsCertificateFingerprint() const = 0;
138 
139   // Specifies request timeout, after which the web server automatically aborts
140   // requests. Should return base::TimeDelta::Max() if there is no timeout.
141   virtual base::TimeDelta GetRequestTimeout() const = 0;
142 
143  protected:
~HttpServer()144   virtual ~HttpServer() {}
145 };
146 
147 }  // namespace provider
148 }  // namespace weave
149 
150 #endif  // LIBWEAVE_INCLUDE_WEAVE_PROVIDER_HTTP_SERVER_H_
151