--- /dev/null
+#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