1 //===-- llvm/Debuginfod/HTTPServer.h - HTTP server library ------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file contains the declarations of the HTTPServer and HTTPServerRequest
11 /// classes, the HTTPResponse, and StreamingHTTPResponse structs, and the
12 /// streamFile function.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef LLVM_DEBUGINFOD_HTTPSERVER_H
17 #define LLVM_DEBUGINFOD_HTTPSERVER_H
18 
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Support/Error.h"
21 
22 #ifdef LLVM_ENABLE_HTTPLIB
23 // forward declarations
24 namespace httplib {
25 class Request;
26 class Response;
27 class Server;
28 } // namespace httplib
29 #endif
30 
31 namespace llvm {
32 
33 struct HTTPResponse;
34 struct StreamingHTTPResponse;
35 class HTTPServer;
36 
37 class HTTPServerError : public ErrorInfo<HTTPServerError, ECError> {
38 public:
39   static char ID;
40   HTTPServerError(const Twine &Msg);
41   void log(raw_ostream &OS) const override;
42 
43 private:
44   std::string Msg;
45 };
46 
47 class HTTPServerRequest {
48   friend HTTPServer;
49 
50 #ifdef LLVM_ENABLE_HTTPLIB
51 private:
52   HTTPServerRequest(const httplib::Request &HTTPLibRequest,
53                     httplib::Response &HTTPLibResponse);
54   httplib::Response &HTTPLibResponse;
55 #endif
56 
57 public:
58   std::string UrlPath;
59   /// The elements correspond to match groups in the url path matching regex.
60   SmallVector<std::string, 1> UrlPathMatches;
61 
62   // TODO bring in HTTP headers
63 
64   void setResponse(StreamingHTTPResponse Response);
65   void setResponse(HTTPResponse Response);
66 };
67 
68 struct HTTPResponse {
69   unsigned Code;
70   const char *ContentType;
71   StringRef Body;
72 };
73 
74 typedef std::function<void(HTTPServerRequest &)> HTTPRequestHandler;
75 
76 /// An HTTPContentProvider is called by the HTTPServer to obtain chunks of the
77 /// streaming response body. The returned chunk should be located at Offset
78 /// bytes and have Length bytes.
79 typedef std::function<StringRef(size_t /*Offset*/, size_t /*Length*/)>
80     HTTPContentProvider;
81 
82 /// Wraps the content provider with HTTP Status code and headers.
83 struct StreamingHTTPResponse {
84   unsigned Code;
85   const char *ContentType;
86   size_t ContentLength;
87   HTTPContentProvider Provider;
88   /// Called after the response transfer is complete with the success value of
89   /// the transfer.
90   std::function<void(bool)> CompletionHandler = [](bool Success) {};
91 };
92 
93 /// Sets the response to stream the file at FilePath, if available, and
94 /// otherwise an HTTP 404 error response.
95 bool streamFile(HTTPServerRequest &Request, StringRef FilePath);
96 
97 /// An HTTP server which can listen on a single TCP/IP port for HTTP
98 /// requests and delgate them to the appropriate registered handler.
99 class HTTPServer {
100 #ifdef LLVM_ENABLE_HTTPLIB
101   std::unique_ptr<httplib::Server> Server;
102   unsigned Port = 0;
103 #endif
104 public:
105   HTTPServer();
106   ~HTTPServer();
107 
108   /// Returns true only if LLVM has been compiled with a working HTTPServer.
109   static bool isAvailable();
110 
111   /// Registers a URL pattern routing rule. When the server is listening, each
112   /// request is dispatched to the first registered handler whose UrlPathPattern
113   /// matches the UrlPath.
114   Error get(StringRef UrlPathPattern, HTTPRequestHandler Handler);
115 
116   /// Attempts to assign the requested port and interface, returning an Error
117   /// upon failure.
118   Error bind(unsigned Port, const char *HostInterface = "0.0.0.0");
119 
120   /// Attempts to assign any available port and interface, returning either the
121   /// port number or an Error upon failure.
122   Expected<unsigned> bind(const char *HostInterface = "0.0.0.0");
123 
124   /// Attempts to listen for requests on the bound port. Returns an Error if
125   /// called before binding a port.
126   Error listen();
127 
128   /// If the server is listening, stop and unbind the socket.
129   void stop();
130 };
131 } // end namespace llvm
132 
133 #endif // LLVM_DEBUGINFOD_HTTPSERVER_H
134