-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 | |||
@@ -1,70 +1,84 @@ | |||
1 | AC_INIT([kingate], [0.0.1], [kingate-bugs@klever.net]) | 1 | 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]) |
5 | 5 | ||
6 | AC_PROG_INSTALL | 6 | AC_PROG_INSTALL |
7 | AC_PROG_AWK | 7 | AC_PROG_AWK |
8 | AC_PROG_CXX | 8 | AC_PROG_CXX |
9 | AC_PROG_CC | 9 | AC_PROG_CC |
10 | AC_PROG_LIBTOOL | 10 | AC_PROG_LIBTOOL |
11 | 11 | ||
12 | AC_HEADER_STDC | 12 | AC_HEADER_STDC |
13 | AC_CHECK_HEADERS([sys/types.h sys/stat.h]) | 13 | AC_CHECK_HEADERS([sys/types.h sys/stat.h]) |
14 | AC_CHECK_DECLS([environ],,,[ | 14 | AC_CHECK_DECLS([environ],,,[ |
15 | #include <unistd.h> | 15 | #include <unistd.h> |
16 | ]) | 16 | ]) |
17 | 17 | ||
18 | HAVE_FCGI=false | 18 | HAVE_FCGI=false |
19 | AC_LANG_PUSH(C++) | 19 | AC_LANG_PUSH(C++) |
20 | AC_CHECK_HEADERS([fcgio.h],[ | 20 | AC_CHECK_HEADERS([fcgio.h],[ |
21 | AC_CHECK_LIB(fcgi,FCGX_Init,[ | 21 | AC_CHECK_LIB(fcgi,FCGX_Init,[ |
22 | LIBS="-lfcgi ${LIBS}" | 22 | LIBS="-lfcgi ${LIBS}" |
23 | AC_CHECK_LIB([fcgi++],[main],[ | 23 | AC_CHECK_LIB([fcgi++],[main],[ |
24 | LIBS="-lfcgi++ ${LIBS}" | 24 | LIBS="-lfcgi++ ${LIBS}" |
25 | HAVE_FCGI=true | 25 | HAVE_FCGI=true |
26 | ]) | 26 | ]) |
27 | ]) | 27 | ]) |
28 | ]) | 28 | ]) |
29 | AC_LANG_POP(C++) | 29 | AC_LANG_POP(C++) |
30 | if ! ${HAVE_FCGI} ; then | 30 | if ! ${HAVE_FCGI} ; then |
31 | AC_MSG_NOTICE([no FastCGI development kit found. It is highly recommnded that you get one. Meanwhile we will proceed without FastCGI support]) | 31 | AC_MSG_NOTICE([no FastCGI development kit found. It is highly recommnded that you get one. Meanwhile we will proceed without FastCGI support]) |
32 | fi | 32 | fi |
33 | AM_CONDITIONAL([HAVE_FCGI],[${HAVE_FCGI}]) | 33 | AM_CONDITIONAL([HAVE_FCGI],[${HAVE_FCGI}]) |
34 | 34 | ||
35 | AC_C_CONST | 35 | AC_C_CONST |
36 | 36 | ||
37 | AC_FUNC_MALLOC | 37 | AC_FUNC_MALLOC |
38 | AC_FUNC_REALLOC | 38 | AC_FUNC_REALLOC |
39 | 39 | ||
40 | AC_PATH_PROG([XSLTPROC],[xsltproc],[true]) | 40 | AC_PATH_PROG([XSLTPROC],[xsltproc],[true]) |
41 | 41 | ||
42 | AC_WITH_PKGCONFIG | 42 | AC_WITH_PKGCONFIG |
43 | 43 | ||
44 | PKG_CHECK_MODULES([KONFORKA],[konforka],,[ | 44 | PKG_CHECK_MODULES([KONFORKA],[konforka],,[ |
45 | AC_MSG_ERROR([no konforka library found. get one from http://kin.klever.net/konforka/]) | 45 | AC_MSG_ERROR([no konforka library found. get one from http://kin.klever.net/konforka/]) |
46 | ]) | 46 | ]) |
47 | 47 | ||
48 | WANT_DOXYGEN="yes" | 48 | WANT_DOXYGEN="yes" |
49 | AC_ARG_ENABLE([doxygen], | 49 | AC_ARG_ENABLE([doxygen], |
50 | AC_HELP_STRING([--disable-doxygen],[do not generate documentation]), | 50 | AC_HELP_STRING([--disable-doxygen],[do not generate documentation]), |
51 | [ | 51 | [ |
52 | test "${enableval}" = "no" && WANT_DOXYGEN="no" | 52 | test "${enableval}" = "no" && WANT_DOXYGEN="no" |
53 | ] | 53 | ] |
54 | ) | 54 | ) |
55 | if test "${WANT_DOXYGEN}" = "yes" ; then | 55 | if test "${WANT_DOXYGEN}" = "yes" ; then |
56 | AC_WITH_DOXYGEN | 56 | AC_WITH_DOXYGEN |
57 | AC_WITH_DOT | 57 | AC_WITH_DOT |
58 | else | 58 | else |
59 | AM_CONDITIONAL([HAVE_DOXYGEN],[false]) | 59 | AM_CONDITIONAL([HAVE_DOXYGEN],[false]) |
60 | AM_CONDITIONAL([HAVE_DOT],[false]) | 60 | AM_CONDITIONAL([HAVE_DOT],[false]) |
61 | fi | 61 | 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([ |
64 | Makefile | 78 | Makefile |
65 | kingate.pc kingate-fcgi.pc kingate-plaincgi.pc | 79 | kingate.pc kingate-fcgi.pc kingate-plaincgi.pc |
66 | Doxyfile | 80 | Doxyfile |
67 | include/Makefile | 81 | include/Makefile |
68 | src/Makefile | 82 | src/Makefile |
69 | ]) | 83 | ]) |
70 | AC_OUTPUT | 84 | AC_OUTPUT |
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 | |||
@@ -1,244 +1,295 @@ | |||
1 | #ifndef __KINGATE_CGI_GATEWAY_H | 1 | #ifndef __KINGATE_CGI_GATEWAY_H |
2 | #define __KINGATE_CGI_GATEWAY_H | 2 | #define __KINGATE_CGI_GATEWAY_H |
3 | 3 | ||
4 | #include <map> | 4 | #include <map> |
5 | #include "kingate/cgi_interface.h" | 5 | #include "kingate/cgi_interface.h" |
6 | #include "kingate/cookies.h" | 6 | #include "kingate/cookies.h" |
7 | 7 | ||
8 | #ifndef __deprecated | 8 | #ifndef __deprecated |
9 | #if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3 | 9 | #if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3 |
10 | #define __deprecated __attribute__((deprecated)) | 10 | #define __deprecated __attribute__((deprecated)) |
11 | #else | 11 | #else |
12 | #define __deprecated | 12 | #define __deprecated |
13 | #endif | 13 | #endif |
14 | #endif | 14 | #endif |
15 | 15 | ||
16 | /** | 16 | /** |
17 | * @file | 17 | * @file |
18 | * @brief the cgi_gateway -- main interface to CGI. | 18 | * @brief the cgi_gateway -- main interface to CGI. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | namespace kingate { | 21 | namespace kingate { |
22 | using namespace std; | 22 | using namespace std; |
23 | 23 | ||
24 | /** | 24 | /** |
25 | * The main class interfacing with the CGI environment. | 25 | * The main class interfacing with the CGI environment. |
26 | */ | 26 | */ |
27 | class cgi_gateway { | 27 | class cgi_gateway { |
28 | public: | 28 | public: |
29 | /** | 29 | /** |
30 | * The interface to CGI environment (e.g. fastcgi). | 30 | * The interface to CGI environment (e.g. fastcgi). |
31 | */ | 31 | */ |
32 | cgi_interface& iface; | 32 | cgi_interface& iface; |
33 | /** | 33 | /** |
34 | * The type describing map holding parameters parsed from query string or input. | 34 | * The type describing map holding parameters parsed from query string or input. |
35 | */ | 35 | */ |
36 | typedef multimap<string,string> params_t; | 36 | typedef multimap<string,string> params_t; |
37 | /** | 37 | /** |
38 | * The GET-passed parameters. | 38 | * The GET-passed parameters. |
39 | */ | 39 | */ |
40 | params_t get; | 40 | params_t get; |
41 | /** | 41 | /** |
42 | * The POST-passed parameters. | 42 | * The POST-passed parameters. |
43 | */ | 43 | */ |
44 | params_t post; | 44 | params_t post; |
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. |
47 | */ | 78 | */ |
48 | cookies_t cookies; | 79 | cookies_t cookies; |
49 | /** | 80 | /** |
50 | * Was the stdin content parsed? | 81 | * Was the stdin content parsed? |
51 | */ | 82 | */ |
52 | bool b_parsed_content; | 83 | bool b_parsed_content; |
53 | 84 | ||
54 | /** | 85 | /** |
55 | * @param ci the interface to use. | 86 | * @param ci the interface to use. |
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 | ||
59 | /** | 96 | /** |
60 | * Check whether there is an 'environment' meta-variable with specific name | 97 | * Check whether there is an 'environment' meta-variable with specific name |
61 | * passed to CGI. | 98 | * passed to CGI. |
62 | * @param n variable name. | 99 | * @param n variable name. |
63 | * @return true if yes. | 100 | * @return true if yes. |
64 | * @see cgi_interface::has_meta() | 101 | * @see cgi_interface::has_meta() |
65 | * @see get_meta() | 102 | * @see get_meta() |
66 | */ | 103 | */ |
67 | bool has_meta(const string& n) const { return iface.has_meta(n); } | 104 | bool has_meta(const string& n) const { return iface.has_meta(n); } |
68 | /** | 105 | /** |
69 | * Retrieve the 'environment' meta-variable value. | 106 | * Retrieve the 'environment' meta-variable value. |
70 | * @param n variable name. | 107 | * @param n variable name. |
71 | * @return variable contents. | 108 | * @return variable contents. |
72 | * @see exception_notfound | 109 | * @see exception_notfound |
73 | * @see cgi_interface::get_meta() | 110 | * @see cgi_interface::get_meta() |
74 | */ | 111 | */ |
75 | const string& get_meta(const string& n) const { return iface.get_meta(n); } | 112 | const string& get_meta(const string& n) const { return iface.get_meta(n); } |
76 | 113 | ||
77 | /** | 114 | /** |
78 | * fetch reference to the 'stdin' stream. | 115 | * fetch reference to the 'stdin' stream. |
79 | * @return the reference to the corresponding istream object. | 116 | * @return the reference to the corresponding istream object. |
80 | * @see cgi_interface::in() | 117 | * @see cgi_interface::in() |
81 | */ | 118 | */ |
82 | istream& in() { return iface.in(); } | 119 | istream& in() { return iface.in(); } |
83 | /** | 120 | /** |
84 | * fetch reference to the 'stdout' stream. | 121 | * fetch reference to the 'stdout' stream. |
85 | * @return the reference to the corresponding ostream object. | 122 | * @return the reference to the corresponding ostream object. |
86 | * @see cgi_interface::out() | 123 | * @see cgi_interface::out() |
87 | */ | 124 | */ |
88 | ostream& out() { return iface.out(); } | 125 | ostream& out() { return iface.out(); } |
89 | /** | 126 | /** |
90 | * fetch reference to the 'stderr' stream. | 127 | * fetch reference to the 'stderr' stream. |
91 | * @return the reference to the corresponding ostream object. | 128 | * @return the reference to the corresponding ostream object. |
92 | * @see cgi_interface::err() | 129 | * @see cgi_interface::err() |
93 | */ | 130 | */ |
94 | ostream& err() { return iface.err(); } | 131 | ostream& err() { return iface.err(); } |
95 | /** | 132 | /** |
96 | * cast to the ostream -- fetches the reference to the 'stdout' | 133 | * cast to the ostream -- fetches the reference to the 'stdout' |
97 | * stream. | 134 | * stream. |
98 | * @see out() | 135 | * @see out() |
99 | */ | 136 | */ |
100 | operator ostream& (void) { return out(); } | 137 | operator ostream& (void) { return out(); } |
101 | 138 | ||
102 | /** | 139 | /** |
103 | * Check to see whether the parameter was passed via GET. | 140 | * Check to see whether the parameter was passed via GET. |
104 | * @param n the parameter name. | 141 | * @param n the parameter name. |
105 | * @return true if yes. | 142 | * @return true if yes. |
106 | */ | 143 | */ |
107 | bool has_GET(const string& n) const; | 144 | bool has_GET(const string& n) const; |
108 | /** | 145 | /** |
109 | * Retrieve the parameter passed via GET. | 146 | * Retrieve the parameter passed via GET. |
110 | * @param n the parameter name. | 147 | * @param n the parameter name. |
111 | * @return the parameter contents. | 148 | * @return the parameter contents. |
112 | * @see exception_notfound | 149 | * @see exception_notfound |
113 | */ | 150 | */ |
114 | const string& get_GET(const string& n) const; | 151 | const string& get_GET(const string& n) const; |
115 | /** | 152 | /** |
116 | * Check to see whether the parameter was passed via POST. | 153 | * Check to see whether the parameter was passed via POST. |
117 | * @param n the parameter name. | 154 | * @param n the parameter name. |
118 | * @return true if yes. | 155 | * @return true if yes. |
119 | */ | 156 | */ |
120 | bool has_POST(const string& n) const; | 157 | bool has_POST(const string& n) const; |
121 | /** | 158 | /** |
122 | * Retrieve the POST-parameter. | 159 | * Retrieve the POST-parameter. |
123 | * @param n the parameter name. | 160 | * @param n the parameter name. |
124 | * @return the parameter contents. | 161 | * @return the parameter contents. |
125 | * @see exception_notfound | 162 | * @see exception_notfound |
126 | */ | 163 | */ |
127 | const string& get_POST(const string& n) const; | 164 | const string& get_POST(const string& n) const; |
128 | /** | 165 | /** |
129 | * Check to see whether the parameter was passed either via POST or | 166 | * Check to see whether the parameter was passed either via POST or |
130 | * GET. | 167 | * GET. |
131 | * @param n the parameter name. | 168 | * @param n the parameter name. |
132 | * @return true if yes. | 169 | * @return true if yes. |
133 | */ | 170 | */ |
134 | bool has_param(const string& n) const; | 171 | bool has_param(const string& n) const; |
135 | /** | 172 | /** |
136 | * Retrieve the parameter passed either via POST or GET | 173 | * Retrieve the parameter passed either via POST or GET |
137 | * (GET-parameter takes precedence). | 174 | * (GET-parameter takes precedence). |
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. |
141 | */ | 178 | */ |
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 | ||
144 | /** | 195 | /** |
145 | * Retrieve the POST content-type (as passed via CONTENT_TYPE | 196 | * Retrieve the POST content-type (as passed via CONTENT_TYPE |
146 | * environment variable). | 197 | * environment variable). |
147 | * @return the content type. | 198 | * @return the content type. |
148 | */ | 199 | */ |
149 | const string& __deprecated get_content_type() const; | 200 | const string& __deprecated get_content_type() const; |
150 | /** | 201 | /** |
151 | * Retrieve the POST content length (as passed via the | 202 | * Retrieve the POST content length (as passed via the |
152 | * CONTENT_LENGTH environment variable). | 203 | * CONTENT_LENGTH environment variable). |
153 | * @return the content length. | 204 | * @return the content length. |
154 | */ | 205 | */ |
155 | unsigned long __deprecated get_content_length() const; | 206 | unsigned long __deprecated get_content_length() const; |
156 | 207 | ||
157 | /** | 208 | /** |
158 | * Check to see whether the content from stdin stream was parsed. | 209 | * Check to see whether the content from stdin stream was parsed. |
159 | * @return true if yes. | 210 | * @return true if yes. |
160 | */ | 211 | */ |
161 | bool is_content_parsed() const { return b_parsed_content; } | 212 | bool is_content_parsed() const { return b_parsed_content; } |
162 | 213 | ||
163 | /** | 214 | /** |
164 | * Retrieve the HTTP header value from the HTTP_ meta-variable. | 215 | * Retrieve the HTTP header value from the HTTP_ meta-variable. |
165 | * (see RFC3875) | 216 | * (see RFC3875) |
166 | * @param hn header field name. | 217 | * @param hn header field name. |
167 | * @return the HTTP header value. | 218 | * @return the HTTP header value. |
168 | */ | 219 | */ |
169 | const string& http_request_header(const string& hn) const; | 220 | const string& http_request_header(const string& hn) const; |
170 | 221 | ||
171 | /** | 222 | /** |
172 | * Retrieve the AUTH_TYPE meta-variable (see RFC3875) | 223 | * Retrieve the AUTH_TYPE meta-variable (see RFC3875) |
173 | * @return authentication type. | 224 | * @return authentication type. |
174 | */ | 225 | */ |
175 | const string& auth_type() const; | 226 | const string& auth_type() const; |
176 | /** | 227 | /** |
177 | * Retrieve the CONTENT_LENGTH meta-variable (see RFC3875) | 228 | * Retrieve the CONTENT_LENGTH meta-variable (see RFC3875) |
178 | * @return size of the request message body. | 229 | * @return size of the request message body. |
179 | */ | 230 | */ |
180 | unsigned long cgi_gateway::content_length() const; | 231 | unsigned long content_length() const; |
181 | /** | 232 | /** |
182 | * Retrieve the CONTENT_TYPE meta-variable (see RFC3875) | 233 | * Retrieve the CONTENT_TYPE meta-variable (see RFC3875) |
183 | * @return media type of the request message body. | 234 | * @return media type of the request message body. |
184 | */ | 235 | */ |
185 | const string& content_type() const; | 236 | const string& content_type() const; |
186 | /** | 237 | /** |
187 | * Retrieve the GATEWAY_INTERFACE meta-variable (see RFC3875) | 238 | * Retrieve the GATEWAY_INTERFACE meta-variable (see RFC3875) |
188 | * @return the gateway interface dialect. | 239 | * @return the gateway interface dialect. |
189 | */ | 240 | */ |
190 | const string& gateway_interface() const; | 241 | const string& gateway_interface() const; |
191 | /** | 242 | /** |
192 | * Retrieve the PATH_INFO meta-variable (see RFC3875) | 243 | * Retrieve the PATH_INFO meta-variable (see RFC3875) |
193 | * @return path to be interpreted by the script. | 244 | * @return path to be interpreted by the script. |
194 | */ | 245 | */ |
195 | const string& path_info() const; | 246 | const string& path_info() const; |
196 | /** | 247 | /** |
197 | * Retrieve the PATH_TRANSLATED meta-variable (see RFC3875) | 248 | * Retrieve the PATH_TRANSLATED meta-variable (see RFC3875) |
198 | * @return the translated path to the document. | 249 | * @return the translated path to the document. |
199 | */ | 250 | */ |
200 | const string& path_translated() const; | 251 | const string& path_translated() const; |
201 | /** | 252 | /** |
202 | * Retrieve the QUERY_STRING meta-variable (see RFC3875) | 253 | * Retrieve the QUERY_STRING meta-variable (see RFC3875) |
203 | * @return the query string. | 254 | * @return the query string. |
204 | */ | 255 | */ |
205 | const string& query_string() const; | 256 | const string& query_string() const; |
206 | /** | 257 | /** |
207 | * Retrieve the REMOTE_ADDR meta-variable (see RFC3875) | 258 | * Retrieve the REMOTE_ADDR meta-variable (see RFC3875) |
208 | * @return the network address of the remote host. | 259 | * @return the network address of the remote host. |
209 | */ | 260 | */ |
210 | const string& remote_addr() const; | 261 | const string& remote_addr() const; |
211 | /** | 262 | /** |
212 | * Retrieve the REMOTE_HOST meta-variable (see RFC3875) | 263 | * Retrieve the REMOTE_HOST meta-variable (see RFC3875) |
213 | * @return the fully qualified domain name of the client if | 264 | * @return the fully qualified domain name of the client if |
214 | * available. REMOTE_ADDR otherwise. | 265 | * available. REMOTE_ADDR otherwise. |
215 | * @see remote_addr() | 266 | * @see remote_addr() |
216 | */ | 267 | */ |
217 | const string& remote_host() const; | 268 | const string& remote_host() const; |
218 | /** | 269 | /** |
219 | * Retrieve the REMOTE_IDENT meta-variable (see RFC3875) | 270 | * Retrieve the REMOTE_IDENT meta-variable (see RFC3875) |
220 | * @return remote user identity (see RFC1413). | 271 | * @return remote user identity (see RFC1413). |
221 | */ | 272 | */ |
222 | const string& remote_ident() const; | 273 | const string& remote_ident() const; |
223 | /** | 274 | /** |
224 | * Retrieve the REMOTE_USER meta-variable (see RFC3875) | 275 | * Retrieve the REMOTE_USER meta-variable (see RFC3875) |
225 | * @return the authenticated user name. | 276 | * @return the authenticated user name. |
226 | */ | 277 | */ |
227 | const string& remote_user() const; | 278 | const string& remote_user() const; |
228 | /** | 279 | /** |
229 | * Retrieve the REQUEST_METHOD meta-variable (see RFC3875) | 280 | * Retrieve the REQUEST_METHOD meta-variable (see RFC3875) |
230 | * @return the http request method. | 281 | * @return the http request method. |
231 | */ | 282 | */ |
232 | const string& request_method() const; | 283 | const string& request_method() const; |
233 | /** | 284 | /** |
234 | * Retrieve the SCRIPT_NAME meta-variable (see RFC3875) | 285 | * Retrieve the SCRIPT_NAME meta-variable (see RFC3875) |
235 | * @return the uri path identifying the script. | 286 | * @return the uri path identifying the script. |
236 | */ | 287 | */ |
237 | const string& script_name() const; | 288 | const string& script_name() const; |
238 | /** | 289 | /** |
239 | * Retrieve the SERVER_NAME meta-variable (see RFC3875) | 290 | * Retrieve the SERVER_NAME meta-variable (see RFC3875) |
240 | * @return the server name of the script. | 291 | * @return the server name of the script. |
241 | */ | 292 | */ |
242 | const string& server_name() const; | 293 | const string& server_name() const; |
243 | /** | 294 | /** |
244 | * Retrieve the SERVER_PORT meta-variable (see RFC3875) | 295 | * Retrieve the SERVER_PORT meta-variable (see RFC3875) |
diff --git a/kingate.pc.in b/kingate.pc.in index 671faac..05cfe1d 100644 --- a/kingate.pc.in +++ b/kingate.pc.in | |||
@@ -1,11 +1,11 @@ | |||
1 | prefix=@prefix@ | 1 | prefix=@prefix@ |
2 | exec_prefix=@exec_prefix@ | 2 | exec_prefix=@exec_prefix@ |
3 | libdir=@libdir@ | 3 | libdir=@libdir@ |
4 | includedir=@includedir@ | 4 | includedir=@includedir@ |
5 | 5 | ||
6 | Name: kingate | 6 | Name: kingate |
7 | Description: C++ CGI support library | 7 | Description: C++ CGI support library |
8 | Version: @VERSION@ | 8 | 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 | |||
@@ -1,129 +1,235 @@ | |||
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 | } |