ghttp.cpp

Go to the documentation of this file.
00001 // ghttp.cpp -- Version 0.8
00002 
00003 // Removed lots of methods, now within gNetInfo/src/gXHttp...!
00004 // Now no content classses, only 'gHttpGeneric'.
00005 
00006 #include <string.h>  //memcpy, ...
00007 #include "ghttp.h"
00008 #include "gstringext.h"
00009 #include "garg.h"
00010 
00011 // Static members
00012 gURI::sSchemeUse gURI::schemeTbl[]={
00013     { gURI::e_ftp, "ftp", 1738 },
00014     { gURI::e_http, "http", 2616 },
00015     { gURI::e_file, "file", 0 },
00016     { gURI::e_invalid, NULL, -1 }
00017     // Note: rfcCode=0 means no RFC; non-zero means special RFC name
00018 };
00019 ////////////////////////////////////////////////////////////
00020 gVersion::gVersion (short major, short minor)
00021     : vMajor( major ),
00022       vMinor( minor )
00023 {
00024 }
00025 
00026 bool gVersion::SetVersion (gString& s)
00027 {
00028  // Must be X, or X.Y (X and Y numerical)
00029  gParam param( s, "." );
00030  unsigned n = param.N();
00031  if ( n<1 ) return false;
00032  vMinor = -1;
00033  if ( n<2 ) {
00034      return thisSetMajorOrMinor( s.Str(), vMajor )==0;
00035  }
00036  vMajor = -1;
00037  // && forces both to be correct (both evaluated)
00038  return
00039      thisSetMajorOrMinor( param.Str(1), vMajor )==0 &&
00040      thisSetMajorOrMinor( param.Str(2), vMinor )==0;
00041 }
00042 
00043 bool gVersion::operator> (gVersion& version)
00044 {
00045  if ( vMajor > version.vMajor ) return true;
00046  if ( vMajor < version.vMajor ) return false;
00047  return vMinor > version.vMinor;
00048 }
00049 
00050 bool gVersion::operator< (gVersion& version)
00051 {
00052  if ( vMajor < version.vMajor ) return true;
00053  if ( vMajor > version.vMajor ) return false;
00054  return vMinor < version.vMinor;
00055 }
00056 
00057 int gVersion::thisSetMajorOrMinor (char* s, short& ver)
00058 {
00059  // Returns 0 on success
00060  t_uint32 m=0;
00061  int error = gStrControl::Self().ConvertToUInt32( s, m );
00062  if ( error!=0 ) return error;
00063  if ( m>(t_uint32)MAX_INT16_I ) return -1;
00064  ver = (short)m;
00065  return 0;
00066 }
00067 ////////////////////////////////////////////////////////////
00068 gBigBuffer::gBigBuffer (t_uint32 bufSize)
00069     : baseBuf( nil ),
00070       isDynamic( bufSize==0 ),
00071       usedSize( 0 ),
00072       nNodes( 0 ), maxNodes( 10 ),
00073       bNode( nil ),
00074       fTemp( nil ),
00075       hasOverbuffer( false ),
00076       baseSizeBuf( 0 )
00077 {
00078  if ( isDynamic ) bufSize = 0x1000;  //at least 4096 starting size
00079 //#ifdef DEBUG_HTTP
00080 // if ( isDynamic ) bufSize = 4;
00081 //#error nop...just for testing...
00082 //#endif //DEBUG_HTTP
00083  thisAllocateBuf( bufSize );
00084 }
00085 
00086 gBigBuffer::~gBigBuffer ()
00087 {
00088  delete baseBuf;
00089  if ( bNode!=nil ) {
00090      for (unsigned idxNode=0; idxNode<maxNodes; idxNode++) delete bNode[ idxNode ];
00091      delete[] bNode;
00092  }
00093  // Finally delete temporary file
00094  delete fTemp;
00095 }
00096 
00097 gBigBuffer::eBufferKind gBigBuffer::GetBufferKind ()
00098 {
00099  if ( hasOverbuffer ) return e_InFile;
00100  return GetNumberNodes()==0 ? e_NormalRAM : e_NodesRAM;
00101 }
00102 
00103 gUCharBuffer* gBigBuffer::GetNode (unsigned idxNode)
00104 {
00105  ASSERTION(idxNode<nNodes,"idxNode<nNodes");
00106  gUCharBuffer* sBuf = bNode[ idxNode ];
00107  ASSERTION(sBuf!=nil,"sBuf!=nil");
00108  return sBuf;
00109 }
00110 
00111 gFileTemp& gBigBuffer::GetFile ()
00112 {
00113  ASSERTION(fTemp!=nil,"fTemp!=nil");
00114  return *fTemp;
00115 }
00116 
00117 bool gBigBuffer::NewFile ()
00118 {
00119  // Returns always true
00120  delete fTemp;
00121  fTemp = new gFileTemp( "htc" );
00122  ASSERTION(fTemp!=nil,"fTemp!=nil");  // Must create temp file!
00123  return true;
00124 }
00125 
00126 bool gBigBuffer::WriteBuf (int fHandle, gUCharBuffer& sBuf, unsigned nBytes)
00127 {
00128  // If the buffer is written, we assume 'overbuffer'
00129  hasOverbuffer = true;
00130  return thisWrite( fHandle, sBuf, nBytes )==0;
00131 }
00132 
00133 bool gBigBuffer::Flush (unsigned nBytes)
00134 {
00135  bool doNeedNode = usedSize>0;
00136  unsigned idxNode;
00137 
00138  ASSERTION(baseBuf!=nil,"Flush(1)");
00139  if ( nBytes==0 ) return true;
00140  if ( doNeedNode==false ) return true;
00141 
00142  if ( nNodes>=maxNodes ) {
00143      return thisOverbuffer( nBytes )==0;
00144  }
00145  idxNode = nNodes++;
00146  ASSERTION(bNode[idxNode]==nil,"bNode[idxNode]==nil");
00147  bNode[ idxNode ] = new gUCharBuffer( nBytes+1 );
00148  gUCharBuffer* sBuf = bNode[ idxNode ];
00149  ASSERTION(sBuf!=nil,"Flush(2)");
00150  memcpy( sBuf->uBuf, baseBuf->uBuf, (size_t)(sBuf->size = nBytes) );
00151  // Re-allocate base-buffer
00152  delete baseBuf;
00153  baseBuf = new gUCharBuffer( baseSizeBuf+1 );
00154  ASSERTION(baseBuf!=nil,"Flush(3)");
00155  return true;
00156 }
00157 
00158 bool gBigBuffer::thisAllocateBuf (t_uint32 bufSize)
00159 {
00160  if ( bufSize==0 ) return true;
00161  //if ( bufSize>=MAX_HTTP_CHUNK_SIZE ) {
00162  //     fprintf(stderr,"Trying to allocate a buffer too big: %ld/%ld\n",(long)bufSize,(long)MAX_HTTP_CHUNK_SIZE);
00163  //     ASSERTION_FALSE("thisAllocateBuf(1)");
00164  //}
00165  ASSERTION(bufSize<MAX_HTTP_CHUNK_SIZE,"thisAllocateBuf(1)");
00166  baseSizeBuf = bufSize;
00167  baseBuf = new gUCharBuffer( bufSize+1 );
00168  bNode = new gUCharBuffer*[ maxNodes ];
00169  ASSERTION(bNode!=nil,"thisAllocateBuf(2)");
00170  for (unsigned idxNode=0; idxNode<maxNodes; idxNode++) bNode[ idxNode ] = nil;
00171  return baseBuf!=nil;
00172 }
00173 
00174 int gBigBuffer::thisOverbuffer (unsigned nBytes)
00175 {
00176  unsigned idxNode;
00177 
00178  hasOverbuffer = true;
00179  if ( fTemp==nil ) {
00180      fTemp = new gFileTemp( "htp" );
00181      ASSERTION(fTemp!=nil,"fTemp!=nil");
00182      // (1st): Flush all nodes into the file
00183      for (idxNode=0; idxNode<nNodes; idxNode++) {
00184          ASSERTION(bNode[idxNode]!=nil,"bNode[idxNode]!=nil");
00185          if ( thisWrite( fTemp->fHandle, *bNode[idxNode], nBytes )!=0 ) return 2;
00186      }
00187  }
00188  // Write the baseBuf
00189  return thisWrite( fTemp->fHandle, *baseBuf, nBytes )!=0 ? 2 : 0;
00190 }
00191 
00192 int gBigBuffer::thisWrite (int fHandle, gUCharBuffer& sBuf, unsigned nBytes)
00193 {
00194  // Returns 0 on success
00195  if ( gFileControl::Self().Write( fHandle, sBuf.uBuf, nBytes ) ) return 0;
00196  return gFileControl::Self().lastOpError;
00197 }
00198 ////////////////////////////////////////////////////////////
00199 gURI::gURI ()
00200     : lastOpError( 0 ),
00201       pathType( e_NoType ),
00202       scheme( gURI::e_invalid ),
00203       isOkScheme( true )
00204 {
00205 }
00206 
00207 gURI::gURI (eScheme aScheme)
00208     : lastOpError( 0 ),
00209       pathType( e_NoType ),
00210       scheme( aScheme ),
00211       isOkScheme( true )
00212 {
00213 }
00214 
00215 gURI::~gURI ()
00216 {
00217 }
00218 
00219 bool gURI::IsOk ()
00220 {
00221  return IsOkScheme()==true && pathType!=e_NoType;
00222 }
00223 
00224 char* gURI::Str ()
00225 {
00226  return gString::Str();  // Check if this is enough
00227 }
00228 
00229 bool gURI::SetString (char* s)
00230 {
00231  // Re-initialize data-members
00232  sDomain.SetEmpty();
00233  sPath.SetEmpty();
00234  sOriginal.SetEmpty();
00235  if ( s==nil ) return false;
00236  // ...and assign relevant ones:
00237  sOriginal.Set( s );
00238  gString sTemp( s );
00239  lastOpError = thisParseString( sTemp.Str(), scheme );
00240  DBGPRINT("DBG: gURI::SetString(%s), lastOpError=%d, scheme=%d\n",s,lastOpError,scheme);
00241  return lastOpError==0;
00242 }
00243 
00244 bool gURI::IsValidDomain ()
00245 {
00246  bool isOkDomain = sDomain.Find('/')==0;
00247  if ( sDomain.Find(' ') ) return false;
00248  // For now, just checking this, not the chars in the domain name...
00249  return isOkDomain;
00250 }
00251 
00252 int gURI::thisParseString (char* s, eScheme aScheme)
00253 {
00254  int error = 0;
00255  unsigned pos;
00256  bool hasSpecScheme;
00257 
00258  ASSERTION(s!=nil,"s!=nil");
00259  pathType = e_NoType;
00260 
00261  // Refer to BNF syntax on W3-ORG:
00262  // (Index: http://www.w3.org/Addressing/URL/URI_Overview.html)
00263  // => http://www.w3.org/Addressing/URL/5_URI_BNF.html
00264 
00265  // uri ::= scheme : path [ ? search ]
00266  // scheme ::= alpha [ xalphas ]
00267  // xalphas ::= ONE OR MORE xalpha
00268  // xalpha ::= alpha | digit | safe | extra | escape
00269  // safe ::= $ | - | _ | @ | . | &
00270  // extra ::= ! | * | " | ' | ( | ) | ,
00271  // escape ::= % hex hex
00272 
00273  // A colon (:) may be present or not
00274  isOkScheme = false;
00275  pos = gStrControl::Self().Find( s, ':' );
00276  if ( (hasSpecScheme = pos>0)==true ) {
00277      // Strip schema and check-it
00278      s[ pos-1 ] = 0;
00279      eScheme inputScheme( thisGetSchemeFromString( s, error ) );
00280      s += pos;  // Not fancy but efficient...
00281      if ( error==0 ) {
00282          // Scheme input is what we expected ?
00283          // If no scheme was specified (e_invalid) any input scheme is accepted
00284          if ( aScheme!=e_invalid && inputScheme!=aScheme ) {
00285              error = 4;
00286          }
00287      }
00288      DBGPRINT("DBG: inputScheme=%d, requested scheme=%d, error=%d\n",inputScheme,aScheme,error);
00289  }
00290 
00291  if ( error!=0 ) return error;
00292  isOkScheme = true;
00293  //
00294  // Check remaining " :" =\/=> " path [ ? search ]"
00295  //
00296  // The 'path' _can_ surely start with // (double slash)
00297  // NOTE 1: Why _can_ ?
00298  //         Refer to "Hierarchies and Relative URIs" at http://www.w3.org/DesignIssues/Axioms.html
00299  //
00300  // When a scheme "XYZ:" is specified it is normally assumed an absolute path via double-slash.
00301 
00302  pos = s[0]=='/';
00303  if ( pos==1 ) {
00304      pos += s[1]=='/';
00305      s += pos;
00306      pathType = pos>=2 ? e_Absolute : e_RelativeQualified;
00307  }
00308  else {
00309      pathType = e_Relative;
00310  }
00311  return thisSetDomainPath( s, hasSpecScheme, aScheme );
00312 }
00313 
00314 int gURI::thisSetDomainPath (char* s, bool hasSpecScheme, eScheme aScheme)
00315 {
00316  gString aStr( s );
00317  unsigned pos;
00318  pos = aStr.Find( '/' );
00319  if ( pos<=1 ) {
00320      // e.g.1: "http://fuji"=\/=> "fuji" has no slash,
00321      // therefore the domain is "fuji" and path is nil
00322      // e.g.2: "http:///fuji"=\/=> "/fuji" has a leading slash,
00323      // therefore the domain is invalidly "/fuji"
00324      // e.g.3: "//afile" : the domain is not 'afile',
00325      // because it was not specified the protocol.
00326      if ( hasSpecScheme==false ) {
00327          // This fits into example 3!
00328          return thisSetPath( s );
00329      }
00330      sDomain.Set( s );
00331      return thisSetPath( nil );
00332  }
00333  // Here the domain has at least one char,
00334  // e.g. "http://f/mypath" or "http://f/mypath/"
00335  //      or just "http://f/"
00336  pos--;
00337  sDomain.CopyFromTo( aStr, 1, pos );
00338  return thisSetPath( s+pos );
00339 }
00340 
00341 int gURI::thisSetPath (char* s)
00342 {
00343  // Return 0 if o.k.
00344  // (i.e. non-empty path)
00345  ;
00346  if ( s==nil ) {
00347      Set( sDomain.Str() );
00348      return 0;
00349  }
00350  if ( s[0]==0 ) {
00351      Set( sDomain.Str() );
00352      // Empty path, thus considering only domain
00353      return 1;
00354  }
00355  // If a path ('s') does not start with a slash,
00356  // then the domain is empty, and the path
00357  // effectively starts by '/' if it is an absolute domain
00358  if ( s[0]!='/' ) {
00359      gString aPath( pathType==e_Absolute ? '/' : '\0' );
00360      aPath.Add( s );
00361      Set( aPath.Str() );
00362      sPath.Set( Str() );
00363      return 0;
00364  }
00365  Set( sDomain.Str() );
00366  Add( s );
00367  sPath.Set( s );
00368  return 0;
00369 }
00370 
00371 gURI::eScheme gURI::thisGetSchemeFromString (char* s, int& error)
00372 {
00373  int i;
00374  char c, lowChar;
00375  bool isValid;
00376  bool isEscape;
00377  eScheme aScheme;
00378 
00379  error = (int)e_invalid;  // Invalid characters used (error-code 2 is not-found!)
00380 
00381  ASSERTION(s!=nil,"s!=nil");
00382  for (i=0; (c = s[i])!='\0'; ) {
00383      // Validate all characters are xalpha
00384      lowChar = ( c>='A' && c<='Z' ) ? c+'a'-'A' : c;
00385      s[ i++ ] = lowChar;  // Changes passed string 's' (and increments cycle index)
00386      isEscape = lowChar=='%';
00387      isValid =
00388          (lowChar>='a' && lowChar<='z') ||
00389          (lowChar>='0' && lowChar<='9') ||
00390          lowChar=='$' || lowChar=='-' || lowChar=='_' ||
00391          lowChar=='@' || lowChar=='.' || lowChar=='&' ||
00392          lowChar=='!' || lowChar=='*' || lowChar=='"' ||
00393          lowChar=='\'' || lowChar=='(' || lowChar==')' ||
00394          lowChar==',' || isEscape==true;
00395      if ( isValid==false ) return e_invalid;
00396      if ( isEscape ) {
00397          c = s[ i++ ];
00398          isValid = (c>='0' && c<='9') || (c>='a' && c<='f');  // If is nul char, is false...
00399          if ( isValid==false ) return e_invalid;
00400          c = s[ i++ ];
00401          isValid = (c>='0' && c<='9') || (c>='a' && c<='f');  // If is nul char, is false...
00402          if ( isValid==false ) return e_invalid;
00403      }
00404  }//end FOR
00405 
00406  // If we get here, we know for sure all characters are ok,
00407  // now we fetch them
00408  error = thisFetchScheme( s, aScheme )<0 ? 2 : 0;
00409  return aScheme;
00410 }
00411 
00412 int gURI::thisFetchScheme (char* s, eScheme& foundScheme)
00413 {
00414  int i;
00415  short rfcCode;
00416  char* name;
00417 
00418  ASSERTION(s!=nil,"s!=nil");
00419  foundScheme = e_invalid;
00420 
00421  for (i=0; (rfcCode = schemeTbl[i].rfcCode)>=0; i++) {
00422      name = schemeTbl[i].name;
00423      if ( gStrControl::Self().Match( s, name ) ) {
00424          foundScheme = schemeTbl[i].theScheme;
00425          return i;
00426      }
00427  }
00428  return -1;
00429 }
00430 ////////////////////////////////////////////////////////////
00431 gHttpGeneric::gHttpGeneric (gTcpConnect& connection)
00432     : pConnection( &connection )
00433 {
00434 }
00435 
00436 gHttpGeneric::~gHttpGeneric ()
00437 {
00438 }
00439 
00440 gUCharBuffer& gHttpGeneric::GetBaseBuffer ()
00441 {
00442  gUCharBuffer* sBuf;
00443  sBuf = GetBuffer().baseBuf;
00444  ASSERTION(sBuf!=nil,"sBuf!=nil");
00445  return *sBuf;
00446 }
00447 
00448 gBigBuffer& gHttpGeneric::GetBuffer ()
00449 {
00450  ASSERTION_FALSE("TODO");
00451  return biffBuffer;
00452 }
00453 ////////////////////////////////////////////////////////////
00454 

Generated on Sat Aug 18 02:40:56 2007 for xpfweb_v2x lib by  doxygen 1.4.2