xref: /freebsd-src/contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp (revision 753f127f3ace09432b2baeffd71a308760641a62)
1*753f127fSDimitry Andric //===-- llvm/Debuginfod/HTTPServer.cpp - HTTP server library -----*- C++-*-===//
2*753f127fSDimitry Andric //
3*753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*753f127fSDimitry Andric //
7*753f127fSDimitry Andric //===----------------------------------------------------------------------===//
8*753f127fSDimitry Andric ///
9*753f127fSDimitry Andric /// \file
10*753f127fSDimitry Andric ///
11*753f127fSDimitry Andric /// This file defines the methods of the HTTPServer class and the streamFile
12*753f127fSDimitry Andric /// function.
13*753f127fSDimitry Andric ///
14*753f127fSDimitry Andric //===----------------------------------------------------------------------===//
15*753f127fSDimitry Andric 
16*753f127fSDimitry Andric #include "llvm/Debuginfod/HTTPServer.h"
17*753f127fSDimitry Andric #include "llvm/ADT/StringExtras.h"
18*753f127fSDimitry Andric #include "llvm/ADT/StringRef.h"
19*753f127fSDimitry Andric #include "llvm/Support/Errc.h"
20*753f127fSDimitry Andric #include "llvm/Support/Error.h"
21*753f127fSDimitry Andric #include "llvm/Support/FileSystem.h"
22*753f127fSDimitry Andric #include "llvm/Support/MemoryBuffer.h"
23*753f127fSDimitry Andric #include "llvm/Support/Regex.h"
24*753f127fSDimitry Andric 
25*753f127fSDimitry Andric #ifdef LLVM_ENABLE_HTTPLIB
26*753f127fSDimitry Andric #include "httplib.h"
27*753f127fSDimitry Andric #endif
28*753f127fSDimitry Andric 
29*753f127fSDimitry Andric using namespace llvm;
30*753f127fSDimitry Andric 
31*753f127fSDimitry Andric bool llvm::streamFile(HTTPServerRequest &Request, StringRef FilePath) {
32*753f127fSDimitry Andric   Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead(FilePath);
33*753f127fSDimitry Andric   if (Error Err = FDOrErr.takeError()) {
34*753f127fSDimitry Andric     consumeError(std::move(Err));
35*753f127fSDimitry Andric     Request.setResponse({404u, "text/plain", "Could not open file to read.\n"});
36*753f127fSDimitry Andric     return false;
37*753f127fSDimitry Andric   }
38*753f127fSDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
39*753f127fSDimitry Andric       MemoryBuffer::getOpenFile(*FDOrErr, FilePath,
40*753f127fSDimitry Andric                                 /*FileSize=*/-1,
41*753f127fSDimitry Andric                                 /*RequiresNullTerminator=*/false);
42*753f127fSDimitry Andric   sys::fs::closeFile(*FDOrErr);
43*753f127fSDimitry Andric   if (Error Err = errorCodeToError(MBOrErr.getError())) {
44*753f127fSDimitry Andric     consumeError(std::move(Err));
45*753f127fSDimitry Andric     Request.setResponse({404u, "text/plain", "Could not memory-map file.\n"});
46*753f127fSDimitry Andric     return false;
47*753f127fSDimitry Andric   }
48*753f127fSDimitry Andric   // Lambdas are copied on conversion to to std::function, preventing use of
49*753f127fSDimitry Andric   // smart pointers.
50*753f127fSDimitry Andric   MemoryBuffer *MB = MBOrErr->release();
51*753f127fSDimitry Andric   Request.setResponse({200u, "application/octet-stream", MB->getBufferSize(),
52*753f127fSDimitry Andric                        [=](size_t Offset, size_t Length) -> StringRef {
53*753f127fSDimitry Andric                          return MB->getBuffer().substr(Offset, Length);
54*753f127fSDimitry Andric                        },
55*753f127fSDimitry Andric                        [=](bool Success) { delete MB; }});
56*753f127fSDimitry Andric   return true;
57*753f127fSDimitry Andric }
58*753f127fSDimitry Andric 
59*753f127fSDimitry Andric #ifdef LLVM_ENABLE_HTTPLIB
60*753f127fSDimitry Andric 
61*753f127fSDimitry Andric bool HTTPServer::isAvailable() { return true; }
62*753f127fSDimitry Andric 
63*753f127fSDimitry Andric HTTPServer::HTTPServer() { Server = std::make_unique<httplib::Server>(); }
64*753f127fSDimitry Andric 
65*753f127fSDimitry Andric HTTPServer::~HTTPServer() { stop(); }
66*753f127fSDimitry Andric 
67*753f127fSDimitry Andric static void expandUrlPathMatches(const std::smatch &Matches,
68*753f127fSDimitry Andric                                  HTTPServerRequest &Request) {
69*753f127fSDimitry Andric   bool UrlPathSet = false;
70*753f127fSDimitry Andric   for (const auto &it : Matches) {
71*753f127fSDimitry Andric     if (UrlPathSet)
72*753f127fSDimitry Andric       Request.UrlPathMatches.push_back(it);
73*753f127fSDimitry Andric     else {
74*753f127fSDimitry Andric       Request.UrlPath = it;
75*753f127fSDimitry Andric       UrlPathSet = true;
76*753f127fSDimitry Andric     }
77*753f127fSDimitry Andric   }
78*753f127fSDimitry Andric }
79*753f127fSDimitry Andric 
80*753f127fSDimitry Andric HTTPServerRequest::HTTPServerRequest(const httplib::Request &HTTPLibRequest,
81*753f127fSDimitry Andric                                      httplib::Response &HTTPLibResponse)
82*753f127fSDimitry Andric     : HTTPLibResponse(HTTPLibResponse) {
83*753f127fSDimitry Andric   expandUrlPathMatches(HTTPLibRequest.matches, *this);
84*753f127fSDimitry Andric }
85*753f127fSDimitry Andric 
86*753f127fSDimitry Andric void HTTPServerRequest::setResponse(HTTPResponse Response) {
87*753f127fSDimitry Andric   HTTPLibResponse.set_content(Response.Body.begin(), Response.Body.size(),
88*753f127fSDimitry Andric                               Response.ContentType);
89*753f127fSDimitry Andric   HTTPLibResponse.status = Response.Code;
90*753f127fSDimitry Andric }
91*753f127fSDimitry Andric 
92*753f127fSDimitry Andric void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) {
93*753f127fSDimitry Andric   HTTPLibResponse.set_content_provider(
94*753f127fSDimitry Andric       Response.ContentLength, Response.ContentType,
95*753f127fSDimitry Andric       [=](size_t Offset, size_t Length, httplib::DataSink &Sink) {
96*753f127fSDimitry Andric         if (Offset < Response.ContentLength) {
97*753f127fSDimitry Andric           StringRef Chunk = Response.Provider(Offset, Length);
98*753f127fSDimitry Andric           Sink.write(Chunk.begin(), Chunk.size());
99*753f127fSDimitry Andric         }
100*753f127fSDimitry Andric         return true;
101*753f127fSDimitry Andric       },
102*753f127fSDimitry Andric       [=](bool Success) { Response.CompletionHandler(Success); });
103*753f127fSDimitry Andric 
104*753f127fSDimitry Andric   HTTPLibResponse.status = Response.Code;
105*753f127fSDimitry Andric }
106*753f127fSDimitry Andric 
107*753f127fSDimitry Andric Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) {
108*753f127fSDimitry Andric   std::string ErrorMessage;
109*753f127fSDimitry Andric   if (!Regex(UrlPathPattern).isValid(ErrorMessage))
110*753f127fSDimitry Andric     return createStringError(errc::argument_out_of_domain, ErrorMessage);
111*753f127fSDimitry Andric   Server->Get(std::string(UrlPathPattern),
112*753f127fSDimitry Andric               [Handler](const httplib::Request &HTTPLibRequest,
113*753f127fSDimitry Andric                         httplib::Response &HTTPLibResponse) {
114*753f127fSDimitry Andric                 HTTPServerRequest Request(HTTPLibRequest, HTTPLibResponse);
115*753f127fSDimitry Andric                 Handler(Request);
116*753f127fSDimitry Andric               });
117*753f127fSDimitry Andric   return Error::success();
118*753f127fSDimitry Andric }
119*753f127fSDimitry Andric 
120*753f127fSDimitry Andric Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) {
121*753f127fSDimitry Andric   if (!Server->bind_to_port(HostInterface, ListenPort))
122*753f127fSDimitry Andric     return createStringError(errc::io_error,
123*753f127fSDimitry Andric                              "Could not assign requested address.");
124*753f127fSDimitry Andric   Port = ListenPort;
125*753f127fSDimitry Andric   return Error::success();
126*753f127fSDimitry Andric }
127*753f127fSDimitry Andric 
128*753f127fSDimitry Andric Expected<unsigned> HTTPServer::bind(const char *HostInterface) {
129*753f127fSDimitry Andric   int ListenPort = Server->bind_to_any_port(HostInterface);
130*753f127fSDimitry Andric   if (ListenPort < 0)
131*753f127fSDimitry Andric     return createStringError(errc::io_error,
132*753f127fSDimitry Andric                              "Could not assign any port on requested address.");
133*753f127fSDimitry Andric   return Port = ListenPort;
134*753f127fSDimitry Andric }
135*753f127fSDimitry Andric 
136*753f127fSDimitry Andric Error HTTPServer::listen() {
137*753f127fSDimitry Andric   if (!Port)
138*753f127fSDimitry Andric     return createStringError(errc::io_error,
139*753f127fSDimitry Andric                              "Cannot listen without first binding to a port.");
140*753f127fSDimitry Andric   if (!Server->listen_after_bind())
141*753f127fSDimitry Andric     return createStringError(
142*753f127fSDimitry Andric         errc::io_error,
143*753f127fSDimitry Andric         "An unknown error occurred when cpp-httplib attempted to listen.");
144*753f127fSDimitry Andric   return Error::success();
145*753f127fSDimitry Andric }
146*753f127fSDimitry Andric 
147*753f127fSDimitry Andric void HTTPServer::stop() {
148*753f127fSDimitry Andric   Server->stop();
149*753f127fSDimitry Andric   Port = 0;
150*753f127fSDimitry Andric }
151*753f127fSDimitry Andric 
152*753f127fSDimitry Andric #else
153*753f127fSDimitry Andric 
154*753f127fSDimitry Andric // TODO: Implement barebones standalone HTTP server implementation.
155*753f127fSDimitry Andric bool HTTPServer::isAvailable() { return false; }
156*753f127fSDimitry Andric 
157*753f127fSDimitry Andric HTTPServer::HTTPServer() = default;
158*753f127fSDimitry Andric 
159*753f127fSDimitry Andric HTTPServer::~HTTPServer() = default;
160*753f127fSDimitry Andric 
161*753f127fSDimitry Andric void HTTPServerRequest::setResponse(HTTPResponse Response) {
162*753f127fSDimitry Andric   llvm_unreachable("No HTTP server implementation available");
163*753f127fSDimitry Andric }
164*753f127fSDimitry Andric 
165*753f127fSDimitry Andric void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) {
166*753f127fSDimitry Andric   llvm_unreachable("No HTTP server implementation available");
167*753f127fSDimitry Andric }
168*753f127fSDimitry Andric 
169*753f127fSDimitry Andric Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) {
170*753f127fSDimitry Andric   llvm_unreachable("No HTTP server implementation available");
171*753f127fSDimitry Andric }
172*753f127fSDimitry Andric 
173*753f127fSDimitry Andric Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) {
174*753f127fSDimitry Andric   llvm_unreachable("No HTTP server implementation available");
175*753f127fSDimitry Andric }
176*753f127fSDimitry Andric 
177*753f127fSDimitry Andric Expected<unsigned> HTTPServer::bind(const char *HostInterface) {
178*753f127fSDimitry Andric   llvm_unreachable("No HTTP server implementation available");
179*753f127fSDimitry Andric }
180*753f127fSDimitry Andric 
181*753f127fSDimitry Andric Error HTTPServer::listen() {
182*753f127fSDimitry Andric   llvm_unreachable("No HTTP server implementation available");
183*753f127fSDimitry Andric }
184*753f127fSDimitry Andric 
185*753f127fSDimitry Andric void HTTPServer::stop() {
186*753f127fSDimitry Andric   llvm_unreachable("No HTTP server implementation available");
187*753f127fSDimitry Andric }
188*753f127fSDimitry Andric 
189*753f127fSDimitry Andric #endif // LLVM_ENABLE_HTTPLIB
190