author | Michael Krelin <hacker@klever.net> | 2005-07-04 22:54:09 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2005-07-04 22:54:09 (UTC) |
commit | c5d7daf77e265b53951e1e2b09c51e2fba5e93dc (patch) (unidiff) | |
tree | 2337ff96d85d8de6d25fbaed75eb9c0d71a1625d | |
parent | c8bcbfb951eec5fe14dac0b14f4faaf4a9f9f229 (diff) | |
download | kingate-c5d7daf77e265b53951e1e2b09c51e2fba5e93dc.zip kingate-c5d7daf77e265b53951e1e2b09c51e2fba5e93dc.tar.gz kingate-c5d7daf77e265b53951e1e2b09c51e2fba5e93dc.tar.bz2 |
1. awkward yet working support for POST file upload (requires mimetic)
2. support for NOT handling/parsing POSTed data (including application/x-www-form-urlencoded)
-rw-r--r-- | configure.ac | 16 | ||||
-rw-r--r-- | include/kingate/cgi_gateway.h | 57 | ||||
-rw-r--r-- | kingate.pc.in | 4 | ||||
-rw-r--r-- | src/cgi_gateway.cc | 132 |
4 files changed, 190 insertions, 19 deletions
diff --git a/configure.ac b/configure.ac index b3141f1..b51d64d 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -2,3 +2,3 @@ AC_INIT([kingate], [0.0.1], [kingate-bugs@klever.net]) | |||
2 | AC_CONFIG_SRCDIR([include/kingate/cgi_gateway.h]) | 2 | AC_CONFIG_SRCDIR([include/kingate/cgi_gateway.h]) |
3 | AC_CONFIG_HEADER([config.h]) | 3 | AC_CONFIG_HEADERS([config.h]) |
4 | AM_INIT_AUTOMAKE([dist-bzip2]) | 4 | AM_INIT_AUTOMAKE([dist-bzip2]) |
@@ -62,2 +62,16 @@ fi | |||
62 | 62 | ||
63 | HAVE_MIMETIC=false | ||
64 | AC_LANG_PUSH(C++) | ||
65 | AC_CHECK_LIB([mimetic],[main],[ | ||
66 | MIMETIC_LIBS=-lmimetic | ||
67 | HAVE_MIMETIC=true | ||
68 | ] | ||
69 | ) | ||
70 | AC_LANG_POP(C++) | ||
71 | AC_SUBST([MIMETIC_LIBS]) | ||
72 | AC_SUBST([MIMETIC_CFLAGS]) | ||
73 | if ${HAVE_MIMETIC} ; then | ||
74 | AC_DEFINE([HAVE_MIMETIC],,[defined in presence of mimetic]) | ||
75 | fi | ||
76 | |||
63 | AC_CONFIG_FILES([ | 77 | AC_CONFIG_FILES([ |
diff --git a/include/kingate/cgi_gateway.h b/include/kingate/cgi_gateway.h index f20d72b..a26b0ae 100644 --- a/include/kingate/cgi_gateway.h +++ b/include/kingate/cgi_gateway.h | |||
@@ -45,2 +45,33 @@ namespace kingate { | |||
45 | /** | 45 | /** |
46 | * Abstract base class for retrieving posted files. | ||
47 | */ | ||
48 | class basic_file_t { | ||
49 | public: | ||
50 | /** | ||
51 | * Retrieve file name. | ||
52 | * @return filename | ||
53 | */ | ||
54 | virtual const string& filename() const = 0; | ||
55 | /** | ||
56 | * Retrieve file content type. | ||
57 | * @return content type | ||
58 | */ | ||
59 | virtual const string& content_type() const = 0; | ||
60 | /** | ||
61 | * Retrieve file contents. | ||
62 | * @return reference to the stream for accessing file content. | ||
63 | */ | ||
64 | virtual istream& content() = 0; | ||
65 | virtual ~basic_file_t(); | ||
66 | }; | ||
67 | typedef basic_file_t *file_t; | ||
68 | /** | ||
69 | * The map holding information pertaining to files uploaded via post. | ||
70 | */ | ||
71 | typedef multimap<string,file_t> files_t; | ||
72 | /** | ||
73 | * Files uploaded via post | ||
74 | */ | ||
75 | files_t files; | ||
76 | /** | ||
46 | * Cookies passed. | 77 | * Cookies passed. |
@@ -56,3 +87,9 @@ namespace kingate { | |||
56 | */ | 87 | */ |
57 | cgi_gateway(cgi_interface& ci); | 88 | cgi_gateway(cgi_interface& ci,bool parsebody = true); |
89 | virtual ~cgi_gateway() throw(); | ||
90 | |||
91 | /** | ||
92 | * Parse request body. | ||
93 | */ | ||
94 | void parse_request_body(); | ||
58 | 95 | ||
@@ -138,3 +175,3 @@ namespace kingate { | |||
138 | * @param n the parameter name. | 175 | * @param n the parameter name. |
139 | * @return true if yes. | 176 | * @return the parameter contents. |
140 | * @see exception_notfound. | 177 | * @see exception_notfound. |
@@ -142,2 +179,16 @@ namespace kingate { | |||
142 | const string& get_param(const string& n) const; | 179 | const string& get_param(const string& n) const; |
180 | /** | ||
181 | * Check to see whether the file was uploaded in the request body. | ||
182 | * @param n the parameter name. | ||
183 | * @return true if yes. | ||
184 | */ | ||
185 | bool has_file(const string& n) const; | ||
186 | /** | ||
187 | * Retrieve the file uploaded in the request body. | ||
188 | * @param n the parameter name. | ||
189 | * @return the file. | ||
190 | * @see exception_notfound. | ||
191 | */ | ||
192 | const file_t get_file(const string& n) const; | ||
193 | file_t get_file(const string& n); | ||
143 | 194 | ||
@@ -179,3 +230,3 @@ namespace kingate { | |||
179 | */ | 230 | */ |
180 | unsigned long cgi_gateway::content_length() const; | 231 | unsigned long content_length() const; |
181 | /** | 232 | /** |
diff --git a/kingate.pc.in b/kingate.pc.in index 671faac..05cfe1d 100644 --- a/kingate.pc.in +++ b/kingate.pc.in | |||
@@ -9,3 +9,3 @@ Version: @VERSION@ | |||
9 | Requires: konforka | 9 | Requires: konforka |
10 | Libs: -L${libdir} -lkingate | 10 | Libs: -L${libdir} -lkingate @MIMETIC_LIBS@ |
11 | Cflags: -I${includedir} | 11 | Cflags: -I${includedir} @MIMETIC_CFLAGS@ |
diff --git a/src/cgi_gateway.cc b/src/cgi_gateway.cc index ab48f78..1706679 100644 --- a/src/cgi_gateway.cc +++ b/src/cgi_gateway.cc | |||
@@ -2,2 +2,3 @@ | |||
2 | #include <ctype.h> | 2 | #include <ctype.h> |
3 | #include <sstream> | ||
3 | #include "kingate/cgi_gateway.h" | 4 | #include "kingate/cgi_gateway.h" |
@@ -5,4 +6,36 @@ | |||
5 | #include "kingate/exception.h" | 6 | #include "kingate/exception.h" |
7 | #include "config.h" | ||
8 | #ifdef HAVE_MIMETIC | ||
9 | # include <mimetic/mimeentity.h> | ||
10 | # include <mimetic/parser/itparser.h> | ||
11 | #endif /* HAVE_MIMETIC */ | ||
6 | 12 | ||
7 | namespace kingate { | 13 | namespace kingate { |
14 | using mimetic::MimeEntity; | ||
15 | |||
16 | #ifdef HAVE_MIMETIC | ||
17 | struct TornMimeEntity : public MimeEntity { | ||
18 | typedef istreambuf_iterator<char> it_type; | ||
19 | typedef it_type::iterator_category it_cat; | ||
20 | struct IParser : public mimetic::IteratorParser<it_type,it_cat> { | ||
21 | typedef mimetic::IteratorParser<it_type,it_cat> BT; | ||
22 | IParser(MimeEntity& me) | ||
23 | : BT::IteratorParser<it_type,it_cat>(me) { } | ||
24 | void loadHeader(it_type bit,it_type eit) { | ||
25 | m_bit = bit; m_eit = eit; | ||
26 | BT::loadHeader(); | ||
27 | } | ||
28 | void loadBody(it_type bit,it_type eit) { | ||
29 | m_bit = bit; m_eit = eit; | ||
30 | BT::loadBody(); | ||
31 | } | ||
32 | }; | ||
33 | void load(istream& hs,istream& bs,int mask=0) { | ||
34 | IParser prs(*this); | ||
35 | prs.iMask(mask); | ||
36 | prs.loadHeader(it_type(hs),it_type()); | ||
37 | prs.loadBody(it_type(bs),it_type()); | ||
38 | } | ||
39 | }; | ||
40 | #endif /* HAVE_MIMETIC */ | ||
8 | 41 | ||
@@ -10,3 +43,18 @@ namespace kingate { | |||
10 | 43 | ||
11 | cgi_gateway::cgi_gateway(cgi_interface& ci) | 44 | cgi_gateway::basic_file_t::~basic_file_t() { } |
45 | |||
46 | class string_file_t : public cgi_gateway::basic_file_t { | ||
47 | public: | ||
48 | string _file_name; | ||
49 | string _content_type; | ||
50 | stringstream _content; | ||
51 | |||
52 | string_file_t(const string& fn,const string& ct,const string& s) | ||
53 | : _file_name(fn), _content_type(ct), _content(s,ios::in) { } | ||
54 | const string& filename() const { return _file_name; } | ||
55 | const string& content_type() const { return _content_type; } | ||
56 | istream& content() { return _content; } | ||
57 | }; | ||
58 | |||
59 | cgi_gateway::cgi_gateway(cgi_interface& ci,bool parsebody) | ||
12 | : iface(ci), b_parsed_content(false) { | 60 | : iface(ci), b_parsed_content(false) { |
@@ -17,14 +65,4 @@ namespace kingate { | |||
17 | }catch(exception_notfound& enf) { } | 65 | }catch(exception_notfound& enf) { } |
18 | // Fetch POST content | 66 | if(parsebody) |
19 | if(!strcasecmp(content_type().c_str(),"application/x-www-form-urlencoded")) { | 67 | parse_request_body(); |
20 | unsigned long cl = content_length(); | ||
21 | if(cl) { | ||
22 | char * tmp = new char[cl]; | ||
23 | iface.in().read(tmp,cl); | ||
24 | string qs(tmp,cl); | ||
25 | delete tmp; | ||
26 | parse_query(qs,post); | ||
27 | } | ||
28 | b_parsed_content = true; | ||
29 | } | ||
30 | // Parse cookies | 68 | // Parse cookies |
@@ -35,2 +73,55 @@ namespace kingate { | |||
35 | 73 | ||
74 | cgi_gateway::~cgi_gateway() throw() { | ||
75 | for(files_t::iterator i=files.begin();i!=files.end();++i) | ||
76 | delete i->second; | ||
77 | files.clear(); | ||
78 | } | ||
79 | |||
80 | void cgi_gateway::parse_request_body() { | ||
81 | if(b_parsed_content) | ||
82 | throw konforka::exception(CODEPOINT,"request body is already parsed"); | ||
83 | // Fetch POST content | ||
84 | if(!strncasecmp( | ||
85 | content_type().c_str(), | ||
86 | "application/x-www-form-urlencoded", | ||
87 | sizeof("application/x-www-form-urlencoded")-1) ) { | ||
88 | unsigned long cl = content_length(); | ||
89 | if(cl) { | ||
90 | char * tmp = new char[cl]; | ||
91 | iface.in().read(tmp,cl); | ||
92 | string qs(tmp,cl); | ||
93 | delete tmp; | ||
94 | parse_query(qs,post); | ||
95 | } | ||
96 | b_parsed_content = true; | ||
97 | } | ||
98 | #ifdef HAVE_MIMETIC | ||
99 | else if(!strncasecmp( | ||
100 | content_type().c_str(), | ||
101 | "multipart/form-data", | ||
102 | sizeof("multipart/form-data")-1) ) { | ||
103 | stringstream h; | ||
104 | h | ||
105 | << "Content-Type: " << content_type() << "\r\n" | ||
106 | << "Content-Length: " << content_length() << "\r\n\n"; | ||
107 | TornMimeEntity me; | ||
108 | me.load(h,iface.in(),0); | ||
109 | mimetic::MimeEntityList& parts = me.body().parts(); | ||
110 | for(mimetic::MimeEntityList::iterator i=parts.begin();i!=parts.end();++i) { | ||
111 | MimeEntity *p = *i; | ||
112 | const mimetic::ContentDisposition& cd = p->header().contentDisposition(); | ||
113 | string n = cd.param("name"); | ||
114 | string fn = cd.param("filename"); | ||
115 | if(fn.empty()) { | ||
116 | post.insert(params_t::value_type(n,p->body())); | ||
117 | }else{ | ||
118 | const mimetic::ContentType& ct = p->header().contentType(); | ||
119 | files.insert(files_t::value_type(n,new string_file_t(fn,ct.str(),p->body()))); | ||
120 | } | ||
121 | } | ||
122 | b_parsed_content = true; | ||
123 | } | ||
124 | #endif /* HAVE_MIMETIC */ | ||
125 | } | ||
126 | |||
36 | bool cgi_gateway::has_GET(const string& n) const { | 127 | bool cgi_gateway::has_GET(const string& n) const { |
@@ -65,2 +156,17 @@ namespace kingate { | |||
65 | } | 156 | } |
157 | bool cgi_gateway::has_file(const string& n) const { | ||
158 | return files.find(n) != files.end(); | ||
159 | } | ||
160 | const cgi_gateway::file_t cgi_gateway::get_file(const string& n) const { | ||
161 | files_t::const_iterator i = files.find(n); | ||
162 | if(i==files.end()) | ||
163 | throw exception_notfound(CODEPOINT,"no such parameter"); | ||
164 | return i->second; | ||
165 | } | ||
166 | cgi_gateway::file_t cgi_gateway::get_file(const string& n) { | ||
167 | files_t::const_iterator i = files.find(n); | ||
168 | if(i==files.end()) | ||
169 | throw exception_notfound(CODEPOINT,"no such parameter"); | ||
170 | return i->second; | ||
171 | } | ||
66 | 172 | ||