4 #include "util/http/http_conn_handler.h" 6 #include <boost/beast/core.hpp> 7 #include <boost/beast/http.hpp> 9 #include "absl/strings/str_join.h" 10 #include "absl/strings/str_split.h" 11 #include "base/logging.h" 12 #include "strings/stringpiece.h" 13 #include "util/asio/yield.h" 14 #include "util/http/status_page.h" 20 using namespace boost;
21 namespace h2 = beast::http;
23 using fibers_ext::yield;
27 inline system::error_code to_asio(system::error_code ec) {
28 if (ec == h2::error::end_of_stream)
29 return asio::error::eof;
33 void FilezHandler(
const QueryArgs& args, HttpHandler::SendFunction* send) {
34 StringPiece file_name;
35 for (
const auto& k_v : args) {
36 if (k_v.first ==
"file") {
37 file_name = k_v.second;
40 if (file_name.empty()) {
41 http::StringResponse resp = MakeStringResponse(h2::status::unauthorized);
42 return send->Invoke(std::move(resp));
44 string fname = strings::AsString(file_name);
46 auto ec = LoadFileResponse(fname, &fresp);
48 StringResponse res = MakeStringResponse(h2::status::not_found);
49 SetMime(kTextMime, &res);
50 if (ec == boost::system::errc::no_such_file_or_directory)
51 res.body() =
"The resource '" + fname +
"' was not found.";
53 res.body() =
"Error '" + ec.message() +
"'.";
54 return send->Invoke(std::move(res));
57 return send->Invoke(std::move(fresp));
62 HttpHandler::HttpHandler(
const ListenerBase* lb, IoContext* cntx)
63 : ConnectionHandler(cntx), registry_(lb) {
64 favicon_ =
"https://rawcdn.githack.com/romange/gaia/master/util/http/favicon-32x32.png";
65 resource_prefix_ =
"https://cdn.jsdelivr.net/gh/romange/gaia/util/http";
68 system::error_code HttpHandler::HandleRequest() {
69 beast::flat_buffer buffer;
72 system::error_code ec;
74 h2::read(*socket_, buffer, request, ec);
78 VLOG(1) <<
"Full Url: " << request.target();
80 SendFunction send(*socket_);
81 HandleRequestInternal(request, &send);
83 VLOG(1) <<
"HandleRequestEnd: " << send.ec;
85 return to_asio(send.ec);
88 void HttpHandler::HandleRequestInternal(
const RequestType& request, SendFunction* send) {
89 StringPiece target = as_absl(request.target());
90 if (target ==
"/favicon.ico") {
91 h2::response<h2::string_body> resp = MakeStringResponse(h2::status::moved_permanently);
92 resp.set(h2::field::location, favicon_);
93 resp.set(h2::field::server,
"GAIA");
94 resp.keep_alive(request.keep_alive());
96 return send->Invoke(std::move(resp));
99 StringPiece path, query;
100 tie(path, query) = ParseQuery(target);
101 auto args = SplitQuery(query);
104 return send->Invoke(BuildStatusPage(args, resource_prefix_));
107 if (path ==
"/flagz") {
108 h2::response<h2::string_body> resp(h2::status::ok, request.version());
109 if (Authorize(args)) {
110 resp = ParseFlagz(args);
112 resp.result(h2::status::unauthorized);
114 return send->Invoke(std::move(resp));
117 if (path ==
"/filez") {
118 FilezHandler(args, send);
122 if (path ==
"/profilez") {
123 send->Invoke(ProfilezHandler(args));
128 auto it = registry_->cb_map_.find(path);
129 if (it == registry_->cb_map_.end() || (it->second.is_protected && !Authorize(args))) {
130 h2::response<h2::string_body> resp(h2::status::unauthorized, request.version());
131 return send->Invoke(std::move(resp));
133 it->second.cb(args, send);
137 bool ListenerBase::RegisterCb(StringPiece path,
bool protect, RequestCb cb) {
138 CbInfo info{protect, cb};
139 auto res = cb_map_.emplace(path, info);