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/HttpUtility.h>
00019 #include <spl/text/StringBuffer.h>
00020 #include <spl/web/Uri.h>
00021
00022 Uri::Uri( )
00023 : m_protocol("http"),
00024 m_server(""),
00025 m_port(80),
00026 m_path(""),
00027 m_filename(""),
00028 m_fileext(""),
00029 m_args(),
00030 m_argIdx()
00031 {
00032 }
00033
00034 Uri::Uri( const String &cpuri )
00035 : m_protocol("http"),
00036 m_server(""),
00037 m_port(80),
00038 m_path(""),
00039 m_filename(""),
00040 m_fileext(""),
00041 m_args(),
00042 m_argIdx()
00043 {
00044 Parse( cpuri );
00045 }
00046
00047 Uri::Uri( const Uri& uri )
00048 : m_protocol(uri.m_protocol),
00049 m_server(uri.m_server),
00050 m_port(uri.m_port),
00051 m_path(uri.m_path),
00052 m_filename(uri.m_filename),
00053 m_fileext(uri.m_fileext),
00054 m_args(uri.m_args),
00055 m_argIdx(uri.m_argIdx)
00056 {
00057 }
00058
00059 Uri::~Uri()
00060 {
00061 }
00062
00063 Uri& Uri::operator =(const Uri& uri)
00064 {
00065 m_protocol = uri.m_protocol;
00066 m_server = uri.m_server;
00067 m_port = uri.m_port;
00068 m_path = uri.m_path;
00069 m_filename = uri.m_filename;
00070 m_fileext = uri.m_fileext;
00071 m_args = uri.m_args;
00072 m_argIdx = uri.m_argIdx;
00073
00074 return *this;
00075 }
00076
00077 void Uri::Parse( const String& cstr )
00078 {
00080
00081 StringPtr str = String(cstr).Replace('\\', '/');
00082
00083 int pos = 0;
00084 int idx = str->IndexOf(':');
00085 if ( idx > -1 )
00086 {
00087
00088 StringPtr proto = str->Substring(pos, idx);
00089 proto->ToLower();
00090 m_protocol.Set(*proto);
00091 pos = idx + 1;
00092
00093 if ( pos >= str->Length() )
00094 {
00095 return;
00096 }
00097 if ( str->CharAt(pos++) != '/' )
00098 {
00099 throw new InvalidArgumentException("Expected ://");
00100 }
00101 if ( pos >= str->Length() )
00102 {
00103 return;
00104 }
00105 if ( str->CharAt(pos++) != '/' )
00106 {
00107 throw new InvalidArgumentException("Expected ://");
00108 }
00109 if ( pos >= str->Length() )
00110 {
00111 return;
00112 }
00113
00114
00115 StringPtr temp;
00116
00117 if ( (idx = str->IndexOf(':', pos + 1)) < 0 )
00118 {
00119 idx = str->IndexOf('/', pos + 1);
00120 }
00121 if ( 0 > idx )
00122 {
00123 temp = str->Substring(pos);
00124 pos += temp->Length();
00125 }
00126 else
00127 {
00128 temp = str->Mid(pos, idx);
00129 pos = idx;
00130 }
00131 m_server.Set( *temp );
00132
00133 if ( pos >= str->Length() )
00134 {
00135 return;
00136 }
00137
00138 if ( str->CharAt(pos) == ':' )
00139 {
00140 pos++;
00141 idx = str->IndexOf('/', pos + 1);
00142 temp = str->Mid(pos, idx);
00143 pos += temp->Length();
00144 ASSERT( Int32::IsInt(*temp) );
00145 m_port = Int32::Parse(*temp);
00146 }
00147 }
00148 if ( pos >= str->Length() )
00149 {
00150 return;
00151 }
00152 StringPtr fullpath;
00153 if ( 0 > (idx = str->IndexOf('?', pos)) )
00154 {
00155
00156 fullpath = str->Substring(pos);
00157 pos = str->Length();
00158 }
00159 else
00160 {
00161
00162 fullpath = str->Mid(pos, idx);
00163 pos = idx;
00164 }
00165 if ( 0 > (idx = fullpath->IndexOf('/')) )
00166 {
00167 m_filename.Set( *fullpath );
00168 }
00169 else if ( fullpath->IndexOf('.') < 0 )
00170 {
00171
00172 m_path.Set( *fullpath );
00173 }
00174 else
00175 {
00176 idx = fullpath->LastIndexOf('/');
00177 ASSERT(idx > -1);
00178 m_filename.Set( *fullpath->Substring(idx+1) );
00179 m_path.Set( *fullpath->Substring(0, idx+1) );
00180 }
00181
00182 if ( (idx = m_filename.IndexOf('.')) > -1 )
00183 {
00184 m_fileext.Set( &m_filename.GetChars()[idx+1] );
00185 }
00186 if ( pos >= str->Length() )
00187 {
00188 return;
00189 }
00190 ASSERT( str->CharAt(pos) == '?' );
00191 StringPtr params = str->Substring(pos+1);
00192 RefCountPtr<Vector<StringPtr> > parts = params->Split("&");
00193
00194 for ( int x = 0; x < parts->Count(); x++ )
00195 {
00196 StringPtr part = parts->ElementAt(x);
00197 if ( 0 > (idx = part->IndexOf('=')) )
00198 {
00199 Association<String, String> pair(*HttpUtility::UrlDecode(*part), String(""));
00200 m_args.Add( pair );
00201 }
00202 else
00203 {
00204 StringPtr key = part->Substring(0, idx);
00205 StringPtr val = part->Substring(idx+1);
00206
00207 Association<String, String> pair(*HttpUtility::UrlDecode(*key), *HttpUtility::UrlDecode(*val));
00208 m_args.Add( pair );
00209 m_argIdx.Set( pair.KeyRef(), pair.ValueRef() );
00210 }
00211 }
00212 }
00213
00214 StringPtr Uri::AbsolutePath() const
00215 {
00216 StringBuffer buf;
00217
00218 if ( ! m_path.StartsWith("/") )
00219 {
00220 buf.Append('/');
00221 }
00222 buf.Append( m_path );
00223 if ( ! m_path.EndsWith("/") )
00224 {
00225 buf.Append('/');
00226 }
00227 buf.Append( m_filename );
00228
00229 int argcount = m_args.Count();
00230 if ( argcount > 0 )
00231 {
00232 buf.Append('?');
00233 }
00234
00235 for ( int x = 0; x < argcount; x++ )
00236 {
00237 Association<String, String>& pair = m_args.ElementAtRef(x);
00238 if ( HttpUtility::UrlEncodeRequired(pair.KeyRef()) )
00239 {
00240 buf.Append( HttpUtility::UrlEncode(pair.KeyRef()) );
00241 }
00242 else
00243 {
00244 buf.Append( pair.KeyRef() );
00245 }
00246 buf.Append( "=" );
00247 if ( HttpUtility::UrlEncodeRequired(pair.ValueRef()) )
00248 {
00249 buf.Append( HttpUtility::UrlEncode(pair.ValueRef()) );
00250 }
00251 else
00252 {
00253 buf.Append( pair.ValueRef() );
00254 }
00255 if ( x + 1 < argcount )
00256 {
00257 buf.Append( "&" );
00258 }
00259 }
00260
00261 return buf.ToString();
00262 }
00263
00264 StringPtr Uri::ToString() const
00265 {
00266 StringBuffer buf;
00267
00268 if ( m_server.Length() > 0 )
00269 {
00270 buf.Append( m_protocol );
00271 buf.Append( "://" );
00272 buf.Append( m_server );
00273 }
00274
00275 if ( m_port != 80 )
00276 {
00277 buf.Append(':');
00278 buf.Append(Int32::ToString(m_port));
00279 }
00280
00281 buf.Append( AbsolutePath() );
00282
00283 return buf.ToString();
00284 }
00285
00286 int32 Uri::HashCode() const
00287 {
00288 return ToString()->HashCode();
00289 }
00290
00291 #ifdef DEBUG
00292 void Uri::ValidateMem() const
00293 {
00294 m_protocol.ValidateMem();
00295 m_server.ValidateMem();
00296 m_path.ValidateMem();
00297 m_filename.ValidateMem();
00298 m_fileext.ValidateMem();
00299 m_args.ValidateMem();
00300 m_argIdx.ValidateMem();
00301 }
00302
00303 void Uri::CheckMem() const
00304 {
00305 m_protocol.CheckMem();
00306 m_server.CheckMem();
00307 m_path.CheckMem();
00308 m_filename.CheckMem();
00309 m_fileext.CheckMem();
00310 m_args.CheckMem();
00311 m_argIdx.CheckMem();
00312 }
00313 #endif