Commit 53243dc3 authored by Raphael Defosseux's avatar Raphael Defosseux

Merge branch 'httpv2_support' into 'develop'

httpv2 support

See merge request oai/cn5g/oai-cn5g-nrf!19
parents c5e1f9b8 b0f69dc4
......@@ -32,6 +32,7 @@ include_directories(${SRC_TOP_DIR}/../build/ext/spdlog/include)
file(GLOB NRF_API_SERVER_src_files
${NRF_API_SERVER_DIR}/nrf-api-server.cpp
${NRF_API_SERVER_DIR}/nrf-http2-server.cpp
${NRF_API_SERVER_DIR}/model/*.cpp
${NRF_API_SERVER_DIR}/api/*.cpp
${NRF_API_SERVER_DIR}/impl/*.cpp
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file nrf_http2-server.cpp
\brief
\author Tien-Thinh NGUYEN
\company Eurecom
\date 2020
\email: tien-thinh.nguyen@eurecom.fr
*/
#include "nrf-http2-server.h"
#include <boost/algorithm/string.hpp>
#include <boost/thread.hpp>
#include <boost/thread/future.hpp>
#include <regex>
#include <nlohmann/json.hpp>
#include <string>
#include "string.hpp"
#include "logger.hpp"
#include "nrf_config.hpp"
#include "3gpp_29.500.h"
#include "mime_parser.hpp"
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
using namespace oai::nrf::model;
extern nrf_config nrf_cfg;
//------------------------------------------------------------------------------
void nrf_http2_server::start() {
boost::system::error_code ec;
Logger::nrf_app().info("HTTP2 server started");
std::string nfInstanceID = {};
std::string subscriptionID = {};
SubscriptionData subscriptionData = {};
// NF Instances (Store)
server.handle(
NNRF_NFM_BASE + nrf_cfg.sbi_api_version + "/nf-instances",
[&](const request& request, const response& response) {
request.on_data([&](const uint8_t* data, std::size_t len) {
std::string msg((char*) data, len);
try {
// Retrieves a collection of NF Instances
if (request.method().compare("GET") == 0) {
std::string split_query = request.uri().raw_query;
// Parse query paramaters
std::string nfType =
util::get_query_param(split_query, "nf-type");
std::string limit_nfs =
util::get_query_param(split_query.c_str(), "limit");
Logger::nrf_sbi().debug(
"/nnrf-nfm/ query params - nfType: %s, limit_nfs: %s, ",
nfType.c_str(), limit_nfs.c_str());
this->get_nf_instances_handler(nfType, limit_nfs, response);
}
} catch (nlohmann::detail::exception& e) {
Logger::nrf_sbi().warn(
"Can not parse the json data (error: %s)!", e.what());
response.write_head(
http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST);
response.end();
return;
}
});
});
// NF Instances ID (Document)
server.handle(
NNRF_NFM_BASE + nrf_cfg.sbi_api_version + NNRF_NFM_NF_INSTANCES,
[&](const request& request, const response& response) {
request.on_data([&](const uint8_t* data, std::size_t len) {
std::string msg((char*) data, len);
NFProfile nFProfile;
try {
// Register a new NF Instance
if (request.method().compare("PUT") == 0 && len > 0) {
nlohmann::json::parse(msg.c_str()).get_to(nFProfile);
this->register_nf_instance_handler(nFProfile, response);
}
// Read the profile of a given NF Instance
if (request.method().compare("GET") == 0) {
std::vector<std::string> split_result;
boost::split(
split_result, request.uri().path, boost::is_any_of("/"));
if (split_result.size() == 5) {
nfInstanceID = split_result[split_result.size() - 1].c_str();
this->get_nf_instance_handler(nfInstanceID, response);
}
}
// Update NF Instance profile
if (request.method().compare("PATCH") == 0 && len > 0) {
std::vector<PatchItem> patchItem;
nlohmann::json::parse(msg.c_str()).get_to(patchItem);
std::vector<std::string> split_result;
boost::split(
split_result, request.uri().path, boost::is_any_of("/"));
nfInstanceID = split_result[split_result.size() - 1].c_str();
this->update_instance_handler(nfInstanceID, patchItem, response);
}
// Deregisters a given NF Instance
if (request.method().compare("DELETE") == 0) {
std::vector<std::string> split_result;
boost::split(
split_result, request.uri().path, boost::is_any_of("/"));
nfInstanceID = split_result[split_result.size() - 1].c_str();
this->deregister_nf_instance_handler(nfInstanceID, response);
}
} catch (nlohmann::detail::exception& e) {
Logger::nrf_sbi().warn(
"Can not parse the json data (error: %s)!", e.what());
response.write_head(
http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST);
response.end();
return;
}
});
});
// Subscriptions (Collection & ID Document)
server.handle(
NNRF_NFM_BASE + nrf_cfg.sbi_api_version + NNRF_NFM_STATUS_SUBSCRIBE_URL,
[&](const request& request, const response& response) {
request.on_data([&](const uint8_t* data, std::size_t len) {
std::string msg((char*) data, len);
try {
// Create a new subscription
if (request.method().compare("POST") == 0 && len > 0) {
nlohmann::json::parse(msg.c_str()).get_to(subscriptionData);
this->create_subscription_handler(subscriptionData, response);
}
// Updates a subscription
if (request.method().compare("PATCH") == 0 && len > 0) {
std::vector<PatchItem> patchItem;
nlohmann::json::parse(msg.c_str()).get_to(patchItem);
std::vector<std::string> split_result;
boost::split(
split_result, request.uri().path, boost::is_any_of("/"));
subscriptionID = split_result[split_result.size() - 1].c_str();
this->update_subscription_handler(
subscriptionID, patchItem, response);
}
// Delete a subscription
if (request.method().compare("DELETE") == 0) {
std::vector<std::string> split_result;
boost::split(
split_result, request.uri().path, boost::is_any_of("/"));
subscriptionID = split_result[split_result.size() - 1].c_str();
this->remove_subscription_handler(subscriptionID, response);
}
} catch (nlohmann::detail::exception& e) {
Logger::nrf_sbi().warn(
"Can not parse the json data (error: %s)!", e.what());
response.write_head(
http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST);
response.end();
return;
}
});
});
// NF Discovery (Store)
server.handle(
NNRF_DISC_BASE + nrf_cfg.sbi_api_version + "/nf-instances",
[&](const request& request, const response& response) {
request.on_data([&](const uint8_t* data, std::size_t len) {
std::string msg((char*) data, len);
try {
// Search a collection of NF Instances
if (request.method().compare("GET") == 0) {
std::string split_query = request.uri().raw_query;
// Parse query paramaters
std::string nfTypeTarget =
util::get_query_param(split_query, "target-nf-type");
std::string nfTypeReq = util::get_query_param(
split_query.c_str(), "requester-nf-type");
std::string requester_nf_instance_id = util::get_query_param(
split_query.c_str(), "requester-nf-instance-id");
std::string limit_nfs =
util::get_query_param(split_query.c_str(), "limit");
// TODO: other query parameters
Logger::nrf_sbi().debug(
"/nnrf-disc/ query params - nfTypeTarget: %s, nfTypeReq: %s, "
"requester-nf-instance-id: %s, limit_nfs %s",
nfTypeTarget.c_str(), nfTypeReq.c_str(),
requester_nf_instance_id.c_str(), limit_nfs.c_str());
this->search_nf_instances_handler(
nfTypeTarget, nfTypeReq, requester_nf_instance_id, limit_nfs,
response);
}
} catch (nlohmann::detail::exception& e) {
Logger::nrf_sbi().warn(
"Can not parse the json data (error: %s)!", e.what());
response.write_head(
http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST);
response.end();
return;
}
});
});
if (server.listen_and_serve(ec, m_address, std::to_string(m_port))) {
std::cerr << "HTTP Server error: " << ec.message() << std::endl;
}
}
void nrf_http2_server::register_nf_instance_handler(
const NFProfile& NFProfiledata, const response& response) {
std::string nfInstanceID = {};
nfInstanceID = NFProfiledata.getNfInstanceId();
Logger::nrf_sbi().info(
"Got a request to register an NF instance/Update an NF instance, "
"Instance ID: %s",
nfInstanceID.c_str());
int http_code = 0;
ProblemDetails problem_details = {};
nlohmann::json json_data = {};
std::string content_type = "application/json";
std::string json_format;
m_nrf_app->handle_register_nf_instance(
nfInstanceID, NFProfiledata, http_code, 2, problem_details);
if ((http_code != HTTP_STATUS_CODE_200_OK) and
(http_code != HTTP_STATUS_CODE_201_CREATED) and
(http_code != HTTP_STATUS_CODE_202_ACCEPTED)) {
to_json(json_data, problem_details);
content_type = "application/problem+json";
} else {
std::shared_ptr<nrf_profile> profile =
m_nrf_app->find_nf_profile(nfInstanceID);
if (profile.get() != nullptr) {
profile.get()->to_json(json_data);
}
}
header_map h;
h.emplace(
"location",
header_value{m_address + NNRF_NFM_BASE + nrf_cfg.sbi_api_version +
"/nf-instances/" + nfInstanceID});
h.emplace("content-type", header_value{content_type});
response.write_head(http_code, h);
response.end(json_data.dump().c_str());
};
void nrf_http2_server::get_nf_instance_handler(
const std::string& nfInstanceID, const response& response) {
Logger::nrf_sbi().info(
"Got a request to retrieve the profile of a given NF Instance, Instance "
"ID: %s",
nfInstanceID.c_str());
int http_code = 0;
ProblemDetails problem_details = {};
nlohmann::json json_data = {};
std::string content_type = "application/json";
std::shared_ptr<nrf_profile> profile = {};
m_nrf_app->handle_get_nf_instance(
nfInstanceID, profile, http_code, 2, problem_details);
if (http_code != HTTP_STATUS_CODE_200_OK) {
to_json(json_data, problem_details);
content_type = "application/problem+json";
} else {
profile.get()->to_json(json_data);
}
header_map h;
h.emplace(
"location",
header_value{m_address + NNRF_NFM_BASE + nrf_cfg.sbi_api_version +
"/nf-instances/" + nfInstanceID});
h.emplace("content-type", header_value{content_type});
response.write_head(http_code, h);
response.end(json_data.dump().c_str());
}
void nrf_http2_server::get_nf_instances_handler(
const std::string& nf_type, const std::string& limit_nfs,
const response& response) {
Logger::nrf_sbi().info(
"Got a request to retrieve a collection of NF Instances");
std::string nfType = {};
if (!nf_type.empty()) {
nfType = nf_type;
Logger::nrf_sbi().debug("\tNF type: %s", nfType.c_str());
}
uint32_t limit_Nfs = 0;
if (!limit_nfs.empty()) {
limit_Nfs = stoi(limit_nfs);
Logger::nrf_sbi().debug(
"\tMaximum number of NFProfiles to be returned in the response: %d",
limit_Nfs);
}
int http_code = 0;
ProblemDetails problem_details = {};
nlohmann::json json_data = {};
std::string content_type = "application/json";
std::shared_ptr<nrf_profile> profile = {};
std::vector<std::string> uris = {};
m_nrf_app->handle_get_nf_instances(
nfType, uris, limit_Nfs, http_code, 2, problem_details);
if (http_code != HTTP_STATUS_CODE_200_OK) {
to_json(json_data, problem_details);
content_type = "application/problem+json";
} else {
profile.get()->to_json(json_data);
}
header_map h;
h.emplace(
"location", header_value{m_address + NNRF_NFM_BASE +
nrf_cfg.sbi_api_version + "/nf-instances/"});
h.emplace("content-type", header_value{content_type});
response.write_head(http_code, h);
response.end();
}
void nrf_http2_server::update_instance_handler(
const std::string& nfInstanceID, const std::vector<PatchItem>& patchItem,
const response& response) {
Logger::nrf_sbi().info("");
Logger::nrf_sbi().info(
"Got a request to update an NF instance, Instance ID: %s",
nfInstanceID.c_str());
int http_code = 0;
ProblemDetails problem_details = {};
m_nrf_app->handle_update_nf_instance(
nfInstanceID, patchItem, http_code, 2, problem_details);
nlohmann::json json_data = {};
std::string content_type = "application/json";
std::shared_ptr<nrf_profile> profile =
m_nrf_app->find_nf_profile(nfInstanceID);
if ((http_code != HTTP_STATUS_CODE_200_OK) and
(http_code != HTTP_STATUS_CODE_204_NO_CONTENT)) {
to_json(json_data, problem_details);
content_type = "application/problem+json";
} else if (http_code == HTTP_STATUS_CODE_200_OK) {
if (profile.get() != nullptr)
// convert the profile to Json
profile.get()->to_json(json_data);
}
Logger::nrf_sbi().debug("Json data: %s", json_data.dump().c_str());
header_map h;
h.emplace(
"location",
header_value{m_address + NNRF_NFM_BASE + nrf_cfg.sbi_api_version +
"/nf-instances/" + nfInstanceID});
h.emplace("content-type", header_value{content_type});
response.write_head(http_code, h);
response.end(json_data.dump().c_str());
}
void nrf_http2_server::deregister_nf_instance_handler(
const std::string& nfInstanceID, const response& response) {
Logger::nrf_sbi().info(
"Got a request to de-register a given NF Instance, Instance ID: %s",
nfInstanceID.c_str());
int http_code = 0;
ProblemDetails problem_details = {};
nlohmann::json json_data = {};
std::string content_type = "application/json";
m_nrf_app->handle_deregister_nf_instance(
nfInstanceID, http_code, 2, problem_details);
header_map h;
h.emplace(
"location",
header_value{m_address + NNRF_NFM_BASE + nrf_cfg.sbi_api_version +
"/nf-instances/" + nfInstanceID});
h.emplace("content-type", header_value{content_type});
response.write_head(http_code, h);
response.end();
};
void nrf_http2_server::create_subscription_handler(
const SubscriptionData& subscriptionData, const response& response) {
Logger::nrf_sbi().info("Got a request to create a new subscription");
int http_code = 0;
ProblemDetails problem_details = {};
std::string sub_id;
nlohmann::json json_sub = {};
nlohmann::json json_data = {};
std::string content_type = "application/json";
Logger::nrf_sbi().debug("Subscription data %s", json_sub.dump().c_str());
m_nrf_app->handle_create_subscription(
subscriptionData, sub_id, http_code, 2, problem_details);
if (http_code != HTTP_STATUS_CODE_201_CREATED) {
to_json(json_data, problem_details);
content_type = "application/problem+json";
} else {
to_json(json_data, subscriptionData);
json_data["subscriptionId"] = sub_id;
}
header_map h;
h.emplace(
"location",
header_value{m_address + NNRF_NFM_BASE + nrf_cfg.sbi_api_version +
NNRF_NFM_STATUS_SUBSCRIBE_URL});
h.emplace("content-type", header_value{content_type});
response.write_head(http_code, h);
response.end(json_data.dump().c_str());
};
void nrf_http2_server::update_subscription_handler(
const std::string& subscriptionID, const std::vector<PatchItem>& patchItem,
const response& response) {
Logger::nrf_sbi().info(
"Got a request to update of subscription to NF instances, subscription "
"ID %s",
subscriptionID.c_str());
int http_code = 0;
ProblemDetails problem_details = {};
nlohmann::json json_data = {};
std::string content_type = "application/json";
m_nrf_app->handle_update_subscription(
subscriptionID, patchItem, http_code, 1, problem_details);
// TODO: (section 5.2.2.5.6, Update of Subscription to NF Instances,
// 3GPP TS 29.510 V16.0.0 (2019-06)) if the NRF accepts the extension
// of the lifetime of the subscription, but it assigns a validity time
// different than the value suggested by the NF Service Consumer, a
// "200 OK" response code shall be returned
header_map h;
h.emplace("content-type", header_value{content_type});
if (http_code != HTTP_STATUS_CODE_204_NO_CONTENT) {
to_json(json_data, problem_details);
response.write_head(http_code, h);
response.end(json_data.dump().c_str());
} else {
response.write_head(http_code, h);
response.end();
}
}
void nrf_http2_server::remove_subscription_handler(
const std::string& subscriptionID, const response& response) {
Logger::nrf_sbi().info(
"Got a request to remove an existing subscription, subscription ID %s",
subscriptionID.c_str());
int http_code = 0;
ProblemDetails problem_details = {};
nlohmann::json json_data = {};
std::string content_type = "application/json";
m_nrf_app->handle_remove_subscription(
subscriptionID, http_code, 2, problem_details);
header_map h;
h.emplace("content-type", header_value{content_type});
if (http_code != HTTP_STATUS_CODE_204_NO_CONTENT) {
to_json(json_data, problem_details);
response.write_head(http_code, h);
response.end(json_data.dump().c_str());
} else {
response.write_head(http_code, h);
response.end();
}
}
void nrf_http2_server::search_nf_instances_handler(
const std::string& target_nf_type, const std::string& requester_nf_type,
const std::string& requester_nf_instance_id, const std::string& limit_nfs,
const response& response) {
Logger::nrf_sbi().info(
"Got a request to discover the set of NF instances that satisfies a "
"number of input query parameters");
std::string target_nfType = {};
if (!target_nf_type.empty()) {
target_nfType = target_nf_type;
Logger::nrf_sbi().debug("\tTarget NF type: %s", target_nfType.c_str());
}
std::string requester_nfType = {};
if (!requester_nf_type.empty()) {
requester_nfType = requester_nf_type;
Logger::nrf_sbi().debug(
"\tRequested NF type: %s", requester_nfType.c_str());
}
std::string requester_nfInstance_id = {};
if (!requester_nf_instance_id.empty()) {
requester_nfInstance_id = requester_nf_instance_id;
Logger::nrf_sbi().debug(
"\tRequested NF instance id: %s", requester_nf_instance_id.c_str());
}
uint32_t limit_Nfs = 0;
if (!limit_nfs.empty()) {
limit_Nfs = stoi(limit_nfs);
Logger::nrf_sbi().debug(
"\tMaximum number of NFProfiles to be returned in the response: %d",
limit_Nfs);
}
// TODO: other query parameters
int http_code = 0;
ProblemDetails problem_details = {};
std::string search_id = {};
m_nrf_app->handle_search_nf_instances(
target_nfType, requester_nfType, requester_nfInstance_id, limit_Nfs,
search_id, http_code, 2, problem_details);
nlohmann::json json_data = {};
std::string content_type = "application/json";
std::shared_ptr<nrf_search_result> search_result = {};
m_nrf_app->find_search_result(search_id, search_result);
if (http_code != HTTP_STATUS_CODE_200_OK) {
to_json(json_data, problem_details);
content_type = "application/problem+json";
} else {
// convert the profile to Json
if (search_result != nullptr)
search_result.get()->to_json(json_data, limit_Nfs);
}
// TODO: applying client restrictions in terms of the number of
// instances to be returned (i.e. "limit" or "max-
// payload-size" query parameters) .
Logger::nrf_sbi().debug("Json data: %s", json_data.dump().c_str());
header_map h;
h.emplace("content-type", header_value{content_type});
response.write_head(http_code, h);
response.end(json_data.dump().c_str());
}
void nrf_http2_server::access_token_request_handler(
const SubscriptionData& subscriptionData, const response& response) {}
//------------------------------------------------------------------------------
void nrf_http2_server::stop() {
server.stop();
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file smf_http2-server.h
\brief
\author Tien-Thinh NGUYEN
\company Eurecom
\date 2020
\email: tien-thinh.nguyen@eurecom.fr
*/
#ifndef FILE_NRF_HTTP2_SERVER_SEEN
#define FILE_NRF_HTTP2_SERVER_SEEN
#include "conversions.hpp"
//#include "nrf.h"
#include "nrf_app.hpp"
#include "uint_generator.hpp"
#include <nghttp2/asio_http2_server.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
using namespace oai::nrf::model;
using namespace oai::nrf::app;
class nrf_http2_server {
public:
nrf_http2_server(std::string addr, uint32_t port, nrf_app* nrf_app_inst)
: m_address(addr), m_port(port), server(), m_nrf_app(nrf_app_inst) {}
void start();
void init(size_t thr) {}
void register_nf_instance_handler(
const NFProfile& NFProfiledata, const response& response);
void deregister_nf_instance_handler(
const std::string& nfInstanceID, const response& response);
void get_nf_instance_handler(
const std::string& nfInstanceID, const response& response);
void get_nf_instances_handler(
const std::string& nf_type, const std::string& limit_nfs,
const response& response);
void update_instance_handler(
const std::string& nfInstanceID, const std::vector<PatchItem>& patchItem,
const response& response);
void create_subscription_handler(
const SubscriptionData& subscriptionData, const response& response);
void update_subscription_handler(
const std::string& subscriptionID,
const std::vector<PatchItem>& patchItem, const response& response);
void remove_subscription_handler(
const std::string& subscriptionID, const response& response);
void search_nf_instances_handler(
const std::string& target_nf_type, const std::string& requester_nf_type,
const std::string& requester_nf_instance_id, const std::string& limit_nfs,
const response& response);
void access_token_request_handler(
const SubscriptionData& subscriptionData, const response& response);
void stop();
private:
util::uint_generator<uint32_t> m_promise_id_generator;
std::string m_address;
uint32_t m_port;
http2 server;
nrf_app* m_nrf_app;
protected:
static uint64_t generate_promise_id() {
return util::uint_uid_generator<uint64_t>::get_instance().get_uid();
}
};
#endif
......@@ -77,7 +77,9 @@ typedef uint32_t evsub_id_t;
#define UNASSIGNED_EVSUB_ID ((evsub_id_t) 0x00000000)
#define NNRF_NFM_BASE "/nnrf-nfm/"
#define NNRF_NFM_NF_INSTANCE "/nf-instances/"
#define NNRF_DISC_BASE "/nnrf-disc/"
#define NNRF_NFM_NF_INSTANCES "/nf-instances/"
#define NNRF_NFM_STATUS_SUBSCRIBE_URL "/subscriptions"
#define NF_CURL_TIMEOUT_MS 1000L
......
......@@ -92,3 +92,15 @@ int conv::ascii_to_hex(uint8_t* dst, const char* h) {
dst[i++] = (high << 4) | low;
}
}
std::string conv::toString(const struct in_addr& inaddr) {
std::string s = {};
char str[INET6_ADDRSTRLEN] = {};
if (inet_ntop(AF_INET, (const void*) &inaddr, str, INET6_ADDRSTRLEN) ==
NULL) {
s.append("Error in_addr");
} else {
s.append(str);
}
return s;
}
\ No newline at end of file
......@@ -19,12 +19,14 @@
* contact@openairinterface.org
*/
#include "string.hpp"
#include <iostream>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
#include <stdarg.h>
#include <regex>
template<class T>
class Buffer {
......@@ -86,3 +88,20 @@ std::string& util::rtrim(std::string& s) {
std::string& util::trim(std::string& s) {
return util::ltrim(util::rtrim(s));
}
// extract query param from given querystring
std::string query_param_tmp;
//
std::string util::get_query_param(std::string querystring, std::string param) {
std::regex reList("([^=]*)=([^&]*)&?");
query_param_tmp.clear();
std::for_each(
std::sregex_iterator(querystring.begin(), querystring.end(), reList),
std::sregex_iterator(), [param](std::smatch match) {
if (match[1] == param) {
query_param_tmp = match[2].str().c_str();
return;
}
});
return query_param_tmp;
}
\ No newline at end of file
......@@ -39,5 +39,7 @@ std::string& ltrim(std::string& s);
std::string& rtrim(std::string& s);
// trim from both ends
std::string& trim(std::string& s);
// extract query param from given querystring
std::string get_query_param(std::string querystring, std::string param);
} // namespace util
#endif
......@@ -436,7 +436,7 @@ void nrf_app::handle_create_subscription(
// generate a subscription ID
generate_ev_subscription_id(evsub_id);
ss.get()->set_subscription_id(evsub_id);
ss.get()->set_http_version(http_version);
// subscribe to NF status registered
// subscribe_nf_status(evsub_id); // from nrf_app
// subscribe to NF status
......@@ -475,7 +475,8 @@ void nrf_app::handle_create_subscription(
for (auto p : profiles) {
// send notifications
nrf_client_inst->notify_subscribed_event(
p, NOTIFICATION_TYPE_NF_REGISTERED, notification_uris);
p, NOTIFICATION_TYPE_NF_REGISTERED, notification_uris,
http_version);
}
}
......@@ -1029,12 +1030,15 @@ void nrf_app::handle_nf_status_registered(const std::string& profile_id) {
find_nf_profile(profile_id, profile);
if (profile.get() != nullptr) {
std::vector<std::string> notification_uris = {};
uint8_t httpVersion = 1;
get_subscription_list(
profile_id, NOTIFICATION_TYPE_NF_REGISTERED, notification_uris);
profile_id, NOTIFICATION_TYPE_NF_REGISTERED, notification_uris,
httpVersion);
// send notifications
if (notification_uris.size() > 0)
nrf_client_inst->notify_subscribed_event(
profile, NOTIFICATION_TYPE_NF_REGISTERED, notification_uris);
profile, NOTIFICATION_TYPE_NF_REGISTERED, notification_uris,
httpVersion);
else
Logger::nrf_app().debug("\tNo subscription found");
......@@ -1060,13 +1064,14 @@ void nrf_app::handle_nf_status_deregistered(
p.get()->get_nf_instance_id().c_str());
std::vector<std::string> notification_uris = {};
uint8_t http_version = 1;
get_subscription_list(
p.get()->get_nf_instance_id(), NOTIFICATION_TYPE_NF_DEREGISTERED,
notification_uris);
notification_uris, http_version);
// send notifications
if (notification_uris.size() > 0)
nrf_client_inst->notify_subscribed_event(
p, NOTIFICATION_TYPE_NF_DEREGISTERED, notification_uris);
p, NOTIFICATION_TYPE_NF_DEREGISTERED, notification_uris, http_version);
else
Logger::nrf_app().debug("\tNo subscription found");
}
......@@ -1089,14 +1094,17 @@ void nrf_app::handle_nf_status_profile_changed(const std::string& profile_id) {
find_nf_profile(profile_id, profile);
if (profile.get() != nullptr) {
std::vector<std::string> notification_uris = {};
uint8_t http_version = 1;
get_subscription_list(
profile_id, NOTIFICATION_TYPE_NF_PROFILE_CHANGED, notification_uris);
profile_id, NOTIFICATION_TYPE_NF_PROFILE_CHANGED, notification_uris,
http_version);
// Notification data includes NF profile (other alternative, includes
// profile_changes)
// send notifications
if (notification_uris.size() > 0)
nrf_client_inst->notify_subscribed_event(
profile, NOTIFICATION_TYPE_NF_PROFILE_CHANGED, notification_uris);
profile, NOTIFICATION_TYPE_NF_PROFILE_CHANGED, notification_uris,
http_version);
else
Logger::nrf_app().debug("\tNo subscription found");
} else {
......@@ -1108,7 +1116,7 @@ void nrf_app::handle_nf_status_profile_changed(const std::string& profile_id) {
//------------------------------------------------------------------------------
void nrf_app::get_subscription_list(
const std::string& profile_id, const uint8_t& notification_type,
std::vector<std::string>& uris) const {
std::vector<std::string>& uris, uint8_t& http_version) const {
Logger::nrf_app().info(
"\tGet the list of subscriptions related to this profile, profile id %s",
profile_id.c_str());
......@@ -1127,6 +1135,8 @@ void nrf_app::get_subscription_list(
std::string uri;
s.second.get()->get_notification_uri(uri);
http_version = s.second.get()->get_http_version();
// check notification event type
bool match_notif_type = false;
for (auto i : s.second.get()->get_notif_events()) {
......
......@@ -409,7 +409,7 @@ class nrf_app {
*/
void get_subscription_list(
const std::string& profile_id, const uint8_t& notification_type,
std::vector<std::string>& uris) const;
std::vector<std::string>& uris, uint8_t& http_version) const;
/*
* Verify whether the requester is allowed to discover the NF services
......
......@@ -88,8 +88,8 @@ nrf_client::~nrf_client() {
//------------------------------------------------------------------------------
CURL* nrf_client::curl_create_handle(
const std::string& uri, const std::string& data,
std::string& response_data) {
const std::string& uri, const std::string& data, std::string& response_data,
uint8_t http_version) {
// create handle for a curl request
CURL* curl = curl_easy_init();
......@@ -106,17 +106,26 @@ CURL* nrf_client::curl_create_handle(
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.length());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
if (http_version == 2) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// curl_easy_setopt(curl, CURLOPT_PORT, 8080);
// We use a self-signed test server, skip verification during debugging
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(
curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
}
}
return curl;
}
//------------------------------------------------------------------------------
void nrf_client::send_curl_multi(
const std::string& uri, const std::string& data,
std::string& response_data) {
const std::string& uri, const std::string& data, std::string& response_data,
uint8_t http_version) {
// create a new handle and add to the multi handle
// the curl will actually be sent in perform_curl_multi
CURL* tmp = curl_create_handle(uri, data, response_data);
CURL* tmp = curl_create_handle(uri, data, response_data, http_version);
curl_multi_add_handle(curl_multi, tmp);
handles.push_back(tmp);
}
......@@ -209,9 +218,11 @@ void nrf_client::curl_release_handles() {
//------------------------------------------------------------------------------
void nrf_client::notify_subscribed_event(
const std::shared_ptr<nrf_profile>& profile, const uint8_t& event_type,
const std::vector<std::string>& uris) {
const std::vector<std::string>& uris, uint8_t http_version) {
Logger::nrf_app().debug(
"Send notification for the subscribed event to the subscriptions");
"Send notification for the subscribed event to the subscriptions (HTTP "
"VERSION %d)",
http_version);
std::map<std::string, std::string> responses = {};
// Fill the json part
......@@ -259,7 +270,7 @@ void nrf_client::notify_subscribed_event(
for (auto uri : uris) {
responses[uri] = "";
std::unique_ptr<std::string> httpData(new std::string());
send_curl_multi(uri, body, responses[uri]);
send_curl_multi(uri, body, responses[uri], http_version);
}
perform_curl_multi(
......
......@@ -64,7 +64,7 @@ class nrf_client {
*/
void notify_subscribed_event(
const std::shared_ptr<nrf_profile>& profile, const uint8_t& event_type,
const std::vector<std::string>& uris);
const std::vector<std::string>& uris, uint8_t http_version);
/*
* Create Curl handle for multi curl
......@@ -75,7 +75,7 @@ class nrf_client {
*/
CURL* curl_create_handle(
const std::string& uri, const std::string& data,
std::string& response_data);
std::string& response_data, uint8_t http_version);
/*
* Prepare to send a request using curl multi
......@@ -86,7 +86,7 @@ class nrf_client {
*/
void send_curl_multi(
const std::string& uri, const std::string& data,
std::string& response_data);
std::string& response_data, uint8_t http_version);
/*
* Perform curl multi to actually process the available data
......
......@@ -115,6 +115,16 @@ boost::posix_time::ptime nrf_subscription::get_validity_time() const {
return validity_time;
}
//------------------------------------------------------------------------------
void nrf_subscription::set_http_version(const uint8_t& httpVersion) {
http_version = httpVersion;
}
//------------------------------------------------------------------------------
uint8_t nrf_subscription::get_http_version() const {
return http_version;
}
//------------------------------------------------------------------------------
void nrf_subscription::display() {
Logger::nrf_app().debug("Subscription information");
......
......@@ -157,7 +157,19 @@ class nrf_subscription {
* @return [boost::posix_time::ptime &] validity time
*/
boost::posix_time::ptime get_validity_time() const;
/*
* Set the http_version
* @param [uint8_t&]: http_version: http_version
* @return void
*/
void set_http_version(const uint8_t& http_version);
/*
* Get the http_version
* @param [void]
* @return http_version
*/
uint8_t get_http_version() const;
/*
* Subscribe to be notified when a new NF registered to the NRF
* @param void
......@@ -188,6 +200,7 @@ class nrf_subscription {
nrf_event& m_event_sub;
bs2::connection ev_connection;
boost::posix_time::ptime validity_time;
uint8_t http_version = 1;
};
} // namespace app
} // namespace nrf
......
......@@ -16,10 +16,12 @@
#include "logger.hpp"
#include "nrf-api-server.h"
#include "nrf-http2-server.h"
#include "nrf_app.hpp"
#include "nrf_client.hpp"
#include "options.hpp"
#include "pid_file.hpp"
#include "conversions.hpp"
#include "pistache/endpoint.h"
#include "pistache/http.h"
......@@ -39,6 +41,7 @@ using namespace std;
nrf_app* nrf_app_inst = nullptr;
nrf_config nrf_cfg;
NRFApiServer* api_server = nullptr;
nrf_http2_server* nrf_api_server_2 = nullptr;
//------------------------------------------------------------------------------
void my_app_signal_handler(int s) {
......@@ -112,7 +115,14 @@ int main(int argc, char** argv) {
api_server = new NRFApiServer(addr, nrf_app_inst);
api_server->init(2);
std::thread nrf_manager(&NRFApiServer::start, api_server);
// NRF NGHTTP API server (HTTP2)
nrf_api_server_2 = new nrf_http2_server(
conv::toString(nrf_cfg.sbi.addr4), nrf_cfg.sbi_http2_port, nrf_app_inst);
std::thread nrf_http2_manager(&nrf_http2_server::start, nrf_api_server_2);
nrf_manager.join();
nrf_http2_manager.join();
FILE* fp = NULL;
std::string filename = fmt::format("/tmp/nrf_{}.status", getpid());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment