1 //===-- llvm/Debuginfod/HTTPServer.cpp - HTTP server library -----*- C++-*-===//
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
7 //===----------------------------------------------------------------------===//
11 /// This file defines the methods of the HTTPServer class and the streamFile
14 //===----------------------------------------------------------------------===//
16 #include "llvm/Debuginfod/HTTPServer.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/Errc.h"
20 #include "llvm/Support/Error.h"
21 #include "llvm/Support/FileSystem.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/Regex.h"
25 #ifdef LLVM_ENABLE_HTTPLIB
31 bool llvm::streamFile(HTTPServerRequest
&Request
, StringRef FilePath
) {
32 Expected
<sys::fs::file_t
> FDOrErr
= sys::fs::openNativeFileForRead(FilePath
);
33 if (Error Err
= FDOrErr
.takeError()) {
34 consumeError(std::move(Err
));
35 Request
.setResponse({404u, "text/plain", "Could not open file to read.\n"});
38 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> MBOrErr
=
39 MemoryBuffer::getOpenFile(*FDOrErr
, FilePath
,
41 /*RequiresNullTerminator=*/false);
42 sys::fs::closeFile(*FDOrErr
);
43 if (Error Err
= errorCodeToError(MBOrErr
.getError())) {
44 consumeError(std::move(Err
));
45 Request
.setResponse({404u, "text/plain", "Could not memory-map file.\n"});
48 // Lambdas are copied on conversion to to std::function, preventing use of
50 MemoryBuffer
*MB
= MBOrErr
->release();
51 Request
.setResponse({200u, "application/octet-stream", MB
->getBufferSize(),
52 [=](size_t Offset
, size_t Length
) -> StringRef
{
53 return MB
->getBuffer().substr(Offset
, Length
);
55 [=](bool Success
) { delete MB
; }});
59 #ifdef LLVM_ENABLE_HTTPLIB
61 bool HTTPServer::isAvailable() { return true; }
63 HTTPServer::HTTPServer() { Server
= std::make_unique
<httplib::Server
>(); }
65 HTTPServer::~HTTPServer() { stop(); }
67 static void expandUrlPathMatches(const std::smatch
&Matches
,
68 HTTPServerRequest
&Request
) {
69 bool UrlPathSet
= false;
70 for (const auto &it
: Matches
) {
72 Request
.UrlPathMatches
.push_back(it
);
80 HTTPServerRequest::HTTPServerRequest(const httplib::Request
&HTTPLibRequest
,
81 httplib::Response
&HTTPLibResponse
)
82 : HTTPLibResponse(HTTPLibResponse
) {
83 expandUrlPathMatches(HTTPLibRequest
.matches
, *this);
86 void HTTPServerRequest::setResponse(HTTPResponse Response
) {
87 HTTPLibResponse
.set_content(Response
.Body
.begin(), Response
.Body
.size(),
88 Response
.ContentType
);
89 HTTPLibResponse
.status
= Response
.Code
;
92 void HTTPServerRequest::setResponse(StreamingHTTPResponse Response
) {
93 HTTPLibResponse
.set_content_provider(
94 Response
.ContentLength
, Response
.ContentType
,
95 [=](size_t Offset
, size_t Length
, httplib::DataSink
&Sink
) {
96 if (Offset
< Response
.ContentLength
) {
97 StringRef Chunk
= Response
.Provider(Offset
, Length
);
98 Sink
.write(Chunk
.begin(), Chunk
.size());
102 [=](bool Success
) { Response
.CompletionHandler(Success
); });
104 HTTPLibResponse
.status
= Response
.Code
;
107 Error
HTTPServer::get(StringRef UrlPathPattern
, HTTPRequestHandler Handler
) {
108 std::string ErrorMessage
;
109 if (!Regex(UrlPathPattern
).isValid(ErrorMessage
))
110 return createStringError(errc::argument_out_of_domain
, ErrorMessage
);
111 Server
->Get(std::string(UrlPathPattern
),
112 [Handler
](const httplib::Request
&HTTPLibRequest
,
113 httplib::Response
&HTTPLibResponse
) {
114 HTTPServerRequest
Request(HTTPLibRequest
, HTTPLibResponse
);
117 return Error::success();
120 Error
HTTPServer::bind(unsigned ListenPort
, const char *HostInterface
) {
121 if (!Server
->bind_to_port(HostInterface
, ListenPort
))
122 return createStringError(errc::io_error
,
123 "Could not assign requested address.");
125 return Error::success();
128 Expected
<unsigned> HTTPServer::bind(const char *HostInterface
) {
129 int ListenPort
= Server
->bind_to_any_port(HostInterface
);
131 return createStringError(errc::io_error
,
132 "Could not assign any port on requested address.");
133 return Port
= ListenPort
;
136 Error
HTTPServer::listen() {
138 return createStringError(errc::io_error
,
139 "Cannot listen without first binding to a port.");
140 if (!Server
->listen_after_bind())
141 return createStringError(
143 "An unknown error occurred when cpp-httplib attempted to listen.");
144 return Error::success();
147 void HTTPServer::stop() {
154 // TODO: Implement barebones standalone HTTP server implementation.
155 bool HTTPServer::isAvailable() { return false; }
157 HTTPServer::HTTPServer() = default;
159 HTTPServer::~HTTPServer() = default;
161 void HTTPServerRequest::setResponse(HTTPResponse Response
) {
162 llvm_unreachable("No HTTP server implementation available");
165 void HTTPServerRequest::setResponse(StreamingHTTPResponse Response
) {
166 llvm_unreachable("No HTTP server implementation available");
169 Error
HTTPServer::get(StringRef UrlPathPattern
, HTTPRequestHandler Handler
) {
170 llvm_unreachable("No HTTP server implementation available");
173 Error
HTTPServer::bind(unsigned ListenPort
, const char *HostInterface
) {
174 llvm_unreachable("No HTTP server implementation available");
177 Expected
<unsigned> HTTPServer::bind(const char *HostInterface
) {
178 llvm_unreachable("No HTTP server implementation available");
181 Error
HTTPServer::listen() {
182 llvm_unreachable("No HTTP server implementation available");
185 void HTTPServer::stop() {
186 llvm_unreachable("No HTTP server implementation available");
189 #endif // LLVM_ENABLE_HTTPLIB