• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/web/HttpResponse.cpp

00001 /*
00002  *   This file is part of the Standard Portable Library (SPL).
00003  *
00004  *   SPL is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   SPL is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with SPL.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 #include <spl/Int32.h>
00018 #include <spl/web/HttpResponse.h>
00019 #include <spl/Int32.h>
00020 #include <spl/text/StringBuffer.h>
00021 
00022 using namespace spl;
00023 
00024 HttpResponse::HttpResponse()
00025 :       m_httpVersion("HTTP/1.0"), 
00026         m_statusCode(200), 
00027         m_header(), 
00028         m_body(new MemoryStream()), 
00029         m_state(HTTPRES_STATE_VERSION), 
00030         m_accum()
00031 {
00032 }
00033 
00034 HttpResponse::HttpResponse(const HttpResponse& resp)
00035 :       m_httpVersion(resp.m_httpVersion), 
00036         m_statusCode(resp.m_statusCode), 
00037         m_header(resp.m_header), 
00038         m_body(new MemoryStream(*resp.m_body)), 
00039         m_state(resp.m_state), 
00040         m_accum()
00041 {
00042 }
00043 
00044 HttpResponse::~HttpResponse()
00045 {
00046 }
00047 
00048 HttpResponse& HttpResponse::operator =(const HttpResponse& resp)
00049 {
00050         m_httpVersion = resp.m_httpVersion;
00051         m_statusCode = resp.m_statusCode;
00052         m_header = resp.m_header;
00053         *m_body = *resp.m_body;
00054 
00055         return *this;
00056 }
00057 
00058 void HttpResponse::Write( IStream& strm )
00059 {
00060         StringBuffer buf;
00061 
00062         m_header.Header("Content-Length") = *Int32::ToString( ContentLength() );
00063 
00064         buf.Append( m_httpVersion );
00065         buf.Append( ' ' );
00066         buf.Append( Int32::ToString(m_statusCode) );
00067         buf.Append( ' ' );
00068         buf.Append( GetResponseText( m_statusCode ) );
00069         buf.Append( "\r\n" );
00070         buf.Append( m_header.ToString() );
00071 
00072         strm.Write( buf.ToByteArray() );
00073 
00074         Array<byte> bbuf(512);
00075         int count;
00076         while ( (count = m_body->Read(bbuf)) > 0 )
00077         {
00078                 strm.Write(bbuf, 0, count);
00079         }
00080 }
00081 
00082 void HttpResponse::Parse( IStream& strm )
00083 {
00084         Array<byte> chbuf(1);
00085         chbuf[0] = strm.ReadByte();
00086 
00087         while ( chbuf[0] > 0 )
00088         {
00089                 Parse( chbuf, 1 );
00090 
00091                 if ( HTTPRES_STATE_BODY == m_state )
00092                 {
00093                         break;
00094                 }
00095 
00096                 chbuf[0] = strm.ReadByte();
00097         }
00098 
00099         Array<byte> bbuf(512);
00100         int count;
00101         while ( (count = strm.Read(bbuf)) > 0 )
00102         {
00103                 Parse(bbuf, count);
00104         }
00105 }
00106 
00107 void HttpResponse::Parse(const Array<byte>& data, int len)
00108 {
00109         if ( m_state == HTTPRES_STATE_BODY )
00110         {
00111                 m_body->Write( data, 0, len );
00112                 return;
00113         }
00114 
00115         for ( int x = 0; x < len; x++ )
00116         {
00117                 char ch = (char)data[x];
00118 
00119                 switch ( m_state )
00120                 {
00121                 case HTTPRES_STATE_VERSION:
00122                         if ( ch == ' ' )
00123                         {
00124                                 m_httpVersion = *m_accum.ToString();
00125                                 m_accum.SetLength(0);
00126                                 m_state = HTTPRES_STATE_CODE;
00127                                 break;
00128                         }
00129                         m_accum.Append( ch );
00130                         break;
00131 
00132                 case HTTPRES_STATE_CODE:
00133                         if ( ch == ' ' )
00134                         {
00135                                 m_statusCode = m_accum.ToInt();
00136                                 m_accum.SetLength(0);
00137                                 m_state = HTTPRES_STATE_MESSAGE;
00138                                 break;
00139                         }
00140                         m_accum.Append( ch );
00141                         break;
00142 
00143                 case HTTPRES_STATE_MESSAGE:
00144                         if ( ch == '\r' )
00145                         {
00146                                 break;
00147                         }
00148                         if ( ch == '\n' )
00149                         {
00150                                 m_accum.SetLength(0);
00151                                 m_state = HTTPRES_STATE_HEADERS;
00152                                 break;
00153                         }
00154                         m_accum.Append( ch );
00155                         break;
00156 
00157                 case HTTPRES_STATE_HEADERS:
00158                         if ( ch == '\r' )
00159                         {
00160                                 break;
00161                         }
00162                         if ( ch == '\n' )
00163                         {
00164                                 if ( m_accum.Length() == 0 )
00165                                 {
00166                                         m_state = HTTPRES_STATE_BODY;
00167                                 }
00168                                 else
00169                                 {
00170                                         StringPtr headerLine = m_accum.ToString();
00171                                         m_header.ParseLine( *headerLine );
00172                                         m_accum.SetLength(0);
00173                                 }
00174                                 break;
00175                         }
00176                         else
00177                         {
00178                                 m_accum.Append( ch );
00179                         }
00180                         break;
00181 
00182                 case HTTPRES_STATE_BODY:
00183                         m_body->WriteByte( (byte)ch );
00184                         break;
00185 
00186                 default:
00187                         throw new Exception("Corrupted state in HttpResponse::Parse");
00188                 }
00189         }
00190 }
00191 
00192 #ifdef DEBUG
00193 void HttpResponse::ValidateMem() const
00194 {
00195         m_httpVersion.ValidateMem();
00196         m_header.ValidateMem();
00197         m_body.ValidateMem();
00198 }
00199 
00200 void HttpResponse::CheckMem() const
00201 {
00202         m_httpVersion.CheckMem();
00203         m_header.CheckMem();
00204         m_body.CheckMem();
00205 }
00206 #endif
00207 
00208 String HttpResponse::GetResponseText(int responseCode)
00209 {
00210         switch (responseCode)
00211         {
00212                 case 100: return String("Continue");
00213                 case 101: return String("Switching Protocols");
00214                 case 102: return String("Processing");
00215                 case 200: return String("OK");
00216                 case 201: return String("Created");
00217                 case 202: return String("Accepted");
00218                 case 203: return String("Non-Authoritative Information");
00219                 case 204: return String("No Content");
00220                 case 205: return String("Reset Content");
00221                 case 206: return String("Partial Content");
00222                 case 207: return String("Multi-Status");
00223                 case 300: return String("Multiple Choices");
00224                 case 301: return String("Moved Permanently");
00225                 case 302: return String("Found");
00226                 case 303: return String("See Other");
00227                 case 304: return String("Not Modified");
00228                 case 305: return String("Use Proxy");
00229                 case 307: return String("Temporary Redirect");
00230                 case 400: return String("Bad Request");
00231                 case 401: return String("Unauthorized");
00232                 case 402: return String("Payment Required");
00233                 case 403: return String("Forbidden");
00234                 case 404: return String("Not Found");
00235                 case 405: return String("Method Not Allowed");
00236                 case 406: return String("Not Acceptable");
00237                 case 407: return String("Proxy Authentication Required");
00238                 case 408: return String("Request Timeout");
00239                 case 409: return String("Conflict");
00240                 case 410: return String("Gone");
00241                 case 411: return String("Length Required");
00242                 case 412: return String("Precondition Failed");
00243                 case 413: return String("Request Entity Too Large");
00244                 case 414: return String("Request-Uri Too Long");
00245                 case 415: return String("Unsupported Media Type");
00246                 case 416: return String("Requested Range Not Satisfiable");
00247                 case 417: return String("Expectation Failed");
00248                 case 422: return String("Unprocessable Entity");
00249                 case 423: return String("Locked");
00250                 case 424: return String("Failed Dependency");
00251                 case 500: return String("Internal Server Error");
00252                 case 501: return String("Not Implemented");
00253                 case 502: return String("Bad Gateway");
00254                 case 503: return String("Service Unavailable");
00255                 case 504: return String("Gateway Timeout");
00256                 case 505: return String("Http Version Not Supported");
00257                 case 507: return String("Insufficient Storage");
00258                 default:
00259                         return String("Unknown");
00260         }
00261 }