From: Mikko Rasa Date: Mon, 16 May 2016 15:13:38 +0000 (+0300) Subject: Add a class for parsing submitted form data X-Git-Url: http://git.tdb.fi/?p=libs%2Fnet.git;a=commitdiff_plain;h=049fc42b671d623815408c3658a450b73063fec5 Add a class for parsing submitted form data parse_query in utils.h already did it for query strings, but not for POST requests. --- diff --git a/source/http/formdata.cpp b/source/http/formdata.cpp new file mode 100644 index 0000000..182c5bb --- /dev/null +++ b/source/http/formdata.cpp @@ -0,0 +1,97 @@ +#include +#include "header.h" +#include "request.h" +#include "submessage.h" +#include "utils.h" +#include "formdata.h" + +using namespace std; + +namespace Msp { +namespace Http { + +FormData::FormData(const Request &req) +{ + const string &method = req.get_method(); + if(method=="GET") + { + Url url = parse_url(req.get_path()); + fields = parse_query(url.query); + } + else if(method=="POST") + { + Header content_type(req, "Content-Type"); + const Header::Value &ct_value = content_type.values.at(0); + if(ct_value.value=="application/x-www-form-urlencoded") + fields = parse_query(req.get_content()); + else if(ct_value.value=="multipart/form-data") + { + const string &boundary = get_item(ct_value.parameters, "boundary"); + parse_multipart(req, boundary); + } + else + throw invalid_argument("FormData::FormData"); + } + else + throw invalid_argument("FormData::FormData"); +} + +void FormData::parse_multipart(const Request &req, const string &boundary) +{ + const string &content = req.get_content(); + + string::size_type line_start = 0; + string::size_type part_start = 0; + while(1) + { + string::size_type lf = content.find('\n', line_start); + if(lf==string::npos) + throw invalid_argument("FormData::parse_multipart"); + + bool is_boundary = !content.compare(line_start, 2, "--"); + is_boundary = (is_boundary && !content.compare(line_start+2, boundary.size(), boundary)); + + if(is_boundary) + { + /* The CRLF preceding the boundary delimiter is treated as part + of the delimiter as per RFC 2046 */ + string::size_type part_end = line_start-1; + if(content[part_end-1]=='\r') + --part_end; + + if(part_start>0) + { + SubMessage part = SubMessage::parse(content.substr(part_start, line_start-part_start)); + Header content_disposition(part, "Content-Disposition"); + const Header::Value &cd_value = content_disposition.values.at(0); + if(cd_value.value=="form-data") + { + const string &name = get_item(cd_value.parameters, "name"); + fields[name] = part.get_content(); + } + } + + part_start = lf+1; + } + + if(!content.compare(line_start+2+boundary.size(), 2, "--")) + break; + + line_start = lf+1; + } +} + +const string &FormData::get_value(const string &key) const +{ + map::const_iterator i = fields.find(key); + if(i==fields.end()) + { + static string dummy; + return dummy; + } + + return i->second; +} + +} // namespace Http +} // namespace Msp diff --git a/source/http/formdata.h b/source/http/formdata.h new file mode 100644 index 0000000..3232891 --- /dev/null +++ b/source/http/formdata.h @@ -0,0 +1,29 @@ +#ifndef MSP_HTTP_FORMDATA_H_ +#define MSP_HTTP_FORMDATA_H_ + +#include +#include + +namespace Msp { +namespace Http { + +class Request; + +class FormData +{ +private: + std::map fields; + +public: + FormData(const Request &); +private: + void parse_multipart(const Request &, const std::string &); + +public: + const std::string &get_value(const std::string &) const; +}; + +} // namespace Http +} // namespace Msp + +#endif diff --git a/source/http/submessage.cpp b/source/http/submessage.cpp new file mode 100644 index 0000000..05b1a30 --- /dev/null +++ b/source/http/submessage.cpp @@ -0,0 +1,24 @@ +#include "submessage.h" + +using namespace std; + +namespace Msp { +namespace Http { + +string SubMessage::str() const +{ + return str_common(); +} + +SubMessage SubMessage::parse(const string &str) +{ + SubMessage result; + + string::size_type pos = result.parse_headers(str); + result.content = str.substr(pos); + + return result; +} + +} // namespace Http +} // namespace Msp diff --git a/source/http/submessage.h b/source/http/submessage.h new file mode 100644 index 0000000..f60276a --- /dev/null +++ b/source/http/submessage.h @@ -0,0 +1,23 @@ +#ifndef MSP_HTTP_SUBMESSAGE_H_ +#define MSP_HTTP_SUBMESSAGE_H_ + +#include "message.h" + +namespace Msp { +namespace Http { + +class SubMessage: public Message +{ +private: + SubMessage() { } + +public: + virtual std::string str() const; + + static SubMessage parse(const std::string &); +}; + +} // namespace Http +} // namespace Msp + +#endif