Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

sessionserver.h

Go to the documentation of this file.
00001 #ifndef DVCGI_SESSIONSERVER_H
00002 #define DVCGI_SESSIONSERVER_H
00003 // $Id: sessionserver.h,v 1.15 2004/03/20 14:57:35 dvermeir Exp $
00004 
00005 #include <iostream>
00006 
00007 #include <dvutil/props.h>
00008 #include <dvnet/usocket.h>
00009 #include <dvnet/userversocket.h>
00010 #include <dvcgi/httphead.h>
00011 /** @file 
00012  *  Defines SessionServer that allows cgi programs to communicate
00013  *  with the browser using stream-like operations.
00014  */
00015 
00016 namespace Dv {
00017 namespace Cgi {
00018 /** A class that packages the link to the hidden server. */
00019 class SessionServer: public std::ostream {
00020 public:
00021   /** Constructor.
00022    * A Dv::Cgi::SessionServer object must be used in a cgi
00023    * program.
00024    * @code
00025    * Dv::Cgi::SessionServer client("myprog",5*1000, "index.html", "http://tinf2.vub.ac.be/index.html");
00026    * @endcode
00027    * - If there is a cookie with the name/key "myprog", its
00028    * value will be interpreted as the name of a file
00029    * that corresponds to a unix socket on which a server
00030    * is listening. 
00031    * - If a server is listening on that socket, this constructor will simply
00032    * transfer the cgi formdata, cookies and environment to
00033    * the server, then copy any input from the server to
00034    * cout and exit the program.
00035    * - If no server is running, it will start the server by
00036    * forking a daemon and then behave as above.
00037    * The constructor will only return in de server daemon
00038    * process.
00039    *
00040    * The server communicates with its (cgi) clients using
00041    * a unix socket attached to a filename 
00042    *    <code>/tmp/program_name.xxx</code>
00043    * where <code>xxx</code> is generated to make the filename
00044    * unique.
00045    *
00046    * Application code is rather simple: the program communicates
00047    * with the client (a Dv::Cgi::SessionServer object) using
00048    * interactions of the form
00049    * @code
00050    * client << .. html .. << Dv::Cgi::eof;
00051    * // now client input is available, e.g. in client.props()
00052    * if ( client("number") ) {
00053    *   int number;
00054    *   client.props() >> "number" >> number;   
00055    *   ..
00056    *   }
00057    * @endcode
00058    *
00059    * Note that all C++ variables are persistent (since they
00060    * reside in the server process). E.g. it is easy to
00061    * write a login function like so:
00062    * @code
00063    * std::string
00064    * login(Dv::Cgi::SessionServer& client) {
00065    * while (client) {
00066    *   client << login_form << Dv::Cgi::eof;
00067    *   if ( client("name") ) {
00068    *     std::string uname = client.props("name");
00069    *     std::string uname = client.props("password");
00070    *     if (check_password_valid)
00071    *       return uname;
00072    *     }
00073    *   }
00074    * throw std::runtime_error("login timed out");
00075    * }
00076    * @endcode
00077    *
00078    * To exit the application use Dv::Cgi::SessionServer::disconnect .
00079    *
00080    * Silly example applications are available in the distribution: see
00081    * test-sessionserver.C and example-session.C .
00082    *
00083    * @param program_name used to generate the server unix server socket
00084    *   filename, also used as the name of the cookie whose value
00085    *   is the actual server filename.
00086    * @param delay (in milliseconds) is used by the client and the
00087    *   server to determine the allowable wait for response.
00088    * @param timeouturl is used to relocate any request that
00089    *   suffers from a timeout
00090    * @param errorurl is used to relocate any request that
00091    *   suffers from an unrecoverable error (except for timeout)
00092    * @param logdir directory where logfile will be created
00093    * @param sockdir directory where sockets will be created
00094    * @warning do not set a cookie with key/name program_name
00095    */
00096   SessionServer(const std::string& program_name, time_t delay,
00097     const std::string& timeouturl, const std::string& errorurl,
00098     const std::string& logdir="/tmp", const std::string& sockdir="/tmp");
00099   /** Destructor. */
00100   virtual ~SessionServer();
00101 
00102   /** Name of server application. */
00103   const std::string& name() const { return name_; }
00104 
00105   /** Get props object containing formdata from client. */
00106   const Util::Props& props() const { return props_; }
00107   /** Get props object containing formdata from client. */
00108   Dv::Util::Props&  props() { return props_; }
00109 
00110   /** Easy check for presence of a formdata item. */
00111   const std::string* operator()(const std::string& key) const { return props().find(key); }
00112   /** @return value of form data variable 
00113    * @exception std::runtime_error if variable is not defined
00114    */
00115   const std::string& props(const std::string& name) const throw (std::runtime_error) {
00116     return props()[name].str(); }
00117   /** @return value of form data variable 
00118    * @exception std::runtime_error if variable is not defined
00119    */
00120   std::string& props(const std::string& name) throw (std::runtime_error) { return props()[name].str(); }
00121 
00122   /** Get Props object containing shell environment from client. */
00123   const Util::Props& env() const { return env_; }
00124   /** @return value of environment variable.
00125    * @exception std::runtime_error if variable is not defined
00126    */
00127   const std::string&  env(const std::string& name) const throw (std::runtime_error) {
00128     return (env()[name]).str() ; }
00129 
00130   /** Get Props object containing cookies from client. */
00131   const Util::Props& cookies() const { return cookies_; }
00132   /** @return value of cookie variable 
00133    * @exception std::runtime_error if variable is not defined
00134    */
00135   const std::string&  cookies(const std::string& name) const throw (std::exception) {
00136     return (cookies()[name]).str() ; }
00137 
00138   /** Return url of current request.
00139    * @return value of REQUEST_URI in env()
00140    * @exception std::runtime_error if not available
00141    * @sa Dv::Cgi::SessionServer::env
00142    */
00143   std::string here() const throw (std::runtime_error);
00144   /** Return base url of current request.
00145    * @return value of here() without parameters, i.e.
00146    *   after removing the first '?' and anything following it.
00147    * @exception std::runtime_error if not available
00148    * @sa Dv::Cgi::SessionServer::here
00149    */
00150   std::string here_base() const throw (std::runtime_error);
00151 
00152   /** Get HttpHeader object containing output headers. */
00153   const HttpHeader& header() const { return header_; }
00154   /** Get HttpHeader object containing output headers. */
00155   HttpHeader& header() { return header_; }
00156   /** Get HttpHeader object containing output headers. 
00157    * @deprecated Use <code>session.header().f()</code> instead of 
00158    *   <code>session->f()</code>.
00159    */
00160   HttpHeader* operator->() { return &header_; }
00161 
00162   /** Get status of server. 
00163    * @retval true iff server is working
00164    * @retval false otherwise
00165    */
00166   operator bool() const { return status_; }
00167 
00168   /** Remove cookie, relocate to url, stop network server and connection.
00169    * @param url to relocate to
00170    */
00171   void  disconnect(const std::string& url);
00172   /** Stop server and network connection. */
00173   void  disconnect();
00174   /** Refresh: send header (if not already sent) and get input from client. */
00175   void  refresh();
00176 
00177   /** Log stream. 
00178    * This is a Dv::Util::logstream: each line is automatically prefixed by
00179    *  the date and the identification of the process.
00180    * @sa Dv::Cgi::SessionServer::name
00181    */
00182   std::ostream&  log() const { return *log_; }
00183 
00184 private:
00185   SessionServer(const SessionServer& s);
00186   SessionServer& operator=(const SessionServer& s);
00187 
00188   /** Filter class that ensures that header_ is output before
00189    * anything else. */
00190   class Filter {
00191   public:
00192     Filter(SessionServer& ss);
00193     int get();
00194     int put(int c);
00195     int sync();
00196     int close() { return 0; }
00197     int count() const { return count_; }
00198     void clear() { count_ = 0; }
00199   private:
00200     unsigned int count_;
00201     SessionServer& server_;
00202   };
00203   friend class Filter;
00204 
00205   void  send_header();
00206   void  get_input();
00207 
00208   std::string  name_;
00209   time_t  delay_;
00210   std::string  timeouturl_;
00211   std::string  errorurl_;
00212   std::string  server_filename_;
00213 
00214   Dv::Net::userversocket* server_socket_;
00215   Dv::Net::usocket* client_socket_;
00216   bool  status_;
00217 
00218   Dv::Util::Props  props_;
00219   Dv::Util::Props  env_;
00220   Dv::Util::Props  cookies_;
00221 
00222   Dv::Cgi::HttpHeader  header_;
00223 
00224   std::ostream*  log_;
00225   Filter  filter_;
00226 };
00227 
00228 /** Convenience function, simply calls refresh on its argument.
00229  * 
00230  *  Example:
00231  *  @code
00232  *  Dv::Cgi::SessionServer s(..);
00233  *
00234  *  s.header().content_type("text/html").no_cache();
00235  *
00236  *  while (s) {
00237  *    Dv::Util::Props& input(s.props());
00238  *
00239  *    s << "<html>..</html>" << Dv::Cgi::eof;
00240  *    }
00241  *  @endcode
00242  * @sa operator<<(std::ostream& os, void (*f)(Dv::Cgi::SessionServer&)
00243  */
00244 void    eof(SessionServer&);
00245 }}
00246 
00247 /** Overloading for SessionServer manipulation.
00248  * @warning Uses <code>dynamic_cast<SessionServer*>(os)</code> internally.
00249  * @sa Dv::Cgi::eof
00250  */
00251 void operator<<(std::ostream& os,void (*f)(Dv::Cgi::SessionServer&));
00252 #endif

dvcgi-0.5.14 [22 January, 2006]