Wexus2 0.20
wexus2.src/wexus/HTTP.h
00001 
00002 /*
00003  * Copyright (c) 2011 Aleksander B. Demko
00004  * This source code is distributed under the MIT license.
00005  * See the accompanying file LICENSE.MIT.txt for details.
00006  */
00007 
00008 #ifndef __INCLUDED_WEXUS_HTTP_H__
00009 #define __INCLUDED_WEXUS_HTTP_H__
00010 
00011 #include <map>
00012 
00013 #include <QMap>
00014 #include <QVariant>
00015 #include <QString>
00016 #include <QTextStream>
00017 
00018 #define WEXUS_VERSION_STRING "2.0.1"
00019 #define WEXUS_COPYRIGHT_STRING "2011"
00020 
00021 #include <wexus/Exception.h>
00022 
00023 namespace wexus
00024 {
00025   QString escapeForXML(const QString &s);
00026 
00027   class HTTPRequest;
00028   class HTTPReply;
00029 
00030   class HTTPHandler;
00031   class ErrorHTTPHandler;
00032 }
00033 
00034 /**
00035  * All the information in a HTTPRequest. The handler
00036  * can use this information to compose their HTTPReply.
00037  *
00038  * @author Aleksander Demko
00039  */ 
00040 class wexus::HTTPRequest
00041 {
00042   public:
00043     //typedef QMap<QString, QVariant> ClientCookies;
00044     typedef QVariantMap ClientCookies;
00045 
00046   public:
00047     HTTPRequest(void);
00048 
00049     const QString & request(void) const { return dm_request; }
00050     const QString & query(void) const { return dm_query; }
00051     const QString & referer(void) const { return dm_referer; }
00052     const QString & userAgent(void) const { return dm_useragent; }
00053 
00054     /**
00055      * The value of the content length field.
00056      * Always will be >=0, even if it wasn't set in the
00057      * headers.
00058      *
00059      * @author Aleksander Demko
00060      */ 
00061     qint64 contentLength(void) const { return dm_contentlength; }
00062 
00063     /**
00064      * Returns the input device that contains any
00065      * data sent after the headers.
00066      *
00067      * Note that some classes will already process this
00068      * stream (like wexus::FormParams)
00069      * QIODevice seem to always be passed by ptr.
00070      *
00071      * @author Aleksander Demko
00072      */ 
00073     QIODevice* input(void) const { return dm_inputdev; }
00074 
00075     /**
00076      * Returns the cookies sent by the client.
00077      *
00078      * @author Aleksander Demko
00079      */ 
00080     const ClientCookies & cookies(void) const { return dm_clientcookies; }
00081 
00082     /**
00083      * Returns the cookies sent by the client.
00084      * non-const version. Callers can fiddle with the cookie
00085      * map for convience.
00086      *
00087      * @author Aleksander Demko
00088      */ 
00089     ClientCookies & cookies(void) { return dm_clientcookies; }
00090 
00091   protected:
00092     /// helper function that decendants can use.
00093     /// parse out the cookies from raw_cookie_str and fill dm_clientcookies
00094     /// with the found cookies
00095     /// never fails (well, never reports failure
00096     /// returns the number of cookies parsed
00097     int parseCookies(const QString &raw_cookie_str);
00098 
00099   protected:
00100     QString dm_request, dm_query, dm_referer, dm_useragent;
00101     qint64 dm_contentlength;
00102     QIODevice *dm_inputdev;
00103 
00104     ClientCookies dm_clientcookies;
00105 };
00106 
00107 /**
00108  * A HTTP reply that is sent back to the client
00109  * as a result of an HTTP request.
00110  *
00111  * The status may be set via the constructor, and or changed
00112  * via setStatus. In eithercase, a reply with a 0 status
00113  * is invalid and cannot be commited (used).
00114  *
00115  * @author Aleksander Demko
00116  */ 
00117 class wexus::HTTPReply
00118 {
00119   public:
00120     // the cookies that will be sent back to the client
00121     struct ServerCookie
00122     {
00123       // there is no name field, name is the key in the QMap structure
00124       QString expires, domain, path;
00125       QVariant value;
00126     };
00127     typedef QMap<QString, ServerCookie> ServerCookies;
00128   public:
00129     /**
00130      * Constructs an http reply, using the given stream
00131      * and with the given status code.
00132      *
00133      * If your handler wants to respond to a request, must call output() (and
00134      * produce some output), setStatus() or both.
00135      *
00136      * @author Aleksander Demko
00137      */ 
00138     HTTPReply(QTextStream &outstream);
00139     /**
00140      * This calls the commitHeader method if status is >0 AND commitHeader() has not
00141      * yet been called.
00142      *
00143      * @author Aleksander Demko
00144      */ 
00145     ~HTTPReply();
00146 
00147     /**
00148      * Converts a status code to a description, null if this is an unkown status
00149      * code. Uses const char * to minimuze copies.
00150      *
00151      * @author Aleksander Demko
00152      */
00153     static const char * statusToString(int status);
00154 
00155     /**
00156      * Sets the current status code that will be returned. The default status
00157      * is 0, unless output() is used, in which case it is 200.
00158      *
00159      * @author Aleksander Demko
00160      */ 
00161     void setStatus(int status);
00162 
00163     /**
00164      * Gets the current return status code. If its 0, it means
00165      * unset (reply not set).
00166      *
00167      * @author Aleksander Demko
00168      */ 
00169     int status(void) const { return dm_status; }
00170 
00171     /**
00172      * True is a reply has been status (status is non-zero)
00173      *
00174      * @author Aleksander Demko
00175      */ 
00176     bool hasReply(void) const { return dm_status != 0; }
00177 
00178     /**
00179      * Sets the content type.
00180      * The default content type is text/html.
00181      *
00182      * @author Aleksander Demko
00183      */ 
00184     void setContentType(const QString &type);
00185 
00186     /**
00187      * Returns the currently set content type.
00188      * The default content type is text/html.
00189      *
00190      * @author Aleksander Demko
00191      */ 
00192     const QString & contentType(void) const { return dm_contenttype; }
00193 
00194     /**
00195      * Returns a stream that you can use to write the 
00196      * reply body. This called commitHeader() before hand, if it hasn't been called already.
00197      *
00198      * You may want to include wx/streamop.h
00199      *
00200      * @author Aleksander Demko
00201      */ 
00202     QTextStream & output(void);
00203 
00204     /**
00205      * Returns the cookies sent by the client.
00206      *
00207      * @author Aleksander Demko
00208      */ 
00209     const ServerCookies & cookies(void) const { return dm_servercookies; }
00210 
00211     /**
00212      * Returns the cookies sent by the client.
00213      * non-const version. Callers can fiddle with the cookie
00214      * map for convience.
00215      *
00216      * @author Aleksander Demko
00217      */ 
00218     ServerCookies & cookies(void) { return dm_servercookies; }
00219 
00220     /**
00221      * Sets a cookie that will be sent to the client. There can
00222      * be many of these.
00223      *
00224      * This cannot be called after commitHeader() has been called.
00225      *
00226      * @param name the name of the cookie
00227      * @param value the value of the cookie
00228      * @param expires the expiry of the cookie, in
00229      * "Wdy, DD-Mon-YYYY HH:MM:SS GMT" format. If empty, a "session cookie"
00230      * will be created. Negative time values aparently delete cookies.
00231      * @param domain the domain name of servers that this cookie will
00232      * be sent to. May be empty ("same as caller"), and may also be a suffix
00233      * (".example.com") I guess to specify a collection of servers
00234      * @param path The path prefix this cookie is good for. examples:
00235      * "/" and "/accounts"
00236      * @author Aleksander Demko
00237      */ 
00238     //void setServerCookie(const QString &name, const QString &value, const QString &expires, const QString &domain, const QString &path);
00239 
00240 
00241     /**
00242      * Redirects the user browser to the given url.
00243      * This sets the status code too.
00244      * output() cannot be called before (or after)
00245      * this call.
00246      *
00247      * @author Aleksander Demko
00248      */ 
00249     void redirectTo(const QString &rawurl);
00250 
00251   private:
00252     /**
00253      * Commits and flushes any data to the output stream.
00254      * The constructor will also automatically call this.
00255      * You can this repeadedly, only the first call does something.
00256      * Calling this with Status set to 0 is an error.
00257      *
00258      * If additionalHeaders is non-null, these headers will also be
00259      * sent. Each string in the list will be a line in the
00260      * headers. The strings should NOT be terminated by \n etc.
00261      *
00262      * @author Aleksander Demko
00263      */ 
00264     void commitHeader(const QStringList *additionalHeaders = 0);
00265 
00266     /// called by commitHeader
00267     void commitCookieHeader(void);
00268 
00269   protected:
00270     QTextStream &dm_outs;
00271     int dm_status;
00272     bool dm_calledcommit;
00273     QString dm_contenttype;
00274 
00275     ServerCookies dm_servercookies;
00276 };
00277 
00278 /**
00279  * A wexus::HTTPHandler handles events from a wexus::HTTPServer.
00280  *
00281  * @author Aleksander Demko
00282  */ 
00283 class wexus::HTTPHandler
00284 {
00285   public:
00286     /**
00287      * An Exception that handlers can throw. The
00288      * serverw ill catch them and display them to the user.
00289      *
00290      * @author Aleksander Demko
00291      */ 
00292     class Exception : public wexus::Exception
00293     {
00294       public:
00295         /// no usermessage constructor
00296         //Exception(void);
00297         /// usermessage constructor
00298         Exception(const QString &usermsg);
00299 
00300         virtual ~Exception() throw ();
00301 
00302         /**
00303          * The user-visable error message string.
00304          *
00305          * @author Aleksander Demko
00306          */ 
00307         const QString & userMessage(void) const { return dm_usermsg; }
00308 
00309       protected:
00310         QString dm_usermsg;
00311     };
00312 
00313   public:
00314     /// destructor
00315     virtual ~HTTPHandler();
00316 
00317     /**
00318      * This is called when a request is to be processed.
00319      *
00320      * @param req the request
00321      * @return true if this consumer has processed this even and no further consumers should
00322      * receive this event. false if this consumer does not want to process this event.
00323      * @author Aleksander Demko
00324      */ 
00325     virtual void handleRequest(wexus::HTTPRequest &req, wexus::HTTPReply &reply) = 0;
00326 };
00327 
00328 /**
00329  * A handler that does nothing but display a deliberatly cryptic error message.
00330  *
00331  * @author Aleksander Demko
00332  */ 
00333 class wexus::ErrorHTTPHandler : public wexus::HTTPHandler
00334 {
00335   public:
00336     /// no userMessage constructor
00337     ErrorHTTPHandler(void);
00338     /// with userMessage constructor
00339     ErrorHTTPHandler(const QString &usermsg);
00340 
00341   public:
00342     virtual void handleRequest(wexus::HTTPRequest &req, wexus::HTTPReply &reply);
00343 
00344   protected:
00345     QString dm_usermsg;
00346 };
00347 
00348 #endif
00349 
 All Classes Namespaces Functions Variables Enumerations Enumerator