• Main Page
  • Classes
  • Files
  • File List
  • File Members

Beesnest/DcResponse.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright 2007 Erez Bibi (erezbibi@users.sourceforge.net)
00003 This file is part of Beesnest.
00004 
00005 Beesnest is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009 
00010 Beesnest is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with Beesnest; if not, write to the Free Software
00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 */
00019 
00020 
00021 /*
00022  * DcResponse.cpp: Implamentation of CdcResponse class.
00023  * for documentation see the header file.
00024  */
00025 
00026 #include "DcResponse.h"
00027 
00028 /* Constructor. */
00029 CdcResponse::CdcResponse (CdcSocket* psock, CdcBuffersList& bflst)
00030 :aBody (bflst)
00031 {
00032     if (psock == NULL)
00033         throw (CdcException ("Socket pointer is null"));
00034 
00035     pSocket = psock;
00036 
00037     Restart ();
00038 }
00039 
00040 void CdcResponse::Clear ()
00041 {
00042     aBody.Clear ();
00043     mHeaderFields.clear ();
00044     mCookies.clear ();
00045 }
00046 
00047 void CdcResponse::Restart ()
00048 {
00049     Clear ();
00050 
00051     CdcHttpTime time;
00052     SetHeaderField ("Accept-Ranges", "None");
00053     SetHeaderField ("Allow", "GET, POST, HEAD");
00054     SetHeaderField ("Date", time.FormatGmt (TIME_FORMAT));
00055     SetHeaderField ("Server", SERVER_NAME);
00056     SetHeaderField ("Connection", "Keep-Alive");
00057 
00058     SetVersion (PROTOCOL11_VRS);
00059     nStatusCode = 200;
00060     sStatusPhrase = EMPTY_STR;
00061 
00062     isHeaderSent = false;
00063 }
00064 
00065 CdcString CdcResponse::GetStatusPhrase (int code) const
00066 {
00067     switch (code)
00068     {
00069     case 100: return CdcString ("Continue");
00070     case 101: return CdcString ("Switching Protocols");
00071     case 200: return CdcString ("OK");
00072     case 201: return CdcString ("Created");
00073     case 202: return CdcString ("Accepted");
00074     case 203: return CdcString ("Non-Authoritative Information");
00075     case 204: return CdcString ("No Content");
00076     case 205: return CdcString ("Reset Content");
00077     case 206: return CdcString ("Partial Content");
00078     case 300: return CdcString ("Multiple Choices");
00079     case 301: return CdcString ("Moved Permanently");
00080     case 302: return CdcString ("Found");
00081     case 303: return CdcString ("See Other");
00082     case 304: return CdcString ("Not Modified");
00083     case 305: return CdcString ("Use Proxy");
00084     case 307: return CdcString ("Temporary Redirect");
00085     case 400: return CdcString ("Bad Request");
00086     case 401: return CdcString ("Unauthorized");
00087     case 402: return CdcString ("Payment Required");
00088     case 403: return CdcString ("Forbidden");
00089     case 404: return CdcString ("Not Found");
00090     case 405: return CdcString ("Method Not Allowed");
00091     case 406: return CdcString ("Not Acceptable");
00092     case 407: return CdcString ("Proxy Authentication Required");
00093     case 408: return CdcString ("Request Time-out");
00094     case 409: return CdcString ("Conflict");
00095     case 410: return CdcString ("Gone");
00096     case 411: return CdcString ("Length Required");
00097     case 412: return CdcString ("Precondition Failed");
00098     case 413: return CdcString ("Request Entity Too Large");
00099     case 414: return CdcString ("Request-URI Too Large");
00100     case 415: return CdcString ("Unsupported Media Type");
00101     case 416: return CdcString ("Requested range not satisfiable");
00102     case 417: return CdcString ("Expectation Failed");
00103     case 500: return CdcString ("Internal Server Error");
00104     case 501: return CdcString ("Not Implemented");
00105     case 502: return CdcString ("Bad Gateway");
00106     case 503: return CdcString ("Service Unavailable");
00107     case 504: return CdcString ("Gateway Time-out");
00108     case 505: return CdcString ("HTTP Version not supported");
00109     }
00110     return CdcString ("Unknown code");
00111 }
00112 
00113 int CdcResponse::HeaderToBuffer (CdcBuffer& buff) const
00114 {
00115     /* Prepare the buffer. */
00116     buff.RemoveAll ();
00117 
00118     /* Insert Status Line. */
00119     buff.Append (sVersion);
00120     buff.Append (' ');
00121     buff.Append (nStatusCode);
00122     buff.Append (' ');
00123     buff.Append (sStatusPhrase);
00124     buff.Append (CRLF);
00125 
00126     /* Insert Header Fields. */
00127     CdcString name, val;
00128     bool length_header = false;
00129     t_map::const_iterator pos;
00130     for (pos = mHeaderFields.begin ();
00131          pos != mHeaderFields.end (); ++pos)
00132     {
00133         name = (*pos).first;
00134         val = (*pos).second;
00135         if (name.CompareNoCase ("Content-Length") == 0)
00136             length_header = true;
00137         buff.Append (name);
00138         buff.Append (": ");
00139         buff.Append (val);
00140         buff.Append (CRLF);
00141     }
00142 
00143     /* Insert Cookies. */
00144     for ( pos = mCookies.begin (); pos != mCookies.end (); ++pos)
00145     {
00146         name = (*pos).first;
00147         val = (*pos).second;
00148         buff.Append ("Set-Cookie: ");
00149         buff.Append (name);
00150         buff.Append (val);
00151         buff.Append (CRLF);
00152     }
00153 
00154     /* Insert the Content-Length header if not there. */
00155     if (length_header == false && GetHeaderField ("Transfer-Encoding").IsEmpty ())
00156     {
00157         buff.Append ("Content-Length: ");
00158         buff.Append (aBody.GetDataSize ());
00159         buff.Append (CRLF);
00160     }
00161 
00162     /* Make place for the body. */
00163     buff.Append (CRLF);
00164 
00165     return buff.GetDataSize ();
00166 }
00167 
00168 
00169 int CdcResponse::SendHeader () throw (CdcException)
00170 {
00171     if (isHeaderSent) return 0;
00172     /* Make the header buffer. */
00173     CdcBuffer buff;
00174     int lng = HeaderToBuffer (buff);
00175     /* Send by the socket.*/
00176     lng = pSocket->Write (buff.GetPointer (), lng);
00177     isHeaderSent = true;
00178     return lng;
00179 }
00180 
00181 int CdcResponse::SendResponse () throw (CdcException)
00182 {
00183 
00184 
00185     int lng = 0;
00186     if (nStatusCode == 0 || (lng = SendHeader ()) > 0)
00187     {   /* Go over buffers list and send it. */
00188         bool ret = aBody.SeekFirst ();
00189         while (ret)
00190         {
00191             lng += pSocket->Write (aBody.GetPointer (), aBody.GetLength ());
00192             ret = aBody.SeekNext ();
00193         }
00194     }
00195     else
00196     {   /* This was started as a chunk response. */
00197         lng += Flush (EMPTY_STR.c_str ());
00198         /* Write end of chunk response. */
00199         CdcString tmp = "0 ";
00200         tmp += CRLFCRLF;
00201         lng += pSocket->Write (tmp.GetBuffer (), tmp.GetLength ());
00202     }
00203     return lng;
00204 }
00205 
00206 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
00207 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.4.6
00208 int CdcResponse::Flush (BufferHolder buff) throw (int)
00209 {
00210     int lng = 0;
00211     try
00212     {
00213         if (nStatusCode > 0 && isHeaderSent == false)
00214         {   /* Send headers just once. */
00215             SetHeaderField ("Transfer-Encoding", "chunked");
00216             lng = SendHeader ();
00217         }
00218 
00219         bool ret = aBody.SeekFirst ();
00220         CdcString cnk_hdr;
00221         while (ret)
00222         {   /* Send all buffers parts that in the buffer list. */
00223             if (nStatusCode > 0)
00224             {
00225                 cnk_hdr = CdcString::IntToString (aBody.GetLength (), "%X ") + CRLF;
00226                 lng += pSocket->Write (cnk_hdr.GetBuffer (), cnk_hdr.GetLength ());
00227             }
00228             lng += pSocket->Write (aBody.GetPointer (), aBody.GetLength ());
00229             if (nStatusCode > 0)
00230                 lng += pSocket->Write (CRLF, CRLF_SIZE);
00231             ret = aBody.SeekNext ();
00232         }
00233 
00234         if (buff.empty () == false)
00235         {   /* Send pbuff. */
00236             if (nStatusCode > 0)
00237             {
00238                 cnk_hdr = CdcString::IntToString (buff.size, "%X ") + CRLF;
00239                 lng += pSocket->Write (cnk_hdr.GetBuffer (), cnk_hdr.GetLength ());
00240             }
00241             lng += pSocket->Write (buff.pointer, buff.size);
00242             if (nStatusCode > 0)
00243                 lng += pSocket->Write (CRLF, CRLF_SIZE);
00244         }
00245         /* Clear all data. */
00246         Clear ();
00247     }
00248     catch (CdcException& e)
00249     {   /* So we don't throw CdcException to the script engine. */
00250         throw e.GetExpCode ();
00251     }
00252     return lng;
00253 }
00254 
00255 
00256 void CdcResponse::SetCookie (const CdcString& name,
00257                              const CdcString& val,
00258                              int days, const CdcString& path)
00259 {
00260     CdcString cookie = "=" + val + "; path=" + path + "; expires=";
00261     CdcHttpTime time;
00262     time.AddDays (days);
00263     cookie += time.FormatGmt ("%a, %d-%b-%Y %H:%M:%S GMT");
00264     mCookies [name] = cookie;
00265 }
00266 
00267 /* Set functions. */
00268 
00269 void CdcResponse::SetVersion (const CdcString& vrs)
00270 {
00271     sVersion = vrs;
00272 }
00273 
00274 void CdcResponse::SetStatus (int code)
00275 {
00276     nStatusCode = code;
00277     sStatusPhrase = GetStatusPhrase (nStatusCode);
00278 }
00279 
00280 void CdcResponse::SetHeaderField (const CdcString& name, const CdcString& value)
00281 {
00282     if (name == BN_SET_STATUS)
00283         SetStatus (atoi (value.GetBuffer ()));
00284     else
00285         mHeaderFields [name] = value;
00286 }
00287 
00288 CdcString CdcResponse::GetHeaderField (CdcString& name)
00289 {
00290     if (name == BN_SET_STATUS)
00291         return CdcString::IntToString (nStatusCode);
00292     else
00293         return mHeaderFields [name];
00294 }
00295 

Generated on Mon Oct 11 2010 16:23:24 for Beesnest by  doxygen 1.7.2