00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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 }