5G-MAG Reference Tools - MBMS Middleware
RestHandler.cpp
Go to the documentation of this file.
1 // 5G-MAG Reference Tools
2 // MBMS Middleware Process
3 //
4 // Copyright (C) 2021 Klaus Kühnhammer (Österreichische Rundfunksender GmbH & Co KG)
5 //
6 // Licensed under the License terms and conditions for use, reproduction, and
7 // distribution of 5G-MAG software (the “License”). You may not use this file
8 // except in compliance with the License. You may obtain a copy of the License at
9 // https://www.5g-mag.com/reference-tools. Unless required by applicable law or
10 // agreed to in writing, software distributed under the License is distributed on
11 // an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12 // or implied.
13 //
14 // See the License for the specific language governing permissions and limitations
15 // under the License.
16 //
17 
18 #include "RestHandler.h"
19 #include "seamless/SeamlessContentStream.h"
20 
21 #include <memory>
22 #include <utility>
23 
24 #include "spdlog/spdlog.h"
25 #include <boost/algorithm/string/join.hpp>
26 
27 using web::json::value;
28 using web::http::methods;
29 using web::http::uri;
30 using web::http::http_request;
31 using web::http::status_codes;
32 using web::http::experimental::listener::http_listener;
33 using web::http::experimental::listener::http_listener_config;
34 
35 MBMS_RT::RestHandler::RestHandler(const libconfig::Config& cfg, const std::string& url, const CacheManagement& cache,
36  const std::unique_ptr<MBMS_RT::ServiceAnnouncement>* service_announcement,
37  const std::map<std::string, std::shared_ptr<Service>>& services )
38  : _cfg(cfg)
39  , _services(services)
40  , _cache(cache)
41  , _service_announcement_h(service_announcement)
42 {
43  http_listener_config server_config;
44  if (url.rfind("https", 0) == 0) {
45  server_config.set_ssl_context_callback(
46  [&](boost::asio::ssl::context& ctx) {
47  std::string cert_file = "/usr/share/5gmag-rt/cert.pem";
48  cfg.lookupValue("mw.http_server.cert", cert_file);
49 
50  std::string key_file = "/usr/share/5gmag-rt/key.pem";
51  cfg.lookupValue("mw.http_server.key", key_file);
52 
53  ctx.set_options(boost::asio::ssl::context::default_workarounds);
54  ctx.use_certificate_chain_file(cert_file);
55  ctx.use_private_key_file(key_file, boost::asio::ssl::context::pem);
56  });
57  }
58 
59  cfg.lookupValue("mw.http_server.api_key.enabled", _require_bearer_token);
61  _api_key = "106cd60-76c8-4c37-944c-df21aa690c1e";
62  cfg.lookupValue("mw.http_server.api_key.key", _api_key);
63  }
64 
65  _api_path = "mw-api";
66  cfg.lookupValue("mw.http_server.api_path", _api_path);
67 
68  _listener = std::make_unique<http_listener>(
69  url, server_config);
70 
71  _listener->support(methods::GET, std::bind(&RestHandler::get, this, std::placeholders::_1)); // NOLINT
72  _listener->support(methods::PUT, std::bind(&RestHandler::put, this, std::placeholders::_1)); // NOLINT
73 
74  _listener->open().wait();
75 }
76 
78 
79 void MBMS_RT::RestHandler::get(http_request message) {
80  auto uri = message.relative_uri();
81  spdlog::debug("request for {}", uri.to_string() );
82  auto paths = uri::split_path(uri::decode(message.relative_uri().path()));
83  if (_require_bearer_token &&
84  (message.headers()["Authorization"] != "Bearer " + _api_key)) {
85  message.reply(status_codes::Unauthorized);
86  return;
87  }
88 
89  if (paths.empty()) {
90  message.reply(status_codes::NotFound);
91  } else {
92  if (paths[0] == _api_path) {
93  if (paths[1] == "service_announcement") {
94  if (*_service_announcement_h) {
95  std::vector<value> items;
96  for (const auto& item : (*_service_announcement_h)->items()) {
97  if (item.content_type != "application/mbms-envelope+xml") {
98  value i;
99  i["location"] = value(item.uri);
100  i["type"] = value(item.content_type);
101  i["valid_from"] = value(item.valid_from);
102  i["valid_until"] = value(item.valid_until);
103  i["version"] = value(item.version);
104  i["content"] = value(item.content);
105  items.push_back(i);
106  }
107  }
108  value sa;
109  sa["id"] = value((*_service_announcement_h)->toi());
110  sa["content"] = value((*_service_announcement_h)->content());
111  sa["items"] = value::array(items);
112  message.reply(status_codes::OK, sa);
113  return;
114  } else {
115  message.reply(status_codes::NotFound);
116  return;
117  }
118  } else if (paths[1] == "files") {
119  std::vector<value> files;
120  for (const auto& item : _cache.item_map()) {
121  value f;
122  f["source"] = value(item.second->item_source_as_string());
123  f["location"] = value(item.second->content_location());
124  f["content_length"] = value(item.second->content_length());
125  f["received_at"] = value(item.second->received_at());
126  if (item.second->received_at() == 0) {
127  f["age"] = value(10000);
128  } else {
129  f["age"] = value(time(nullptr) - item.second->received_at());
130  }
131  files.push_back(f);
132  }
133  message.reply(status_codes::OK, value::array(files));
134  return;
135  } else if (paths[1] == "services") {
136  std::vector<value> services;
137  for (const auto& service : _services) {
138  auto s = service.second;
139  value ser;
140 
141  std::vector<value> names;
142  for (const auto& name : s->names()) {
143  value n;
144  n["lang"] = value(name.first);
145  n["name"] = value(name.second);
146  names.push_back(n);
147  }
148  ser["names"] = value::array(names);
149  ser["protocol"] = value(s->delivery_protocol_string());
150  ser["manifest_path"] = value(s->manifest_path());
151 
152  std::vector<value> streams;
153  for (const auto& stream : s->content_streams()) {
154  value s;
155  s["base"] = value(stream.second->base());
156  s["type"] = value(stream.second->stream_type_string());
157  s["flute_info"] = value(stream.second->flute_info());
158  s["resolution"] = value(stream.second->resolution());
159  s["codecs"] = value(stream.second->codecs());
160  s["bandwidth"] = value(stream.second->bandwidth());
161  s["frame_rate"] = value(stream.second->frame_rate());
162  s["playlist_path"] = value(stream.second->playlist_path());
163  if (stream.second->stream_type() == ContentStream::StreamType::SeamlessSwitching) {
164  s["cdn_ept"] = value(std::dynamic_pointer_cast<SeamlessContentStream>(stream.second)->cdn_endpoint());
165  } else {
166  s["cdn_ept"] = value("n/a");
167  }
168  streams.push_back(s);
169  }
170  ser["streams"] = value::array(streams);
171 
172  services.push_back(ser);
173  }
174  message.reply(status_codes::OK, value::array(services));
175  return;
176  } else {
177  message.reply(status_codes::NotFound);
178  return;
179  }
180  } else {
181  auto path = uri.to_string().erase(0,1); // remove leading /
182  spdlog::debug("checking for file at path {}", path );
183 
184  auto it = _cache.item_map().find(path);
185  if (it != _cache.item_map().cend()) {
186  if (it->second->buffer() != nullptr) {
187  web::http::http_response response(status_codes::OK);
188  response.headers().add(U("RT-MBMS-MW-File-Origin"), it->second->item_source_as_string());
189  auto instream = Concurrency::streams::rawptr_stream<uint8_t>::open_istream((uint8_t*)it->second->buffer(), it->second->content_length());
190  response.set_body(instream);
191  message.reply(response);
192  } else {
193  message.reply(status_codes::NotFound);
194  }
195  } else {
196  message.reply(status_codes::NotFound);
197  }
198  }
199  }
200 }
201 
202 void MBMS_RT::RestHandler::put(http_request message) {
203  if (_require_bearer_token &&
204  (message.headers()["Authorization"] != "Bearer " + _api_key)) {
205  message.reply(status_codes::Unauthorized);
206  return;
207  }
208 
209  auto paths = uri::split_path(uri::decode(message.relative_uri().path()));
210  if (paths.empty()) {
211  message.reply(status_codes::NotFound);
212  } else {
213  // not yet implemented
214  }
215 }
216 
RestHandler(const libconfig::Config &cfg, const std::string &url, const CacheManagement &cache, const std::unique_ptr< MBMS_RT::ServiceAnnouncement > *service_announcement, const std::map< std::string, std::shared_ptr< MBMS_RT::Service >> &services)
Default constructor.
Definition: RestHandler.cpp:35
void put(web::http::http_request message)
std::unique_ptr< web::http::experimental::listener::http_listener > _listener
Definition: RestHandler.h:69
void get(web::http::http_request message)
Definition: RestHandler.cpp:79
std::string _api_path
Definition: RestHandler.h:72
virtual ~RestHandler()
Default destructor.
std::string _api_key
Definition: RestHandler.h:71
static Config cfg
Global configuration object.
Definition: main.cpp:111