webengine/osswebengine/cache/src/HttpCacheHandler.cpp
changeset 10 a359256acfc6
parent 5 10e98eab6f85
child 11 c8a366e56285
equal deleted inserted replaced
5:10e98eab6f85 10:a359256acfc6
    22 #include "HttpCacheLookupTable.h"
    22 #include "HttpCacheLookupTable.h"
    23 #include "HttpCacheStreamHandler.h"
    23 #include "HttpCacheStreamHandler.h"
    24 #include "HttpCacheUtil.h"
    24 #include "HttpCacheUtil.h"
    25 #include "HttpCacheEvictionHandler.h"
    25 #include "HttpCacheEvictionHandler.h"
    26 #include "HttpCacheObserver.h"
    26 #include "HttpCacheObserver.h"
       
    27 #include "HttpCacheFileWriteHandler.h"
    27 #include <http/RHTTPTransaction.h>
    28 #include <http/RHTTPTransaction.h>
    28 #include <http/rhttpsession.h>
    29 #include <http/rhttpsession.h>
    29 #include <http/rhttpheaders.h>
    30 #include <http/rhttpheaders.h>
    30 #include <HttpStringConstants.h>
    31 #include <HttpStringConstants.h>
    31 #include <httperr.h>
    32 #include <httperr.h>
    32 #include <s32file.h>
    33 #include <s32file.h>
       
    34 #include <s32mem.h>
    33 #include <BrCtlDefs.h>
    35 #include <BrCtlDefs.h>
    34 
    36 
    35 // EXTERNAL DATA STRUCTURES
    37 // EXTERNAL DATA STRUCTURES
    36 
    38 
    37 // EXTERNAL FUNCTION PROTOTYPES
    39 // EXTERNAL FUNCTION PROTOTYPES
    38 
    40 
    39 // CONSTANTS
    41 // CONSTANTS
    40 
    42 
    41 // MACROS
    43 // MACROS
       
    44 //#define __USE_VALIDATION_FILES__
    42 
    45 
    43 // LOCAL CONSTANTS AND MACROS
    46 // LOCAL CONSTANTS AND MACROS
    44 
    47 
    45 // MODULE DATA STRUCTURES
    48 // MODULE DATA STRUCTURES
    46 
    49 
    56 
    59 
    57     User::Panic( KCachePanic, aError );
    60     User::Panic( KCachePanic, aError );
    58     }
    61     }
    59 
    62 
    60 // ============================ MEMBER FUNCTIONS ===============================
    63 // ============================ MEMBER FUNCTIONS ===============================
       
    64 THttpCachePostponeParameters::THttpCachePostponeParameters()
       
    65     {
       
    66     iEnabled = EFalse;
       
    67     iFreeRamThreshold = 0;
       
    68     iImmediateWriteThreshold = 0;
       
    69     iWriteTimeout = 0;
       
    70     }
    61 
    71 
    62 // -----------------------------------------------------------------------------
    72 // -----------------------------------------------------------------------------
    63 // CHttpCacheHandler::CHttpCacheHandler
    73 // CHttpCacheHandler::CHttpCacheHandler
    64 // C++ default constructor can NOT contain any code, that
    74 // C++ default constructor can NOT contain any code, that
    65 // might leave.
    75 // might leave.
    66 // -----------------------------------------------------------------------------
    76 // -----------------------------------------------------------------------------
    67 //
    77 //
    68 CHttpCacheHandler::CHttpCacheHandler(
    78 CHttpCacheHandler::CHttpCacheHandler( TInt aSize )
    69     TInt aSize ) : iSize( aSize )
    79     : iSize( aSize )
    70     {
    80     {
    71     }
    81     }
    72 
    82 
    73 // -----------------------------------------------------------------------------
    83 // -----------------------------------------------------------------------------
    74 // CHttpCacheHandler::ConstructL
    84 // CHttpCacheHandler::ConstructL
    76 // -----------------------------------------------------------------------------
    86 // -----------------------------------------------------------------------------
    77 //
    87 //
    78 void CHttpCacheHandler::ConstructL(
    88 void CHttpCacheHandler::ConstructL(
    79     const TDesC& aDirectory,
    89     const TDesC& aDirectory,
    80     const TDesC& aIndexFile,
    90     const TDesC& aIndexFile,
    81     TInt aCriticalLevel)
    91     TInt aCriticalLevel,
    82     {
    92     const THttpCachePostponeParameters& aPostpone)
    83 	User::LeaveIfError(iRfs.Connect());
    93     {
       
    94     User::LeaveIfError(iRfs.Connect());
    84     //
    95     //
    85     iIndexFile = aIndexFile.AllocL();
    96     iIndexFile = aIndexFile.AllocL();
    86     //
    97     //
    87     iDirectory = aDirectory.AllocL();
    98     iDirectory = aDirectory.AllocL();
    88     //
    99     //1. Set up top-level cache directory if it doesn't exist.
    89     iEvictionHandler = CHttpCacheEvictionHandler::NewL();
       
    90     //
       
    91     iStreamHandler = CHttpCacheStreamHandler::NewL( iDirectory->Des(), aCriticalLevel );
       
    92     //
       
    93     iLookupTable = CHttpCacheLookupTable::NewL( *iEvictionHandler, *iStreamHandler );
       
    94     //1. Set up top-level cache directory if it doesn't exist. 
       
    95     TEntry entry;
   100     TEntry entry;
    96     TInt err( KErrNone );
   101     TInt err( KErrNone );
    97     if (iRfs.Entry(iDirectory->Des(), entry) != KErrNone)
   102     if ( iRfs.Entry(iDirectory->Des(), entry) != KErrNone )
    98         {
   103         {
    99         err = iRfs.MkDirAll(iDirectory->Des());
   104         err = iRfs.MkDirAll( iDirectory->Des() );
   100         }
   105         }
   101 
   106 
   102     //2. Create subdirectories to store header/body files
   107     //2. Create subdirectories to store header/body files
   103     if ( err == KErrNone || err == KErrAlreadyExists ) { //harmless errors
   108     if ( err == KErrNone || err == KErrAlreadyExists ) { //harmless errors
   104     
   109 
   105         __ASSERT_DEBUG ( (iDirectory->Des().LocateReverse( KPathDelimiter ) == (iDirectory->Des().Length() - 1)),
   110         __ASSERT_DEBUG ( (iDirectory->Des().LocateReverse( KPathDelimiter ) == (iDirectory->Des().Length() - 1)),
   106                 PanicCacheHandler( KErrCorrupt ) ); // We assume that iDirectory is terminated by a forward slash
   111                 PanicCacheHandler( KErrCorrupt ) ); // We assume that iDirectory is terminated by a forward slash
   107         
   112 
   108         HBufC* subDir = HBufC::NewL(KMaxPath); // Base cache dir + subdir name + another delimiter
   113         HBufC* subDir = HBufC::NewL(KMaxPath); // Base cache dir + subdir name + another delimiter
   109         _LIT(KFormat,"%S%x%c");
   114         _LIT(KFormat,"%S%x%c");
   110         for (TUint i = 0; i < KCacheSubdirCount; i++)
   115         for ( TUint i = 0; i < KCacheSubdirCount; i++ )
   111             {
   116             {
   112             TPtrC ptr (iDirectory->Des());
   117             TPtrC ptr ( iDirectory->Des() );
   113             subDir->Des().Format(KFormat, &ptr, i, KPathDelimiter); 
   118             subDir->Des().Format( KFormat, &ptr, i, KPathDelimiter );
   114             TInt err2 = iRfs.MkDir(subDir->Des()); 
   119             TInt err2 = iRfs.MkDir( subDir->Des() );
   115             __ASSERT_DEBUG ( (err2 == KErrNone || err2 == KErrAlreadyExists), PanicCacheHandler( err2 ) ); 
   120             __ASSERT_DEBUG ( (err2 == KErrNone || err2 == KErrAlreadyExists), PanicCacheHandler( err2 ) );
   116             }
   121             }
   117         delete subDir;
   122         delete subDir;
   118         //end cache dir + subdir creation
   123         //end cache dir + subdir creation
   119     } else {
   124     } else {
   120         User::Leave(err);
   125         User::Leave(err);
   121     }
   126     }
   122 
   127 
   123     OpenLookupTableL();
   128     // set path for the entries
       
   129     iRfs.SetSessionPath( aDirectory );
       
   130 #ifdef __USE_VALIDATION_FILES__
       
   131     // create validation file
       
   132     TFileName validateFile;
       
   133     GenerateValidationFilename(validateFile, aIndexFile);
       
   134 
       
   135     TBool validateCacheEntries( EFalse );
       
   136     RFile validate;
       
   137     TInt validateErr = validate.Create(iRfs, validateFile, EFileShareExclusive | EFileWrite);
       
   138     if ( validateErr != KErrNone )
       
   139         {
       
   140         if ( validateErr == KErrAlreadyExists )
       
   141             {
       
   142             validateCacheEntries = ETrue;
       
   143             }
       
   144 #ifdef _DEBUG
       
   145         else
       
   146             {
       
   147             // oh dear, we failed to create the file for some other reason, something must have gone properly wrong...
       
   148             User::Panic(_L("CacheHandler"), -9999);
       
   149             }
       
   150 #endif
       
   151         }
       
   152     validate.Close();
       
   153 #endif
       
   154     //
       
   155     iEvictionHandler = CHttpCacheEvictionHandler::NewL();
       
   156     //
       
   157     iStreamHandler = CHttpCacheStreamHandler::NewL( iDirectory->Des(), aCriticalLevel, iRfs );
       
   158     //
       
   159     if ( aPostpone.iEnabled )
       
   160         {
       
   161         iPostponeHandler = CHttpCacheFileWriteHandler::NewL(this, iStreamHandler, iRfs, aPostpone.iWriteTimeout);
       
   162         }
       
   163     //
       
   164     iLookupTable = CHttpCacheLookupTable::NewL( *iEvictionHandler, *iStreamHandler );
       
   165     TRAP( err, OpenLookupTableL() );
       
   166     if ( err != KErrNone )
       
   167         {
       
   168         // failed to open the lookup table, delete the old one and start again.
       
   169         delete iLookupTable;
       
   170         iLookupTable = NULL;
       
   171         iLookupTable = CHttpCacheLookupTable::NewL( *iEvictionHandler, *iStreamHandler );
       
   172         }
       
   173 #ifdef __USE_VALIDATION_FILES__
       
   174     if ( validateCacheEntries )
       
   175 #endif
       
   176         // ensure that the disk content matches the cache content
       
   177         ValidateCacheEntriesL();
       
   178 
   124     //
   179     //
   125     iHttpCacheObserver = CHttpCacheObserver::NewL(iDirectory, iIndexFile, this);
   180     iHttpCacheObserver = CHttpCacheObserver::NewL(iDirectory, iIndexFile, this);
   126     iHttpCacheObserver->StartObserver();
   181     iHttpCacheObserver->StartObserver();
   127     }
   182     }
   128 
   183 
   133 //
   188 //
   134 CHttpCacheHandler* CHttpCacheHandler::NewL(
   189 CHttpCacheHandler* CHttpCacheHandler::NewL(
   135     TInt aSize,
   190     TInt aSize,
   136     const TDesC& aDirectory,
   191     const TDesC& aDirectory,
   137     const TDesC& aIndexFile,
   192     const TDesC& aIndexFile,
   138     TInt aCriticalLevel)
   193     TInt aCriticalLevel,
       
   194     const THttpCachePostponeParameters& aPostpone)
   139     {
   195     {
   140     CHttpCacheHandler* self = new( ELeave ) CHttpCacheHandler( aSize );
   196     CHttpCacheHandler* self = new( ELeave ) CHttpCacheHandler( aSize );
   141 
   197 
   142     CleanupStack::PushL( self );
   198     CleanupStack::PushL( self );
   143     self->ConstructL( aDirectory, aIndexFile, aCriticalLevel );
   199     self->ConstructL( aDirectory, aIndexFile, aCriticalLevel, aPostpone );
   144     CleanupStack::Pop();
   200     CleanupStack::Pop();
   145 
   201 
   146     return self;
   202     return self;
   147     }
   203     }
   148 
   204 
   150 // Destructor
   206 // Destructor
   151 // -----------------------------------------------------------------------------
   207 // -----------------------------------------------------------------------------
   152 //
   208 //
   153 CHttpCacheHandler::~CHttpCacheHandler()
   209 CHttpCacheHandler::~CHttpCacheHandler()
   154     {
   210     {
       
   211 #ifndef __USE_VALIDATION_FILES__
   155     TRAP_IGNORE( SaveLookupTableL() );
   212     TRAP_IGNORE( SaveLookupTableL() );
       
   213 #else
       
   214 
       
   215     TRAPD( err, SaveLookupTableL() );
       
   216     if ( err == KErrNone && iIndexFile )
       
   217         {
       
   218         TFileName validateFile;
       
   219         GenerateValidationFilename(validateFile, iIndexFile->Des());
       
   220         // we saved the index successfully, remove the validate file marker
       
   221         iRfs.Delete(validateFile);
       
   222         }
       
   223 #endif
   156     //
   224     //
   157     delete iHttpCacheObserver;
   225     delete iHttpCacheObserver;
       
   226     // must delete before eviction handler
       
   227     delete iPostponeHandler;
   158     //
   228     //
   159     if ( iEvictionHandler )
   229     if ( iEvictionHandler )
   160         {
   230         {
   161         iEvictionHandler->RemoveAll();
   231         iEvictionHandler->RemoveAll();
   162         }
   232         }
   185     THttpCacheEntry& aCacheEntry )
   255     THttpCacheEntry& aCacheEntry )
   186     {
   256     {
   187 #ifdef __CACHELOG__
   257 #ifdef __CACHELOG__
   188     HttpCacheUtil::WriteUrlToLog( 0, _L( "request item" ), aTrans.Request().URI().UriDes() );
   258     HttpCacheUtil::WriteUrlToLog( 0, _L( "request item" ), aTrans.Request().URI().UriDes() );
   189 #endif
   259 #endif
   190 
       
   191     TInt status( KErrNotFound );
   260     TInt status( KErrNotFound );
   192     CHttpCacheEntry* entry = NULL;
   261     CHttpCacheEntry* entry = NULL;
   193     // 0. check if we need to check cache at all (protected vs no cache mode)
   262     // 0. check if we need to check cache at all (protected vs no cache mode)
   194     // 1. check if the url is in the cache
   263     // 1. check if the url is in the cache
   195     // 2. check if it is complete
   264     // 2. check if it is complete
   196     // 3. see if it is useable
   265     // 3. see if it is useable
   197 
   266 
   198     // use protected item on reload
   267     // use protected item on reload
   199     // currently not and do not use cache for post
   268     // currently not and do not use cache for post
   200     if( aCacheMode != TBrCtlDefs::ECacheModeNoCache &&
   269     if ( aCacheMode != TBrCtlDefs::ECacheModeNoCache &&
   201         HttpCacheUtil::MethodFromStr( aTrans.Request().Method(), aTrans.Session().StringPool() ) != EMethodPost )
   270          HttpCacheUtil::MethodFromStr( aTrans.Request().Method(), aTrans.Session().StringPool() ) != EMethodPost )
   202         {
   271         {
   203         // If the cacheMode is noCache then it must ignore the cached entry.
   272         // If the cacheMode is noCache then it must ignore the cached entry.
   204         entry = iLookupTable->Find( aTrans.Request().URI().UriDes() );
   273         entry = iLookupTable->Find( aTrans.Request().URI().UriDes() );
       
   274 
   205         // check if the trailing slash is missing
   275         // check if the trailing slash is missing
   206         if( !entry )
   276         if ( !entry )
   207             {
   277             {
   208             TUriC8 uri = aTrans.Request().URI();
   278             TUriC8 uri = aTrans.Request().URI();
   209 
   279 
   210             if( uri.Extract( EUriPath ).Length() == 0 )
   280             if ( uri.Extract( EUriPath ).Length() == 0 )
   211                 {
   281                 {
   212                 CUri8* fixeduri = CUri8::NewLC( uri );
   282                 CUri8* fixeduri = CUri8::NewLC( uri );
   213                 fixeduri->SetComponentL( _L8("/"), EUriPath );
   283                 fixeduri->SetComponentL( _L8("/"), EUriPath );
   214                 //
   284                 //
   215                 entry = iLookupTable->Find( fixeduri->Uri().UriDes() );
   285                 entry = iLookupTable->Find( fixeduri->Uri().UriDes() );
   216                 //
   286                 //
   217                 CleanupStack::PopAndDestroy(); // fixeduri
   287                 CleanupStack::PopAndDestroy(); // fixeduri
   218                 }
   288                 }
   219             }
   289             }
   220         //
   290         //
   221         if( entry && entry->State() == CHttpCacheEntry::ECacheComplete )
   291         if ( entry && entry->State() == CHttpCacheEntry::ECacheComplete )
   222             {
   292             {
   223 #ifdef __CACHELOG__
   293 #ifdef __CACHELOG__
   224             HttpCacheUtil::WriteLog( 0, _L( "item is in the cache" ) );
   294             HttpCacheUtil::WriteLog( 0, _L( "item is in the cache" ) );
   225 #endif            
   295 #endif
   226             //
   296             //
   227             status = CacheNeedsValidationL( *entry, aTrans, aCacheMode ) ? KErrNotReady : KErrNone;
   297             status = CacheNeedsValidationL( *entry, aTrans, aCacheMode ) ? KErrNotReady : KErrNone;
   228             // entry could be invalidated at this point. check for status to make sure
   298             // entry could be invalidated at this point. check for status to make sure
   229             // the entry is still valid
   299             // the entry is still valid
       
   300 
   230             }
   301             }
   231         // prepare stream for request
   302         // prepare stream for request
   232         if( status == KErrNone )
   303         if ( status == KErrNone )
   233             {
   304             {
   234 #ifdef __CACHELOG__
   305 #ifdef __CACHELOG__
   235             HttpCacheUtil::WriteLog( 0, _L( "prepare item for sending" ) );
   306             HttpCacheUtil::WriteLog( 0, _L( "prepare item for sending" ) );
   236 #endif
   307 #endif
   237             // attach entry to the stream
   308             // access the entry
   238             if( iStreamHandler->AttachL( *entry ) )
   309             entry->SetState( CHttpCacheEntry::ECacheRequesting );
   239                 {
   310             entry->Accessed();
   240                 entry->SetState( CHttpCacheEntry::ECacheRequesting );
       
   241                 entry->Accessed();
       
   242                 }
       
   243             else
       
   244                 {
       
   245                 // cleanup on the corrupt entry
       
   246                 DeleteCacheEntry( *entry );
       
   247                 entry = NULL;
       
   248                 // item is not in cache
       
   249                 status = KErrNotFound;
       
   250                 }
       
   251             }
   311             }
   252         // cleanup
   312         // cleanup
   253         if( status == KErrNone && entry )
   313         if ( status == KErrNone && entry )
   254             {
   314             {
   255             // save handler and entry so that
   315             // save handler and entry so that
   256             // on next call we don't have to start a lookup again
   316             // on next call we don't have to start a lookup again
   257             aCacheEntry.iCacheHandler = this;
   317             aCacheEntry.iCacheHandler = this;
   258             aCacheEntry.iCacheEntry = entry;
   318             aCacheEntry.iCacheEntry = entry;
   268             }
   328             }
   269         }
   329         }
   270 #ifdef __CACHELOG__
   330 #ifdef __CACHELOG__
   271     else
   331     else
   272         {
   332         {
   273         HttpCacheUtil::WriteLog( 0, _L( "reload: do not use cache" ) );
   333         HttpCacheUtil::WriteLog( 0, _L( "reload or post: do not use cache" ) );
   274         }
   334         }
   275     if( status != KErrNone && entry )
   335 
   276         {
   336     if ( status != KErrNone && entry )
   277         //
   337         {
   278         HttpCacheUtil::WriteLog( 0, _L( "item needs validation" ) );
   338         HttpCacheUtil::WriteLog( 0, _L( "item needs validation" ) );
   279         }
   339         }
   280     else
   340 
       
   341     if ( !entry )
   281         {
   342         {
   282         //
   343         //
   283         HttpCacheUtil::WriteLog( 0, _L( "item is not in the cache" ) );
   344         HttpCacheUtil::WriteLog( 0, _L( "item is not in the cache" ) );
   284         }
   345         }
   285 #endif // __CACHELOG__
   346 #endif // __CACHELOG__
   299     HttpCacheUtil::WriteUrlToLog( 0, _L( "request http headers" ), aTrans.Request().URI().UriDes() );
   360     HttpCacheUtil::WriteUrlToLog( 0, _L( "request http headers" ), aTrans.Request().URI().UriDes() );
   300     //
   361     //
   301     TInt status( KErrNotFound );
   362     TInt status( KErrNotFound );
   302     CHttpCacheEntry* entry = aCacheEntry.iCacheEntry;
   363     CHttpCacheEntry* entry = aCacheEntry.iCacheEntry;
   303     //
   364     //
   304     if( entry && entry->State() == CHttpCacheEntry::ECacheRequesting )
   365     if ( entry && entry->State() == CHttpCacheEntry::ECacheRequesting )
   305         {
   366         {
   306         // response headers should already have all the headers
   367         // response headers should already have all the headers
   307         // as RequestL call adds them all.
   368         // as RequestL call adds them all.
   308         // no need to do much here
   369         // no need to do much here
   309         // get header from file
   370         // get header from file
   310         status = KErrNone;
   371         status = KErrNone;
   311 #ifdef __CACHELOG__
   372 #ifdef __CACHELOG__
   312         HttpCacheUtil::WriteLog( 0, _L( "sending http headers" ) );
   373         HttpCacheUtil::WriteLog( 0, _L( "sending http headers" ) );
   313 #endif        
   374 #endif
   314         }
   375         }
   315     return status;
   376     return status;
   316     }
   377     }
   317 
   378 
   318 // -----------------------------------------------------------------------------
   379 // -----------------------------------------------------------------------------
   328     (void)aTrans; //suppress compiler and PC-lint warnings
   389     (void)aTrans; //suppress compiler and PC-lint warnings
   329     //
   390     //
   330     HBufC8* bodyStr = NULL;
   391     HBufC8* bodyStr = NULL;
   331     CHttpCacheEntry* entry = aCacheEntry.iCacheEntry;
   392     CHttpCacheEntry* entry = aCacheEntry.iCacheEntry;
   332     //
   393     //
   333     if( entry && entry->State() == CHttpCacheEntry::ECacheRequesting )
   394     if ( entry && entry->State() == CHttpCacheEntry::ECacheRequesting )
   334         {
   395         {
   335         // get next chunk
   396         // get next chunk
   336         bodyStr = iStreamHandler->NextChunkL( *entry, aLastChunk );
   397         bodyStr = iStreamHandler->NextChunkL( *entry, aLastChunk );
   337         }
   398         }
   338     return bodyStr;
   399     return bodyStr;
   359         {
   420         {
   360         // normal close on a request - when the content is loaded from the cache
   421         // normal close on a request - when the content is loaded from the cache
   361         if ( entry->State() == CHttpCacheEntry::ECacheRequesting )
   422         if ( entry->State() == CHttpCacheEntry::ECacheRequesting )
   362             {
   423             {
   363             entry->SetState( CHttpCacheEntry::ECacheComplete );
   424             entry->SetState( CHttpCacheEntry::ECacheComplete );
   364             iStreamHandler->Detach( *entry );
       
   365             }
   425             }
   366         // transaction is closed without being completed
   426         // transaction is closed without being completed
   367         else if ( entry->State() == CHttpCacheEntry::ECacheResponding ||
   427         else if ( entry->State() == CHttpCacheEntry::ECacheResponding ||
   368                   entry->State() == CHttpCacheEntry::ECacheDestroyed )
   428                   entry->State() == CHttpCacheEntry::ECacheDestroyed )
   369             {
   429             {
   370             // remove uncompleted/destroyed entry
   430             // remove uncompleted/destroyed entry
   371             iStreamHandler->Detach( *entry );
       
   372             DeleteCacheEntry( *entry );
   431             DeleteCacheEntry( *entry );
   373             entry = NULL;
   432             entry = NULL;
   374             aCacheEntry.iCacheEntry = NULL;
   433             aCacheEntry.iCacheEntry = NULL;
   375 #ifdef __CACHELOG__
   434 #ifdef __CACHELOG__
   376             HttpCacheUtil::WriteLog( 0, _L( "CHttpCacheHandler::RequestClosed - uncompleted entry" ) );
   435             HttpCacheUtil::WriteLog( 0, _L( "CHttpCacheHandler::RequestClosed - uncompleted entry" ) );
   460 #endif
   519 #endif
   461 
   520 
   462     TBool protectedEntry( EFalse );
   521     TBool protectedEntry( EFalse );
   463     // check if the item is cacheable
   522     // check if the item is cacheable
   464     // no item should be bigger than the 1/3 of the cache size
   523     // no item should be bigger than the 1/3 of the cache size
   465     if( HttpCacheUtil::IsCacheable( aTrans, ( iSize / 3 ), protectedEntry ) )
   524     if ( HttpCacheUtil::IsCacheable( aTrans, ( iSize / 3 ), protectedEntry ) )
   466         {
   525         {
   467         // check if the entry is already in the cache
   526         // check if the entry is already in the cache
   468         CHttpCacheEntry* entry = iLookupTable->Find( aTrans.Request().URI().UriDes() );
   527         CHttpCacheEntry* entry = iLookupTable->Find( aTrans.Request().URI().UriDes() );
   469         if( entry )
   528         if ( entry )
   470             {
   529             {
   471 #ifdef __CACHELOG__
   530 #ifdef __CACHELOG__
   472         	HttpCacheUtil::WriteLogFilenameAndUrl( 0,
   531             HttpCacheUtil::WriteLogFilenameAndUrl( 0,
   473                                        _L("CHttpCacheHandler::ReceivedResponseHeadersL"),
   532                                        _L("CHttpCacheHandler::ReceivedResponseHeadersL"),
   474                                        entry->Filename(),
   533                                        entry->Filename(),
   475                                        entry->Url(),
   534                                        entry->Url(),
   476                                        entry->BodySize(), 
   535                                        entry->BodySize(),
   477                                        ELogEntrySize );
   536                                        ELogEntrySize );
   478 #endif
   537 #endif
   479 
   538 
   480             if( entry->State() != CHttpCacheEntry::ECacheComplete )
   539             if ( entry->State() != CHttpCacheEntry::ECacheComplete )
   481                 {
   540                 {
   482                 // multiple incoming entries doh.
   541                 // multiple incoming entries doh.
   483 #ifdef __CACHELOG__
   542 #ifdef __CACHELOG__
   484         		HttpCacheUtil::WriteLogFilenameAndUrl( 0,
   543                 HttpCacheUtil::WriteLogFilenameAndUrl( 0,
   485                                        _L("CHttpCacheHandler::ReceivedResponseHeadersL - ERROR MULTIPLE requests"),
   544                                        _L("CHttpCacheHandler::ReceivedResponseHeadersL - ERROR MULTIPLE requests"),
   486                                        entry->Filename(),
   545                                        entry->Filename(),
   487                                        entry->Url(),
   546                                        entry->Url(),
   488                                        entry->BodySize(), 
   547                                        entry->BodySize(),
   489                                        ELogEntrySize );
   548                                        ELogEntrySize );
   490 #endif
   549 #endif
   491                 // ignore this one and the first will proceed.
   550                 // ignore this one and the first will proceed.
   492                 entry = NULL;
   551                 entry = NULL;
   493                 }
   552                 }
   499 #endif
   558 #endif
   500             //Check adjustment of response time is required or not.
   559             //Check adjustment of response time is required or not.
   501             AdjustResponseTime( aTrans );
   560             AdjustResponseTime( aTrans );
   502             // hash it
   561             // hash it
   503             entry = iLookupTable->InsertL( aTrans.Request().URI().UriDes() );
   562             entry = iLookupTable->InsertL( aTrans.Request().URI().UriDes() );
   504             if( entry )
   563             if ( entry )
   505                 {
   564                 {
   506                 // protect this entry
   565                 // protect this entry
   507                 if( protectedEntry )
   566                 if ( protectedEntry )
   508                     {
   567                     {
   509 #ifdef __CACHELOG__
   568 #ifdef __CACHELOG__
   510         			HttpCacheUtil::WriteLogFilenameAndUrl( 0,
   569                     HttpCacheUtil::WriteLogFilenameAndUrl( 0,
   511                                        _L("CHttpCacheHandler::ReceivedResponseHeadersL - this is protected item"),
   570                                        _L("CHttpCacheHandler::ReceivedResponseHeadersL - this is protected item"),
   512                                        entry->Filename(),
   571                                        entry->Filename(),
   513                                        entry->Url(),
   572                                        entry->Url(),
   514                                        entry->BodySize(), 
   573                                        entry->BodySize(),
   515                                        ELogEntrySize );
   574                                        ELogEntrySize );
   516 #endif
   575 #endif
   517                     entry->SetProtected();
   576                     entry->SetProtected();
   518                     RHTTPHeaders responseHeaders = aTrans.Response().GetHeaderCollection();
   577                     RHTTPHeaders responseHeaders = aTrans.Response().GetHeaderCollection();
   519                     RStringPool strP = aTrans.Session().StringPool();
   578                     RStringPool strP = aTrans.Session().StringPool();
   526                 {
   585                 {
   527                 // no luck with the lookuptable
   586                 // no luck with the lookuptable
   528                 __ASSERT_DEBUG( EFalse, PanicCacheHandler( KErrCorrupt ) );
   587                 __ASSERT_DEBUG( EFalse, PanicCacheHandler( KErrCorrupt ) );
   529                 }
   588                 }
   530             }
   589             }
       
   590 
   531         // save headers
   591         // save headers
   532         if( entry )
   592         if ( entry )
   533             {
   593             {
   534             // attach it to the stream handler
   594             entry->SetState( CHttpCacheEntry::ECacheResponding );
   535             if( iStreamHandler->AttachL( *entry ) )
   595             // 1. handle only 304 and 200
   536                 {
   596             // 2. check if either the header or the body ( or both ) need to be updated
   537                 entry->SetState( CHttpCacheEntry::ECacheResponding );
   597             // 3. update the headers anyway in case of notmodified (304)
   538                 // 1. handle only 304 and 200
   598             // 4. remove the old body in case of bodyupdate
   539                 // 2. check if either the header or the body ( or both ) need to be updated
   599             TInt httpStatus( aTrans.Response().StatusCode() );
   540                 // 3. update the headers anyway in case of notmodified (304)
   600 
   541                 // 4. remove the old body in case of bodyupdate
   601 #ifdef __CACHELOG__
   542                 TInt httpStatus( aTrans.Response().StatusCode() );
   602             HttpCacheUtil::WriteLog( 0,  _L("CHttpCacheHandler::ReceivedResponseHeadersL - status code ="), httpStatus );
   543 
   603 #endif
   544 #ifdef __CACHELOG__
   604             TBool ok( EFalse );
   545                 HttpCacheUtil::WriteLog( 0,  _L("CHttpCacheHandler::ReceivedResponseHeadersL - status code ="), httpStatus );
   605             if ( httpStatus == HTTPStatus::EOk )
   546 #endif
   606                 {
   547                 TBool ok( EFalse );
   607                 ok = HandleResponseOkL( *entry, aTrans );
   548                 if( httpStatus == HTTPStatus::EOk )
   608                 }
   549                     {
   609             else if ( httpStatus == HTTPStatus::ENotModified )
   550                     ok = HandleResponseOkL( *entry, aTrans );
   610                 {
   551                     }
   611                 ok = HandleResponseNotModifiedL( *entry, aTrans );
   552                 else if( httpStatus == HTTPStatus::ENotModified )
   612                 }
   553                     {
   613 
   554                     ok = HandleResponseNotModifiedL( *entry, aTrans );
   614             // entry could be corrupted at this point
   555                     }
   615             if ( ok )
   556 
   616                 {
   557                 // entry could be corrupted at this point
   617                 // save handler and entry so that
   558                 if( ok )
   618                 // on next call we don't have to start a lookup again
   559                     {
   619                 aCacheEntry.iCacheHandler = this;
   560                     // save handler and entry so that
   620                 aCacheEntry.iCacheEntry = entry;
   561                     // on next call we don't have to start a lookup again
       
   562                     aCacheEntry.iCacheHandler = this;
       
   563                     aCacheEntry.iCacheEntry = entry;
       
   564                     }
       
   565                 else
       
   566                     {
       
   567                     iStreamHandler->Detach( *entry );
       
   568                     DeleteCacheEntry( *entry );
       
   569                     entry = NULL;
       
   570                     }
       
   571                 }
   621                 }
   572             else
   622             else
   573                 {
   623                 {
   574                 DeleteCacheEntry( *entry );
   624                 DeleteCacheEntry( *entry );
   575                 entry = NULL;
   625                 entry = NULL;
   600         {
   650         {
   601 #ifdef __CACHELOG__
   651 #ifdef __CACHELOG__
   602         HttpCacheUtil::WriteLog( 0, _L("---> CHttpCacheHandler::ReceivedResponseBodyDataL"), entry->BodySize() );
   652         HttpCacheUtil::WriteLog( 0, _L("---> CHttpCacheHandler::ReceivedResponseBodyDataL"), entry->BodySize() );
   603 #endif
   653 #endif
   604         HBufC8* bodyStr = HttpCacheUtil::BodyToBufferL( aBodyDataSupplier );
   654         HBufC8* bodyStr = HttpCacheUtil::BodyToBufferL( aBodyDataSupplier );
   605         if ( bodyStr )
   655         if( bodyStr )
   606             {
   656             {
   607             // Do we have old body data to remove first
   657             // Do we have old body data to remove first
   608             if ( entry->BodyFileDeleteNeeded() ) {
   658             if ( entry->BodyFileDeleteNeeded() ) {
   609                 iStreamHandler->RemoveBodyData( *entry );
   659                 iStreamHandler->RemoveBodyData( *entry );
   610                 entry->SetBodyFileDeleteNeeded( EFalse );
   660                 entry->SetBodyFileDeleteNeeded( EFalse );
   611             	}
   661                 }
   612             
   662 
   613             // erase entry if we are unable to save it (low disk space)
   663             // erase entry if we are unable to save it (low disk space)
   614             if( !SaveBuffer( *entry, bodyStr->Des(), ETrue ) )
   664             if ( !SaveBuffer( *entry, bodyStr->Des(), ETrue ) )
   615                 {
   665                 {
   616                 // detach it from the stream and erase it
   666                 // erase it
   617                 iStreamHandler->Detach( *entry );
       
   618                 DeleteCacheEntry( *entry );
   667                 DeleteCacheEntry( *entry );
   619 #ifdef __CACHELOG__                
   668 #ifdef __CACHELOG__
   620                 HttpCacheUtil::WriteLog( 0, _L( "CHttpCacheHandler::ReceivedResponseBodyDataL - body cannot be saved" ) );
   669                 HttpCacheUtil::WriteLog( 0, _L( "CHttpCacheHandler::ReceivedResponseBodyDataL - body cannot be saved" ) );
   621 #endif                
   670 #endif
   622                 entry = NULL;
   671                 entry = NULL;
   623                 // remove entry
   672                 // remove entry
   624                 aCacheEntry.iCacheEntry = NULL;
   673                 aCacheEntry.iCacheEntry = NULL;
   625                 }
   674                 }
   626 #ifdef __CACHELOG__
   675 #ifdef __CACHELOG__
   661                                            ELogEntrySize );
   710                                            ELogEntrySize );
   662 #endif
   711 #endif
   663 
   712 
   664         if ( entry->State() == CHttpCacheEntry::ECacheResponding )
   713         if ( entry->State() == CHttpCacheEntry::ECacheResponding )
   665             {
   714             {
   666             // Flush the entry
   715             TBool postponed( EFalse );
   667             if ( !iStreamHandler->Flush( *entry ) )
   716             // flush the entry if necessary
   668                 {
   717             if ( iPostponeHandler )
   669                 // We failed saving (flush), cleanup
   718                 {
   670                 iStreamHandler->Detach( *entry );
   719                 CHttpCacheFileWriteHandler::TAddStatus addStatus;
   671 
   720                 TInt err = iPostponeHandler->AddEntry( addStatus, entry );
   672                 // Deleting the entry frees cache buffer
   721 
   673                 DeleteCacheEntry( *entry );
   722                 switch ( addStatus )
   674                 entry = NULL;
   723                     {
   675                 aCacheEntry.iCacheEntry = NULL;
   724                     case CHttpCacheFileWriteHandler::EAddedOk:
   676                 }
   725                         entry->SetState( CHttpCacheEntry::ECacheComplete );
   677             else
   726                         postponed = ETrue;
   678                 {
   727 #ifdef __CACHELOG__
   679                 // We successfully saved (flush) body
   728                         HttpCacheUtil::WriteLog( 0, _L("  Added object to postpone list."));
   680                 entry->SetState( CHttpCacheEntry::ECacheComplete );
   729 #endif
   681                 iStreamHandler->Detach( *entry );
   730                         break;
   682 
   731                     case CHttpCacheFileWriteHandler::EBodySmallerThanThreshold:
   683                 // Clear the flushed cache buffer, we were using for incoming body
   732 #ifdef __CACHELOG__
   684                 TRAP_IGNORE( entry->SetCacheBufferL( KBufferSizeZero ) );
   733                         HttpCacheUtil::WriteLog( 0, _L("  Not postponed. EBodySmallerThanThreshold"));
   685                 }
   734 #endif
   686             }
   735                         break;
   687         else if( entry->State() == CHttpCacheEntry::ECacheDestroyed )
   736                     case CHttpCacheFileWriteHandler::ENotEnoughFreeMemory:
   688             {
   737 #ifdef __CACHELOG__
   689             iStreamHandler->Detach( *entry );
   738                         HttpCacheUtil::WriteLog( 0, _L("  Not postponed. ENotEnoughFreeMemory"));
   690 
   739 #endif
   691             // Deleting the entry frees cache buffer
   740                         break;
       
   741                     case CHttpCacheFileWriteHandler::ECheckReturn:
       
   742 #ifdef __CACHELOG__
       
   743                         HttpCacheUtil::WriteLog( 0, _L("  Not postponed. ECheckReturn - %d"), err );
       
   744 #endif
       
   745                     default:
       
   746                         break;
       
   747                     }
       
   748                 }
       
   749 
       
   750             if ( !postponed )
       
   751                 {
       
   752                 if ( !iStreamHandler->Flush( *entry ) )
       
   753                     {
       
   754                     // remove entry
       
   755                     DeleteCacheEntry( *entry );
       
   756                     entry = NULL;
       
   757                     aCacheEntry.iCacheEntry = NULL;
       
   758                     }
       
   759                 else
       
   760                     {
       
   761                     // We successfully saved (flushed) body
       
   762                     entry->SetState( CHttpCacheEntry::ECacheComplete );
       
   763                     }
       
   764                 }
       
   765             }
       
   766         else if ( entry->State() == CHttpCacheEntry::ECacheDestroyed )
       
   767             {
   692             DeleteCacheEntry( *entry, EFalse );
   768             DeleteCacheEntry( *entry, EFalse );
   693             entry = NULL;
   769             entry = NULL;
   694             aCacheEntry.iCacheEntry = NULL;
   770             aCacheEntry.iCacheEntry = NULL;
   695             }
   771             }
   696         }
   772         }
   697     }
   773     }
   698 
   774 
   699 // -----------------------------------------------------------------------------
   775 // -----------------------------------------------------------------------------
   700 // Removes all entries in the Cache lookup table, commits table to disk. 
   776 // Removes all entries in the Cache lookup table, commits table to disk.
   701 //
   777 //
   702 // -----------------------------------------------------------------------------
   778 // -----------------------------------------------------------------------------
   703 //
   779 //
   704 TInt CHttpCacheHandler::RemoveAllL()
   780 TInt CHttpCacheHandler::RemoveAllL()
   705     {
   781     {
   706 #ifdef __CACHELOG__
   782 #ifdef __CACHELOG__
   707     HttpCacheUtil::WriteLog( 0, _L( "remove all items" ) );
   783     HttpCacheUtil::WriteLog( 0, _L( "remove all items" ) );
   708 #endif
   784 #endif
   709     TInt numberOfBytes;
   785     TInt numberOfBytes;
       
   786 
       
   787     // by definition, all entries in the postpone handler aren't active.
       
   788     if ( iPostponeHandler )
       
   789         {
       
   790         iPostponeHandler->RemoveAll();
       
   791         }
       
   792 
   710     // clear all the inactive entries
   793     // clear all the inactive entries
   711     numberOfBytes = iLookupTable->RemoveAll();
   794     numberOfBytes = iLookupTable->RemoveAll();
       
   795 
   712     // and save it. user initiated. no need to do idle save
   796     // and save it. user initiated. no need to do idle save
   713     SaveLookupTableL();
   797     SaveLookupTableL();
   714     return numberOfBytes;
   798     return numberOfBytes;
   715     }
   799     }
   716 
   800 
   776     const TDesC8& aContent )
   860     const TDesC8& aContent )
   777     {
   861     {
   778     TBool saved( EFalse );
   862     TBool saved( EFalse );
   779     // check if entry exist. do not overwrite.
   863     // check if entry exist. do not overwrite.
   780     CHttpCacheEntry* entry = iLookupTable->Find( aUrl );
   864     CHttpCacheEntry* entry = iLookupTable->Find( aUrl );
   781     if( !entry )
   865     if ( !entry )
   782         {
   866         {
   783         entry = iLookupTable->InsertL( aUrl );
   867         entry = iLookupTable->InsertL( aUrl );
   784         // prepare for saving
   868         // prepare for saving
   785         if( entry && iStreamHandler->AttachL( *entry ) )
   869         if ( entry )
   786             {
   870             {
   787             // save header and body
   871             // save header and body
   788             saved = SaveBuffer( *entry, aHeader, EFalse ) && SaveBuffer( *entry, aContent, ETrue );
   872             saved = SaveBuffer( *entry, aHeader, EFalse ) && SaveBuffer( *entry, aContent, ETrue );
   789             if( saved )
   873             if ( saved )
   790                 {
   874                 {
   791                 // flush
   875                 // flush
   792                 saved = iStreamHandler->Flush( *entry );
   876                 saved = iStreamHandler->Flush( *entry );
   793                 if( saved )
   877                 if ( saved )
   794                     {
   878                     {
   795                     entry->SetState( CHttpCacheEntry::ECacheComplete );
   879                     entry->SetState( CHttpCacheEntry::ECacheComplete );
   796                     }
   880                     }
   797                 }
   881                 }
   798             iStreamHandler->Detach( *entry );
       
   799             }
   882             }
   800         // cleanup
   883         // cleanup
   801         if( !saved && entry )
   884         if ( !saved && entry )
   802             {
   885             {
   803             DeleteCacheEntry( *entry );
   886             DeleteCacheEntry( *entry );
   804             }
   887             }
   805         }
   888         }
   806     return saved;
   889     return saved;
   817     const TDesC8& aValue )
   900     const TDesC8& aValue )
   818     {
   901     {
   819     TInt status( KErrNotFound );
   902     TInt status( KErrNotFound );
   820     //
   903     //
   821     CHttpCacheEntry* entry = iLookupTable->Find( aUrl );
   904     CHttpCacheEntry* entry = iLookupTable->Find( aUrl );
   822     if( entry )
   905     if ( entry )
   823         {
   906         {
   824         TBool attached;
       
   825         //
       
   826         attached = iStreamHandler->AttachL( *entry );
       
   827         // get headers
   907         // get headers
   828         HBufC8* headersStr = iStreamHandler->HeadersL( *entry );
   908         HBufC8* headersStr = iStreamHandler->HeadersL( *entry );
   829         if( headersStr )
   909         if ( headersStr )
   830             {
   910             {
   831             CleanupStack::PushL( headersStr );
   911             CleanupStack::PushL( headersStr );
   832             // alter headers and save them
   912             // alter headers and save them
   833             HBufC8* newHeaderStr = HttpCacheUtil::AddHeaderLC( aName, aValue, headersStr->Des() );
   913             HBufC8* newHeaderStr = HttpCacheUtil::AddHeaderLC( aName, aValue, headersStr->Des() );
   834             if( newHeaderStr )
   914             if ( newHeaderStr )
   835                 {
   915                 {
   836                 // remove old headers first
   916                 // remove old headers first
   837                 iStreamHandler->RemoveHeaders( *entry );
   917                 iStreamHandler->RemoveHeaders( *entry );
   838                 // save new headers
   918                 // save new headers
   839                 if( !SaveBuffer( *entry, newHeaderStr->Des(), EFalse ) )
   919                 if ( !SaveBuffer( *entry, newHeaderStr->Des(), EFalse ) )
   840                     {
   920                     {
   841                     status = KErrDirFull;
   921                     status = KErrDirFull;
   842                     // failed. should we save the original headers?
   922                     // failed. should we save the original headers?
   843                     TBool saveOk( SaveBuffer( *entry, headersStr->Des(), EFalse ) );
   923                     TBool saveOk( SaveBuffer( *entry, headersStr->Des(), EFalse ) );
   844                     // original save should never fail
   924                     // original save should never fail
   845                     __ASSERT_DEBUG( saveOk, PanicCacheHandler( KErrCorrupt ) );
   925                     __ASSERT_DEBUG( saveOk, PanicCacheHandler( KErrCorrupt ) );
   846 
   926 
   847                     if( !saveOk )
   927                     if ( !saveOk )
   848                         {
   928                         {
   849                         // sorry, we made this entry corrupt. remove it
   929                         // sorry, we made this entry corrupt. remove it
   850                         iStreamHandler->Detach( *entry );
       
   851                         DeleteCacheEntry( *entry );
   930                         DeleteCacheEntry( *entry );
   852                         entry = NULL;
   931                         entry = NULL;
   853                         }
   932                         }
   854                     }
   933                     }
   855                 else
   934                 else
   858                     }
   937                     }
   859                 CleanupStack::PopAndDestroy(); // newHeaderStr
   938                 CleanupStack::PopAndDestroy(); // newHeaderStr
   860                 }
   939                 }
   861             CleanupStack::PopAndDestroy(); // headersStr
   940             CleanupStack::PopAndDestroy(); // headersStr
   862             }
   941             }
   863         // detach
       
   864         if( attached )
       
   865             {
       
   866             iStreamHandler->Detach( *entry );
       
   867             }
       
   868         }
   942         }
   869     return status;
   943     return status;
   870     }
   944     }
   871 
   945 
   872 // -----------------------------------------------------------------------------
   946 // -----------------------------------------------------------------------------
   889     //
   963     //
   890     // Note: Cache also set the cacheMode to PreferCache after a resource has
   964     // Note: Cache also set the cacheMode to PreferCache after a resource has
   891     //       been validated -- that is when it tries to refetch an entry from
   965     //       been validated -- that is when it tries to refetch an entry from
   892     //       cache after receiving a 304 response.
   966     //       cache after receiving a 304 response.
   893     // get cached headers
   967     // get cached headers
   894     if( iStreamHandler->AttachL( aCacheEntry ) )
   968     HBufC8* headersStr = iStreamHandler->HeadersL( aCacheEntry );
   895         {
   969     CleanupStack::PushL( headersStr );
   896         HBufC8* headersStr = iStreamHandler->HeadersL( aCacheEntry );
   970     // headersStr == NULL happens if you erase the cache directory
   897         CleanupStack::PushL( headersStr );
   971     // using a file manager
   898         iStreamHandler->Detach( aCacheEntry );
   972     if ( headersStr )
   899         // headersStr == NULL happens if you erase the cache directory
   973         {
   900         // using a file manager
   974         // use response headers for retreiving cached headers
   901         if( headersStr )
   975         RHTTPHeaders responseHeaders = aTrans.Response().GetHeaderCollection();
   902             {
   976         RHTTPHeaders requestHeaders = aTrans.Request().GetHeaderCollection();
   903             // use response headers for retreiving cached headers
   977         RStringPool strP = aTrans.Session().StringPool();
   904             RHTTPHeaders responseHeaders = aTrans.Response().GetHeaderCollection();
   978         // convert the buffer to httpHeader
   905             RHTTPHeaders requestHeaders = aTrans.Request().GetHeaderCollection();
   979         HttpCacheUtil::BufferToHeadersL( headersStr->Des(), responseHeaders, strP );
   906             RStringPool strP = aTrans.Session().StringPool();
   980 
   907             // convert the buffer to httpHeader
   981         // check if we need to validate the cahce
   908             HttpCacheUtil::BufferToHeadersL( headersStr->Des(), responseHeaders, strP );
   982         if ( aCacheMode == TBrCtlDefs::ECacheModeOnlyCache || aCacheMode == TBrCtlDefs::ECacheModeHistory  )
   909 
   983             {
   910             // check if we need to validate the cahce
   984             // no validation required
   911             if( aCacheMode == TBrCtlDefs::ECacheModeOnlyCache || aCacheMode == TBrCtlDefs::ECacheModeHistory  )
   985 #ifdef __CACHELOG__
   912                 {
   986             HttpCacheUtil::WriteLog( 0, _L( "prefer cache mode. no need to revalidate" ), aCacheMode );
   913                 // no validation required
   987 #endif
   914 #ifdef __CACHELOG__
   988             mustRevalidate = EFalse;
   915                 HttpCacheUtil::WriteLog( 0, _L( "prefer cache mode. no need to revalidate" ), aCacheMode );
   989             }
   916 #endif                
   990         else
   917                 mustRevalidate = EFalse;
   991             {
   918                 }
   992             // Get the pragma no-cache header from the headers
   919             else
   993             // no-cache on request header means "do not use cache"
   920                 {
   994             if ( !HttpCacheUtil::PragmaNoCache( aTrans ) )
   921                 // Get the pragma no-cache header from the headers
   995                 {
   922                 // no-cache on request header means "do not use cache"
   996                 if ( !HttpCacheUtil::CacheTimeIsFresh( requestHeaders, responseHeaders, strP  ) )
   923                 if( !HttpCacheUtil::PragmaNoCache( aTrans ) )
       
   924                     {
   997                     {
   925                     if( !HttpCacheUtil::CacheTimeIsFresh( requestHeaders, responseHeaders, strP  ) )
   998 #ifdef __CACHELOG__
   926                         {
   999                     HttpCacheUtil::WriteLog( 0, _L( "cache item is not fresh. needs revalidation" ) );
   927 #ifdef __CACHELOG__
  1000 #endif
   928                         HttpCacheUtil::WriteLog( 0, _L( "cache item is not fresh. needs revalidation" ) );
  1001                     // Avoid removing cache entry here
   929 #endif
  1002                     mustRevalidate = ETrue;
   930                         // MKLE-7PRD27: Avoid removing cache entry here 
  1003                     // add headers like EIfModifiedSince, EETag, EIfNoneMatch
   931                         mustRevalidate = ETrue;
  1004                     HttpCacheUtil::AddValidationHeaders( responseHeaders, requestHeaders, strP );
   932                         // add headers like EIfModifiedSince, EETag, EIfNoneMatch
       
   933                         HttpCacheUtil::AddValidationHeaders( responseHeaders, requestHeaders, strP );
       
   934                         }
       
   935                     else
       
   936                         {
       
   937 #ifdef __CACHELOG__
       
   938                         HttpCacheUtil::WriteLog( 0, _L( "cache item is fresh. needs no revalidation" ) );
       
   939 #endif                        
       
   940                         //
       
   941                         mustRevalidate = EFalse;
       
   942                         }
       
   943                     }
  1005                     }
   944                 else
  1006                 else
   945                     {
  1007                     {
   946                     // needs validation
  1008 #ifdef __CACHELOG__
   947 #ifdef __CACHELOG__
  1009                     HttpCacheUtil::WriteLog( 0, _L( "cache item is fresh. needs no revalidation" ) );
   948                     HttpCacheUtil::WriteLog( 0, _L( "no cache/no store header present. need revalidation" ) );
  1010 #endif
   949 #endif
  1011                     //
   950                     mustRevalidate = ETrue;
  1012                     mustRevalidate = EFalse;
   951                     }
  1013                     }
   952 
  1014                 }
   953                 }
  1015             else
   954             }
  1016                 {
   955         CleanupStack::PopAndDestroy(); // headersStr
  1017                 // needs validation
   956         }
  1018 #ifdef __CACHELOG__
   957     else
  1019                 HttpCacheUtil::WriteLog( 0, _L( "no cache/no store header present. need revalidation" ) );
   958         {
  1020 #endif
   959         DeleteCacheEntry( aCacheEntry );
  1021                 mustRevalidate = ETrue;
   960         // needs validation
  1022                 }
   961         mustRevalidate = ETrue;
  1023             }
   962         }
  1024         }
       
  1025     CleanupStack::PopAndDestroy(); // headersStr
       
  1026 
   963     return mustRevalidate;
  1027     return mustRevalidate;
   964     }
  1028     }
   965 
  1029 
   966 // -----------------------------------------------------------------------------
  1030 // -----------------------------------------------------------------------------
   967 // CHttpCacheHandler::CacheNeedsSpaceL
  1031 // CHttpCacheHandler::CacheNeedsSpaceL
   985         // items in the cache
  1049         // items in the cache
   986         TInt size( 0 );
  1050         TInt size( 0 );
   987         HttpCacheUtil::WriteLog( 0, _L( "cached items" ) );
  1051         HttpCacheUtil::WriteLog( 0, _L( "cached items" ) );
   988 
  1052 
   989         const CArrayPtrFlat<CHttpCacheEntry>& entries = iLookupTable->Entries();
  1053         const CArrayPtrFlat<CHttpCacheEntry>& entries = iLookupTable->Entries();
   990         for( TInt i = 0; i < entries.Count(); i++ )
  1054         for ( TInt i = 0; i < entries.Count(); i++ )
   991             {
  1055             {
   992             CHttpCacheEntry* entry = entries.At( i );
  1056             CHttpCacheEntry* entry = entries.At( i );
   993             if( entry && entry != (CHttpCacheEntry*)0xffffffff )
  1057             if ( entry && entry != (CHttpCacheEntry*)0xffffffff )
   994                 {
  1058                 {
   995                 HttpCacheUtil::WriteUrlToLog( 0, entry->Url(), entry->BodySize() );
  1059                 HttpCacheUtil::WriteUrlToLog( 0, entry->Url(), entry->BodySize() );
   996                 size += entry->BodySize();
  1060                 size += entry->BodySize();
   997                 size += entry->HeaderSize();
  1061                 size += entry->HeaderSize();
   998                 }
  1062                 }
  1001 #endif // __CACHELOG__
  1065 #endif // __CACHELOG__
  1002 
  1066 
  1003         CArrayPtrFlat<CHttpCacheEntry>* evictedList = iEvictionHandler->EvictL( aSize );
  1067         CArrayPtrFlat<CHttpCacheEntry>* evictedList = iEvictionHandler->EvictL( aSize );
  1004         if ( evictedList && evictedList->Count() )
  1068         if ( evictedList && evictedList->Count() )
  1005             {
  1069             {
  1006             // Delete entry items marked for eviction
  1070             // destroy items
  1007             CHttpCacheEntry* entry;
  1071             CHttpCacheEntry* entry;
  1008             for ( TInt i = 0; i < evictedList->Count(); i++ )
  1072             for ( TInt i = 0; i < evictedList->Count(); i++ )
  1009                 {
  1073                 {
       
  1074                 //
  1010                 entry = evictedList->At( i );
  1075                 entry = evictedList->At( i );
  1011 
       
  1012                 if ( entry )
  1076                 if ( entry )
  1013                     {
  1077                     {
  1014                     // Handle removing valid and invalid entries. Check entry
  1078                     if ( iPostponeHandler )
  1015                     // for validity, and if in lookup table. It has been
       
  1016                     // found that the evictList can have invalid entries in it.
       
  1017                     // These invalid entries are not in the lookup table.
       
  1018                     TInt lookupTableIndex( -1 );
       
  1019                     iLookupTable->FindCacheEntryIndex( *entry, &lookupTableIndex );
       
  1020                     
       
  1021                     TInt sizeBody = entry->BodySize();
       
  1022                     if ( sizeBody == 0 && lookupTableIndex >= 0 )
       
  1023                         {
  1079                         {
  1024                         // This is an empty body cache entry that exists
  1080                         iPostponeHandler->RemoveEntry( entry );
  1025                         // in the lookup table, remove it from file system and
       
  1026                         // lookup table.
       
  1027 						// Use CreateNewFilesL() to open file handles, so we can delete
       
  1028 						// the files associated with the cache entry. We don't check
       
  1029                         // return value of RemoveByPosition(), because we already
       
  1030                         // checked for index in FindCacheEntryIndex(). 
       
  1031                         iStreamHandler->CreateNewFilesL( *entry );
       
  1032                         iStreamHandler->EraseCacheFile( *entry );
       
  1033                         iLookupTable->RemoveByPosition( lookupTableIndex );
       
  1034                         }
  1081                         }
  1035                     else if ( lookupTableIndex >= 0 )
  1082 
  1036                         {
  1083                     // when an item is destroyed, it will attempt to remove itself from the lookup table which will fail and panic
  1037                         // Remove valid entries that are found in lookup table
  1084                     // because EvictL already removed it.
  1038                         iLookupTable->Remove( entry->Url() );
  1085                     // In this scenario, we need to tell the item that it's no longer a candidate to prevent that.
  1039                         }
  1086                     // we don't want to make lookuptable::remove do that though, because this only applies when we are removing
       
  1087                     // an item because of eviction and NOT for any other reason.
       
  1088                     entry->UnsetEvictionCandidate();
       
  1089 
       
  1090                     // destroy
       
  1091                     iLookupTable->Remove( entry->Url() );
  1040                     }
  1092                     }
  1041                 }
  1093                 }
  1042 
  1094 
  1043             // ok = ETrue if there is enough space
  1095             // ok = ETrue if there is enough space
  1044             ok = ( iStreamHandler->SavedContentSize() + aSize < iSize );
  1096             ok = ( iStreamHandler->SavedContentSize() + aSize < iSize );
  1048             // interesting...nobody can be evicted...
  1100             // interesting...nobody can be evicted...
  1049             // they are all protected entries?
  1101             // they are all protected entries?
  1050             // or the incoming -not yet complete- items take the entire cache?
  1102             // or the incoming -not yet complete- items take the entire cache?
  1051 #ifdef __CACHELOG__
  1103 #ifdef __CACHELOG__
  1052             HttpCacheUtil::WriteLog( 0, _L( "NO SPACE can be released!!!" ) );
  1104             HttpCacheUtil::WriteLog( 0, _L( "NO SPACE can be released!!!" ) );
  1053 #endif            
  1105 #endif
  1054             ok = EFalse;
  1106             ok = EFalse;
  1055             }
  1107             }
  1056 
       
  1057         // Cleanup the evicted list, including any invalid entries
       
  1058         delete evictedList;
  1108         delete evictedList;
  1059         }
  1109         }
  1060     return ok;
  1110     return ok;
  1061     }
  1111     }
  1062 
  1112 
  1075     HBufC8* responseHeaderStr = HttpCacheUtil::HeadersToBufferLC( responseHeader, strP );
  1125     HBufC8* responseHeaderStr = HttpCacheUtil::HeadersToBufferLC( responseHeader, strP );
  1076 
  1126 
  1077     TBool update( ETrue );
  1127     TBool update( ETrue );
  1078     // get cached headers to compare
  1128     // get cached headers to compare
  1079     HBufC8* cachedHeaderStr = iStreamHandler->HeadersL( aEntry );
  1129     HBufC8* cachedHeaderStr = iStreamHandler->HeadersL( aEntry );
  1080     
  1130 
  1081     // we've got some headers to update, check if we really need to update them
  1131     // we've got some headers to update, check if we really need to update them
  1082     if ( cachedHeaderStr )
  1132     if ( cachedHeaderStr )
  1083         {
  1133         {
  1084         CleanupStack::PushL( cachedHeaderStr );
  1134         CleanupStack::PushL( cachedHeaderStr );
  1085 
  1135 
  1093 #ifdef __CACHELOG__
  1143 #ifdef __CACHELOG__
  1094         HttpCacheUtil::WriteLogFilenameAndUrl( 0,
  1144         HttpCacheUtil::WriteLogFilenameAndUrl( 0,
  1095                                        _L("CHttpCacheHandler::HandleResponseOkL - cache UPDATE needed"),
  1145                                        _L("CHttpCacheHandler::HandleResponseOkL - cache UPDATE needed"),
  1096                                        aEntry.Filename(),
  1146                                        aEntry.Filename(),
  1097                                        aEntry.Url(),
  1147                                        aEntry.Url(),
  1098                                        aEntry.BodySize(), 
  1148                                        aEntry.BodySize(),
  1099                                        ELogEntrySize );
  1149                                        ELogEntrySize );
  1100 #endif
  1150 #endif
  1101         if ( aEntry.HeaderSize() )
  1151         if ( aEntry.HeaderSize() )
  1102             {
  1152             {
  1103             // remove headers from headerFile first
  1153             // remove headers from headerFile first
  1104             iStreamHandler->RemoveHeaders( aEntry );
  1154             iStreamHandler->RemoveHeaders( aEntry );
  1105             }
  1155             }
  1106 
  1156 
  1107         // save new headerFile
  1157         // save new headerFile
  1108         saveOk = SaveBuffer( aEntry, responseHeaderStr->Des() );
  1158         saveOk = SaveBuffer( aEntry, responseHeaderStr->Des() );
  1109         
  1159 
  1110         if ( aEntry.BodySize() )
  1160         if ( aEntry.BodySize() )
  1111             {
  1161             {
  1112             // We will remove this body data, after we confirm that we get new
  1162             // We will remove this body data, after we confirm that we get new
  1113             // body data
  1163             // body data
  1114             aEntry.SetBodyFileDeleteNeeded( ETrue );
  1164             aEntry.SetBodyFileDeleteNeeded( ETrue );
  1115             }
  1165             }
  1116 
       
  1117         // Setup a cache buffer to hold the incoming body
       
  1118         aEntry.SetCacheBufferL( KBufferSize32k );
       
  1119         }
  1166         }
  1120     else
  1167     else
  1121         {
  1168         {
  1122         // if neither the header nor the body need to be updated, then
  1169         // neither the header nor the body need to be updated
  1123         // detach entry to protect from being updated
       
  1124 #ifdef __CACHELOG__
  1170 #ifdef __CACHELOG__
  1125         HttpCacheUtil::WriteLog( 0, _L( "CHttpCacheHandler::HandleResponseOkL - no update needed, ignore response" ) );
  1171         HttpCacheUtil::WriteLog( 0, _L( "CHttpCacheHandler::HandleResponseOkL - no update needed, ignore response" ) );
  1126 #endif        
  1172 #endif
  1127         //
  1173         //
  1128         aEntry.SetState( CHttpCacheEntry::ECacheComplete );
  1174         aEntry.SetState( CHttpCacheEntry::ECacheComplete );
  1129         iStreamHandler->Detach( aEntry );
       
  1130         // pretend that save was ok.
  1175         // pretend that save was ok.
  1131         saveOk = ETrue;
  1176         saveOk = ETrue;
  1132         }
  1177         }
  1133 
  1178 
  1134     CleanupStack::PopAndDestroy(); // responseHeaderStr
  1179     CleanupStack::PopAndDestroy(); // responseHeaderStr
  1144 //
  1189 //
  1145 TBool CHttpCacheHandler::HandleResponseNotModifiedL(
  1190 TBool CHttpCacheHandler::HandleResponseNotModifiedL(
  1146     CHttpCacheEntry& aEntry,
  1191     CHttpCacheEntry& aEntry,
  1147     RHTTPTransaction& aTrans )
  1192     RHTTPTransaction& aTrans )
  1148     {
  1193     {
  1149     // oos? -out of space
  1194     // Are we out of space ?
  1150     TBool saveOk( ETrue );
  1195     TBool saveOk( ETrue );
  1151     RHTTPHeaders responseHeader = aTrans.Response().GetHeaderCollection();
  1196     RHTTPHeaders responseHeader = aTrans.Response().GetHeaderCollection();
  1152     RStringPool strP = aTrans.Session().StringPool();
  1197     RStringPool strP = aTrans.Session().StringPool();
  1153     HBufC8* responseHeaderStr = HttpCacheUtil::HeadersToBufferLC( responseHeader, strP );
  1198     HBufC8* responseHeaderStr = HttpCacheUtil::HeadersToBufferLC( responseHeader, strP );
  1154     // If a cache uses a received 304 response to update a cache entry,
  1199     // If a cache uses a received 304 response to update a cache entry,
  1155     // the cache MUST update the entry to reflect any new field values given in the response.
  1200     // the cache MUST update the entry to reflect any new field values given in the response.
  1156     HBufC8* mergedHeadersStr = NULL;
  1201     HBufC8* mergedHeadersStr = NULL;
  1157     HBufC8* cachedHeaderStr = iStreamHandler->HeadersL( aEntry );
  1202     HBufC8* cachedHeaderStr = iStreamHandler->HeadersL( aEntry );
  1158     CleanupStack::PushL( cachedHeaderStr );
  1203     CleanupStack::PushL( cachedHeaderStr );
       
  1204 
  1159     // don't merge with empty headers
  1205     // don't merge with empty headers
  1160     if( cachedHeaderStr )
  1206     if ( cachedHeaderStr )
  1161         {
  1207         {
  1162         mergedHeadersStr = HttpCacheUtil::MergeHeadersLC( cachedHeaderStr->Des(), responseHeader, strP );
  1208         mergedHeadersStr = HttpCacheUtil::MergeHeadersLC( cachedHeaderStr->Des(), responseHeader, strP );
  1163         CleanupStack::Pop(); // mergedHeadersStr
  1209         CleanupStack::Pop(); // mergedHeadersStr
  1164         }
  1210         }
  1165     // don't update empty headers
  1211     // don't update empty headers
  1166     if( mergedHeadersStr || responseHeaderStr )
  1212     if ( mergedHeadersStr || responseHeaderStr )
  1167         {
  1213         {
  1168         // remove cached headers first
  1214         // remove cached headers first
  1169         iStreamHandler->RemoveHeaders( aEntry );
  1215         iStreamHandler->RemoveHeaders( aEntry );
  1170         // save merged headers  (reponse + cached)
  1216         // save merged headers  (reponse + cached)
  1171         if( mergedHeadersStr )
  1217         if ( mergedHeadersStr )
  1172             {
  1218             {
  1173             saveOk = SaveBuffer( aEntry, mergedHeadersStr->Des() );
  1219             saveOk = SaveBuffer( aEntry, mergedHeadersStr->Des() );
  1174             }
  1220             }
  1175         else if( responseHeaderStr )
  1221         else if ( responseHeaderStr )
  1176             {
  1222             {
  1177             // save responseheader instead
  1223             // save responseheader instead
  1178             saveOk = SaveBuffer( aEntry, responseHeaderStr->Des() );
  1224             saveOk = SaveBuffer( aEntry, responseHeaderStr->Des() );
  1179             }
  1225             }
  1180         // if save failed, let's see if we can save old
  1226         // if save failed, let's see if we can save old
  1181         // headers
  1227         // headers
  1182         if( !saveOk && cachedHeaderStr )
  1228         if ( !saveOk && cachedHeaderStr )
  1183             {
  1229             {
  1184             saveOk = SaveBuffer( aEntry, cachedHeaderStr->Des() );
  1230             saveOk = SaveBuffer( aEntry, cachedHeaderStr->Des() );
  1185             }
  1231             }
  1186         }
  1232         }
  1187     // do not remove the body as it was not modified
  1233     // do not remove the body as it was not modified
  1188     delete mergedHeadersStr;
  1234     delete mergedHeadersStr;
  1189     CleanupStack::PopAndDestroy( 2 ); // cachedHeaderStr, responseHeaderStr
  1235     CleanupStack::PopAndDestroy( 2 ); // cachedHeaderStr, responseHeaderStr
  1190     // check if save was ok.
  1236     // check if save was ok.
  1191     // or nothing was not saved at all
  1237     // or nothing was not saved at all
  1192     if( saveOk )
  1238     if ( saveOk )
  1193         {
  1239         {
  1194         // this item does not need update
  1240         // this item does not need update
  1195         aEntry.SetState( CHttpCacheEntry::ECacheComplete );
  1241         aEntry.SetState( CHttpCacheEntry::ECacheComplete );
  1196         iStreamHandler->Detach( aEntry );
  1242         //iStreamHandler->Detach( aEntry );
  1197         }
  1243         }
       
  1244 
  1198     return saveOk;
  1245     return saveOk;
  1199     }
  1246     }
  1200 
  1247 
  1201 // -----------------------------------------------------------------------------
  1248 // -----------------------------------------------------------------------------
  1202 // CHttpCacheHandler::OpenLookupTableL
  1249 // CHttpCacheHandler::OpenLookupTableL
  1203 //
  1250 //
  1204 // -----------------------------------------------------------------------------
  1251 // -----------------------------------------------------------------------------
  1205 //
  1252 //
  1206 void CHttpCacheHandler::OpenLookupTableL()
  1253 void CHttpCacheHandler::OpenLookupTableL()
  1207     {
  1254     {
  1208     OpenLookupTableL(iLookupTable);
  1255     OpenLookupTableL( iLookupTable );
  1209     }
  1256     }
  1210 
  1257 
  1211 // -----------------------------------------------------------------------------
  1258 // -----------------------------------------------------------------------------
  1212 // CHttpCacheHandler::OpenLookupTableL
  1259 // CHttpCacheHandler::OpenLookupTableL
  1213 // Opens the index*.dat lookup table from file system. 
  1260 // Opens the index*.dat lookup table from file system.
  1214 // -----------------------------------------------------------------------------
  1261 // -----------------------------------------------------------------------------
  1215 //
  1262 //
  1216 void CHttpCacheHandler::OpenLookupTableL(CHttpCacheLookupTable* aLookupTable)
  1263 void CHttpCacheHandler::OpenLookupTableL(CHttpCacheLookupTable* aLookupTable)
  1217     {
  1264     {
       
  1265 #if 0
  1218     // read entries from index.dat
  1266     // read entries from index.dat
  1219     RFileReadStream readStream;
  1267     RFileReadStream readStream;
  1220 
  1268 
  1221         iRfs.SetSessionPath( iDirectory->Des() );
  1269     iRfs.SetSessionPath( iDirectory->Des() );
  1222 
  1270 
  1223         TInt ret = KErrNone;
       
  1224         TInt tryCount = 0;
       
  1225         for (tryCount = 0; tryCount < 5; tryCount++) 
       
  1226             {
       
  1227             ret = readStream.Open( iRfs, iIndexFile->Des(), EFileRead | EFileShareAny );
       
  1228             if (ret == KErrInUse)
       
  1229                 {
       
  1230                 // When the cache is full, it takes 65 - 85 miliseconds to write the index.
       
  1231                 // So wait 50 miliseconds and try again
       
  1232                 User::After(50000);
       
  1233                 }
       
  1234             else
       
  1235                 {
       
  1236                 break;
       
  1237                 }
       
  1238             }
       
  1239         if( ret == KErrNone )
       
  1240             {
       
  1241             TRAPD ( err, aLookupTable->InternalizeL( readStream, iDirectory->Des() ) );
       
  1242             readStream.Close(); 
       
  1243             if ( err != KErrNone ) 
       
  1244                 {
       
  1245                 // In case Bad Things Happen (TM), do RemoveAllL() which clears this cache's 
       
  1246                 // in-memory data structures + saves an updated lookup table to disk replacing the old one. 
       
  1247                 TRAP_IGNORE( RemoveAllL() );
       
  1248                 } 
       
  1249             }
       
  1250     }
       
  1251 
       
  1252 // -----------------------------------------------------------------------------
       
  1253 // CHttpCacheHandler::SaveLookupTableL
       
  1254 //
       
  1255 // -----------------------------------------------------------------------------
       
  1256 //
       
  1257 void CHttpCacheHandler::SaveLookupTableL()
       
  1258     {
       
  1259 #ifdef __CACHELOG__
       
  1260     HttpCacheUtil::WriteLog( 0, _L( "lookup table is saved" ) );
       
  1261 #endif
       
  1262     // save entries to index.dat
       
  1263     RFileWriteStream writeStream;
       
  1264 
       
  1265     // Don't get notified about own changes
       
  1266     if ( iHttpCacheObserver ) 
       
  1267         iHttpCacheObserver->Cancel();
       
  1268     
       
  1269     TInt ret = KErrNone;
  1271     TInt ret = KErrNone;
  1270     TInt tryCount = 0;
  1272     TInt tryCount = 0;
  1271     for (tryCount = 0; tryCount < 5; tryCount++) 
  1273     for (tryCount = 0; tryCount < 5; tryCount++)
  1272         {
  1274         {
  1273         ret = writeStream.Replace( iRfs, iIndexFile->Des(), EFileWrite );
  1275         ret = readStream.Open( iRfs, iIndexFile->Des(), EFileRead | EFileShareAny );
  1274         if (ret == KErrInUse)
  1276         if (ret == KErrInUse)
  1275             {
  1277             {
  1276             // When the cache is full, it takes 65 - 85 miliseconds to write the index.
  1278             // When the cache is full, it takes 65 - 85 miliseconds to write the index.
  1277             // So wait 50 miliseconds and try again
  1279             // So wait 50 miliseconds and try again
  1278             User::After(50000);
  1280             User::After(50000);
  1282             break;
  1284             break;
  1283             }
  1285             }
  1284         }
  1286         }
  1285     if( ret == KErrNone )
  1287     if( ret == KErrNone )
  1286         {
  1288         {
       
  1289         CleanupClosePushL( readStream );
       
  1290         aLookupTable->InternalizeL( readStream, iDirectory->Des() );
       
  1291         CleanupStack::PopAndDestroy(1); // readStream
       
  1292         }
       
  1293 #else
       
  1294     RFile readFile;
       
  1295     iRfs.SetSessionPath( iDirectory->Des() );
       
  1296 
       
  1297     TInt ret = KErrNone;
       
  1298     TInt tryCount = 0;
       
  1299     for (tryCount = 0; tryCount < 5; tryCount++)
       
  1300         {
       
  1301         ret = readFile.Open( iRfs, iIndexFile->Des(), EFileRead | EFileShareAny );
       
  1302         if (ret == KErrInUse)
       
  1303             {
       
  1304             // When the cache is full, it takes 65 - 85 miliseconds to write the index.
       
  1305             // So wait 50 miliseconds and try again
       
  1306             User::After(50000);
       
  1307             }
       
  1308         else
       
  1309             {
       
  1310             break;
       
  1311             }
       
  1312         }
       
  1313 
       
  1314     if ( ret == KErrNone )
       
  1315         {
       
  1316         CleanupClosePushL(readFile);
       
  1317         TInt size;
       
  1318         readFile.Size(size);
       
  1319 
       
  1320         if ( size )
       
  1321             {
       
  1322             HBufC8* buffer = HBufC8::NewLC(size);
       
  1323             TPtr8 buf( buffer->Des() );
       
  1324             User::LeaveIfError( readFile.Read(buf, size) );
       
  1325             RDesReadStream readStream( buf );
       
  1326             CleanupClosePushL(readStream);
       
  1327             aLookupTable->InternalizeL( readStream, iDirectory->Des() );
       
  1328             CleanupStack::PopAndDestroy(3); // read stream, buffer then file
       
  1329             }
       
  1330         else
       
  1331             {
       
  1332             CleanupStack::PopAndDestroy(1);  // close the file.
       
  1333             }
       
  1334         }
       
  1335 #endif
       
  1336     }
       
  1337 
       
  1338 // -----------------------------------------------------------------------------
       
  1339 // CHttpCacheHandler::SaveLookupTableL
       
  1340 //
       
  1341 // -----------------------------------------------------------------------------
       
  1342 //
       
  1343 void CHttpCacheHandler::SaveLookupTableL()
       
  1344     {
       
  1345 #ifdef __CACHELOG__
       
  1346     HttpCacheUtil::WriteLog( 0, _L( "lookup table is saved" ) );
       
  1347 #endif
       
  1348     // save entries to index.dat
       
  1349     RFileWriteStream writeStream;
       
  1350 
       
  1351     // Don't get notified about own changes
       
  1352     iHttpCacheObserver->Cancel();
       
  1353     TInt ret = KErrNone;
       
  1354     TInt tryCount = 0;
       
  1355     for (tryCount = 0; tryCount < 5; tryCount++)
       
  1356         {
       
  1357         ret = writeStream.Replace( iRfs, iIndexFile->Des(), EFileWrite );
       
  1358         if (ret == KErrInUse)
       
  1359             {
       
  1360             // When the cache is full, it takes 65 - 85 miliseconds to write the index.
       
  1361             // So wait 50 miliseconds and try again
       
  1362             User::After(50000);
       
  1363             }
       
  1364         else
       
  1365             {
       
  1366             break;
       
  1367             }
       
  1368         }
       
  1369     if ( ret == KErrNone )
       
  1370         {
  1287         CleanupClosePushL( writeStream );
  1371         CleanupClosePushL( writeStream );
  1288         iLookupTable->ExternalizeL( writeStream );
  1372         iLookupTable->ExternalizeL( writeStream , iDirectory->Des() );
  1289         writeStream.CommitL();
  1373         writeStream.CommitL();
  1290         CleanupStack::PopAndDestroy(); // writeStream
  1374         CleanupStack::PopAndDestroy(); // writeStream
  1291         }
  1375         }
  1292     
  1376     iHttpCacheObserver->StartObserver();
  1293     if ( iHttpCacheObserver ) 
       
  1294         iHttpCacheObserver->StartObserver();
       
  1295     }
  1377     }
  1296 
  1378 
  1297 // -----------------------------------------------------------------------------
  1379 // -----------------------------------------------------------------------------
  1298 // CHttpCacheHandler::DeleteCacheEntry
  1380 // CHttpCacheHandler::DeleteCacheEntry
  1299 //
  1381 //
  1300 // -----------------------------------------------------------------------------
  1382 // -----------------------------------------------------------------------------
  1301 //
  1383 //
  1302 void CHttpCacheHandler::DeleteCacheEntry(
  1384 void CHttpCacheHandler::DeleteCacheEntry(
  1303     CHttpCacheEntry& aEntry,
  1385     CHttpCacheEntry& aStrayEntry,
  1304     TBool aUpdate )
  1386     TBool aUpdate )
  1305     {
  1387     {
  1306     // suppress compiler and PC-lint warnings
  1388     (void)aUpdate;//suppress compiler and PC-lint warnings
  1307     (void)aUpdate;
  1389 #ifdef __CACHELOG__
  1308 
  1390     HttpCacheUtil::WriteLog( 0, _L( "delete this stray entry" ) );
  1309 #ifdef __CACHELOG__
  1391 #endif
  1310         HttpCacheUtil::WriteLogFilenameAndUrl( 0,
  1392 
  1311                                        _L("CHttpCacheHandler::DeleteCacheEntry"),
  1393     // need to make sure this entry is removed from postpone handler, if it might be there.
  1312                                        aEntry.Filename(),
  1394     if ( iPostponeHandler )
  1313                                        aEntry.Url(),
  1395         {
  1314                                        aEntry.BodySize(), 
  1396         iPostponeHandler->RemoveEntry( &aStrayEntry );
  1315                                        ELogEntrySize );
  1397         }
  1316 #endif
  1398 
  1317 
  1399     // remove from the lookuptable
  1318     // Remove from the lookuptable
  1400     iLookupTable->EraseCacheEntry( aStrayEntry.Url() );
  1319     iLookupTable->EraseCacheEntry( aEntry.Url() );
  1401     }
  1320     }
  1402 
  1321 
  1403 // -----------------------------------------------------------------------------
  1322 // -----------------------------------------------------------------------------
  1404 // There used to be a CHttpCacheHandler::FixLookupTableL here.
  1323 // There used to be a CHttpCacheHandler::FixLookupTableL here. 
       
  1324 // Go back in SVN to re-discover it :)
  1405 // Go back in SVN to re-discover it :)
  1325 //
  1406 //
  1326 // -----------------------------------------------------------------------------
  1407 // -----------------------------------------------------------------------------
  1327 
  1408 
  1328 // -----------------------------------------------------------------------------
  1409 // -----------------------------------------------------------------------------
  1334     CHttpCacheEntry& aEntry,
  1415     CHttpCacheEntry& aEntry,
  1335     const TDesC8& aBuffer,
  1416     const TDesC8& aBuffer,
  1336     TBool aBody )
  1417     TBool aBody )
  1337     {
  1418     {
  1338     TBool ok( EFalse );
  1419     TBool ok( EFalse );
  1339     
  1420 
  1340     TRAPD( err, ok = CacheNeedsSpaceL( aBuffer.Length() ) );
  1421     TRAPD( err, ok = CacheNeedsSpaceL( aBuffer.Length() ) );
  1341     if ( err == KErrNone && ok )
  1422     if ( err == KErrNone && ok )
  1342         {
  1423         {
  1343         // Did we have a safe save of the body or header
  1424         // Did we have a safe save of the body or header
  1344         ok = aBody ? iStreamHandler->SaveBodyData( aEntry, aBuffer ) : iStreamHandler->SaveHeaders( aEntry, aBuffer );
  1425         ok = aBody ? iStreamHandler->SaveBodyData( aEntry, aBuffer ) : iStreamHandler->SaveHeaders( aEntry, aBuffer );
  1348         {
  1429         {
  1349         // stop saving this entry
  1430         // stop saving this entry
  1350         HttpCacheUtil::WriteUrlToLog( 0, _L( "item cannot be saved. remove it please" ), aEntry.Url() );
  1431         HttpCacheUtil::WriteUrlToLog( 0, _L( "item cannot be saved. remove it please" ), aEntry.Url() );
  1351         }
  1432         }
  1352 #endif // __CACHELOG__
  1433 #endif // __CACHELOG__
       
  1434 
  1353     return ok;
  1435     return ok;
  1354     }
  1436     }
  1355 
  1437 
  1356 
       
  1357 // -----------------------------------------------------------------------------
  1438 // -----------------------------------------------------------------------------
  1358 // CHttpCacheHandler::UpdateLookupTable
  1439 // CHttpCacheHandler::UpdateLookupTable
  1359 //
  1440 //
  1360 // -----------------------------------------------------------------------------
  1441 // -----------------------------------------------------------------------------
  1361 //
  1442 //
  1362 void CHttpCacheHandler::UpdateLookupTable()
  1443 void CHttpCacheHandler::UpdateLookupTable()
  1363     {
  1444     {
  1364     TRAP_IGNORE(UpdateLookupTableL());
  1445     TRAP_IGNORE(UpdateLookupTableL());
  1365     
  1446     iHttpCacheObserver->StartObserver();
  1366     if ( iHttpCacheObserver ) 
       
  1367         iHttpCacheObserver->StartObserver();
       
  1368     }
  1447     }
  1369 
  1448 
  1370 // -----------------------------------------------------------------------------
  1449 // -----------------------------------------------------------------------------
  1371 // CHttpCacheHandler::UpdateLookupTableL
  1450 // CHttpCacheHandler::UpdateLookupTableL
  1372 // Slow method due to much file-system interaction. Don't call it from performance critical code. 
  1451 // Slow method due to much file-system interaction. Don't call it from performance critical code.
  1373 // -----------------------------------------------------------------------------
  1452 // -----------------------------------------------------------------------------
  1374 //
  1453 //
  1375 void CHttpCacheHandler::UpdateLookupTableL()
  1454 void CHttpCacheHandler::UpdateLookupTableL()
  1376     {
  1455     {
  1377     CHttpCacheEvictionHandler* evictionHandler = CHttpCacheEvictionHandler::NewL();
  1456     CHttpCacheEvictionHandler* evictionHandler = CHttpCacheEvictionHandler::NewL();
  1378     CleanupStack::PushL(evictionHandler);
  1457     CleanupStack::PushL(evictionHandler);
  1379     CHttpCacheLookupTable* lookupTable = CHttpCacheLookupTable::NewL( *evictionHandler, *iStreamHandler );
  1458     CHttpCacheLookupTable* lookupTable = CHttpCacheLookupTable::NewL( *evictionHandler, *iStreamHandler );
  1380     CleanupStack::PushL(lookupTable);
  1459     CleanupStack::PushL(lookupTable);
  1381     OpenLookupTableL(lookupTable);
  1460     OpenLookupTableL(lookupTable);
  1382     iLookupTable->MergeL(lookupTable, iRfs);
  1461     iLookupTable->MergeL(lookupTable, iRfs);
  1383 	CleanupStack::PopAndDestroy(2); // lookupTable, evictionHandler
  1462     CleanupStack::PopAndDestroy(2); // lookupTable, evictionHandler
       
  1463     }
       
  1464 
       
  1465 // -----------------------------------------------------------------------------
       
  1466 // CHttpCacheHandler::GenerateValidationFilename
       
  1467 // -----------------------------------------------------------------------------
       
  1468 //
       
  1469 #ifdef __USE_VALIDATION_FILES__
       
  1470     void CHttpCacheHandler::GenerateValidationFilename(TDes& aFilename, const TDesC& aIndexFilename) const
       
  1471 #else
       
  1472     void CHttpCacheHandler::GenerateValidationFilename(TDes& /*aFilename*/, const TDesC& /*aIndexFilename*/) const
       
  1473 #endif
       
  1474     {
       
  1475 #ifdef __USE_VALIDATION_FILES__
       
  1476     _LIT(KValidationExtension, ".val");
       
  1477     TParse filenameParser;
       
  1478     filenameParser.Set(aIndexFilename, NULL, NULL);
       
  1479     aFilename.Copy(filenameParser.DriveAndPath());
       
  1480     aFilename.Append(filenameParser.Name());
       
  1481     aFilename.Append(KValidationExtension);
       
  1482 #else
       
  1483     PanicCacheHandler(KErrNotSupported);
       
  1484 #endif
       
  1485     }
       
  1486 
       
  1487 // -----------------------------------------------------------------------------
       
  1488 // DestroyBadUrlArray
       
  1489 // -----------------------------------------------------------------------------
       
  1490 //
       
  1491 static void DestroyBadUrlArray(TAny* aPtr)
       
  1492     {
       
  1493     RPointerArray<HBufC8> *tmp = (RPointerArray<HBufC8>*)aPtr;
       
  1494     tmp->ResetAndDestroy();
       
  1495     }
       
  1496 
       
  1497 // -----------------------------------------------------------------------------
       
  1498 // CHttpCacheHandler::ValidateCacheEntriesL
       
  1499 // -----------------------------------------------------------------------------
       
  1500 //
       
  1501 void CHttpCacheHandler::ValidateCacheEntriesL()
       
  1502     {
       
  1503     // iterate through entries and check if file is present.
       
  1504     // if not, add URL to a list of bad ones otherwise remove directory entry from list
       
  1505     // at the end, go through list of bad entries and remove them from cache,
       
  1506     // go through list of unreferenced files and delete them too.
       
  1507     THttpCacheLookupTableEntryIterator iter;
       
  1508     iLookupTable->BeginEntryIteration(iter);
       
  1509 #ifdef __CACHELOG__
       
  1510     HttpCacheUtil::WriteLog(0, _L("CHttpCacheHandler::ValidateCacheEntriesL"));
       
  1511 #endif
       
  1512     // if the cache contains no items, we should still do this so we detect other files.
       
  1513 
       
  1514     // get list of files on disk
       
  1515     CCacheDirectoryFiles *dirFiles = CCacheDirectoryFiles::NewLC(iRfs, *iDirectory);
       
  1516 
       
  1517     // look for bad entries
       
  1518     RPointerArray<HBufC8> badEntries;
       
  1519     CleanupStack::PushL(TCleanupItem(DestroyBadUrlArray, &badEntries));
       
  1520     const CHttpCacheEntry *tmpEntry;
       
  1521     while(tmpEntry = iLookupTable->NextEntry(iter), tmpEntry)
       
  1522         {
       
  1523         if(!dirFiles->ValidateEntryL(*tmpEntry))
       
  1524             {
       
  1525 #ifdef __CACHELOG__
       
  1526             HttpCacheUtil::WriteUrlToLog(0, _L("Bad Entry: "), tmpEntry->Url() );
       
  1527 #endif
       
  1528             badEntries.AppendL(tmpEntry->Url().AllocL());
       
  1529             }
       
  1530         }
       
  1531 
       
  1532     // remove bad entries
       
  1533     for(TInt i=0; i < badEntries.Count(); i++)
       
  1534         {
       
  1535         iLookupTable->Remove(badEntries[i]->Des());
       
  1536         }
       
  1537     CleanupStack::PopAndDestroy(1); // bad entry list
       
  1538 
       
  1539     // remove orphan files
       
  1540     dirFiles->RemoveLeftoverFilesL();
       
  1541     CleanupStack::PopAndDestroy(dirFiles);
       
  1542     }
       
  1543 
       
  1544 // -----------------------------------------------------------------------------
       
  1545 // CCacheDirectoryFiles::NewL
       
  1546 // -----------------------------------------------------------------------------
       
  1547 //
       
  1548 CCacheDirectoryFiles* CCacheDirectoryFiles::NewL(RFs aRfs, const TDesC& aDir)
       
  1549     {
       
  1550     CCacheDirectoryFiles* me = CCacheDirectoryFiles::NewLC(aRfs, aDir);
       
  1551     CleanupStack::Pop(me);
       
  1552     return me;
       
  1553     }
       
  1554 
       
  1555 // -----------------------------------------------------------------------------
       
  1556 // CCacheDirectoryFiles::NewLC
       
  1557 // -----------------------------------------------------------------------------
       
  1558 //
       
  1559 CCacheDirectoryFiles* CCacheDirectoryFiles::NewLC(RFs aRfs, const TDesC& aDir)
       
  1560     {
       
  1561     CCacheDirectoryFiles *me = new (ELeave) CCacheDirectoryFiles(aRfs, aDir);
       
  1562     CleanupStack::PushL(me);
       
  1563     me->ConstructL();
       
  1564     return me;
       
  1565     }
       
  1566 
       
  1567 // -----------------------------------------------------------------------------
       
  1568 // CCacheDirectoryFiles::ValidateEntryL
       
  1569 // -----------------------------------------------------------------------------
       
  1570 //
       
  1571 TBool CCacheDirectoryFiles::ValidateEntryL(const CHttpCacheEntry& aEntry)
       
  1572     {
       
  1573     // check the files associated with the cache entry are present where they should be
       
  1574     // if the file is present, then remove it from the dir list
       
  1575     // if the file is present AND the size matches the entry, then return ETrue in aPresentAndValid
       
  1576     // otherwise, return EFalse there.
       
  1577     TBool presentAndValid = EFalse;
       
  1578 
       
  1579     TParse tmpParse;
       
  1580     tmpParse.Set(aEntry.Filename(), NULL, NULL);
       
  1581     // for this file to be part of the cache it must meet the following rules..
       
  1582     // length of name is 8 chars
       
  1583     if(tmpParse.Name().Length() != 8)
       
  1584         return presentAndValid;
       
  1585 
       
  1586     // this filename has a chance of existing and we can assume correct format from now on
       
  1587     TUint32 cacheUintName;
       
  1588     if(TCompressedEntry::ConvertANameToUint32(tmpParse.Name(), cacheUintName))
       
  1589         {
       
  1590         TInt arrayIndex = cacheUintName & 0x0000000F;
       
  1591         presentAndValid = iDirContent[arrayIndex]->ValidateCacheEntryL( aEntry );
       
  1592         }
       
  1593     // after all cache entries have been checked against the list, it should only contain orphaned files
       
  1594     // files which match but are corrupt will have been removed from this list
       
  1595     // however they should be cleaned up when the 'corrupt' entries are removed at a later date.
       
  1596     return presentAndValid;
       
  1597     }
       
  1598 
       
  1599 // -----------------------------------------------------------------------------
       
  1600 // CCacheDirectoryFiles::RemoveLeftoverFilesL
       
  1601 // -----------------------------------------------------------------------------
       
  1602 //
       
  1603 void CCacheDirectoryFiles::RemoveLeftoverFilesL()
       
  1604     {
       
  1605     // delete all the files which are still listed.
       
  1606     TFileName tempFilename;
       
  1607     for (TInt subDir=0; subDir < 16; subDir++)
       
  1608         {
       
  1609         for (TInt fileIdx = 0; fileIdx < iDirContent[subDir]->Count(); fileIdx++ )
       
  1610             {
       
  1611             // each file needs to have the full path prepended in order to delete
       
  1612             HBufC *name = iDirContent[subDir]->NameAtL(fileIdx);
       
  1613             tempFilename.Format(_L("%S%x\\%S"), &iDir, subDir, name);
       
  1614 #ifdef __CACHELOG__
       
  1615             HttpCacheUtil::WriteFormatLog(0, _L("Deleting file %S"), &tempFilename);
       
  1616 #endif
       
  1617             iRfs.Delete(tempFilename);
       
  1618             delete name;
       
  1619             }
       
  1620         }
       
  1621     }
       
  1622 
       
  1623 // -----------------------------------------------------------------------------
       
  1624 // CCacheDirectoryFiles::~CCacheDirectoryFiles
       
  1625 // -----------------------------------------------------------------------------
       
  1626 //
       
  1627 CCacheDirectoryFiles::~CCacheDirectoryFiles()
       
  1628     {
       
  1629     iDirContent.ResetAndDestroy();
       
  1630     }
       
  1631 
       
  1632 // -----------------------------------------------------------------------------
       
  1633 // CCacheDirectoryFiles::ConstructL
       
  1634 // -----------------------------------------------------------------------------
       
  1635 //
       
  1636 void CCacheDirectoryFiles::ConstructL()
       
  1637     {
       
  1638     CDir* baseDirs;
       
  1639     User::LeaveIfError(iRfs.GetDir(iDir,KEntryAttDir,ESortByName,baseDirs));
       
  1640     CleanupStack::PushL(baseDirs);
       
  1641 
       
  1642     // we know that the cache format is a single letter directory from 0-f
       
  1643     // so we ignore any other directories - they might belong to other caches
       
  1644     // and our cache will not have written any files out into anywhere except the
       
  1645     // 0-f dirs, even if we lost track of something.
       
  1646     // See HttpCacheUtil::GenerateNameLC
       
  1647     iDirContent.ReserveL(16);
       
  1648 
       
  1649     TInt numdirs = baseDirs->Count();
       
  1650     // storage for <c:/system/cache/> + '0/'
       
  1651     HBufC* currentDir = HBufC::NewLC( iDir.Length() + KSubdirNameLength );
       
  1652     for(TInt i=0; i < numdirs; i++)
       
  1653         {
       
  1654         TInt arrayIndex = -1;
       
  1655         const TEntry& entry = (*baseDirs)[i];
       
  1656         if(entry.IsDir() && entry.iName.Length()==1)
       
  1657             {
       
  1658             TUint16 chr = *(entry.iName.Right(1).Ptr());
       
  1659             arrayIndex = TCompressedEntry::ConvertAsciiToIntSingleHexDigit(chr);
       
  1660             }
       
  1661 
       
  1662         if(arrayIndex >=0 && arrayIndex <= 15)
       
  1663             {
       
  1664             // initialise subdir name to base directory
       
  1665             currentDir->Des().Copy(iDir);
       
  1666             currentDir->Des().AppendFormat(_L("%x\\"), arrayIndex); // if base path wasn't terminated with trailing / we would have blown up at creation time.
       
  1667 
       
  1668             // get subdirectory content
       
  1669             CDir *dir;
       
  1670             iRfs.GetDir(currentDir->Des(), KEntryAttMatchExclude | KEntryAttDir, ESortByName, dir); // only files this time...
       
  1671             if(dir)
       
  1672                 {
       
  1673                 iDirContent.Insert( CCustomCacheDirList::NewL( dir ), arrayIndex );
       
  1674                 }
       
  1675             delete dir;
       
  1676             }
       
  1677         }
       
  1678         CleanupStack::PopAndDestroy(2); // baseDirs & currentDir
       
  1679     }
       
  1680 
       
  1681 // -----------------------------------------------------------------------------
       
  1682 // CCustomCacheDirList::NewL
       
  1683 // -----------------------------------------------------------------------------
       
  1684 //
       
  1685 CCustomCacheDirList* CCustomCacheDirList::NewL(CDir *aSrc)
       
  1686     {
       
  1687     CCustomCacheDirList *me = new (ELeave) CCustomCacheDirList;
       
  1688     CleanupStack::PushL( me );
       
  1689     me->ConstructL( aSrc );
       
  1690     CleanupStack::Pop( me );
       
  1691     return me;
       
  1692     }
       
  1693 
       
  1694 // -----------------------------------------------------------------------------
       
  1695 // CCustomCacheDirList::ValidateCacheEntryL
       
  1696 // -----------------------------------------------------------------------------
       
  1697 //
       
  1698 TBool CCustomCacheDirList::ValidateCacheEntryL( const CHttpCacheEntry& aEntry )
       
  1699     {
       
  1700     TBool presentAndValid = EFalse;
       
  1701     TUint32 shortName;
       
  1702     if( TCompressedEntry::ConvertANameToUint32( aEntry.Filename().Right(8), shortName) )
       
  1703         {
       
  1704         for(TInt i=0; i<iDirList.Count(); i++)
       
  1705             {
       
  1706             if(iDirList[i]->IsCompressed() &&
       
  1707                     (iDirList[i]->GetCompressedName() == shortName) &&
       
  1708                     (iDirList[i]->GetSize() == aEntry.BodySize()))
       
  1709                 {
       
  1710                 presentAndValid = ETrue;
       
  1711                 iDirList.Remove(i);
       
  1712                 break;
       
  1713                 }
       
  1714             }
       
  1715         }
       
  1716     return presentAndValid;
       
  1717     }
       
  1718 
       
  1719 // -----------------------------------------------------------------------------
       
  1720 // CCustomCacheDirList::Count
       
  1721 // -----------------------------------------------------------------------------
       
  1722 //
       
  1723 TInt CCustomCacheDirList::Count()
       
  1724     {
       
  1725     return iDirList.Count();
       
  1726     }
       
  1727 
       
  1728 // -----------------------------------------------------------------------------
       
  1729 // CCustomCacheDirList::NameAtL
       
  1730 // -----------------------------------------------------------------------------
       
  1731 //
       
  1732 HBufC* CCustomCacheDirList::NameAtL( TInt aIndex )
       
  1733     {
       
  1734     return iDirList[aIndex]->GetNameL();
       
  1735     }
       
  1736 
       
  1737 // -----------------------------------------------------------------------------
       
  1738 // CCustomCacheDirList::CCustomCacheDirList
       
  1739 // -----------------------------------------------------------------------------
       
  1740 //
       
  1741 CCustomCacheDirList::CCustomCacheDirList()
       
  1742     {
       
  1743     }
       
  1744 
       
  1745 // -----------------------------------------------------------------------------
       
  1746 // CCustomCacheDirList::ConstructL
       
  1747 // -----------------------------------------------------------------------------
       
  1748 //
       
  1749 void CCustomCacheDirList::ConstructL(CDir *aSrc)
       
  1750     {
       
  1751     TInt items = aSrc->Count();
       
  1752     if(items)
       
  1753         {
       
  1754         iDirList.ReserveL(items);
       
  1755         for(TInt i=0; i < items; i++)
       
  1756             {
       
  1757             TCompressedEntry *newDirEntry = TCompressedEntry::NewL( (*aSrc)[i] );
       
  1758             iDirList.AppendL( newDirEntry );
       
  1759             }
       
  1760         }
       
  1761     }
       
  1762 
       
  1763 // -----------------------------------------------------------------------------
       
  1764 // TCompressedEntry::NewL
       
  1765 // -----------------------------------------------------------------------------
       
  1766 //
       
  1767 TCompressedEntry *TCompressedEntry::NewL( const TEntry& aEntry )
       
  1768     {
       
  1769     TCompressedEntry *newEntry = new (ELeave) TCompressedEntry;
       
  1770     CleanupStack::PushL( newEntry );
       
  1771     newEntry->ConstructL( aEntry );
       
  1772     CleanupStack::Pop( newEntry );
       
  1773 
       
  1774     return newEntry;
       
  1775     }
       
  1776 
       
  1777 // -----------------------------------------------------------------------------
       
  1778 // TCompressedEntry::ConstructL
       
  1779 // -----------------------------------------------------------------------------
       
  1780 //
       
  1781 void TCompressedEntry::ConstructL( const TEntry& aEntry )
       
  1782     {
       
  1783     TUint32 compressedName;
       
  1784     if ( ConvertANameToUint32(aEntry.iName, compressedName) )
       
  1785         {
       
  1786         iFlags |= EFilenameStoredAsUint32;
       
  1787         iName.iNameAsUint32 = compressedName;
       
  1788         }
       
  1789     else
       
  1790         {
       
  1791         iName.iNameAsHBuf = aEntry.iName.AllocL();
       
  1792         }
       
  1793     iSize = aEntry.iSize;
       
  1794     }
       
  1795 
       
  1796 // -----------------------------------------------------------------------------
       
  1797 // TCompressedEntry::ConvertANameToUint32
       
  1798 // -----------------------------------------------------------------------------
       
  1799 //
       
  1800 TBool TCompressedEntry::ConvertANameToUint32( const TDesC& aName, TUint32& aConverted)
       
  1801     {
       
  1802     TBool success = EFalse;
       
  1803     aConverted = 0;
       
  1804 
       
  1805     if ( aName.Length() == 8 )
       
  1806         {
       
  1807         TUint32 scratch = 0;
       
  1808         for ( TInt i=0; i < 8; i++ )
       
  1809             {
       
  1810             scratch <<= 4;
       
  1811             TInt val = TCompressedEntry::ConvertAsciiToIntSingleHexDigit(aName[i]);
       
  1812             if ( val >= 0 )
       
  1813                 {
       
  1814                 scratch += val & 0x0F;
       
  1815                 }
       
  1816             else
       
  1817                 break;
       
  1818 
       
  1819             if ( i==7 )
       
  1820                 {
       
  1821                 aConverted = scratch;
       
  1822                 success = ETrue;
       
  1823                 }
       
  1824             }
       
  1825         }
       
  1826 
       
  1827     return success;
       
  1828     }
       
  1829 
       
  1830 // -----------------------------------------------------------------------------
       
  1831 // TCompressedEntry::ConvertAsciiToIntSingleHexDigit
       
  1832 // -----------------------------------------------------------------------------
       
  1833 //
       
  1834 TInt TCompressedEntry::ConvertAsciiToIntSingleHexDigit(const TUint16& aDigitChar)
       
  1835     {
       
  1836     if ( aDigitChar >=48 && aDigitChar <=57 )
       
  1837         {
       
  1838         return (aDigitChar - 48); //numerals
       
  1839         }
       
  1840     else if ( aDigitChar >= 65 && aDigitChar <= 70 )
       
  1841         {
       
  1842         return (aDigitChar - 55); // uppercase hex letters
       
  1843         }
       
  1844     else if ( aDigitChar >= 97 && aDigitChar <= 102 )
       
  1845         {
       
  1846         return (aDigitChar - 87); // lowercase hex letters
       
  1847         }
       
  1848 
       
  1849     return -1;
       
  1850     }
       
  1851 
       
  1852 // -----------------------------------------------------------------------------
       
  1853 // TCompressedEntry::GetNameL
       
  1854 // -----------------------------------------------------------------------------
       
  1855 //
       
  1856 HBufC* TCompressedEntry::GetNameL()
       
  1857     {
       
  1858     if ( !IsCompressed() )
       
  1859         {
       
  1860         return iName.iNameAsHBuf->AllocL();
       
  1861         }
       
  1862 
       
  1863     HBufC* name = HBufC::NewL(8);
       
  1864     name->Des().Format(_L("%08x"), iName.iNameAsUint32);
       
  1865 
       
  1866     return name;
  1384     }
  1867     }
  1385 //  End of File
  1868 //  End of File