blob: 9946990bedfdfa988ed36a7803c3288ec86c5fc2 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
Ed Tanous7045c8d2017-04-03 10:04:37 -07003#pragma once
4
zhanghch058d1b46d2021-04-01 11:18:24 +08005#include "async_resp.hpp"
Ed Tanous796ba932020-08-02 04:29:21 +00006#include "http_connect_types.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -07007#include "http_request.hpp"
8#include "http_server.hpp"
Ed Tanous9838eb22025-01-29 16:24:42 -08009#include "io_context_singleton.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070010#include "logging.hpp"
Ed Tanous04e438c2020-10-03 08:06:26 -070011#include "routing.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080012#include "routing/dynamicrule.hpp"
Ed Tanous46f780f2025-02-09 09:35:23 -080013#include "str_utility.hpp"
Tanousf00032d2018-11-05 01:18:10 -030014
Ed Tanousd7857202025-01-28 15:32:26 -080015#include <sys/socket.h>
Ed Tanous8db83742024-04-13 09:11:15 -070016#include <systemd/sd-daemon.h>
17
Nan Zhoucec58fe2022-06-14 20:45:45 +000018#include <boost/asio/ip/tcp.hpp>
Nan Zhoucec58fe2022-06-14 20:45:45 +000019
Ed Tanous796ba932020-08-02 04:29:21 +000020#include <cstddef>
Ed Tanous7045c8d2017-04-03 10:04:37 -070021#include <cstdint>
Ed Tanous7045c8d2017-04-03 10:04:37 -070022#include <memory>
Ed Tanousd7857202025-01-28 15:32:26 -080023#include <optional>
Ed Tanous796ba932020-08-02 04:29:21 +000024#include <span>
Ed Tanous7045c8d2017-04-03 10:04:37 -070025#include <string>
Ed Tanous46f780f2025-02-09 09:35:23 -080026#include <string_view>
Ed Tanous911ac312017-08-15 09:37:42 -070027#include <utility>
Ed Tanousd7857202025-01-28 15:32:26 -080028#include <vector>
Ed Tanous1abe55e2018-09-05 08:30:59 -070029
Patrick Williamsa2323432023-05-12 10:06:35 -050030// NOLINTNEXTLINE(cppcoreguidelines-macro-usage, clang-diagnostic-unused-macros)
Ed Tanous1abe55e2018-09-05 08:30:59 -070031#define BMCWEB_ROUTE(app, url) \
Ed Tanous47488a92023-06-26 18:19:33 -070032 app.template route<crow::utility::getParameterTag(url)>(url)
Ed Tanous7045c8d2017-04-03 10:04:37 -070033
Ed Tanous1abe55e2018-09-05 08:30:59 -070034namespace crow
35{
Ed Tanous52cc1122020-07-18 13:51:21 -070036class App
Ed Tanous1abe55e2018-09-05 08:30:59 -070037{
38 public:
Ed Tanous8db83742024-04-13 09:11:15 -070039 using raw_socket_t = boost::asio::ip::tcp::socket;
Ed Tanous796ba932020-08-02 04:29:21 +000040 using server_type = Server<App, raw_socket_t>;
Ed Tanousceac6f72018-12-02 11:58:47 -080041
Ed Tanous1abe55e2018-09-05 08:30:59 -070042 template <typename Adaptor>
Jonathan Doman102a4cd2024-04-15 16:56:23 -070043 void handleUpgrade(const std::shared_ptr<Request>& req,
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053044 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
45 Adaptor&& adaptor)
Ed Tanous1abe55e2018-09-05 08:30:59 -070046 {
P Dheeraj Srujan Kumara9f076e2021-10-18 22:45:37 +053047 router.handleUpgrade(req, asyncResp, std::forward<Adaptor>(adaptor));
Ed Tanous1abe55e2018-09-05 08:30:59 -070048 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070049
Jonathan Doman102a4cd2024-04-15 16:56:23 -070050 void handle(const std::shared_ptr<Request>& req,
zhanghch058d1b46d2021-04-01 11:18:24 +080051 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -070052 {
zhanghch058d1b46d2021-04-01 11:18:24 +080053 router.handle(req, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -070054 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070055
Ed Tanous8cb2c022024-03-27 16:31:46 -070056 DynamicRule& routeDynamic(const std::string& rule)
Ed Tanous1abe55e2018-09-05 08:30:59 -070057 {
58 return router.newRuleDynamic(rule);
59 }
60
Gunnar Mills1214b7e2020-06-04 10:11:30 -050061 template <uint64_t Tag>
62 auto& route(std::string&& rule)
Ed Tanous1abe55e2018-09-05 08:30:59 -070063 {
64 return router.newRuleTagged<Tag>(std::move(rule));
65 }
66
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 void validate()
68 {
69 router.validate();
70 }
71
Ed Tanous3281bcf2024-06-25 16:02:05 -070072 void loadCertificate()
73 {
74 BMCWEB_LOG_DEBUG("Loading certificate");
75 if (!server)
76 {
77 return;
78 }
79 server->loadCertificate();
80 }
81
Ed Tanous796ba932020-08-02 04:29:21 +000082 static HttpType getHttpType(std::string_view socketTypeString)
Ed Tanous8db83742024-04-13 09:11:15 -070083 {
Ed Tanous796ba932020-08-02 04:29:21 +000084 if (socketTypeString == "http")
Ed Tanous8db83742024-04-13 09:11:15 -070085 {
Ed Tanous796ba932020-08-02 04:29:21 +000086 BMCWEB_LOG_DEBUG("Got http socket");
87 return HttpType::HTTP;
88 }
89 if (socketTypeString == "https")
90 {
91 BMCWEB_LOG_DEBUG("Got https socket");
92 return HttpType::HTTPS;
93 }
94 if (socketTypeString == "both")
95 {
96 BMCWEB_LOG_DEBUG("Got hybrid socket");
97 return HttpType::BOTH;
98 }
99
100 // all other types https
101 BMCWEB_LOG_ERROR("Unknown http type={} assuming HTTPS only",
102 socketTypeString);
103 return HttpType::HTTPS;
104 }
105
106 static std::vector<Acceptor> setupSocket()
107 {
108 std::vector<Acceptor> acceptors;
109 char** names = nullptr;
110 int listenFdCount = sd_listen_fds_with_names(0, &names);
111 BMCWEB_LOG_DEBUG("Got {} sockets to open", listenFdCount);
112
113 if (listenFdCount < 0)
114 {
115 BMCWEB_LOG_CRITICAL("Failed to read socket files");
116 return acceptors;
117 }
118 int socketIndex = 0;
119 for (char* name :
120 std::span<char*>(names, static_cast<size_t>(listenFdCount)))
121 {
122 if (name == nullptr)
123 {
124 continue;
125 }
126 // name looks like bmcweb_443_https_auth
127 // Assume HTTPS as default
128 std::string socketName(name);
129
130 std::vector<std::string> socknameComponents;
131 bmcweb::split(socknameComponents, socketName, '_');
132 HttpType httpType = getHttpType(socknameComponents[2]);
133
134 int listenFd = socketIndex + SD_LISTEN_FDS_START;
135 if (sd_is_socket_inet(listenFd, AF_UNSPEC, SOCK_STREAM, 1, 0) > 0)
Ed Tanous8db83742024-04-13 09:11:15 -0700136 {
137 BMCWEB_LOG_INFO("Starting webserver on socket handle {}",
Ed Tanous796ba932020-08-02 04:29:21 +0000138 listenFd);
139 acceptors.emplace_back(Acceptor{
140 boost::asio::ip::tcp::acceptor(
141 getIoContext(), boost::asio::ip::tcp::v6(), listenFd),
142 httpType});
Ed Tanous8db83742024-04-13 09:11:15 -0700143 }
Ed Tanous796ba932020-08-02 04:29:21 +0000144 socketIndex++;
Ed Tanous8db83742024-04-13 09:11:15 -0700145 }
Ed Tanous796ba932020-08-02 04:29:21 +0000146
Janet Adkins58d3aab2025-02-19 14:45:43 -0600147 if (acceptors.empty())
148 {
149 constexpr int defaultPort = 18080;
150 BMCWEB_LOG_INFO("Starting webserver on port {}", defaultPort);
151 using boost::asio::ip::tcp;
152 tcp::endpoint end(tcp::v6(), defaultPort);
153 tcp::acceptor acc(getIoContext(), end);
154 acceptors.emplace_back(std::move(acc), HttpType::HTTPS);
155 }
156
Ed Tanous796ba932020-08-02 04:29:21 +0000157 return acceptors;
Ed Tanous8db83742024-04-13 09:11:15 -0700158 }
159
Ed Tanous1abe55e2018-09-05 08:30:59 -0700160 void run()
161 {
162 validate();
Ed Tanous789a6a32018-11-29 15:17:22 -0800163
Ed Tanous796ba932020-08-02 04:29:21 +0000164 std::vector<Acceptor> acceptors = setupSocket();
165
166 server.emplace(this, std::move(acceptors));
Ed Tanous789a6a32018-11-29 15:17:22 -0800167 server->run();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168 }
169
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 void debugPrint()
171 {
Ed Tanous62598e32023-07-17 17:06:25 -0700172 BMCWEB_LOG_DEBUG("Routing:");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 router.debugPrint();
174 }
175
176 std::vector<const std::string*> getRoutes()
177 {
Ed Tanouse05aec52022-01-25 10:28:56 -0800178 const std::string root;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 return router.getRoutes(root);
180 }
181 std::vector<const std::string*> getRoutes(const std::string& parent)
182 {
183 return router.getRoutes(parent);
184 }
Ed Tanousb4a7bfa2017-04-04 17:23:00 -0700185
Ed Tanous8db83742024-04-13 09:11:15 -0700186 std::optional<server_type> server;
187
188 Router router;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700189};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700190} // namespace crow
Ed Tanous52cc1122020-07-18 13:51:21 -0700191using App = crow::App;