http_handler.cc
1 // Copyright 2020, Beeri 15. All rights reserved.
2 // Author: Roman Gershman (romange@gmail.com)
3 //
4 
5 #include "util/uring/http_handler.h"
6 
7 #include <boost/beast/core.hpp> // for flat_buffer.
8 #include <boost/beast/http.hpp>
9 
10 #include "base/logging.h"
11 
12 namespace util {
13 using namespace http;
14 using namespace std;
15 using namespace boost;
16 namespace h2 = beast::http;
17 
18 namespace uring {
19 
20 namespace {
21 
22 void FilezHandler(const QueryArgs& args, HttpContext* send) {
23  StringPiece file_name;
24  for (const auto& k_v : args) {
25  if (k_v.first == "file") {
26  file_name = k_v.second;
27  }
28  }
29  if (file_name.empty()) {
30  http::StringResponse resp = MakeStringResponse(h2::status::unauthorized);
31  return send->Invoke(std::move(resp));
32  }
33 
34  FileResponse fresp;
35  string fname = strings::AsString(file_name);
36  auto ec = LoadFileResponse(fname, &fresp);
37  if (ec) {
38  StringResponse res = MakeStringResponse(h2::status::not_found);
39  SetMime(kTextMime, &res);
40  if (ec == boost::system::errc::no_such_file_or_directory)
41  res.body() = "The resource '" + fname + "' was not found.";
42  else
43  res.body() = "Error '" + ec.message() + "'.";
44  return send->Invoke(std::move(res));
45  }
46 
47  return send->Invoke(std::move(fresp));
48 }
49 
50 } // namespace
51 
52 HttpListenerBase::HttpListenerBase() {
53  favicon_ =
54  "https://rawcdn.githack.com/romange/gaia/master/util/http/"
55  "favicon-32x32.png";
56  resource_prefix_ = "https://cdn.jsdelivr.net/gh/romange/gaia/util/http";
57 }
58 
59 bool HttpListenerBase::HandleRoot(const RequestType& request,
60  HttpContext* cntx) const {
61  StringPiece target = as_absl(request.target());
62  if (target == "/favicon.ico") {
63  h2::response<h2::string_body> resp =
64  MakeStringResponse(h2::status::moved_permanently);
65  resp.set(h2::field::location, favicon_);
66  resp.set(h2::field::server, "GAIA");
67  resp.keep_alive(request.keep_alive());
68 
69  cntx->Invoke(std::move(resp));
70  return true;
71  }
72 
73  StringPiece path, query;
74  tie(path, query) = ParseQuery(target);
75  auto args = SplitQuery(query);
76 
77  if (path == "/") {
78  cntx->Invoke(BuildStatusPage(args, resource_prefix_));
79  return true;
80  }
81 
82  if (path == "/flagz") {
83  h2::response<h2::string_body> resp(h2::status::ok, request.version());
84  cntx->Invoke(ParseFlagz(args));
85  return true;
86  }
87 
88  if (path == "/filez") {
89  FilezHandler(args, cntx);
90  return true;
91  }
92 
93  if (path == "/profilez") {
94  cntx->Invoke(ProfilezHandler(args));
95  return true;
96  }
97  return false;
98 }
99 
100 bool HttpListenerBase::RegisterCb(StringPiece path, RequestCb cb) {
101  CbInfo cb_info{.cb = cb};
102 
103  auto res = cb_map_.emplace(path, cb_info);
104  return res.second;
105 }
106 
107 HttpHandler2::HttpHandler2(const HttpListenerBase* base) : base_(base) {
108 }
109 
110 void HttpHandler2::HandleRequests() {
111  CHECK(socket_.IsOpen());
112  beast::flat_buffer buffer;
113  RequestType request;
114 
115  system::error_code ec;
116  AsioStreamAdapter<> asa(socket_);
117 
118  while (true) {
119  h2::read(asa, buffer, request, ec);
120  if (ec) {
121  break;
122  }
123  HttpContext cntx(asa);
124  VLOG(1) << "Full Url: " << request.target();
125  HandleOne(request, &cntx);
126  }
127  VLOG(1) << "HttpHandler2 exit";
128 }
129 
130 void HttpHandler2::HandleOne(const RequestType& req, HttpContext* cntx) {
131  CHECK(base_);
132 
133  if (base_->HandleRoot(req, cntx)) {
134  return;
135  }
136  StringPiece target = as_absl(req.target());
137  StringPiece path, query;
138  tie(path, query) = ParseQuery(target);
139  VLOG(2) << "Searching for " << path;
140 
141  auto it = base_->cb_map_.find(path);
142  if (it == base_->cb_map_.end()) {
143  h2::response<h2::string_body> resp(h2::status::unauthorized, req.version());
144  return cntx->Invoke(std::move(resp));
145  }
146  auto args = SplitQuery(query);
147  it->second.cb(args, cntx);
148 }
149 
150 } // namespace uring
151 } // namespace util
bool IsOpen() const
IsOpen does not promise that the socket is TCP connected or live,.
Definition: fiber_socket.h:88