]> git.tdb.fi Git - libs/net.git/commitdiff
Add a class for parsing submitted form data
authorMikko Rasa <tdb@tdb.fi>
Mon, 16 May 2016 15:13:38 +0000 (18:13 +0300)
committerMikko Rasa <tdb@tdb.fi>
Mon, 16 May 2016 15:13:38 +0000 (18:13 +0300)
parse_query in utils.h already did it for query strings, but not for
POST requests.

source/http/formdata.cpp [new file with mode: 0644]
source/http/formdata.h [new file with mode: 0644]
source/http/submessage.cpp [new file with mode: 0644]
source/http/submessage.h [new file with mode: 0644]

diff --git a/source/http/formdata.cpp b/source/http/formdata.cpp
new file mode 100644 (file)
index 0000000..182c5bb
--- /dev/null
@@ -0,0 +1,97 @@
+#include <msp/core/maputils.h>
+#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<string, string>::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 (file)
index 0000000..3232891
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef MSP_HTTP_FORMDATA_H_
+#define MSP_HTTP_FORMDATA_H_
+
+#include <map>
+#include <string>
+
+namespace Msp {
+namespace Http {
+
+class Request;
+
+class FormData
+{
+private:
+       std::map<std::string, std::string> 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 (file)
index 0000000..05b1a30
--- /dev/null
@@ -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 (file)
index 0000000..f60276a
--- /dev/null
@@ -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