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

src/web/Uri.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/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                 // protocol
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                 // server dns name
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                 // no params
00156                 fullpath = str->Substring(pos);
00157                 pos = str->Length();
00158         }
00159         else
00160         {
00161                 // params
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                 // there is no file name
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