24#include <boost/algorithm/string.hpp>
33struct MimeMultipart::Data {
38struct MimeMultipart::Part::Data {
42 unordered_map<string, string> headers;
83 parse(contentType, std::move(content));
86void MimeMultipart::parse(std::string
const& contentType, std::string content) {
87 regex findBoundary(R
"X(boundary="?([A-Za-z0-9'()+_,\-.\/:=? ]+)"?)X");
89 if (!regex_search(contentType, boundaryMatch, findBoundary) || boundaryMatch.size() != 2) {
90 throw Exception(__PRETTY_FUNCTION__, 1,
"Could not find boundary in content type.");
92 string boundary =
"--";
93 boundary += boundaryMatch[1];
94 size_t boundaryLen = boundary.length();
96 regex matchPartAndFileName(R
"X((;| )name="?([^"]+)"?(; ?filename="?([^"]+)"?)?)X");
97 auto extractPartAndFileName = [&](
string const& contentDisposition) -> pair<string, string> {
99 if (!regex_search(contentDisposition, sm, matchPartAndFileName) || sm.size() < 3) {
100 return make_pair(
string(),
string());
102 return make_pair(sm[2], sm.size() >= 5 ? sm[4] :
string());
106 while (!content.empty()) {
109 if (content.length() < boundaryLen + 2 || content.substr(0, boundaryLen) != boundary) {
110 throw Exception(__PRETTY_FUNCTION__, 2,
"Malformed MIME payload.");
112 content = content.substr(boundaryLen);
115 if (content.substr(0, 2) ==
"--") {
120 if (content.length() < boundaryLen + 6 || content.substr(0, 2) !=
"\r\n") {
121 throw Exception(__PRETTY_FUNCTION__, 2,
"Malformed MIME payload.");
123 content = content.substr(2);
126 size_t nextBoundaryPos = content.find(boundary);
127 if (nextBoundaryPos == string::npos) {
128 throw Exception(__PRETTY_FUNCTION__, 2,
"Malformed MIME payload.");
132 size_t headersEndPos = content.find(
"\r\n\r\n");
133 if (headersEndPos > nextBoundaryPos) {
134 headersEndPos = nextBoundaryPos;
136 if (headersEndPos < 4) {
137 throw Exception(__PRETTY_FUNCTION__, 2,
"Malformed MIME payload.");
145 if (currentPart.data->
headers.count(
"content-disposition")) {
146 tie(currentPart.data->
partName, currentPart.data->
filename) = extractPartAndFileName(
147 currentPart.data->
headers.at(
"content-disposition"));
151 if (nextBoundaryPos > headersEndPos + 7) {
152 currentPart.data->
content = content.substr(headersEndPos + 4, nextBoundaryPos - 2 - (headersEndPos + 4));
155 data->parts.push_back(currentPart);
156 content = content.substr(nextBoundaryPos);
159 data->contentType = contentType.substr(0, contentType.find_first_of(
';'));
163 data->contentType.clear();
Exception class that can be used by apps to catch errors resulting from nawa function calls.
Parser for MIME multipart, especially in POST form data.
std::string & content() noexcept
std::string & filename() noexcept
std::string & partName() noexcept
HeadersMap & headers() noexcept
std::string & contentType() noexcept
std::unordered_map< std::string, std::string > HeadersMap
#define NAWA_DEFAULT_DESTRUCTOR_IMPL(Class)
#define NAWA_MOVE_CONSTRUCTOR_IMPL_WITH_NS(Namespace, Class)
#define NAWA_COPY_CONSTRUCTOR_IMPL(Class)
#define NAWA_MOVE_ASSIGNMENT_OPERATOR_IMPL_WITH_NS(Namespace, Class)
#define NAWA_COMPLEX_DATA_ACCESSORS_IMPL(Class, Member, Type)
#define NAWA_DEFAULT_CONSTRUCTOR_IMPL_WITH_NS(Namespace, Class)
#define NAWA_MOVE_ASSIGNMENT_OPERATOR_IMPL(Class)
#define NAWA_DEFAULT_CONSTRUCTOR_IMPL(Class)
#define NAWA_COPY_ASSIGNMENT_OPERATOR_IMPL(Class)
#define NAWA_MOVE_CONSTRUCTOR_IMPL(Class)
#define NAWA_COPY_CONSTRUCTOR_IMPL_WITH_NS(Namespace, Class)
#define NAWA_COPY_ASSIGNMENT_OPERATOR_IMPL_WITH_NS(Namespace, Class)
#define NAWA_DEFAULT_DESTRUCTOR_IMPL_WITH_NS(Namespace, Class)
std::unordered_map< std::string, std::string > parseHeaders(std::string rawHeaders)
Contains useful functions that improve the readability and facilitate maintenance of the NAWA code.