HTTPServer.cpp 6.2 KB

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