Path: blob/main/contrib/llvm-project/llvm/lib/Debuginfod/HTTPServer.cpp
35233 views
//===-- llvm/Debuginfod/HTTPServer.cpp - HTTP server library -----*- C++-*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9///10/// This file defines the methods of the HTTPServer class and the streamFile11/// function.12///13//===----------------------------------------------------------------------===//1415#include "llvm/Debuginfod/HTTPServer.h"16#include "llvm/ADT/StringExtras.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/Support/Errc.h"19#include "llvm/Support/Error.h"20#include "llvm/Support/FileSystem.h"21#include "llvm/Support/MemoryBuffer.h"22#include "llvm/Support/Regex.h"2324#ifdef LLVM_ENABLE_HTTPLIB25#include "httplib.h"26#endif2728using namespace llvm;2930char HTTPServerError::ID = 0;3132HTTPServerError::HTTPServerError(const Twine &Msg) : Msg(Msg.str()) {}3334void HTTPServerError::log(raw_ostream &OS) const { OS << Msg; }3536bool llvm::streamFile(HTTPServerRequest &Request, StringRef FilePath) {37Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead(FilePath);38if (Error Err = FDOrErr.takeError()) {39consumeError(std::move(Err));40Request.setResponse({404u, "text/plain", "Could not open file to read.\n"});41return false;42}43ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =44MemoryBuffer::getOpenFile(*FDOrErr, FilePath,45/*FileSize=*/-1,46/*RequiresNullTerminator=*/false);47sys::fs::closeFile(*FDOrErr);48if (Error Err = errorCodeToError(MBOrErr.getError())) {49consumeError(std::move(Err));50Request.setResponse({404u, "text/plain", "Could not memory-map file.\n"});51return false;52}53// Lambdas are copied on conversion to std::function, preventing use of54// smart pointers.55MemoryBuffer *MB = MBOrErr->release();56Request.setResponse({200u, "application/octet-stream", MB->getBufferSize(),57[=](size_t Offset, size_t Length) -> StringRef {58return MB->getBuffer().substr(Offset, Length);59},60[=](bool Success) { delete MB; }});61return true;62}6364#ifdef LLVM_ENABLE_HTTPLIB6566bool HTTPServer::isAvailable() { return true; }6768HTTPServer::HTTPServer() { Server = std::make_unique<httplib::Server>(); }6970HTTPServer::~HTTPServer() { stop(); }7172static void expandUrlPathMatches(const std::smatch &Matches,73HTTPServerRequest &Request) {74bool UrlPathSet = false;75for (const auto &it : Matches) {76if (UrlPathSet)77Request.UrlPathMatches.push_back(it);78else {79Request.UrlPath = it;80UrlPathSet = true;81}82}83}8485HTTPServerRequest::HTTPServerRequest(const httplib::Request &HTTPLibRequest,86httplib::Response &HTTPLibResponse)87: HTTPLibResponse(HTTPLibResponse) {88expandUrlPathMatches(HTTPLibRequest.matches, *this);89}9091void HTTPServerRequest::setResponse(HTTPResponse Response) {92HTTPLibResponse.set_content(Response.Body.begin(), Response.Body.size(),93Response.ContentType);94HTTPLibResponse.status = Response.Code;95}9697void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) {98HTTPLibResponse.set_content_provider(99Response.ContentLength, Response.ContentType,100[=](size_t Offset, size_t Length, httplib::DataSink &Sink) {101if (Offset < Response.ContentLength) {102StringRef Chunk = Response.Provider(Offset, Length);103Sink.write(Chunk.begin(), Chunk.size());104}105return true;106},107[=](bool Success) { Response.CompletionHandler(Success); });108109HTTPLibResponse.status = Response.Code;110}111112Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) {113std::string ErrorMessage;114if (!Regex(UrlPathPattern).isValid(ErrorMessage))115return createStringError(errc::argument_out_of_domain, ErrorMessage);116Server->Get(std::string(UrlPathPattern),117[Handler](const httplib::Request &HTTPLibRequest,118httplib::Response &HTTPLibResponse) {119HTTPServerRequest Request(HTTPLibRequest, HTTPLibResponse);120Handler(Request);121});122return Error::success();123}124125Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) {126if (!Server->bind_to_port(HostInterface, ListenPort))127return createStringError(errc::io_error,128"Could not assign requested address.");129Port = ListenPort;130return Error::success();131}132133Expected<unsigned> HTTPServer::bind(const char *HostInterface) {134int ListenPort = Server->bind_to_any_port(HostInterface);135if (ListenPort < 0)136return createStringError(errc::io_error,137"Could not assign any port on requested address.");138return Port = ListenPort;139}140141Error HTTPServer::listen() {142if (!Port)143return createStringError(errc::io_error,144"Cannot listen without first binding to a port.");145if (!Server->listen_after_bind())146return createStringError(147errc::io_error,148"An unknown error occurred when cpp-httplib attempted to listen.");149return Error::success();150}151152void HTTPServer::stop() {153Server->stop();154Port = 0;155}156157#else158159// TODO: Implement barebones standalone HTTP server implementation.160bool HTTPServer::isAvailable() { return false; }161162HTTPServer::HTTPServer() = default;163164HTTPServer::~HTTPServer() = default;165166void HTTPServerRequest::setResponse(HTTPResponse Response) {167llvm_unreachable("no httplib");168}169170void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) {171llvm_unreachable("no httplib");172}173174Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) {175// TODO(https://github.com/llvm/llvm-project/issues/63873) We would ideally176// return an error as well but that's going to require refactoring of error177// handling in DebuginfodServer.178return Error::success();179}180181Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) {182return make_error<HTTPServerError>("no httplib");183}184185Expected<unsigned> HTTPServer::bind(const char *HostInterface) {186return make_error<HTTPServerError>("no httplib");187}188189Error HTTPServer::listen() {190return make_error<HTTPServerError>("no httplib");191}192193void HTTPServer::stop() {194llvm_unreachable("no httplib");195}196197#endif // LLVM_ENABLE_HTTPLIB198199200