diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp | 189 |
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 |