-rw-r--r-- | src/cgi_gateway.cc | 132 |
1 files changed, 119 insertions, 13 deletions
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 | |||
@@ -1,245 +1,351 @@ | |||
1 | #include <errno.h> | 1 | #include <errno.h> |
2 | #include <ctype.h> | 2 | #include <ctype.h> |
3 | #include <sstream> | ||
3 | #include "kingate/cgi_gateway.h" | 4 | #include "kingate/cgi_gateway.h" |
4 | #include "kingate/util.h" | 5 | #include "kingate/util.h" |
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 | ||
9 | static string empty_string; | 42 | static string empty_string; |
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) { |
13 | // Fetch GET content | 61 | // Fetch GET content |
14 | try { | 62 | try { |
15 | string qs = get_meta("QUERY_STRING"); | 63 | string qs = get_meta("QUERY_STRING"); |
16 | parse_query(qs,get); | 64 | parse_query(qs,get); |
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 |
31 | try { | 69 | try { |
32 | cookies.parse_cookies(get_meta("HTTP_COOKIE")); | 70 | cookies.parse_cookies(get_meta("HTTP_COOKIE")); |
33 | }catch(exception_notfound& enf) { } | 71 | }catch(exception_notfound& enf) { } |
34 | } | 72 | } |
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 { |
37 | return get.find(n) != get.end(); | 128 | return get.find(n) != get.end(); |
38 | } | 129 | } |
39 | const string& cgi_gateway::get_GET(const string& n) const { | 130 | const string& cgi_gateway::get_GET(const string& n) const { |
40 | params_t::const_iterator i = get.find(n); | 131 | params_t::const_iterator i = get.find(n); |
41 | if(i==get.end()) | 132 | if(i==get.end()) |
42 | throw exception_notfound(CODEPOINT,"no such parameter"); | 133 | throw exception_notfound(CODEPOINT,"no such parameter"); |
43 | return i->second; | 134 | return i->second; |
44 | } | 135 | } |
45 | bool cgi_gateway::has_POST(const string& n) const { | 136 | bool cgi_gateway::has_POST(const string& n) const { |
46 | return post.find(n) != post.end(); | 137 | return post.find(n) != post.end(); |
47 | } | 138 | } |
48 | const string& cgi_gateway::get_POST(const string& n) const { | 139 | const string& cgi_gateway::get_POST(const string& n) const { |
49 | params_t::const_iterator i = post.find(n); | 140 | params_t::const_iterator i = post.find(n); |
50 | if(i==post.end()) | 141 | if(i==post.end()) |
51 | throw exception_notfound(CODEPOINT,"no such parameter"); | 142 | throw exception_notfound(CODEPOINT,"no such parameter"); |
52 | return i->second; | 143 | return i->second; |
53 | } | 144 | } |
54 | bool cgi_gateway::has_param(const string& n) const { | 145 | bool cgi_gateway::has_param(const string& n) const { |
55 | return has_GET(n) || has_POST(n); | 146 | return has_GET(n) || has_POST(n); |
56 | } | 147 | } |
57 | const string& cgi_gateway::get_param(const string& n) const { | 148 | const string& cgi_gateway::get_param(const string& n) const { |
58 | params_t::const_iterator i = get.find(n); | 149 | params_t::const_iterator i = get.find(n); |
59 | if(i!=get.end()) | 150 | if(i!=get.end()) |
60 | return i->second; | 151 | return i->second; |
61 | i = post.find(n); | 152 | i = post.find(n); |
62 | if(i!=post.end()) | 153 | if(i!=post.end()) |
63 | return i->second; | 154 | return i->second; |
64 | throw exception_notfound(CODEPOINT,"no such parameter"); | 155 | throw exception_notfound(CODEPOINT,"no such parameter"); |
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 | ||
67 | /* | 173 | /* |
68 | * deprecated stuff. | 174 | * deprecated stuff. |
69 | */ | 175 | */ |
70 | const string& cgi_gateway::get_content_type() const { | 176 | const string& cgi_gateway::get_content_type() const { |
71 | if(!has_meta("CONTENT_TYPE")) | 177 | if(!has_meta("CONTENT_TYPE")) |
72 | return empty_string; | 178 | return empty_string; |
73 | return get_meta("CONTENT_TYPE"); | 179 | return get_meta("CONTENT_TYPE"); |
74 | } | 180 | } |
75 | unsigned long cgi_gateway::get_content_length() const { | 181 | unsigned long cgi_gateway::get_content_length() const { |
76 | if(!has_meta("CONTENT_LENGTH")) | 182 | if(!has_meta("CONTENT_LENGTH")) |
77 | return 0; | 183 | return 0; |
78 | string cl = get_meta("CONTENT_LENGTH"); | 184 | string cl = get_meta("CONTENT_LENGTH"); |
79 | return strtol(cl.c_str(),NULL,10); | 185 | return strtol(cl.c_str(),NULL,10); |
80 | } | 186 | } |
81 | /* | 187 | /* |
82 | * | 188 | * |
83 | */ | 189 | */ |
84 | 190 | ||
85 | const string& cgi_gateway::http_request_header(const string& hn) const { | 191 | const string& cgi_gateway::http_request_header(const string& hn) const { |
86 | string mvn = "HTTP_"; | 192 | string mvn = "HTTP_"; |
87 | for(const char* p=hn.c_str();*p;p++) { | 193 | for(const char* p=hn.c_str();*p;p++) { |
88 | if(*p=='-') | 194 | if(*p=='-') |
89 | mvn += '_'; | 195 | mvn += '_'; |
90 | else | 196 | else |
91 | mvn += toupper(*p); | 197 | mvn += toupper(*p); |
92 | } | 198 | } |
93 | return get_meta(mvn); | 199 | return get_meta(mvn); |
94 | } | 200 | } |
95 | 201 | ||
96 | const string& cgi_gateway::auth_type() const { | 202 | const string& cgi_gateway::auth_type() const { |
97 | try { | 203 | try { |
98 | return get_meta("AUTH_TYPE"); | 204 | return get_meta("AUTH_TYPE"); |
99 | }catch(exception_notfound& enf) { | 205 | }catch(exception_notfound& enf) { |
100 | return empty_string; | 206 | return empty_string; |
101 | } | 207 | } |
102 | } | 208 | } |
103 | unsigned long cgi_gateway::content_length() const { | 209 | unsigned long cgi_gateway::content_length() const { |
104 | try { | 210 | try { |
105 | const string& cl = get_meta("CONTENT_LENGTH"); | 211 | const string& cl = get_meta("CONTENT_LENGTH"); |
106 | errno = 0; | 212 | errno = 0; |
107 | const char *clp = cl.c_str(); | 213 | const char *clp = cl.c_str(); |
108 | unsigned long rv = strtol(clp,(char**)&clp,10); | 214 | unsigned long rv = strtol(clp,(char**)&clp,10); |
109 | if(errno || *clp) | 215 | if(errno || *clp) |
110 | throw server_error(CODEPOINT,"Invalid CONTENT_LENGTH value passed from server"); | 216 | throw server_error(CODEPOINT,"Invalid CONTENT_LENGTH value passed from server"); |
111 | return rv; | 217 | return rv; |
112 | }catch(exception_notfound& enf) { | 218 | }catch(exception_notfound& enf) { |
113 | return 0; | 219 | return 0; |
114 | } | 220 | } |
115 | } | 221 | } |
116 | const string& cgi_gateway::content_type() const { | 222 | const string& cgi_gateway::content_type() const { |
117 | try { | 223 | try { |
118 | return get_meta("CONTENT_TYPE"); | 224 | return get_meta("CONTENT_TYPE"); |
119 | }catch(exception_notfound& enf) { | 225 | }catch(exception_notfound& enf) { |
120 | return empty_string; | 226 | return empty_string; |
121 | } | 227 | } |
122 | } | 228 | } |
123 | const string& cgi_gateway::gateway_interface() const { | 229 | const string& cgi_gateway::gateway_interface() const { |
124 | try { | 230 | try { |
125 | return get_meta("GATEWAY_INTERFACE"); | 231 | return get_meta("GATEWAY_INTERFACE"); |
126 | }catch(exception_notfound& enf) { | 232 | }catch(exception_notfound& enf) { |
127 | return empty_string; | 233 | return empty_string; |
128 | } | 234 | } |
129 | } | 235 | } |
130 | const string& cgi_gateway::path_info() const { | 236 | const string& cgi_gateway::path_info() const { |
131 | try { | 237 | try { |
132 | return get_meta("PATH_INFO"); | 238 | return get_meta("PATH_INFO"); |
133 | }catch(exception_notfound& enf) { | 239 | }catch(exception_notfound& enf) { |
134 | return empty_string; | 240 | return empty_string; |
135 | } | 241 | } |
136 | } | 242 | } |
137 | const string& cgi_gateway::path_translated() const { | 243 | const string& cgi_gateway::path_translated() const { |
138 | try { | 244 | try { |
139 | return get_meta("PATH_TRANSLATED"); | 245 | return get_meta("PATH_TRANSLATED"); |
140 | }catch(exception_notfound& enf) { | 246 | }catch(exception_notfound& enf) { |
141 | return empty_string; | 247 | return empty_string; |
142 | } | 248 | } |
143 | } | 249 | } |
144 | const string& cgi_gateway::query_string() const { | 250 | const string& cgi_gateway::query_string() const { |
145 | try { | 251 | try { |
146 | return get_meta("QUERY_STRING"); | 252 | return get_meta("QUERY_STRING"); |
147 | }catch(exception_notfound& enf) { | 253 | }catch(exception_notfound& enf) { |
148 | return empty_string; | 254 | return empty_string; |
149 | } | 255 | } |
150 | } | 256 | } |
151 | const string& cgi_gateway::remote_addr() const { | 257 | const string& cgi_gateway::remote_addr() const { |
152 | try { | 258 | try { |
153 | return get_meta("REMOTE_ADDR"); | 259 | return get_meta("REMOTE_ADDR"); |
154 | }catch(exception_notfound& enf) { | 260 | }catch(exception_notfound& enf) { |
155 | return empty_string; | 261 | return empty_string; |
156 | } | 262 | } |
157 | } | 263 | } |
158 | const string& cgi_gateway::remote_host() const { | 264 | const string& cgi_gateway::remote_host() const { |
159 | try { | 265 | try { |
160 | return get_meta("REMOTE_HOST"); | 266 | return get_meta("REMOTE_HOST"); |
161 | }catch(exception_notfound& enf) { | 267 | }catch(exception_notfound& enf) { |
162 | return remote_addr(); | 268 | return remote_addr(); |
163 | } | 269 | } |
164 | } | 270 | } |
165 | const string& cgi_gateway::remote_ident() const { | 271 | const string& cgi_gateway::remote_ident() const { |
166 | try { | 272 | try { |
167 | return get_meta("REMOTE_IDENT"); | 273 | return get_meta("REMOTE_IDENT"); |
168 | }catch(exception_notfound& enf) { | 274 | }catch(exception_notfound& enf) { |
169 | return empty_string; | 275 | return empty_string; |
170 | } | 276 | } |
171 | } | 277 | } |
172 | const string& cgi_gateway::remote_user() const { | 278 | const string& cgi_gateway::remote_user() const { |
173 | try { | 279 | try { |
174 | return get_meta("REMOTE_USER"); | 280 | return get_meta("REMOTE_USER"); |
175 | }catch(exception_notfound& enf) { | 281 | }catch(exception_notfound& enf) { |
176 | return empty_string; | 282 | return empty_string; |
177 | } | 283 | } |
178 | } | 284 | } |
179 | const string& cgi_gateway::request_method() const { | 285 | const string& cgi_gateway::request_method() const { |
180 | try { | 286 | try { |
181 | return get_meta("REQUEST_METHOD"); | 287 | return get_meta("REQUEST_METHOD"); |
182 | }catch(exception_notfound& enf) { | 288 | }catch(exception_notfound& enf) { |
183 | throw server_error(CODEPOINT,"No REQUEST_METHOD passed from server"); | 289 | throw server_error(CODEPOINT,"No REQUEST_METHOD passed from server"); |
184 | } | 290 | } |
185 | } | 291 | } |
186 | const string& cgi_gateway::script_name() const { | 292 | const string& cgi_gateway::script_name() const { |
187 | try { | 293 | try { |
188 | return get_meta("SCRIPT_NAME"); | 294 | return get_meta("SCRIPT_NAME"); |
189 | }catch(exception_notfound& enf) { | 295 | }catch(exception_notfound& enf) { |
190 | throw server_error(CODEPOINT,"No SCRIPT_NAME passed from server"); | 296 | throw server_error(CODEPOINT,"No SCRIPT_NAME passed from server"); |
191 | } | 297 | } |
192 | } | 298 | } |
193 | const string& cgi_gateway::server_name() const { | 299 | const string& cgi_gateway::server_name() const { |
194 | try { | 300 | try { |
195 | return get_meta("SERVER_NAME"); | 301 | return get_meta("SERVER_NAME"); |
196 | }catch(exception_notfound& enf) { | 302 | }catch(exception_notfound& enf) { |
197 | throw server_error(CODEPOINT,"No SERVER_NAME passed from server"); | 303 | throw server_error(CODEPOINT,"No SERVER_NAME passed from server"); |
198 | } | 304 | } |
199 | } | 305 | } |
200 | unsigned int cgi_gateway::server_port() const { | 306 | unsigned int cgi_gateway::server_port() const { |
201 | try { | 307 | try { |
202 | const string& sp = get_meta("SERVER_PORT"); | 308 | const string& sp = get_meta("SERVER_PORT"); |
203 | errno = 0; | 309 | errno = 0; |
204 | const char *spp = sp.c_str(); | 310 | const char *spp = sp.c_str(); |
205 | unsigned int rv = strtol(spp,(char**)&spp,10); | 311 | unsigned int rv = strtol(spp,(char**)&spp,10); |
206 | if(errno || *spp) | 312 | if(errno || *spp) |
207 | throw server_error(CODEPOINT,"Invalid SERVER_PORT value passed from server"); | 313 | throw server_error(CODEPOINT,"Invalid SERVER_PORT value passed from server"); |
208 | return rv; | 314 | return rv; |
209 | }catch(exception_notfound& enf) { | 315 | }catch(exception_notfound& enf) { |
210 | throw server_error(CODEPOINT,"No SERVER_PORT passed from server"); | 316 | throw server_error(CODEPOINT,"No SERVER_PORT passed from server"); |
211 | } | 317 | } |
212 | } | 318 | } |
213 | const string& cgi_gateway::server_protocol() const { | 319 | const string& cgi_gateway::server_protocol() const { |
214 | try { | 320 | try { |
215 | return get_meta("SERVER_PROTOCOL"); | 321 | return get_meta("SERVER_PROTOCOL"); |
216 | }catch(exception_notfound& enf) { | 322 | }catch(exception_notfound& enf) { |
217 | throw server_error(CODEPOINT,"No SERVER_PROTOCOL passed from server"); | 323 | throw server_error(CODEPOINT,"No SERVER_PROTOCOL passed from server"); |
218 | } | 324 | } |
219 | } | 325 | } |
220 | const string& cgi_gateway::server_software() const { | 326 | const string& cgi_gateway::server_software() const { |
221 | try { | 327 | try { |
222 | return get_meta("SERVER_SOFTWARE"); | 328 | return get_meta("SERVER_SOFTWARE"); |
223 | }catch(exception_notfound& enf) { | 329 | }catch(exception_notfound& enf) { |
224 | throw server_error(CODEPOINT,"No SERVER_SOFTWARE passed from server"); | 330 | throw server_error(CODEPOINT,"No SERVER_SOFTWARE passed from server"); |
225 | } | 331 | } |
226 | } | 332 | } |
227 | 333 | ||
228 | void cgi_gateway::parse_query(string& q,params_t& p) { | 334 | void cgi_gateway::parse_query(string& q,params_t& p) { |
229 | while(!q.empty()) { | 335 | while(!q.empty()) { |
230 | string::size_type amp = q.find('&'); | 336 | string::size_type amp = q.find('&'); |
231 | string pp = (amp==string::npos)?q:q.substr(0,amp); | 337 | string pp = (amp==string::npos)?q:q.substr(0,amp); |
232 | if(amp==string::npos) | 338 | if(amp==string::npos) |
233 | q.clear(); | 339 | q.clear(); |
234 | else | 340 | else |
235 | q.erase(0,amp+1); | 341 | q.erase(0,amp+1); |
236 | string::size_type eq = pp.find('='); | 342 | string::size_type eq = pp.find('='); |
237 | if(eq == string::npos) { | 343 | if(eq == string::npos) { |
238 | p.insert(params_t::value_type("",url_decode(pp))); | 344 | p.insert(params_t::value_type("",url_decode(pp))); |
239 | }else{ | 345 | }else{ |
240 | p.insert(params_t::value_type(url_decode(pp.substr(0,eq)),url_decode(pp.substr(eq+1)))); | 346 | p.insert(params_t::value_type(url_decode(pp.substr(0,eq)),url_decode(pp.substr(eq+1)))); |
241 | } | 347 | } |
242 | } | 348 | } |
243 | } | 349 | } |
244 | 350 | ||
245 | } | 351 | } |