Commit 9d95c753 authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen

use a simple parser for Mime/related part

parent 502f5ade
......@@ -43,10 +43,7 @@
#include "logger.hpp"
#include "Helpers.h"
extern "C" {
#include "multipartparser.h"
#include "dynamic_memory_check.h"
}
#include "simple_parser.hpp"
namespace oai {
namespace smf_server {
......@@ -141,91 +138,39 @@ void IndividualSMContextApi::update_sm_context_handler(
Logger::smf_api_server().info(
"Received a SM context update request from AMF.");
Logger::smf_api_server().debug("Request body: %s\n", request.body().c_str());
//find boundary
std::size_t found = request.body().find("Content-Type");
std::string boundary_str = request.body().substr(2, found - 4);
Logger::smf_api_server().debug("Boundary: %s", boundary_str.c_str());
SmContextUpdateMessage smContextUpdateMessage = { };
//step 1. use multipartparser to decode the request
multipartparser_callbacks_init(&g_callbacks);
g_callbacks.on_body_begin = &on_body_begin;
g_callbacks.on_part_begin = &on_part_begin;
g_callbacks.on_header_field = &on_header_field;
g_callbacks.on_header_value = &on_header_value;
g_callbacks.on_headers_complete = &on_headers_complete;
g_callbacks.on_data = &on_data;
g_callbacks.on_part_end = &on_part_end;
g_callbacks.on_body_end = &on_body_end;
multipartparser parser = { };
init_globals();
multipartparser_init(&parser,
reinterpret_cast<const char*>(boundary_str.c_str()));
unsigned int str_len = request.body().length();
unsigned char *data = (unsigned char*) malloc(str_len + 1);
memset(data, 0, str_len + 1);
memcpy((void*) data, (void*) request.body().c_str(), str_len);
//if ((multipartparser_execute(&parser, &g_callbacks, request.body().c_str(), strlen(request.body().c_str())) != strlen(request.body().c_str())) or (!g_body_begin_called)){
if ((multipartparser_execute(&parser, &g_callbacks,
reinterpret_cast<const char*>(data), str_len)
!= strlen(request.body().c_str())) or (!g_body_begin_called)) {
Logger::smf_api_server().debug(
"The received message can not be parsed properly!");
//TODO: fix this issue
//response.send(Pistache::Http::Code::Bad_Request, "");
//return;
}
//simple parser
simple_parser sp = { };
sp.parse(request.body());
free_wrapper((void**) &data);
uint8_t size = g_parts.size();
Logger::smf_api_server().debug("Number of MIME parts %d", g_parts.size());
part p0 = { };
part p1 = { };
if (size > 0) {
p0 = g_parts.front();
g_parts.pop_front();
Logger::smf_api_server().debug("Request body, part 1: %s", p0.body.c_str());
}
if (size > 1) {
p1 = g_parts.front();
g_parts.pop_front();
Logger::smf_api_server().debug("Request body, part 2: %s (%d bytes)",
p1.body.c_str(), p1.body.length());
//part p2 = g_parts.front(); g_parts.pop_front();
//Logger::smf_api_server().debug("Request body, part 3: \n %s",p2.body.c_str());
}
std::vector<mime_part> parts = { };
sp.get_mime_parts(parts);
uint8_t size = parts.size();
Logger::smf_api_server().debug("Number of MIME parts %d", size);
// Getting the body param
SmContextUpdateData smContextUpdateData = { };
try {
if (size > 0) {
nlohmann::json::parse(p0.body.c_str()).get_to(smContextUpdateData);
nlohmann::json::parse(parts[0].body.c_str()).get_to(smContextUpdateData);
} else {
nlohmann::json::parse(request.body().c_str()).get_to(smContextUpdateData);
}
smContextUpdateMessage.setJsonData(smContextUpdateData);
if (size > 1) {
if (smContextUpdateData.n2SmInfoIsSet()) {
//N2 SM (for Session establishment, or for session modification)
Logger::smf_api_server().debug("N2 SM information is set");
smContextUpdateMessage.setBinaryDataN2SmInformation(p1.body);
}
if (smContextUpdateData.n1SmMsgIsSet()) {
//N1 SM (for session modification, UE-initiated)
for (int i = 1; i < size; i++) {
if (parts[i].content_type.compare("application/vnd.3gpp.5gnas") == 0) {
smContextUpdateMessage.setBinaryDataN1SmMessage(parts[i].body);
Logger::smf_api_server().debug("N1 SM message is set");
smContextUpdateMessage.setBinaryDataN1SmMessage(p1.body);
} else if (parts[i].content_type.compare("application/vnd.3gpp.ngap")
== 0) {
smContextUpdateMessage.setBinaryDataN2SmInformation(parts[i].body);
Logger::smf_api_server().debug("N2 SM information is set");
}
}
// Getting the path params
auto smContextRef = request.param(":smContextRef").as<std::string>();
this->update_sm_context(smContextRef, smContextUpdateMessage, response);
......
......@@ -43,8 +43,9 @@
#include "logger.hpp"
#include "Helpers.h"
#include "simple_parser.hpp"
extern "C" {
#include "multipartparser.h"
#include "dynamic_memory_check.h"
}
......@@ -85,77 +86,34 @@ void SMContextsCollectionApi::post_sm_contexts_handler(
Logger::smf_api_server().debug("");
Logger::smf_api_server().info(
"Received a SM context create request from AMF.");
Logger::smf_api_server().debug("Request body: %s", request.body().c_str());
//find boundary
std::size_t found = request.body().find("Content-Type");
std::string boundary_str = request.body().substr(2, found - 4);
Logger::smf_api_server().debug("Boundary: %s", boundary_str.c_str());
SmContextMessage smContextMessage = { };
SmContextCreateData smContextCreateData = { };
//step 1. use multipartparser to decode the request
multipartparser_callbacks_init(&g_callbacks);
g_callbacks.on_body_begin = &on_body_begin;
g_callbacks.on_part_begin = &on_part_begin;
g_callbacks.on_header_field = &on_header_field;
g_callbacks.on_header_value = &on_header_value;
g_callbacks.on_headers_complete = &on_headers_complete;
g_callbacks.on_data = &on_data;
g_callbacks.on_part_end = &on_part_end;
g_callbacks.on_body_end = &on_body_end;
multipartparser parser = { };
init_globals();
multipartparser_init(&parser,
reinterpret_cast<const char*>(boundary_str.c_str()));
unsigned int str_len = request.body().length();
unsigned char *data = (unsigned char*) malloc(str_len + 1);
memset(data, 0, str_len + 1);
memcpy((void*) data, (void*) request.body().c_str(), str_len);
//if ((multipartparser_execute(&parser, &g_callbacks, request.body().c_str(), strlen(request.body().c_str())) != strlen(request.body().c_str())) or (!g_body_begin_called)){
if ((multipartparser_execute(&parser, &g_callbacks,
reinterpret_cast<const char*>(data), str_len)
!= strlen(request.body().c_str())) or (!g_body_begin_called)) {
Logger::smf_api_server().debug(
"The received message can not be parsed properly!");
//TODO: fix this issue
//response.send(Pistache::Http::Code::Bad_Request, "");
//return;
}
free_wrapper((void**) &data);
//simple parser
simple_parser sp = { };
sp.parse(request.body());
uint8_t size = g_parts.size();
Logger::smf_api_server().debug("Number of MIME parts %d", g_parts.size());
std::vector<mime_part> parts = { };
sp.get_mime_parts(parts);
uint8_t size = parts.size();
Logger::smf_api_server().debug("Number of MIME parts %d", size);
//at least 2 parts for Json data and N1 (+ N2)
if (g_parts.size() < 2) {
if (size < 2) {
response.send(Pistache::Http::Code::Bad_Request, "");
return;
}
part p0 = g_parts.front();
g_parts.pop_front();
Logger::smf_api_server().debug("Request body, part 1: \n%s", p0.body.c_str());
part p1 = g_parts.front();
g_parts.pop_front();
Logger::smf_api_server().debug("Request body, part 2: \n %s",
p1.body.c_str());
if (g_parts.size() > 0) {
part p2 = g_parts.front();
g_parts.pop_front();
Logger::smf_api_server().debug("Request body, part 3: \n %s",
p2.body.c_str());
}
//step 2. process the request
try {
nlohmann::json::parse(p0.body.c_str()).get_to(smContextCreateData);
nlohmann::json::parse(parts[0].body.c_str()).get_to(smContextCreateData);
smContextMessage.setJsonData(smContextCreateData);
smContextMessage.setBinaryDataN1SmMessage(p1.body);
if (parts[1].content_type.compare("application/vnd.3gpp.5gnas") == 0) {
smContextMessage.setBinaryDataN1SmMessage(parts[1].body);
} else if (parts[1].content_type.compare("application/vnd.3gpp.ngap")
== 0) {
smContextMessage.setBinaryDataN2SmInformation(parts[1].body);
}
this->post_sm_contexts(smContextMessage, response);
} catch (nlohmann::detail::exception &e) {
//send a 400 error
......
/*
* 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 Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* 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
*/
#ifndef FILE_AMF_SEEN
#define FILE_AMF_SEEN
#endif
......@@ -36,6 +36,7 @@ set(CN_UTILS_SRC STATIC
${CMAKE_CURRENT_SOURCE_DIR}/pid_file.cpp
${CMAKE_CURRENT_SOURCE_DIR}/string.cpp
${CMAKE_CURRENT_SOURCE_DIR}/thread_sched.cpp
${CMAKE_CURRENT_SOURCE_DIR}/simple_parser.cpp
)
......
/* From https://gist.github.com/javiermon/6272065#file-gateway_netlink-c */
/*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#include "simple_parser.hpp"
#include "logger.hpp"
bool simple_parser::parse(const std::string &str) {
std::string CRLF = "\r\n";
Logger::smf_app().debug("");
Logger::smf_app().debug("Simple parser, parsing a string:");
Logger::smf_app().debug("%s", str.c_str());
//find boundary
std::size_t content_type_pos = str.find("Content-Type"); //first part
if ((content_type_pos <= 4) or (content_type_pos == std::string::npos))
return false;
std::string boundary_str = str.substr(2, content_type_pos - 4); // 2 for -- and 2 for CRLF
Logger::smf_app().debug("Boundary: %s", boundary_str.c_str());
std::string boundary_full = "--" + boundary_str + CRLF;
std::string last_boundary = "--" + boundary_str + "--" + CRLF;
std::size_t crlf_pos = str.find(CRLF, content_type_pos);
std::size_t boundary_pos = str.find(boundary_full);
std::size_t boundary_last_post = str.find(last_boundary);
while (boundary_pos < boundary_last_post) {
mime_part p = { };
content_type_pos = str.find("Content-Type", boundary_pos);
crlf_pos = str.find(CRLF, content_type_pos);
if ((content_type_pos == std::string::npos)
or (crlf_pos == std::string::npos))
break;
p.content_type = str.substr(content_type_pos + 14,
crlf_pos - (content_type_pos + 14));
Logger::smf_app().debug("Content Type: %s", p.content_type.c_str());
crlf_pos = str.find(CRLF + CRLF, content_type_pos); //beginning of content
boundary_pos = str.find(boundary_full, crlf_pos);
if (boundary_pos == std::string::npos) {
boundary_pos = str.find(last_boundary, crlf_pos);
}
if (boundary_pos > 0) {
p.body = str.substr(crlf_pos + 4, boundary_pos - 2 - (crlf_pos + 4));
Logger::smf_app().debug("Body: %s", p.body.c_str());
mime_parts.push_back(p);
}
}
return true;
}
void simple_parser::get_mime_parts(std::vector<mime_part> &parts) const {
for (auto it : mime_parts) {
parts.push_back(it);
}
}
/*
* 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 Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* 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 simple_parser.hpp
\brief
\author
\company Eurecom
\email:
*/
#ifndef FILE_SIMPLE_PARSER_HPP_SEEN
#define FILE_SIMPLE_PARSER_HPP_SEEN
# include <string>
#include <map>
#include <vector>
typedef struct mime_part {
std::string content_type;
std::string body;
} mime_part;
class simple_parser {
public:
bool parse(const std::string &str);
void get_mime_parts(std::vector<mime_part> &parts) const;
private:
std::vector<mime_part> mime_parts;
};
#endif /* FILE_SIMPLE_PARSER_HPP_SEEN */
......@@ -419,7 +419,6 @@ void send_pdu_session_modification_request_step1(std::string smf_ip_address) {
ENCODE_U8(buffer + size, 0x01, size); //QoS Rules
ENCODE_U8(buffer + size, 0x06, size); //QoS Rules
std::cout << "Buffer: " << std::endl;
for (int i = 0; i < size; i++) {
printf("%02x ", buffer[i]);
......@@ -1241,11 +1240,14 @@ int main(int argc, char *argv[]) {
usleep(200000);
send_pdu_session_update_sm_context_ue_service_request_step2(smf_ip_address);
usleep(200000);
/*
//PDU Session Modification
send_pdu_session_modification_request_step1(smf_ip_address);
usleep(200000);
send_pdu_session_modification_request_step2(smf_ip_address);
usleep(200000);
send_pdu_session_modification_complete(smf_ip_address);
usleep(200000);
//PDU Session Release procedure
send_pdu_session_release_request(smf_ip_address);
usleep(200000);
......@@ -1253,7 +1255,7 @@ int main(int argc, char *argv[]) {
usleep(200000);
send_pdu_session_release_complete(smf_ip_address);
usleep(200000);
//Release SM context
*/ //Release SM context
//send_release_sm_context_request(smf_ip_address);
return 0;
}
......
This diff is collapsed.
/*
* https://github.com/iafonov/multipart-parser-c
*/
#ifndef MULTIPARTPARSER_H
#define MULTIPARTPARSER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
typedef struct multipartparser multipartparser;
typedef struct multipartparser_callbacks multipartparser_callbacks;
typedef int (*multipart_cb) (multipartparser*);
typedef int (*multipart_data_cb) (multipartparser*, const char* data, size_t size);
struct multipartparser {
/** PRIVATE **/
char boundary[70];
int boundary_length;
int index;
uint16_t state;
/** PUBLIC **/
void* data;
};
struct multipartparser_callbacks {
multipart_cb on_body_begin;
multipart_cb on_part_begin;
multipart_data_cb on_header_field;
multipart_data_cb on_header_value;
multipart_cb on_headers_complete;
multipart_data_cb on_data;
multipart_cb on_part_end;
multipart_cb on_body_end;
};
void multipartparser_init(multipartparser* parser, const char* boundary);
void multipartparser_callbacks_init(multipartparser_callbacks* callbacks);
size_t multipartparser_execute(multipartparser* parser,
multipartparser_callbacks* callbacks,
const char* data,
size_t size);
#ifdef __cplusplus
}
#define BOUNDARY "----Boundary"
typedef struct part {
std::map<std::string,std::string> headers;
std::string body;
} part;
static multipartparser_callbacks g_callbacks;
static bool g_body_begin_called;
static std::string g_header_name;
static std::string g_header_value;
static std::list<part> g_parts;
static bool g_body_end_called;
static void init_globals()
{
g_body_begin_called = false;
g_header_name.clear();
g_header_value.clear();
g_parts.clear();
g_body_end_called = false;
}
static int on_body_begin(multipartparser* /*parser*/)
{
g_body_begin_called = true;
return 0;
}
static int on_part_begin(multipartparser* /*parser*/)
{
g_parts.push_back(part());
return 0;
}
static void on_header_done()
{
g_parts.back().headers[g_header_name] = g_header_value;
g_header_name.clear();
g_header_value.clear();
}
static int on_header_field(multipartparser* /*parser*/, const char* data, size_t size)
{
if (g_header_value.size() > 0)
on_header_done();
g_header_name.append(data, size);
return 0;
}
static int on_header_value(multipartparser* /*parser*/, const char* data, size_t size)
{
g_header_value.append(data, size);
return 0;
}
static int on_headers_complete(multipartparser* /*parser*/)
{
if (g_header_value.size() > 0)
on_header_done();
return 0;
}
static int on_data(multipartparser* /*parser*/, const char* data, size_t size)
{
std::string str;
//g_parts.back().body.append(data, size);
for(int i = 0;i < size; i++)
{
//printf("%02x ",data[i]);
str.push_back(data[i]);
}
g_parts.back().body.append(str);
return 0;
}
static int on_part_end(multipartparser* /*parser*/)
{
return 0;
}
static int on_body_end(multipartparser* /*parser*/)
{
g_body_end_called = true;
return 0;
}
#endif
#endif // MULTIPARTPARSER_H
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