brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.4 KiB · 1264353 Raw
199 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10///11/// This file defines the methods of the HTTPServer class and the streamFile12/// 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_HTTPLIB26#include "httplib.h"27#endif28 29using namespace llvm;30 31char HTTPServerError::ID = 0;32 33HTTPServerError::HTTPServerError(const Twine &Msg) : Msg(Msg.str()) {}34 35void HTTPServerError::log(raw_ostream &OS) const { OS << Msg; }36 37bool 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 of55  // 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_HTTPLIB66 67bool HTTPServer::isAvailable() { return true; }68 69HTTPServer::HTTPServer() { Server = std::make_unique<httplib::Server>(); }70 71HTTPServer::~HTTPServer() { stop(); }72 73static 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 86HTTPServerRequest::HTTPServerRequest(const httplib::Request &HTTPLibRequest,87                                     httplib::Response &HTTPLibResponse)88    : HTTPLibResponse(HTTPLibResponse) {89  expandUrlPathMatches(HTTPLibRequest.matches, *this);90}91 92void HTTPServerRequest::setResponse(HTTPResponse Response) {93  HTTPLibResponse.set_content(Response.Body.begin(), Response.Body.size(),94                              Response.ContentType);95  HTTPLibResponse.status = Response.Code;96}97 98void 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 113Error 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 126Error 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 134Expected<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 142Error 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 153void HTTPServer::stop() {154  Server->stop();155  Port = 0;156}157 158#else159 160// TODO: Implement barebones standalone HTTP server implementation.161bool HTTPServer::isAvailable() { return false; }162 163HTTPServer::HTTPServer() = default;164 165HTTPServer::~HTTPServer() = default;166 167void HTTPServerRequest::setResponse(HTTPResponse Response) {168  llvm_unreachable("no httplib");169}170 171void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) {172  llvm_unreachable("no httplib");173}174 175Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) {176  // TODO(https://github.com/llvm/llvm-project/issues/63873) We would ideally177  // return an error as well but that's going to require refactoring of error178  // handling in DebuginfodServer.179  return Error::success();180}181 182Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) {183  return make_error<HTTPServerError>("no httplib");184}185 186Expected<unsigned> HTTPServer::bind(const char *HostInterface) {187  return make_error<HTTPServerError>("no httplib");188}189 190Error HTTPServer::listen() {191  return make_error<HTTPServerError>("no httplib");192}193 194void HTTPServer::stop() {195  llvm_unreachable("no httplib");196}197 198#endif // LLVM_ENABLE_HTTPLIB199