]> git.tdb.fi Git - libs/net.git/blob - source/http/formdata.cpp
182c5bbbdc7bfc1890cbf6e74380f6ac785902c1
[libs/net.git] / source / http / formdata.cpp
1 #include <msp/core/maputils.h>
2 #include "header.h"
3 #include "request.h"
4 #include "submessage.h"
5 #include "utils.h"
6 #include "formdata.h"
7
8 using namespace std;
9
10 namespace Msp {
11 namespace Http {
12
13 FormData::FormData(const Request &req)
14 {
15         const string &method = req.get_method();
16         if(method=="GET")
17         {
18                 Url url = parse_url(req.get_path());
19                 fields = parse_query(url.query);
20         }
21         else if(method=="POST")
22         {
23                 Header content_type(req, "Content-Type");
24                 const Header::Value &ct_value = content_type.values.at(0);
25                 if(ct_value.value=="application/x-www-form-urlencoded")
26                         fields = parse_query(req.get_content());
27                 else if(ct_value.value=="multipart/form-data")
28                 {
29                         const string &boundary = get_item(ct_value.parameters, "boundary");
30                         parse_multipart(req, boundary);
31                 }
32                 else
33                         throw invalid_argument("FormData::FormData");
34         }
35         else
36                 throw invalid_argument("FormData::FormData");
37 }
38
39 void FormData::parse_multipart(const Request &req, const string &boundary)
40 {
41         const string &content = req.get_content();
42
43         string::size_type line_start = 0;
44         string::size_type part_start = 0;
45         while(1)
46         {
47                 string::size_type lf = content.find('\n', line_start);
48                 if(lf==string::npos)
49                         throw invalid_argument("FormData::parse_multipart");
50
51                 bool is_boundary = !content.compare(line_start, 2, "--");
52                 is_boundary = (is_boundary && !content.compare(line_start+2, boundary.size(), boundary));
53
54                 if(is_boundary)
55                 {
56                         /* The CRLF preceding the boundary delimiter is treated as part
57                         of the delimiter as per RFC 2046 */
58                         string::size_type part_end = line_start-1;
59                         if(content[part_end-1]=='\r')
60                                 --part_end;
61
62                         if(part_start>0)
63                         {
64                                 SubMessage part = SubMessage::parse(content.substr(part_start, line_start-part_start));
65                                 Header content_disposition(part, "Content-Disposition");
66                                 const Header::Value &cd_value = content_disposition.values.at(0);
67                                 if(cd_value.value=="form-data")
68                                 {
69                                         const string &name = get_item(cd_value.parameters, "name");
70                                         fields[name] = part.get_content();
71                                 }
72                         }
73
74                         part_start = lf+1;
75                 }
76
77                 if(!content.compare(line_start+2+boundary.size(), 2, "--"))
78                         break;
79
80                 line_start = lf+1;
81         }
82 }
83
84 const string &FormData::get_value(const string &key) const
85 {
86         map<string, string>::const_iterator i = fields.find(key);
87         if(i==fields.end())
88         {
89                 static string dummy;
90                 return dummy;
91         }
92
93         return i->second;
94 }
95
96 } // namespace Http
97 } // namespace Msp