aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp189
1 files changed, 189 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp b/contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp
new file mode 100644
index 000000000000..2ea923d5a734
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp
@@ -0,0 +1,189 @@
+//===-- llvm/Debuginfod/HTTPServer.cpp - HTTP server library -----*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// This file defines the methods of the HTTPServer class and the streamFile
+/// function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Debuginfod/HTTPServer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Regex.h"
+
+#ifdef LLVM_ENABLE_HTTPLIB
+#include "httplib.h"
+#endif
+
+using namespace llvm;
+
+bool llvm::streamFile(HTTPServerRequest &Request, StringRef FilePath) {
+ Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead(FilePath);
+ if (Error Err = FDOrErr.takeError()) {
+ consumeError(std::move(Err));
+ Request.setResponse({404u, "text/plain", "Could not open file to read.\n"});
+ return false;
+ }
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
+ MemoryBuffer::getOpenFile(*FDOrErr, FilePath,
+ /*FileSize=*/-1,
+ /*RequiresNullTerminator=*/false);
+ sys::fs::closeFile(*FDOrErr);
+ if (Error Err = errorCodeToError(MBOrErr.getError())) {
+ consumeError(std::move(Err));
+ Request.setResponse({404u, "text/plain", "Could not memory-map file.\n"});
+ return false;
+ }
+ // Lambdas are copied on conversion to to std::function, preventing use of
+ // smart pointers.
+ MemoryBuffer *MB = MBOrErr->release();
+ Request.setResponse({200u, "application/octet-stream", MB->getBufferSize(),
+ [=](size_t Offset, size_t Length) -> StringRef {
+ return MB->getBuffer().substr(Offset, Length);
+ },
+ [=](bool Success) { delete MB; }});
+ return true;
+}
+
+#ifdef LLVM_ENABLE_HTTPLIB
+
+bool HTTPServer::isAvailable() { return true; }
+
+HTTPServer::HTTPServer() { Server = std::make_unique<httplib::Server>(); }
+
+HTTPServer::~HTTPServer() { stop(); }
+
+static void expandUrlPathMatches(const std::smatch &Matches,
+ HTTPServerRequest &Request) {
+ bool UrlPathSet = false;
+ for (const auto &it : Matches) {
+ if (UrlPathSet)
+ Request.UrlPathMatches.push_back(it);
+ else {
+ Request.UrlPath = it;
+ UrlPathSet = true;
+ }
+ }
+}
+
+HTTPServerRequest::HTTPServerRequest(const httplib::Request &HTTPLibRequest,
+ httplib::Response &HTTPLibResponse)
+ : HTTPLibResponse(HTTPLibResponse) {
+ expandUrlPathMatches(HTTPLibRequest.matches, *this);
+}
+
+void HTTPServerRequest::setResponse(HTTPResponse Response) {
+ HTTPLibResponse.set_content(Response.Body.begin(), Response.Body.size(),
+ Response.ContentType);
+ HTTPLibResponse.status = Response.Code;
+}
+
+void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) {
+ HTTPLibResponse.set_content_provider(
+ Response.ContentLength, Response.ContentType,
+ [=](size_t Offset, size_t Length, httplib::DataSink &Sink) {
+ if (Offset < Response.ContentLength) {
+ StringRef Chunk = Response.Provider(Offset, Length);
+ Sink.write(Chunk.begin(), Chunk.size());
+ }
+ return true;
+ },
+ [=](bool Success) { Response.CompletionHandler(Success); });
+
+ HTTPLibResponse.status = Response.Code;
+}
+
+Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) {
+ std::string ErrorMessage;
+ if (!Regex(UrlPathPattern).isValid(ErrorMessage))
+ return createStringError(errc::argument_out_of_domain, ErrorMessage);
+ Server->Get(std::string(UrlPathPattern),
+ [Handler](const httplib::Request &HTTPLibRequest,
+ httplib::Response &HTTPLibResponse) {
+ HTTPServerRequest Request(HTTPLibRequest, HTTPLibResponse);
+ Handler(Request);
+ });
+ return Error::success();
+}
+
+Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) {
+ if (!Server->bind_to_port(HostInterface, ListenPort))
+ return createStringError(errc::io_error,
+ "Could not assign requested address.");
+ Port = ListenPort;
+ return Error::success();
+}
+
+Expected<unsigned> HTTPServer::bind(const char *HostInterface) {
+ int ListenPort = Server->bind_to_any_port(HostInterface);
+ if (ListenPort < 0)
+ return createStringError(errc::io_error,
+ "Could not assign any port on requested address.");
+ return Port = ListenPort;
+}
+
+Error HTTPServer::listen() {
+ if (!Port)
+ return createStringError(errc::io_error,
+ "Cannot listen without first binding to a port.");
+ if (!Server->listen_after_bind())
+ return createStringError(
+ errc::io_error,
+ "An unknown error occurred when cpp-httplib attempted to listen.");
+ return Error::success();
+}
+
+void HTTPServer::stop() {
+ Server->stop();
+ Port = 0;
+}
+
+#else
+
+// TODO: Implement barebones standalone HTTP server implementation.
+bool HTTPServer::isAvailable() { return false; }
+
+HTTPServer::HTTPServer() = default;
+
+HTTPServer::~HTTPServer() = default;
+
+void HTTPServerRequest::setResponse(HTTPResponse Response) {
+ llvm_unreachable("No HTTP server implementation available");
+}
+
+void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) {
+ llvm_unreachable("No HTTP server implementation available");
+}
+
+Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) {
+ llvm_unreachable("No HTTP server implementation available");
+}
+
+Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) {
+ llvm_unreachable("No HTTP server implementation available");
+}
+
+Expected<unsigned> HTTPServer::bind(const char *HostInterface) {
+ llvm_unreachable("No HTTP server implementation available");
+}
+
+Error HTTPServer::listen() {
+ llvm_unreachable("No HTTP server implementation available");
+}
+
+void HTTPServer::stop() {
+ llvm_unreachable("No HTTP server implementation available");
+}
+
+#endif // LLVM_ENABLE_HTTPLIB