Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp
35233 views
1
//===-- llvm/Debuginfod/HTTPServer.cpp - 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
///
11
/// This file defines the methods of the HTTPServer class and the streamFile
12
/// function.
13
///
14
//===----------------------------------------------------------------------===//
15
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"
24
25
#ifdef LLVM_ENABLE_HTTPLIB
26
#include "httplib.h"
27
#endif
28
29
using namespace llvm;
30
31
char HTTPServerError::ID = 0;
32
33
HTTPServerError::HTTPServerError(const Twine &Msg) : Msg(Msg.str()) {}
34
35
void HTTPServerError::log(raw_ostream &OS) const { OS << Msg; }
36
37
bool llvm::streamFile(HTTPServerRequest &Request, StringRef FilePath) {
38
Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead(FilePath);
39
if (Error Err = FDOrErr.takeError()) {
40
consumeError(std::move(Err));
41
Request.setResponse({404u, "text/plain", "Could not open file to read.\n"});
42
return false;
43
}
44
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
45
MemoryBuffer::getOpenFile(*FDOrErr, FilePath,
46
/*FileSize=*/-1,
47
/*RequiresNullTerminator=*/false);
48
sys::fs::closeFile(*FDOrErr);
49
if (Error Err = errorCodeToError(MBOrErr.getError())) {
50
consumeError(std::move(Err));
51
Request.setResponse({404u, "text/plain", "Could not memory-map file.\n"});
52
return false;
53
}
54
// Lambdas are copied on conversion to std::function, preventing use of
55
// smart pointers.
56
MemoryBuffer *MB = MBOrErr->release();
57
Request.setResponse({200u, "application/octet-stream", MB->getBufferSize(),
58
[=](size_t Offset, size_t Length) -> StringRef {
59
return MB->getBuffer().substr(Offset, Length);
60
},
61
[=](bool Success) { delete MB; }});
62
return true;
63
}
64
65
#ifdef LLVM_ENABLE_HTTPLIB
66
67
bool HTTPServer::isAvailable() { return true; }
68
69
HTTPServer::HTTPServer() { Server = std::make_unique<httplib::Server>(); }
70
71
HTTPServer::~HTTPServer() { stop(); }
72
73
static void expandUrlPathMatches(const std::smatch &Matches,
74
HTTPServerRequest &Request) {
75
bool UrlPathSet = false;
76
for (const auto &it : Matches) {
77
if (UrlPathSet)
78
Request.UrlPathMatches.push_back(it);
79
else {
80
Request.UrlPath = it;
81
UrlPathSet = true;
82
}
83
}
84
}
85
86
HTTPServerRequest::HTTPServerRequest(const httplib::Request &HTTPLibRequest,
87
httplib::Response &HTTPLibResponse)
88
: HTTPLibResponse(HTTPLibResponse) {
89
expandUrlPathMatches(HTTPLibRequest.matches, *this);
90
}
91
92
void HTTPServerRequest::setResponse(HTTPResponse Response) {
93
HTTPLibResponse.set_content(Response.Body.begin(), Response.Body.size(),
94
Response.ContentType);
95
HTTPLibResponse.status = Response.Code;
96
}
97
98
void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) {
99
HTTPLibResponse.set_content_provider(
100
Response.ContentLength, Response.ContentType,
101
[=](size_t Offset, size_t Length, httplib::DataSink &Sink) {
102
if (Offset < Response.ContentLength) {
103
StringRef Chunk = Response.Provider(Offset, Length);
104
Sink.write(Chunk.begin(), Chunk.size());
105
}
106
return true;
107
},
108
[=](bool Success) { Response.CompletionHandler(Success); });
109
110
HTTPLibResponse.status = Response.Code;
111
}
112
113
Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) {
114
std::string ErrorMessage;
115
if (!Regex(UrlPathPattern).isValid(ErrorMessage))
116
return createStringError(errc::argument_out_of_domain, ErrorMessage);
117
Server->Get(std::string(UrlPathPattern),
118
[Handler](const httplib::Request &HTTPLibRequest,
119
httplib::Response &HTTPLibResponse) {
120
HTTPServerRequest Request(HTTPLibRequest, HTTPLibResponse);
121
Handler(Request);
122
});
123
return Error::success();
124
}
125
126
Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) {
127
if (!Server->bind_to_port(HostInterface, ListenPort))
128
return createStringError(errc::io_error,
129
"Could not assign requested address.");
130
Port = ListenPort;
131
return Error::success();
132
}
133
134
Expected<unsigned> HTTPServer::bind(const char *HostInterface) {
135
int ListenPort = Server->bind_to_any_port(HostInterface);
136
if (ListenPort < 0)
137
return createStringError(errc::io_error,
138
"Could not assign any port on requested address.");
139
return Port = ListenPort;
140
}
141
142
Error HTTPServer::listen() {
143
if (!Port)
144
return createStringError(errc::io_error,
145
"Cannot listen without first binding to a port.");
146
if (!Server->listen_after_bind())
147
return createStringError(
148
errc::io_error,
149
"An unknown error occurred when cpp-httplib attempted to listen.");
150
return Error::success();
151
}
152
153
void HTTPServer::stop() {
154
Server->stop();
155
Port = 0;
156
}
157
158
#else
159
160
// TODO: Implement barebones standalone HTTP server implementation.
161
bool HTTPServer::isAvailable() { return false; }
162
163
HTTPServer::HTTPServer() = default;
164
165
HTTPServer::~HTTPServer() = default;
166
167
void HTTPServerRequest::setResponse(HTTPResponse Response) {
168
llvm_unreachable("no httplib");
169
}
170
171
void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) {
172
llvm_unreachable("no httplib");
173
}
174
175
Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) {
176
// TODO(https://github.com/llvm/llvm-project/issues/63873) We would ideally
177
// return an error as well but that's going to require refactoring of error
178
// handling in DebuginfodServer.
179
return Error::success();
180
}
181
182
Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) {
183
return make_error<HTTPServerError>("no httplib");
184
}
185
186
Expected<unsigned> HTTPServer::bind(const char *HostInterface) {
187
return make_error<HTTPServerError>("no httplib");
188
}
189
190
Error HTTPServer::listen() {
191
return make_error<HTTPServerError>("no httplib");
192
}
193
194
void HTTPServer::stop() {
195
llvm_unreachable("no httplib");
196
}
197
198
#endif // LLVM_ENABLE_HTTPLIB
199
200