Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-AMF
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenXG
OpenXG-AMF
Commits
a5e65b39
Commit
a5e65b39
authored
Jul 28, 2020
by
Tien-Thinh Nguyen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use a simple Mime parser instead of multipartparser
parent
824102f8
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
318 additions
and
573 deletions
+318
-573
src/sbi/amf_server/api/N1N2MessageCollectionDocumentApi.cpp
src/sbi/amf_server/api/N1N2MessageCollectionDocumentApi.cpp
+21
-51
src/utils/CMakeLists.txt
src/utils/CMakeLists.txt
+1
-1
src/utils/http_multi_parser.cpp
src/utils/http_multi_parser.cpp
+25
-51
src/utils/mime_parser.cpp
src/utils/mime_parser.cpp
+165
-0
src/utils/mime_parser.hpp
src/utils/mime_parser.hpp
+106
-0
src/utils/multipartparser.cpp
src/utils/multipartparser.cpp
+0
-328
src/utils/multipartparser.hpp
src/utils/multipartparser.hpp
+0
-142
No files found.
src/sbi/amf_server/api/N1N2MessageCollectionDocumentApi.cpp
View file @
a5e65b39
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
#include "N1N2MessageCollectionDocumentApi.h"
#include "N1N2MessageCollectionDocumentApi.h"
#include "Helpers.h"
#include "Helpers.h"
#include "m
ultipart
parser.hpp"
#include "m
ime_
parser.hpp"
#include "logger.hpp"
#include "logger.hpp"
namespace
oai
{
namespace
oai
{
...
@@ -45,71 +45,42 @@ void N1N2MessageCollectionDocumentApi::n1_n2_message_transfer_handler(const Pist
...
@@ -45,71 +45,42 @@ void N1N2MessageCollectionDocumentApi::n1_n2_message_transfer_handler(const Pist
Logger
::
amf_server
().
debug
(
"Received a N1N2MessageTrasfer request with ue_ctx_id(%s) "
,
ueContextId
.
c_str
());
Logger
::
amf_server
().
debug
(
"Received a N1N2MessageTrasfer request with ue_ctx_id(%s) "
,
ueContextId
.
c_str
());
// Getting the body param
// Getting the body param
std
::
size_t
found
=
request
.
body
().
find
(
"Content-Type"
);
//simple parser
std
::
string
boundary_str
=
request
.
body
().
substr
(
2
,
found
-
4
);
mime_parser
sp
=
{
};
Logger
::
amf_server
().
debug
(
"Boundary: %s"
,
boundary_str
.
c_str
());
sp
.
parse
(
request
.
body
());
//step 1. use multipartparser to decode the request
std
::
vector
<
mime_part
>
parts
=
{
};
multipartparser_callbacks_init
(
&
g_callbacks
);
sp
.
get_mime_parts
(
parts
);
g_callbacks
.
on_body_begin
=
&
on_body_begin
;
uint8_t
size
=
parts
.
size
();
g_callbacks
.
on_part_begin
=
&
on_part_begin
;
Logger
::
amf_server
().
debug
(
"Number of MIME parts %d"
,
size
);
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
::
amf_server
().
warn
(
"The received message can not be parsed properly!"
);
//response.send(Pistache::Http::Code::Bad_Request, "");
//return;
}
Logger
::
amf_server
().
debug
(
"Number of g_parts %d"
,
g_parts
.
size
());
//at least 2 parts for Json data and N1 (+ N2)
//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
,
""
);
response
.
send
(
Pistache
::
Http
::
Code
::
Bad_Request
);
return
;
return
;
}
}
part
p0
=
g_parts
.
front
();
g_parts
.
pop_front
();
Logger
::
amf_server
().
debug
(
"Request body, part 1:
\n
%s"
,
parts
[
0
].
body
.
c_str
());
Logger
::
amf_server
().
debug
(
"Request body, part 1:
\n
%s"
,
p0
.
body
.
c_str
());
Logger
::
amf_server
().
debug
(
"Request body, part 2:
\n
%s"
,
parts
[
1
].
body
.
c_str
());
part
p1
=
g_parts
.
front
();
g_parts
.
pop_front
();
Logger
::
amf_server
().
debug
(
"Request body, part 2:
\n
%s"
,
p1
.
body
.
c_str
());
bool
is_ngap
=
false
;
part
p2
;
bool
is_ngap
=
false
;
if
(
size
>
2
)
{
if
(
g_parts
.
size
()
>
0
)
{
p2
=
g_parts
.
front
();
g_parts
.
pop_front
();
is_ngap
=
true
;
is_ngap
=
true
;
Logger
::
amf_server
().
debug
(
"Request body, part 3:
\n
%s"
,
p
2
.
body
.
c_str
());
Logger
::
amf_server
().
debug
(
"Request body, part 3:
\n
%s"
,
p
arts
[
2
]
.
body
.
c_str
());
}
}
N1N2MessageTransferReqData
n1N2MessageTransferReqData
=
{};
N1N2MessageTransferReqData
n1N2MessageTransferReqData
=
{};
try
{
try
{
//from_json(nlohmann::json::parse(p0.body.c_str()), n1N2MessageTransferReqData);
nlohmann
::
json
::
parse
(
parts
[
0
].
body
.
c_str
()).
get_to
(
n1N2MessageTransferReqData
);
nlohmann
::
json
::
parse
(
p0
.
body
.
c_str
()).
get_to
(
n1N2MessageTransferReqData
);
if
(
!
is_ngap
)
if
(
!
is_ngap
)
this
->
n1_n2_message_transfer
(
ueContextId
,
n1N2MessageTransferReqData
,
p
1
.
body
,
response
);
this
->
n1_n2_message_transfer
(
ueContextId
,
n1N2MessageTransferReqData
,
p
arts
[
1
]
.
body
,
response
);
else
else
this
->
n1_n2_message_transfer
(
ueContextId
,
n1N2MessageTransferReqData
,
p
1
.
body
,
p2
.
body
,
response
);
this
->
n1_n2_message_transfer
(
ueContextId
,
n1N2MessageTransferReqData
,
p
arts
[
1
].
body
,
parts
[
2
]
.
body
,
response
);
}
catch
(
nlohmann
::
detail
::
exception
&
e
)
{
}
catch
(
nlohmann
::
detail
::
exception
&
e
)
{
//send a 400 error
//send a 400 error
Logger
::
amf_server
().
error
(
"response 400 error"
);
Logger
::
amf_server
().
error
(
"response 400 error"
);
response
.
send
(
Pistache
::
Http
::
Code
::
Bad_Request
,
e
.
what
());
response
.
send
(
Pistache
::
Http
::
Code
::
Bad_Request
,
e
.
what
());
//response.send(Pistache::Http::Code::Bad_Request, "error");
return
;
return
;
}
catch
(
std
::
exception
&
e
)
{
}
catch
(
std
::
exception
&
e
)
{
//send a 500 error
//send a 500 error
...
@@ -117,7 +88,6 @@ void N1N2MessageCollectionDocumentApi::n1_n2_message_transfer_handler(const Pist
...
@@ -117,7 +88,6 @@ void N1N2MessageCollectionDocumentApi::n1_n2_message_transfer_handler(const Pist
response
.
send
(
Pistache
::
Http
::
Code
::
Internal_Server_Error
,
e
.
what
());
response
.
send
(
Pistache
::
Http
::
Code
::
Internal_Server_Error
,
e
.
what
());
return
;
return
;
}
}
}
}
void
N1N2MessageCollectionDocumentApi
::
n1_n2_message_collection_document_api_default_handler
(
const
Pistache
::
Rest
::
Request
&
,
Pistache
::
Http
::
ResponseWriter
response
)
{
void
N1N2MessageCollectionDocumentApi
::
n1_n2_message_collection_document_api_default_handler
(
const
Pistache
::
Rest
::
Request
&
,
Pistache
::
Http
::
ResponseWriter
response
)
{
...
...
src/utils/CMakeLists.txt
View file @
a5e65b39
...
@@ -11,8 +11,8 @@ add_library (AMF_UTILS STATIC
...
@@ -11,8 +11,8 @@ add_library (AMF_UTILS STATIC
${
CMAKE_CURRENT_SOURCE_DIR
}
/hex_string_convert.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/hex_string_convert.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/http_multi_parser.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/http_multi_parser.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/if.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/if.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/multipartparser.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/string.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/string.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/thread_sched.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/thread_sched.cpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/mime_parser.cpp
)
)
src/utils/http_multi_parser.cpp
View file @
a5e65b39
#include "multipartparser.hpp"
#include "mime_parser.hpp"
#include <string>
#include <string>
#include <iostream>
#include <iostream>
using
namespace
std
;
using
namespace
std
;
extern
"C"
{
#include <string.h>
}
bool
multipart_parser
(
string
input
,
string
&
jsonData
,
string
&
n1sm
,
string
&
n2sm
){
std
::
size_t
found
=
input
.
find
(
"Content-Type"
);
std
::
string
boundary_str
=
input
.
substr
(
2
,
found
-
4
);
//step 1. use multipartparser to decode the input
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
=
{};
bool
multipart_parser
(
std
::
string
input
,
std
::
string
&
jsonData
,
std
::
string
&
n1sm
,
std
::
string
&
n2sm
)
{
init_globals
();
multipartparser_init
(
&
parser
,
reinterpret_cast
<
const
char
*>
(
boundary_str
.
c_str
()));
unsigned
int
str_len
=
input
.
length
();
//simple parser
unsigned
char
*
data
=
(
unsigned
char
*
)
malloc
(
str_len
+
1
);
mime_parser
sp
=
{
};
memset
(
data
,
0
,
str_len
+
1
);
sp
.
parse
(
input
);
memcpy
((
void
*
)
data
,
(
void
*
)
input
.
c_str
(),
str_len
);
if
((
multipartparser_execute
(
&
parser
,
&
g_callbacks
,
reinterpret_cast
<
const
char
*>
(
data
),
str_len
)
!=
strlen
(
input
.
c_str
()))
or
(
!
g_body_begin_called
))
{
//return;
std
::
cout
<<
"multipartparser_execute"
<<
std
::
endl
;
}
std
::
vector
<
mime_part
>
parts
=
{
};
sp
.
get_mime_parts
(
parts
);
uint8_t
size
=
parts
.
size
();
//at least 2 parts for Json data and N1 (+ N2)
//at least 2 parts for Json data and N1 (+ N2)
if
(
g_parts
.
size
()
<
2
)
{
if
(
size
<
2
)
{
return
false
;
return
false
;
}
}
part
p0
=
g_parts
.
front
();
g_parts
.
pop_front
();
jsonData
=
p0
.
body
;
jsonData
=
parts
[
0
].
body
;
part
p1
=
g_parts
.
front
();
g_parts
.
pop_front
();
n1sm
=
p1
.
body
;
n1sm
=
parts
[
1
].
body
;
part
p2
;
bool
is_ngap
=
false
;
bool
is_ngap
=
false
;
if
(
g_parts
.
size
()
>
0
)
{
if
(
size
>
2
)
{
p2
=
g_parts
.
front
();
g_parts
.
pop_front
();
n2sm
=
parts
[
2
].
body
;
is_ngap
=
true
;
}
else
{
n2sm
=
"null"
;
}
}
if
(
is_ngap
)
n2sm
=
p2
.
body
;
else
n2sm
=
"null"
;
return
true
;
return
true
;
}
}
src/utils/mime_parser.cpp
0 → 100644
View file @
a5e65b39
/*
* 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
*/
#include "mime_parser.hpp"
#include "logger.hpp"
#include "conversions.hpp"
bool
mime_parser
::
parse
(
const
std
::
string
&
str
)
{
std
::
string
CRLF
=
"
\r\n
"
;
Logger
::
amf_app
().
debug
(
"Parsing the message with Simple Parser"
);
//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
::
amf_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
::
amf_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
::
amf_app
().
debug
(
"Body: %s"
,
p
.
body
.
c_str
());
mime_parts
.
push_back
(
p
);
}
}
return
true
;
}
void
mime_parser
::
get_mime_parts
(
std
::
vector
<
mime_part
>
&
parts
)
const
{
for
(
auto
it
:
mime_parts
)
{
parts
.
push_back
(
it
);
}
}
//---------------------------------------------------------------------------------------------
unsigned
char
*
mime_parser
::
format_string_as_hex
(
const
std
::
string
&
str
)
{
unsigned
int
str_len
=
str
.
length
();
char
*
data
=
(
char
*
)
malloc
(
str_len
+
1
);
memset
(
data
,
0
,
str_len
+
1
);
memcpy
((
void
*
)
data
,
(
void
*
)
str
.
c_str
(),
str_len
);
unsigned
char
*
data_hex
=
(
uint8_t
*
)
malloc
(
str_len
/
2
+
1
);
conv
::
ascii_to_hex
(
data_hex
,
(
const
char
*
)
data
);
Logger
::
amf_app
().
debug
(
"[Format string as Hex] Input string (%d bytes): %s "
,
str_len
,
str
.
c_str
());
Logger
::
amf_app
().
debug
(
"Data (formatted):"
);
#if DEBUG_IS_ON
for
(
int
i
=
0
;
i
<
str_len
/
2
;
i
++
)
printf
(
" %02x "
,
data_hex
[
i
]);
printf
(
"
\n
"
);
#endif
//free memory
//free_wrapper((void**) &data);
free
(
data
);
data
=
NULL
;
return
data_hex
;
}
//------------------------------------------------------------------------------
void
mime_parser
::
create_multipart_related_content
(
std
::
string
&
body
,
const
std
::
string
&
json_part
,
const
std
::
string
boundary
,
const
std
::
string
&
n1_message
,
const
std
::
string
&
n2_message
)
{
//TODO: provide Content-Ids as function parameters
//format string as hex
unsigned
char
*
n1_msg_hex
=
format_string_as_hex
(
n1_message
);
unsigned
char
*
n2_msg_hex
=
format_string_as_hex
(
n2_message
);
std
::
string
CRLF
=
"
\r\n
"
;
body
.
append
(
"--"
+
boundary
+
CRLF
);
body
.
append
(
"Content-Type: application/json"
+
CRLF
);
body
.
append
(
CRLF
);
body
.
append
(
json_part
+
CRLF
);
body
.
append
(
"--"
+
boundary
+
CRLF
);
body
.
append
(
"Content-Type: application/vnd.3gpp.5gnas"
+
CRLF
+
"Content-Id: n1SmMsg"
+
CRLF
);
body
.
append
(
CRLF
);
body
.
append
(
std
::
string
((
char
*
)
n1_msg_hex
,
n1_message
.
length
()
/
2
)
+
CRLF
);
body
.
append
(
"--"
+
boundary
+
CRLF
);
body
.
append
(
"Content-Type: application/vnd.3gpp.ngap"
+
CRLF
+
"Content-Id: n2msg"
+
CRLF
);
body
.
append
(
CRLF
);
body
.
append
(
std
::
string
((
char
*
)
n2_msg_hex
,
n2_message
.
length
()
/
2
)
+
CRLF
);
body
.
append
(
"--"
+
boundary
+
"--"
+
CRLF
);
}
//------------------------------------------------------------------------------
void
mime_parser
::
create_multipart_related_content
(
std
::
string
&
body
,
const
std
::
string
&
json_part
,
const
std
::
string
boundary
,
const
std
::
string
&
message
,
const
multipart_related_content_part_e
content_type
)
{
//TODO: provide Content-Id as function parameters
//format string as hex
unsigned
char
*
msg_hex
=
format_string_as_hex
(
message
);
std
::
string
CRLF
=
"
\r\n
"
;
body
.
append
(
"--"
+
boundary
+
CRLF
);
body
.
append
(
"Content-Type: application/json"
+
CRLF
);
body
.
append
(
CRLF
);
body
.
append
(
json_part
+
CRLF
);
body
.
append
(
"--"
+
boundary
+
CRLF
);
if
(
content_type
==
multipart_related_content_part_e
::
NAS
)
{
//NAS
body
.
append
(
"Content-Type: application/vnd.3gpp.5gnas"
+
CRLF
+
"Content-Id: n1SmMsg"
+
CRLF
);
}
else
if
(
content_type
==
multipart_related_content_part_e
::
NGAP
)
{
//NGAP
body
.
append
(
"Content-Type: application/vnd.3gpp.ngap"
+
CRLF
+
"Content-Id: n2msg"
+
CRLF
);
}
body
.
append
(
CRLF
);
body
.
append
(
std
::
string
((
char
*
)
msg_hex
,
message
.
length
()
/
2
)
+
CRLF
);
body
.
append
(
"--"
+
boundary
+
"--"
+
CRLF
);
}
src/utils/mime_parser.hpp
0 → 100644
View file @
a5e65b39
/*
* 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 mime_parser.hpp
\brief
\author
\company Eurecom
\email:
*/
#ifndef FILE_MIME_PARSER_HPP_SEEN
#define FILE_MIME_PARSER_HPP_SEEN
# include <string>
#include <map>
#include <vector>
enum
class
multipart_related_content_part_e
{
JSON
=
0
,
NAS
=
1
,
NGAP
=
2
};
static
const
std
::
vector
<
std
::
string
>
multipart_related_content_part_e2str
=
{
"JSON"
,
"NAS"
,
"NGAP"
};
typedef
struct
mime_part
{
std
::
string
content_type
;
std
::
string
body
;
}
mime_part
;
class
mime_parser
{
public:
/*
* Parse the input string into different Mime parts
* @param [const std::string &] str: input string
* @return void
*/
bool
parse
(
const
std
::
string
&
str
);
/*
* Get vector of Mime parts
* @param [std::vector<mime_part> &] parts: store vector of Mime parts
* @return void
*/
void
get_mime_parts
(
std
::
vector
<
mime_part
>
&
parts
)
const
;
/*
* Represent a string as hex
* @param [const std::string&] str: input string
* @return String represents string in hex format
*/
unsigned
char
*
format_string_as_hex
(
const
std
::
string
&
str
);
/*
* Create HTTP body content for multipart/related message
* @param [std::string] body: Body of the created message
* @param [std::string] json_part: Json part of multipart/related msg
* @param [std::string] boundary: Boundary of multipart/related msg
* @param [std::string] n1_message: N1 (NAS) part
* @param [std::string] n2_message: N2 (NGAP) part
* @return void
*/
void
create_multipart_related_content
(
std
::
string
&
body
,
const
std
::
string
&
json_part
,
const
std
::
string
boundary
,
const
std
::
string
&
n1_message
,
const
std
::
string
&
n2_message
);
/*
* Create HTTP body content for multipart/related message
* @param [std::string] body: Body of the created message
* @param [std::string] json_part: Json part of multipart/related msg
* @param [std::string] boundary: Boundary of multipart/related msg
* @param [std::string] message: N1 (NAS) or N2 (NGAP) part
* @param [uint8_t] content_type: 1 for NAS content, else NGAP content
* @return void
*/
void
create_multipart_related_content
(
std
::
string
&
body
,
const
std
::
string
&
json_part
,
const
std
::
string
boundary
,
const
std
::
string
&
message
,
const
multipart_related_content_part_e
content_type
);
private:
std
::
vector
<
mime_part
>
mime_parts
;
};
#endif
/* FILE_MIME_PARSER_HPP_SEEN */
src/utils/multipartparser.cpp
deleted
100644 → 0
View file @
824102f8
/*
* https://github.com/iafonov/multipart-parser-c
*/
#include "multipartparser.hpp"
#include <string.h>
#define CR '\r'
#define LF '\n'
#define SP ' '
#define HT '\t'
#define HYPHEN '-'
#define CALLBACK_NOTIFY(NAME) \
if (callbacks->on_##NAME != NULL) { \
if (callbacks->on_##NAME(parser) != 0) \
goto error; \
}
#define CALLBACK_DATA(NAME, P, S) \
if (callbacks->on_##NAME != NULL) { \
if (callbacks->on_##NAME(parser, P, S) != 0) \
goto error; \
}
enum
state
{
s_preamble
,
s_preamble_hy_hy
,
s_first_boundary
,
s_header_field_start
,
s_header_field
,
s_header_value_start
,
s_header_value
,
s_header_value_cr
,
s_headers_done
,
s_data
,
s_data_cr
,
s_data_cr_lf
,
s_data_cr_lf_hy
,
s_data_boundary_start
,
s_data_boundary
,
s_data_boundary_done
,
s_data_boundary_done_cr_lf
,
s_data_boundary_done_hy_hy
,
s_epilogue
,
};
/* Header field name as defined by rfc 2616. Also lowercases them.
* field-name = token
* token = 1*<any CHAR except CTLs or tspecials>
* CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
* tspecials = "(" | ")" | "<" | ">" | "@"
* | "," | ";" | ":" | "\" | DQUOTE
* | "/" | "[" | "]" | "?" | "="
* | "{" | "}" | SP | HT
* DQUOTE = <US-ASCII double-quote mark (34)>
* SP = <US-ASCII SP, space (32)>
* HT = <US-ASCII HT, horizontal-tab (9)>
*/
static
const
char
header_field_chars
[
256
]
=
{
/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
0
,
'!'
,
0
,
'#'
,
'$'
,
'%'
,
'&'
,
'\''
,
/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
0
,
0
,
'*'
,
'+'
,
0
,
'-'
,
'.'
,
0
,
/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
'8'
,
'9'
,
0
,
0
,
0
,
0
,
0
,
0
,
/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
0
,
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
,
'G'
,
/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
'H'
,
'I'
,
'J'
,
'K'
,
'L'
,
'M'
,
'N'
,
'O'
,
/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
'P'
,
'Q'
,
'R'
,
'S'
,
'T'
,
'U'
,
'V'
,
'W'
,
/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
'X'
,
'Y'
,
'Z'
,
0
,
0
,
0
,
'^'
,
'_'
,
/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
'`'
,
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
,
'g'
,
/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
'h'
,
'i'
,
'j'
,
'k'
,
'l'
,
'm'
,
'n'
,
'o'
,
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
'p'
,
'q'
,
'r'
,
's'
,
't'
,
'u'
,
'v'
,
'w'
,
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
'x'
,
'y'
,
'z'
,
0
,
'|'
,
0
,
'~'
,
0
};
void
multipartparser_init
(
multipartparser
*
parser
,
const
char
*
boundary
)
{
memset
(
parser
,
0
,
sizeof
(
*
parser
));
//strncpy(parser->boundary, boundary, sizeof(parser->boundary));
strcpy
(
parser
->
boundary
,
boundary
);
parser
->
boundary_length
=
strlen
(
parser
->
boundary
);
parser
->
state
=
s_preamble
;
}
void
multipartparser_callbacks_init
(
multipartparser_callbacks
*
callbacks
)
{
memset
(
callbacks
,
0
,
sizeof
(
*
callbacks
));
}
size_t
multipartparser_execute
(
multipartparser
*
parser
,
multipartparser_callbacks
*
callbacks
,
const
char
*
data
,
size_t
size
)
{
const
char
*
mark
;
const
char
*
p
;
unsigned
char
c
;
for
(
p
=
data
;
p
<
data
+
size
;
++
p
)
{
c
=
*
p
;
reexecute:
switch
(
parser
->
state
)
{
case
s_preamble
:
if
(
c
==
HYPHEN
)
parser
->
state
=
s_preamble_hy_hy
;
// else ignore everything before first boundary
break
;
case
s_preamble_hy_hy
:
if
(
c
==
HYPHEN
)
parser
->
state
=
s_first_boundary
;
else
parser
->
state
=
s_preamble
;
break
;
case
s_first_boundary
:
if
(
parser
->
index
==
parser
->
boundary_length
)
{
if
(
c
!=
CR
)
goto
error
;
parser
->
index
++
;
break
;
}
if
(
parser
->
index
==
parser
->
boundary_length
+
1
)
{
if
(
c
!=
LF
)
goto
error
;
CALLBACK_NOTIFY
(
body_begin
);
CALLBACK_NOTIFY
(
part_begin
);
parser
->
index
=
0
;
parser
->
state
=
s_header_field_start
;
break
;
}
if
(
c
==
parser
->
boundary
[
parser
->
index
])
{
parser
->
index
++
;
break
;
}
goto
error
;
case
s_header_field_start
:
if
(
c
==
CR
)
{
parser
->
state
=
s_headers_done
;
break
;
}
parser
->
state
=
s_header_field
;
// fallthrough;
case
s_header_field
:
mark
=
p
;
while
(
p
!=
data
+
size
)
{
c
=
*
p
;
if
(
header_field_chars
[
c
]
==
0
)
break
;
++
p
;
}
if
(
p
>
mark
)
{
CALLBACK_DATA
(
header_field
,
mark
,
p
-
mark
);
}
if
(
p
==
data
+
size
)
{
break
;
}
if
(
c
==
':'
)
{
parser
->
state
=
s_header_value_start
;
break
;
}
goto
error
;
case
s_header_value_start
:
if
(
c
==
SP
||
c
==
HT
)
{
break
;
}
parser
->
state
=
s_header_value
;
// fallthrough;
case
s_header_value
:
mark
=
p
;
while
(
p
!=
data
+
size
)
{
c
=
*
p
;
if
(
c
==
CR
)
{
parser
->
state
=
s_header_value_cr
;
break
;
}
++
p
;
}
if
(
p
>
mark
)
{
CALLBACK_DATA
(
header_value
,
mark
,
p
-
mark
);
}
break
;
case
s_header_value_cr
:
if
(
c
==
LF
)
{
parser
->
state
=
s_header_field_start
;
break
;
}
goto
error
;
case
s_headers_done
:
if
(
c
==
LF
)
{
CALLBACK_NOTIFY
(
headers_complete
);
parser
->
state
=
s_data
;
break
;
}
goto
error
;
case
s_data
:
mark
=
p
;
while
(
p
!=
data
+
size
)
{
c
=
*
p
;
if
(
c
==
CR
)
{
parser
->
state
=
s_data_cr
;
break
;
}
++
p
;
}
if
(
p
>
mark
)
{
CALLBACK_DATA
(
data
,
mark
,
p
-
mark
);
}
break
;
case
s_data_cr
:
if
(
c
==
LF
)
{
parser
->
state
=
s_data_cr_lf
;
break
;
}
CALLBACK_DATA
(
data
,
"
\r
"
,
1
);
parser
->
state
=
s_data
;
goto
reexecute
;
case
s_data_cr_lf
:
if
(
c
==
HYPHEN
)
{
parser
->
state
=
s_data_cr_lf_hy
;
break
;
}
CALLBACK_DATA
(
data
,
"
\r\n
"
,
2
);
parser
->
state
=
s_data
;
goto
reexecute
;
case
s_data_cr_lf_hy
:
if
(
c
==
HYPHEN
)
{
parser
->
state
=
s_data_boundary_start
;
break
;
}
CALLBACK_DATA
(
data
,
"
\r\n
-"
,
3
);
parser
->
state
=
s_data
;
goto
reexecute
;
case
s_data_boundary_start
:
parser
->
index
=
0
;
parser
->
state
=
s_data_boundary
;
// fallthrough;
case
s_data_boundary
:
if
(
parser
->
index
==
parser
->
boundary_length
)
{
parser
->
index
=
0
;
parser
->
state
=
s_data_boundary_done
;
goto
reexecute
;
}
if
(
c
==
parser
->
boundary
[
parser
->
index
])
{
parser
->
index
++
;
break
;
}
CALLBACK_DATA
(
data
,
parser
->
boundary
,
parser
->
index
);
parser
->
state
=
s_data
;
goto
reexecute
;
case
s_data_boundary_done
:
if
(
c
==
CR
)
{
parser
->
state
=
s_data_boundary_done_cr_lf
;
break
;
}
if
(
c
==
HYPHEN
)
{
parser
->
state
=
s_data_boundary_done_hy_hy
;
break
;
}
goto
error
;
case
s_data_boundary_done_cr_lf
:
if
(
c
==
LF
)
{
CALLBACK_NOTIFY
(
part_end
);
CALLBACK_NOTIFY
(
part_begin
);
parser
->
state
=
s_header_field_start
;
break
;
}
goto
error
;
case
s_data_boundary_done_hy_hy
:
if
(
c
==
HYPHEN
)
{
CALLBACK_NOTIFY
(
part_end
);
CALLBACK_NOTIFY
(
body_end
);
parser
->
state
=
s_epilogue
;
break
;
}
goto
error
;
case
s_epilogue
:
// Must be ignored according to rfc 1341.
break
;
}
}
return
size
;
error:
return
p
-
data
;
}
src/utils/multipartparser.hpp
deleted
100644 → 0
View file @
824102f8
/*
* https://github.com/iafonov/multipart-parser-c
*/
#ifndef MULTIPARTPARSER_H
#define MULTIPARTPARSER_H
#include <map>
#include <string>
#include <list>
extern
"C"
{
#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
);
#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 // MULTIPARTPARSER_H
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment