1*753f127fSDimitry Andric //===-- llvm/Debuginfod/HTTPServer.cpp - HTTP server library -----*- C++-*-===// 2*753f127fSDimitry Andric // 3*753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*753f127fSDimitry Andric // 7*753f127fSDimitry Andric //===----------------------------------------------------------------------===// 8*753f127fSDimitry Andric /// 9*753f127fSDimitry Andric /// \file 10*753f127fSDimitry Andric /// 11*753f127fSDimitry Andric /// This file defines the methods of the HTTPServer class and the streamFile 12*753f127fSDimitry Andric /// function. 13*753f127fSDimitry Andric /// 14*753f127fSDimitry Andric //===----------------------------------------------------------------------===// 15*753f127fSDimitry Andric 16*753f127fSDimitry Andric #include "llvm/Debuginfod/HTTPServer.h" 17*753f127fSDimitry Andric #include "llvm/ADT/StringExtras.h" 18*753f127fSDimitry Andric #include "llvm/ADT/StringRef.h" 19*753f127fSDimitry Andric #include "llvm/Support/Errc.h" 20*753f127fSDimitry Andric #include "llvm/Support/Error.h" 21*753f127fSDimitry Andric #include "llvm/Support/FileSystem.h" 22*753f127fSDimitry Andric #include "llvm/Support/MemoryBuffer.h" 23*753f127fSDimitry Andric #include "llvm/Support/Regex.h" 24*753f127fSDimitry Andric 25*753f127fSDimitry Andric #ifdef LLVM_ENABLE_HTTPLIB 26*753f127fSDimitry Andric #include "httplib.h" 27*753f127fSDimitry Andric #endif 28*753f127fSDimitry Andric 29*753f127fSDimitry Andric using namespace llvm; 30*753f127fSDimitry Andric 31*753f127fSDimitry Andric bool llvm::streamFile(HTTPServerRequest &Request, StringRef FilePath) { 32*753f127fSDimitry Andric Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead(FilePath); 33*753f127fSDimitry Andric if (Error Err = FDOrErr.takeError()) { 34*753f127fSDimitry Andric consumeError(std::move(Err)); 35*753f127fSDimitry Andric Request.setResponse({404u, "text/plain", "Could not open file to read.\n"}); 36*753f127fSDimitry Andric return false; 37*753f127fSDimitry Andric } 38*753f127fSDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = 39*753f127fSDimitry Andric MemoryBuffer::getOpenFile(*FDOrErr, FilePath, 40*753f127fSDimitry Andric /*FileSize=*/-1, 41*753f127fSDimitry Andric /*RequiresNullTerminator=*/false); 42*753f127fSDimitry Andric sys::fs::closeFile(*FDOrErr); 43*753f127fSDimitry Andric if (Error Err = errorCodeToError(MBOrErr.getError())) { 44*753f127fSDimitry Andric consumeError(std::move(Err)); 45*753f127fSDimitry Andric Request.setResponse({404u, "text/plain", "Could not memory-map file.\n"}); 46*753f127fSDimitry Andric return false; 47*753f127fSDimitry Andric } 48*753f127fSDimitry Andric // Lambdas are copied on conversion to to std::function, preventing use of 49*753f127fSDimitry Andric // smart pointers. 50*753f127fSDimitry Andric MemoryBuffer *MB = MBOrErr->release(); 51*753f127fSDimitry Andric Request.setResponse({200u, "application/octet-stream", MB->getBufferSize(), 52*753f127fSDimitry Andric [=](size_t Offset, size_t Length) -> StringRef { 53*753f127fSDimitry Andric return MB->getBuffer().substr(Offset, Length); 54*753f127fSDimitry Andric }, 55*753f127fSDimitry Andric [=](bool Success) { delete MB; }}); 56*753f127fSDimitry Andric return true; 57*753f127fSDimitry Andric } 58*753f127fSDimitry Andric 59*753f127fSDimitry Andric #ifdef LLVM_ENABLE_HTTPLIB 60*753f127fSDimitry Andric 61*753f127fSDimitry Andric bool HTTPServer::isAvailable() { return true; } 62*753f127fSDimitry Andric 63*753f127fSDimitry Andric HTTPServer::HTTPServer() { Server = std::make_unique<httplib::Server>(); } 64*753f127fSDimitry Andric 65*753f127fSDimitry Andric HTTPServer::~HTTPServer() { stop(); } 66*753f127fSDimitry Andric 67*753f127fSDimitry Andric static void expandUrlPathMatches(const std::smatch &Matches, 68*753f127fSDimitry Andric HTTPServerRequest &Request) { 69*753f127fSDimitry Andric bool UrlPathSet = false; 70*753f127fSDimitry Andric for (const auto &it : Matches) { 71*753f127fSDimitry Andric if (UrlPathSet) 72*753f127fSDimitry Andric Request.UrlPathMatches.push_back(it); 73*753f127fSDimitry Andric else { 74*753f127fSDimitry Andric Request.UrlPath = it; 75*753f127fSDimitry Andric UrlPathSet = true; 76*753f127fSDimitry Andric } 77*753f127fSDimitry Andric } 78*753f127fSDimitry Andric } 79*753f127fSDimitry Andric 80*753f127fSDimitry Andric HTTPServerRequest::HTTPServerRequest(const httplib::Request &HTTPLibRequest, 81*753f127fSDimitry Andric httplib::Response &HTTPLibResponse) 82*753f127fSDimitry Andric : HTTPLibResponse(HTTPLibResponse) { 83*753f127fSDimitry Andric expandUrlPathMatches(HTTPLibRequest.matches, *this); 84*753f127fSDimitry Andric } 85*753f127fSDimitry Andric 86*753f127fSDimitry Andric void HTTPServerRequest::setResponse(HTTPResponse Response) { 87*753f127fSDimitry Andric HTTPLibResponse.set_content(Response.Body.begin(), Response.Body.size(), 88*753f127fSDimitry Andric Response.ContentType); 89*753f127fSDimitry Andric HTTPLibResponse.status = Response.Code; 90*753f127fSDimitry Andric } 91*753f127fSDimitry Andric 92*753f127fSDimitry Andric void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) { 93*753f127fSDimitry Andric HTTPLibResponse.set_content_provider( 94*753f127fSDimitry Andric Response.ContentLength, Response.ContentType, 95*753f127fSDimitry Andric [=](size_t Offset, size_t Length, httplib::DataSink &Sink) { 96*753f127fSDimitry Andric if (Offset < Response.ContentLength) { 97*753f127fSDimitry Andric StringRef Chunk = Response.Provider(Offset, Length); 98*753f127fSDimitry Andric Sink.write(Chunk.begin(), Chunk.size()); 99*753f127fSDimitry Andric } 100*753f127fSDimitry Andric return true; 101*753f127fSDimitry Andric }, 102*753f127fSDimitry Andric [=](bool Success) { Response.CompletionHandler(Success); }); 103*753f127fSDimitry Andric 104*753f127fSDimitry Andric HTTPLibResponse.status = Response.Code; 105*753f127fSDimitry Andric } 106*753f127fSDimitry Andric 107*753f127fSDimitry Andric Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) { 108*753f127fSDimitry Andric std::string ErrorMessage; 109*753f127fSDimitry Andric if (!Regex(UrlPathPattern).isValid(ErrorMessage)) 110*753f127fSDimitry Andric return createStringError(errc::argument_out_of_domain, ErrorMessage); 111*753f127fSDimitry Andric Server->Get(std::string(UrlPathPattern), 112*753f127fSDimitry Andric [Handler](const httplib::Request &HTTPLibRequest, 113*753f127fSDimitry Andric httplib::Response &HTTPLibResponse) { 114*753f127fSDimitry Andric HTTPServerRequest Request(HTTPLibRequest, HTTPLibResponse); 115*753f127fSDimitry Andric Handler(Request); 116*753f127fSDimitry Andric }); 117*753f127fSDimitry Andric return Error::success(); 118*753f127fSDimitry Andric } 119*753f127fSDimitry Andric 120*753f127fSDimitry Andric Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) { 121*753f127fSDimitry Andric if (!Server->bind_to_port(HostInterface, ListenPort)) 122*753f127fSDimitry Andric return createStringError(errc::io_error, 123*753f127fSDimitry Andric "Could not assign requested address."); 124*753f127fSDimitry Andric Port = ListenPort; 125*753f127fSDimitry Andric return Error::success(); 126*753f127fSDimitry Andric } 127*753f127fSDimitry Andric 128*753f127fSDimitry Andric Expected<unsigned> HTTPServer::bind(const char *HostInterface) { 129*753f127fSDimitry Andric int ListenPort = Server->bind_to_any_port(HostInterface); 130*753f127fSDimitry Andric if (ListenPort < 0) 131*753f127fSDimitry Andric return createStringError(errc::io_error, 132*753f127fSDimitry Andric "Could not assign any port on requested address."); 133*753f127fSDimitry Andric return Port = ListenPort; 134*753f127fSDimitry Andric } 135*753f127fSDimitry Andric 136*753f127fSDimitry Andric Error HTTPServer::listen() { 137*753f127fSDimitry Andric if (!Port) 138*753f127fSDimitry Andric return createStringError(errc::io_error, 139*753f127fSDimitry Andric "Cannot listen without first binding to a port."); 140*753f127fSDimitry Andric if (!Server->listen_after_bind()) 141*753f127fSDimitry Andric return createStringError( 142*753f127fSDimitry Andric errc::io_error, 143*753f127fSDimitry Andric "An unknown error occurred when cpp-httplib attempted to listen."); 144*753f127fSDimitry Andric return Error::success(); 145*753f127fSDimitry Andric } 146*753f127fSDimitry Andric 147*753f127fSDimitry Andric void HTTPServer::stop() { 148*753f127fSDimitry Andric Server->stop(); 149*753f127fSDimitry Andric Port = 0; 150*753f127fSDimitry Andric } 151*753f127fSDimitry Andric 152*753f127fSDimitry Andric #else 153*753f127fSDimitry Andric 154*753f127fSDimitry Andric // TODO: Implement barebones standalone HTTP server implementation. 155*753f127fSDimitry Andric bool HTTPServer::isAvailable() { return false; } 156*753f127fSDimitry Andric 157*753f127fSDimitry Andric HTTPServer::HTTPServer() = default; 158*753f127fSDimitry Andric 159*753f127fSDimitry Andric HTTPServer::~HTTPServer() = default; 160*753f127fSDimitry Andric 161*753f127fSDimitry Andric void HTTPServerRequest::setResponse(HTTPResponse Response) { 162*753f127fSDimitry Andric llvm_unreachable("No HTTP server implementation available"); 163*753f127fSDimitry Andric } 164*753f127fSDimitry Andric 165*753f127fSDimitry Andric void HTTPServerRequest::setResponse(StreamingHTTPResponse Response) { 166*753f127fSDimitry Andric llvm_unreachable("No HTTP server implementation available"); 167*753f127fSDimitry Andric } 168*753f127fSDimitry Andric 169*753f127fSDimitry Andric Error HTTPServer::get(StringRef UrlPathPattern, HTTPRequestHandler Handler) { 170*753f127fSDimitry Andric llvm_unreachable("No HTTP server implementation available"); 171*753f127fSDimitry Andric } 172*753f127fSDimitry Andric 173*753f127fSDimitry Andric Error HTTPServer::bind(unsigned ListenPort, const char *HostInterface) { 174*753f127fSDimitry Andric llvm_unreachable("No HTTP server implementation available"); 175*753f127fSDimitry Andric } 176*753f127fSDimitry Andric 177*753f127fSDimitry Andric Expected<unsigned> HTTPServer::bind(const char *HostInterface) { 178*753f127fSDimitry Andric llvm_unreachable("No HTTP server implementation available"); 179*753f127fSDimitry Andric } 180*753f127fSDimitry Andric 181*753f127fSDimitry Andric Error HTTPServer::listen() { 182*753f127fSDimitry Andric llvm_unreachable("No HTTP server implementation available"); 183*753f127fSDimitry Andric } 184*753f127fSDimitry Andric 185*753f127fSDimitry Andric void HTTPServer::stop() { 186*753f127fSDimitry Andric llvm_unreachable("No HTTP server implementation available"); 187*753f127fSDimitry Andric } 188*753f127fSDimitry Andric 189*753f127fSDimitry Andric #endif // LLVM_ENABLE_HTTPLIB 190