-rw-r--r-- | include/kingate/cgi_gateway.h | 1 | ||||
-rw-r--r-- | include/kingate/cookies.h | 4 | ||||
-rw-r--r-- | src/cookies.cc | 7 |
3 files changed, 7 insertions, 5 deletions
diff --git a/include/kingate/cgi_gateway.h b/include/kingate/cgi_gateway.h index a26b0ae..087f7d0 100644 --- a/include/kingate/cgi_gateway.h +++ b/include/kingate/cgi_gateway.h @@ -1,325 +1,324 @@ #ifndef __KINGATE_CGI_GATEWAY_H #define __KINGATE_CGI_GATEWAY_H #include <map> #include "kingate/cgi_interface.h" #include "kingate/cookies.h" #ifndef __deprecated #if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3 #define __deprecated __attribute__((deprecated)) #else #define __deprecated #endif #endif /** * @file * @brief the cgi_gateway -- main interface to CGI. */ namespace kingate { using namespace std; /** * The main class interfacing with the CGI environment. */ class cgi_gateway { public: /** * The interface to CGI environment (e.g. fastcgi). */ cgi_interface& iface; /** * The type describing map holding parameters parsed from query string or input. */ typedef multimap<string,string> params_t; /** * The GET-passed parameters. */ params_t get; /** * The POST-passed parameters. */ params_t post; /** * Abstract base class for retrieving posted files. */ class basic_file_t { public: /** * Retrieve file name. * @return filename */ virtual const string& filename() const = 0; /** * Retrieve file content type. * @return content type */ virtual const string& content_type() const = 0; /** * Retrieve file contents. * @return reference to the stream for accessing file content. */ virtual istream& content() = 0; virtual ~basic_file_t(); }; typedef basic_file_t *file_t; /** * The map holding information pertaining to files uploaded via post. */ typedef multimap<string,file_t> files_t; /** * Files uploaded via post */ files_t files; /** * Cookies passed. */ cookies_t cookies; /** * Was the stdin content parsed? */ bool b_parsed_content; /** * @param ci the interface to use. */ cgi_gateway(cgi_interface& ci,bool parsebody = true); virtual ~cgi_gateway() throw(); /** * Parse request body. */ void parse_request_body(); /** * Check whether there is an 'environment' meta-variable with specific name * passed to CGI. * @param n variable name. * @return true if yes. * @see cgi_interface::has_meta() * @see get_meta() */ bool has_meta(const string& n) const { return iface.has_meta(n); } /** * Retrieve the 'environment' meta-variable value. * @param n variable name. * @return variable contents. * @see exception_notfound * @see cgi_interface::get_meta() */ const string& get_meta(const string& n) const { return iface.get_meta(n); } /** * fetch reference to the 'stdin' stream. * @return the reference to the corresponding istream object. * @see cgi_interface::in() */ istream& in() { return iface.in(); } /** * fetch reference to the 'stdout' stream. * @return the reference to the corresponding ostream object. * @see cgi_interface::out() */ ostream& out() { return iface.out(); } /** * fetch reference to the 'stderr' stream. * @return the reference to the corresponding ostream object. * @see cgi_interface::err() */ ostream& err() { return iface.err(); } /** * cast to the ostream -- fetches the reference to the 'stdout' * stream. * @see out() */ operator ostream& (void) { return out(); } /** * Check to see whether the parameter was passed via GET. * @param n the parameter name. * @return true if yes. */ bool has_GET(const string& n) const; /** * Retrieve the parameter passed via GET. * @param n the parameter name. * @return the parameter contents. * @see exception_notfound */ const string& get_GET(const string& n) const; /** * Check to see whether the parameter was passed via POST. * @param n the parameter name. * @return true if yes. */ bool has_POST(const string& n) const; /** * Retrieve the POST-parameter. * @param n the parameter name. * @return the parameter contents. * @see exception_notfound */ const string& get_POST(const string& n) const; /** * Check to see whether the parameter was passed either via POST or * GET. * @param n the parameter name. * @return true if yes. */ bool has_param(const string& n) const; /** * Retrieve the parameter passed either via POST or GET * (GET-parameter takes precedence). * @param n the parameter name. * @return the parameter contents. * @see exception_notfound. */ const string& get_param(const string& n) const; /** * Check to see whether the file was uploaded in the request body. * @param n the parameter name. * @return true if yes. */ bool has_file(const string& n) const; /** * Retrieve the file uploaded in the request body. * @param n the parameter name. * @return the file. * @see exception_notfound. */ const file_t get_file(const string& n) const; file_t get_file(const string& n); /** * Retrieve the POST content-type (as passed via CONTENT_TYPE * environment variable). * @return the content type. */ const string& __deprecated get_content_type() const; /** * Retrieve the POST content length (as passed via the * CONTENT_LENGTH environment variable). * @return the content length. */ unsigned long __deprecated get_content_length() const; /** * Check to see whether the content from stdin stream was parsed. * @return true if yes. */ bool is_content_parsed() const { return b_parsed_content; } /** * Retrieve the HTTP header value from the HTTP_ meta-variable. * (see RFC3875) * @param hn header field name. * @return the HTTP header value. */ const string& http_request_header(const string& hn) const; /** * Retrieve the AUTH_TYPE meta-variable (see RFC3875) * @return authentication type. */ const string& auth_type() const; /** * Retrieve the CONTENT_LENGTH meta-variable (see RFC3875) * @return size of the request message body. */ unsigned long content_length() const; /** * Retrieve the CONTENT_TYPE meta-variable (see RFC3875) * @return media type of the request message body. */ const string& content_type() const; /** * Retrieve the GATEWAY_INTERFACE meta-variable (see RFC3875) * @return the gateway interface dialect. */ const string& gateway_interface() const; /** * Retrieve the PATH_INFO meta-variable (see RFC3875) * @return path to be interpreted by the script. */ const string& path_info() const; /** * Retrieve the PATH_TRANSLATED meta-variable (see RFC3875) * @return the translated path to the document. */ const string& path_translated() const; /** * Retrieve the QUERY_STRING meta-variable (see RFC3875) * @return the query string. */ const string& query_string() const; /** * Retrieve the REMOTE_ADDR meta-variable (see RFC3875) * @return the network address of the remote host. */ const string& remote_addr() const; /** * Retrieve the REMOTE_HOST meta-variable (see RFC3875) * @return the fully qualified domain name of the client if * available. REMOTE_ADDR otherwise. * @see remote_addr() */ const string& remote_host() const; /** * Retrieve the REMOTE_IDENT meta-variable (see RFC3875) * @return remote user identity (see RFC1413). */ const string& remote_ident() const; /** * Retrieve the REMOTE_USER meta-variable (see RFC3875) * @return the authenticated user name. */ const string& remote_user() const; /** * Retrieve the REQUEST_METHOD meta-variable (see RFC3875) * @return the http request method. */ const string& request_method() const; /** * Retrieve the SCRIPT_NAME meta-variable (see RFC3875) * @return the uri path identifying the script. */ const string& script_name() const; /** * Retrieve the SERVER_NAME meta-variable (see RFC3875) * @return the server name of the script. */ const string& server_name() const; /** * Retrieve the SERVER_PORT meta-variable (see RFC3875) * @return the port on which request was received. */ unsigned int server_port() const; /** * Retrieve the SERVER_PROTOCOL meta-variable (see RFC3875) * @return the protocol used for the request. */ const string& server_protocol() const; /** * Retrieve the SERVER_SOFTWARE meta-variable (see RFC3875) * @return the name and version of server software. */ const string& server_software() const; - private: /** * Parse the query string, putting the parameters into the map * specified. * @param q the query string. * @param p destination parameters map. */ static void parse_query(string& q,params_t& p); }; } #endif /* __KINGATE_CGI_GATEWAY_H */ /* * vim:set ft=cpp: */ diff --git a/include/kingate/cookies.h b/include/kingate/cookies.h index 83ef0c6..a1e813c 100644 --- a/include/kingate/cookies.h +++ b/include/kingate/cookies.h @@ -1,300 +1,300 @@ #ifndef __KINGATE_COOKIES_H #define __KINGATE_COOKIES_H #include <string> #include <map> #include <ostream> /** * @file * @brief cookies-related classes. */ namespace kingate { using namespace std; /** * Class, holding the cookie with parameters. */ class cookie : public map<string,string> { public: /** * Cookie name. */ string name; /** * Cookie value. */ string value; cookie() { } /** * @param n cookie name. * @param v cookie value. */ cookie(const string& n,const string& v) : name(n), value(v) { } /** * set cookie parameter. * @param p parameter name. * @param v parameter value. * @see _get_string() */ void _set_string(const string& p,const string& v); /** * @param n cookie name. * @see get_name() */ void set_name(const string& n) { name = n; } /** * @param v cookie value. * @see set_value() */ void set_value(const string& v) { value = v; } /** * @param c coomment. * @see get_comment() * @see has_comment() * @see unset_comment() */ void set_comment(const string& c); /** * @param d domain. * @see get_domain() * @see has_domain() * @see unset_domain() */ void set_domain(const string& d); /** * @param ma max-age. * @see get_max_age() * @see has_max_age() * @see unset_max_age() */ void set_max_age(const string& ma); /** * @param p path. * @see get_path() * @see has_path() * @see unset_path() */ void set_path(const string& p); /** * set cookie security. * @param s true if secure. * @see get_secure() * @see is_secure() */ void set_secure(bool s); /** * @param e expiration time. * @see get_expires() * @see has_expires() * @see unset_expires() */ void set_expires(const string& e); /** * get cookie parameter. * @param p parameter name. * @return parameter value. * @see _set_string() */ const string& _get_string(const string& p) const; /** * @return cookie name. * @see set_name() */ const string& get_name() const { return name; } /** * @return cookie value. * @see set_value() */ const string& get_value() const { return value; } /** * @return cookie comment. * @see set_comment() * @see has_comment() * @see unset_comment() */ const string& get_comment() const; /** * @return cookie domain. * @see set_domain() * @see has_domain() * @see unset_domain() */ const string& get_domain() const; /** * @return cookie max-age. * @see set_max_age() * @see has_max_age() * @see unset_max_age() */ const string& get_max_age() const; /** * @return cookie path. * @see set_path() * @see has_path() * @see unset_path() */ const string& get_path() const; /** * @return cookie security. * @see is_secure() * @see set_secure() */ bool get_secure() const; /** * @return cookie security. * @see get_secure() * @see set_secure() */ bool is_secure() const { return get_secure(); } /** * @return cookie expiration time. * @see set_expires() * @see has_expires() * @see unset_expires() */ const string& get_expires() const; /** * @return true if cookie has comment. * @see set_comment() * @see get_comment() * @see unset_comment() */ bool has_comment() const; /** * @return true if cookie has domain. * @see set_domain() * @see get_domain() * @see unset_domain() */ bool has_domain() const; /** * @return true if cookie has max-age. * @see set_max_age() * @see get_max_age() * @see unset_max_age() */ bool has_max_age() const; /** * @return true if cookie has path. * @see set_path() * @see get_path() * @see unset_path() */ bool has_path() const; /** * @return true if cookie has expiration time. * @see set_expires() * @see get_expires() * @see unset_expires() */ bool has_expires() const; /** * rid cookie of comment. * @see set_comment() * @see get_comment() * @see has_comment() */ void unset_comment(); /** * rid cookie of domain. * @see set_domain() * @see get_domain() * @see has_domain() */ void unset_domain(); /** * rid cookie of max-age. * @see set_max_age() * @see get_max_age() * @see has_max_age() */ void unset_max_age(); /** * rid cookie of path. * @see set_path() * @see get_path() * @see has_path() */ void unset_path(); /** * rid cookie of expiration time. * @see set_expires() * @see get_expires() * @see has_expires() */ void unset_expires(); /** * render the 'Set-Cookie' HTTP header according to RFC2109. * Absolutely useless, only works with lynx. * @return the rendered header content. */ string set_cookie_header_rfc2109() const; /** * render the 'Set-Cookie' header according to the early vague * netscape specs and common practice. * @return the rendered header content. */ string set_cookie_header() const; }; /** * Cookies container class. */ - class cookies_t : public map<string,cookie> { + class cookies_t : public multimap<string,cookie> { public: cookies_t() { } /** * @param s 'Cookie:' HTTP header contents to parse. */ cookies_t(const string& s) { parse_cookies(s); } /** * @param c cookie to set. */ - void set_cookie(const cookie& c) { (*this)[c.get_name()]=c; } + void set_cookie(const cookie& c); /** * @param n cookie name to remove. */ void unset_cookie(const key_type& n) { erase(n); } /** * @param n cookie name. * @return true if exists. */ bool has_cookie(const key_type& n) const; /** * Return the named cookie if one exists. * @param n cookie name. * @return const reference to cookie object. */ const cookie& get_cookie(const key_type& n) const; /** * Return the named cookie if one exists. * @param n cookie name. * @return reference to cookie object. */ cookie& get_cookie(const key_type& n); /** * @param s HTTP 'Cookie' header content. */ void parse_cookies(const string& s); }; } #endif /* __KINGATE_COOKIES_H */ diff --git a/src/cookies.cc b/src/cookies.cc index 40a0c8b..1ee4f7c 100644 --- a/src/cookies.cc +++ b/src/cookies.cc @@ -1,242 +1,245 @@ #include "kingate/cookies.h" #include "kingate/util.h" #include "kingate/exception.h" namespace kingate { /* * RFC 2109: * av-pairs = av-pair *(";" av-pair) * av-pair = attr ["=" value] ; optional value * attr = token * value = word * word = token | quoted-string */ /* RFC 2109: * * The origin server effectively ends a session by sending the client a * Set-Cookie header with Max-Age=0. * * An origin server may include multiple Set-Cookie headers in a response. * Note that an intervening gateway could fold multiple such headers into a * single header. * * * set-cookie = "Set-Cookie:" cookies * cookies = 1#cookie * cookie = NAME "=" VALUE *(";" cookie-av) * NAME = attr * VALUE = value * cookie-av = "Comment" "=" value * | "Domain" "=" value * | "Max-Age" "=" value * | "Path" "=" value * | "Secure" * | "Version" "=" 1*DIGIT * * * The origin server should send the following additional HTTP/1.1 * response headers, depending on circumstances: * * * To suppress caching of the Set-Cookie header: Cache-control: no- * cache="set-cookie". * * and one of the following: * * * To suppress caching of a private document in shared caches: Cache- * control: private. * * * To allow caching of a document and require that it be validated * before returning it to the client: Cache-control: must-revalidate. * * * To allow caching of a document, but to require that proxy caches * (not user agent caches) validate it before returning it to the * client: Cache-control: proxy-revalidate. * * * To allow caching of a document and request that it be validated * before returning it to the client (by "pre-expiring" it): * Cache-control: max-age=0. Not all caches will revalidate the * document in every case. * * HTTP/1.1 servers must send Expires: old-date (where old-date is a * date long in the past) on responses containing Set-Cookie response * headers unless they know for certain (by out of band means) that * there are no downsteam HTTP/1.0 proxies. HTTP/1.1 servers may send * other Cache-Control directives that permit caching by HTTP/1.1 * proxies in addition to the Expires: old-date directive; the Cache- * Control directive will override the Expires: old-date for HTTP/1.1 * proxies. * */ void cookie::_set_string(const string& p,const string& v) { (*this)[p]=v; } void cookie::set_comment(const string& c) { _set_string("comment",c); } void cookie::set_domain(const string& d) { _set_string("domain",d); } void cookie::set_max_age(const string& ma) { _set_string("max-age",ma); } void cookie::set_path(const string& p) { _set_string("path",p); } void cookie::set_secure(bool s) { if(s) _set_string("secure",""); else erase("secure"); } void cookie::set_expires(const string& e) { (*this)["expires"] = e; } const string& cookie::_get_string(const string& s) const { const_iterator i = find(s); if(i==end()) throw exception_notfound(CODEPOINT,"No parameter set"); return i->second; } const string& cookie::get_comment() const { return _get_string("comment"); } const string& cookie::get_domain() const { return _get_string("domain"); } const string& cookie::get_max_age() const { return _get_string("max-age"); } const string& cookie::get_path() const { return _get_string("path"); } bool cookie::get_secure() const { return find("secure")!=end(); } const string& cookie::get_expires() const { return _get_string("expires"); } bool cookie::has_comment() const { return find("comment")!=end(); } bool cookie::has_domain() const { return find("domain")!=end(); } bool cookie::has_max_age() const { return find("max-age")!=end(); } bool cookie::has_path() const { return find("path")!=end(); } bool cookie::has_expires() const { return find("expires")!=end(); } void cookie::unset_comment() { erase("comment"); } void cookie::unset_domain() { erase("domain"); } void cookie::unset_max_age() { erase("max-age"); } void cookie::unset_path() { erase("path"); } void cookie::unset_expires() { erase("expires"); } string cookie::set_cookie_header_rfc2109() const { string rv = name + "=" + http_quoted_string(value); for(const_iterator i=begin();i!=end();++i) { if(i->first=="secure") { rv += "; secure"; }else{ rv += "; "+i->first+"="+http_quote(i->second); } } rv += "; Version=1"; return rv; } string cookie::set_cookie_header() const { string rv = name + "=" + value; for(const_iterator i=begin();i!=end();++i) { if(i->first=="secure") { rv += "; secure"; }else{ rv += "; "+i->first+"="+i->second; } } return rv; } + void cookies_t::set_cookie(const cookie& c) { + insert(value_type(c.get_name(),c)); + } + bool cookies_t::has_cookie(const key_type& n) const { return find(n)!=end(); } const cookie& cookies_t::get_cookie(const key_type& n) const { const_iterator i=find(n); if(i==end()) throw exception_notfound(CODEPOINT,"No cookie with such name found"); return i->second; } cookie& cookies_t::get_cookie(const key_type& n) { iterator i=find(n); if(i==end()) throw exception_notfound(CODEPOINT,"No cookie with such name found"); return i->second; } void cookies_t::parse_cookies(const string& s) { string str = s; while(!str.empty()) { string::size_type sc = str.find(';'); string s; if(sc==string::npos) { s = str; str.erase(); }else{ s = str.substr(0,sc); str.erase(0,sc+1); } string::size_type nsp=s.find_first_not_of(" \t"); if((nsp!=string::npos) && nsp) s.erase(0,nsp); string::size_type eq=s.find('='); if(eq==string::npos) continue; string n = s.substr(0,eq); s.erase(0,eq+1); nsp = n.find_last_not_of(" \t"); n.erase(nsp+1); nsp = s.find_first_not_of(" \t"); string v; if(nsp!=string::npos) v = s.substr(nsp); else v = s; nsp = v.find_last_not_of(" \t"); if(nsp==string::npos) v.erase(); else v.erase(nsp+1); - cookie& c = (*this)[n]; - c.set_name(n); c.set_value(v); + set_cookie(cookie(n,v)); } } } |