Wexus2 0.20
|
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