--- a/webengine/osswebengine/cache/src/HttpCacheHandler.cpp Fri Jul 03 15:54:40 2009 +0100
+++ b/webengine/osswebengine/cache/src/HttpCacheHandler.cpp Thu Aug 27 07:44:59 2009 +0300
@@ -24,12 +24,14 @@
#include "HttpCacheUtil.h"
#include "HttpCacheEvictionHandler.h"
#include "HttpCacheObserver.h"
+#include "HttpCacheFileWriteHandler.h"
#include <http/RHTTPTransaction.h>
#include <http/rhttpsession.h>
#include <http/rhttpheaders.h>
#include <HttpStringConstants.h>
#include <httperr.h>
#include <s32file.h>
+#include <s32mem.h>
#include <BrCtlDefs.h>
// EXTERNAL DATA STRUCTURES
@@ -39,6 +41,7 @@
// CONSTANTS
// MACROS
+//#define __USE_VALIDATION_FILES__
// LOCAL CONSTANTS AND MACROS
@@ -58,6 +61,13 @@
}
// ============================ MEMBER FUNCTIONS ===============================
+THttpCachePostponeParameters::THttpCachePostponeParameters()
+ {
+ iEnabled = EFalse;
+ iFreeRamThreshold = 0;
+ iImmediateWriteThreshold = 0;
+ iWriteTimeout = 0;
+ }
// -----------------------------------------------------------------------------
// CHttpCacheHandler::CHttpCacheHandler
@@ -65,8 +75,8 @@
// might leave.
// -----------------------------------------------------------------------------
//
-CHttpCacheHandler::CHttpCacheHandler(
- TInt aSize ) : iSize( aSize )
+CHttpCacheHandler::CHttpCacheHandler( TInt aSize )
+ : iSize( aSize )
{
}
@@ -78,41 +88,36 @@
void CHttpCacheHandler::ConstructL(
const TDesC& aDirectory,
const TDesC& aIndexFile,
- TInt aCriticalLevel)
+ TInt aCriticalLevel,
+ const THttpCachePostponeParameters& aPostpone)
{
- User::LeaveIfError(iRfs.Connect());
+ User::LeaveIfError(iRfs.Connect());
//
iIndexFile = aIndexFile.AllocL();
//
iDirectory = aDirectory.AllocL();
- //
- iEvictionHandler = CHttpCacheEvictionHandler::NewL();
- //
- iStreamHandler = CHttpCacheStreamHandler::NewL( iDirectory->Des(), aCriticalLevel );
- //
- iLookupTable = CHttpCacheLookupTable::NewL( *iEvictionHandler, *iStreamHandler );
- //1. Set up top-level cache directory if it doesn't exist.
+ //1. Set up top-level cache directory if it doesn't exist.
TEntry entry;
TInt err( KErrNone );
- if (iRfs.Entry(iDirectory->Des(), entry) != KErrNone)
+ if ( iRfs.Entry(iDirectory->Des(), entry) != KErrNone )
{
- err = iRfs.MkDirAll(iDirectory->Des());
+ err = iRfs.MkDirAll( iDirectory->Des() );
}
//2. Create subdirectories to store header/body files
if ( err == KErrNone || err == KErrAlreadyExists ) { //harmless errors
-
+
__ASSERT_DEBUG ( (iDirectory->Des().LocateReverse( KPathDelimiter ) == (iDirectory->Des().Length() - 1)),
PanicCacheHandler( KErrCorrupt ) ); // We assume that iDirectory is terminated by a forward slash
-
+
HBufC* subDir = HBufC::NewL(KMaxPath); // Base cache dir + subdir name + another delimiter
_LIT(KFormat,"%S%x%c");
- for (TUint i = 0; i < KCacheSubdirCount; i++)
+ for ( TUint i = 0; i < KCacheSubdirCount; i++ )
{
- TPtrC ptr (iDirectory->Des());
- subDir->Des().Format(KFormat, &ptr, i, KPathDelimiter);
- TInt err2 = iRfs.MkDir(subDir->Des());
- __ASSERT_DEBUG ( (err2 == KErrNone || err2 == KErrAlreadyExists), PanicCacheHandler( err2 ) );
+ TPtrC ptr ( iDirectory->Des() );
+ subDir->Des().Format( KFormat, &ptr, i, KPathDelimiter );
+ TInt err2 = iRfs.MkDir( subDir->Des() );
+ __ASSERT_DEBUG ( (err2 == KErrNone || err2 == KErrAlreadyExists), PanicCacheHandler( err2 ) );
}
delete subDir;
//end cache dir + subdir creation
@@ -120,7 +125,57 @@
User::Leave(err);
}
- OpenLookupTableL();
+ // set path for the entries
+ iRfs.SetSessionPath( aDirectory );
+#ifdef __USE_VALIDATION_FILES__
+ // create validation file
+ TFileName validateFile;
+ GenerateValidationFilename(validateFile, aIndexFile);
+
+ TBool validateCacheEntries( EFalse );
+ RFile validate;
+ TInt validateErr = validate.Create(iRfs, validateFile, EFileShareExclusive | EFileWrite);
+ if ( validateErr != KErrNone )
+ {
+ if ( validateErr == KErrAlreadyExists )
+ {
+ validateCacheEntries = ETrue;
+ }
+#ifdef _DEBUG
+ else
+ {
+ // oh dear, we failed to create the file for some other reason, something must have gone properly wrong...
+ User::Panic(_L("CacheHandler"), -9999);
+ }
+#endif
+ }
+ validate.Close();
+#endif
+ //
+ iEvictionHandler = CHttpCacheEvictionHandler::NewL();
+ //
+ iStreamHandler = CHttpCacheStreamHandler::NewL( iDirectory->Des(), aCriticalLevel, iRfs );
+ //
+ if ( aPostpone.iEnabled )
+ {
+ iPostponeHandler = CHttpCacheFileWriteHandler::NewL(this, iStreamHandler, iRfs, aPostpone.iWriteTimeout);
+ }
+ //
+ iLookupTable = CHttpCacheLookupTable::NewL( *iEvictionHandler, *iStreamHandler );
+ TRAP( err, OpenLookupTableL() );
+ if ( err != KErrNone )
+ {
+ // failed to open the lookup table, delete the old one and start again.
+ delete iLookupTable;
+ iLookupTable = NULL;
+ iLookupTable = CHttpCacheLookupTable::NewL( *iEvictionHandler, *iStreamHandler );
+ }
+#ifdef __USE_VALIDATION_FILES__
+ if ( validateCacheEntries )
+#endif
+ // ensure that the disk content matches the cache content
+ ValidateCacheEntriesL();
+
//
iHttpCacheObserver = CHttpCacheObserver::NewL(iDirectory, iIndexFile, this);
iHttpCacheObserver->StartObserver();
@@ -135,12 +190,13 @@
TInt aSize,
const TDesC& aDirectory,
const TDesC& aIndexFile,
- TInt aCriticalLevel)
+ TInt aCriticalLevel,
+ const THttpCachePostponeParameters& aPostpone)
{
CHttpCacheHandler* self = new( ELeave ) CHttpCacheHandler( aSize );
CleanupStack::PushL( self );
- self->ConstructL( aDirectory, aIndexFile, aCriticalLevel );
+ self->ConstructL( aDirectory, aIndexFile, aCriticalLevel, aPostpone );
CleanupStack::Pop();
return self;
@@ -152,9 +208,23 @@
//
CHttpCacheHandler::~CHttpCacheHandler()
{
+#ifndef __USE_VALIDATION_FILES__
TRAP_IGNORE( SaveLookupTableL() );
+#else
+
+ TRAPD( err, SaveLookupTableL() );
+ if ( err == KErrNone && iIndexFile )
+ {
+ TFileName validateFile;
+ GenerateValidationFilename(validateFile, iIndexFile->Des());
+ // we saved the index successfully, remove the validate file marker
+ iRfs.Delete(validateFile);
+ }
+#endif
//
delete iHttpCacheObserver;
+ // must delete before eviction handler
+ delete iPostponeHandler;
//
if ( iEvictionHandler )
{
@@ -187,7 +257,6 @@
#ifdef __CACHELOG__
HttpCacheUtil::WriteUrlToLog( 0, _L( "request item" ), aTrans.Request().URI().UriDes() );
#endif
-
TInt status( KErrNotFound );
CHttpCacheEntry* entry = NULL;
// 0. check if we need to check cache at all (protected vs no cache mode)
@@ -197,17 +266,18 @@
// use protected item on reload
// currently not and do not use cache for post
- if( aCacheMode != TBrCtlDefs::ECacheModeNoCache &&
- HttpCacheUtil::MethodFromStr( aTrans.Request().Method(), aTrans.Session().StringPool() ) != EMethodPost )
+ if ( aCacheMode != TBrCtlDefs::ECacheModeNoCache &&
+ HttpCacheUtil::MethodFromStr( aTrans.Request().Method(), aTrans.Session().StringPool() ) != EMethodPost )
{
// If the cacheMode is noCache then it must ignore the cached entry.
entry = iLookupTable->Find( aTrans.Request().URI().UriDes() );
+
// check if the trailing slash is missing
- if( !entry )
+ if ( !entry )
{
TUriC8 uri = aTrans.Request().URI();
- if( uri.Extract( EUriPath ).Length() == 0 )
+ if ( uri.Extract( EUriPath ).Length() == 0 )
{
CUri8* fixeduri = CUri8::NewLC( uri );
fixeduri->SetComponentL( _L8("/"), EUriPath );
@@ -218,39 +288,29 @@
}
}
//
- if( entry && entry->State() == CHttpCacheEntry::ECacheComplete )
+ if ( entry && entry->State() == CHttpCacheEntry::ECacheComplete )
{
#ifdef __CACHELOG__
HttpCacheUtil::WriteLog( 0, _L( "item is in the cache" ) );
-#endif
+#endif
//
status = CacheNeedsValidationL( *entry, aTrans, aCacheMode ) ? KErrNotReady : KErrNone;
// entry could be invalidated at this point. check for status to make sure
// the entry is still valid
+
}
// prepare stream for request
- if( status == KErrNone )
+ if ( status == KErrNone )
{
#ifdef __CACHELOG__
HttpCacheUtil::WriteLog( 0, _L( "prepare item for sending" ) );
#endif
- // attach entry to the stream
- if( iStreamHandler->AttachL( *entry ) )
- {
- entry->SetState( CHttpCacheEntry::ECacheRequesting );
- entry->Accessed();
- }
- else
- {
- // cleanup on the corrupt entry
- DeleteCacheEntry( *entry );
- entry = NULL;
- // item is not in cache
- status = KErrNotFound;
- }
+ // access the entry
+ entry->SetState( CHttpCacheEntry::ECacheRequesting );
+ entry->Accessed();
}
// cleanup
- if( status == KErrNone && entry )
+ if ( status == KErrNone && entry )
{
// save handler and entry so that
// on next call we don't have to start a lookup again
@@ -270,14 +330,15 @@
#ifdef __CACHELOG__
else
{
- HttpCacheUtil::WriteLog( 0, _L( "reload: do not use cache" ) );
+ HttpCacheUtil::WriteLog( 0, _L( "reload or post: do not use cache" ) );
}
- if( status != KErrNone && entry )
+
+ if ( status != KErrNone && entry )
{
- //
HttpCacheUtil::WriteLog( 0, _L( "item needs validation" ) );
}
- else
+
+ if ( !entry )
{
//
HttpCacheUtil::WriteLog( 0, _L( "item is not in the cache" ) );
@@ -301,7 +362,7 @@
TInt status( KErrNotFound );
CHttpCacheEntry* entry = aCacheEntry.iCacheEntry;
//
- if( entry && entry->State() == CHttpCacheEntry::ECacheRequesting )
+ if ( entry && entry->State() == CHttpCacheEntry::ECacheRequesting )
{
// response headers should already have all the headers
// as RequestL call adds them all.
@@ -310,7 +371,7 @@
status = KErrNone;
#ifdef __CACHELOG__
HttpCacheUtil::WriteLog( 0, _L( "sending http headers" ) );
-#endif
+#endif
}
return status;
}
@@ -330,7 +391,7 @@
HBufC8* bodyStr = NULL;
CHttpCacheEntry* entry = aCacheEntry.iCacheEntry;
//
- if( entry && entry->State() == CHttpCacheEntry::ECacheRequesting )
+ if ( entry && entry->State() == CHttpCacheEntry::ECacheRequesting )
{
// get next chunk
bodyStr = iStreamHandler->NextChunkL( *entry, aLastChunk );
@@ -361,14 +422,12 @@
if ( entry->State() == CHttpCacheEntry::ECacheRequesting )
{
entry->SetState( CHttpCacheEntry::ECacheComplete );
- iStreamHandler->Detach( *entry );
}
// transaction is closed without being completed
else if ( entry->State() == CHttpCacheEntry::ECacheResponding ||
entry->State() == CHttpCacheEntry::ECacheDestroyed )
{
// remove uncompleted/destroyed entry
- iStreamHandler->Detach( *entry );
DeleteCacheEntry( *entry );
entry = NULL;
aCacheEntry.iCacheEntry = NULL;
@@ -462,30 +521,30 @@
TBool protectedEntry( EFalse );
// check if the item is cacheable
// no item should be bigger than the 1/3 of the cache size
- if( HttpCacheUtil::IsCacheable( aTrans, ( iSize / 3 ), protectedEntry ) )
+ if ( HttpCacheUtil::IsCacheable( aTrans, ( iSize / 3 ), protectedEntry ) )
{
// check if the entry is already in the cache
CHttpCacheEntry* entry = iLookupTable->Find( aTrans.Request().URI().UriDes() );
- if( entry )
+ if ( entry )
{
#ifdef __CACHELOG__
- HttpCacheUtil::WriteLogFilenameAndUrl( 0,
+ HttpCacheUtil::WriteLogFilenameAndUrl( 0,
_L("CHttpCacheHandler::ReceivedResponseHeadersL"),
entry->Filename(),
entry->Url(),
- entry->BodySize(),
+ entry->BodySize(),
ELogEntrySize );
#endif
- if( entry->State() != CHttpCacheEntry::ECacheComplete )
+ if ( entry->State() != CHttpCacheEntry::ECacheComplete )
{
// multiple incoming entries doh.
#ifdef __CACHELOG__
- HttpCacheUtil::WriteLogFilenameAndUrl( 0,
+ HttpCacheUtil::WriteLogFilenameAndUrl( 0,
_L("CHttpCacheHandler::ReceivedResponseHeadersL - ERROR MULTIPLE requests"),
entry->Filename(),
entry->Url(),
- entry->BodySize(),
+ entry->BodySize(),
ELogEntrySize );
#endif
// ignore this one and the first will proceed.
@@ -501,17 +560,17 @@
AdjustResponseTime( aTrans );
// hash it
entry = iLookupTable->InsertL( aTrans.Request().URI().UriDes() );
- if( entry )
+ if ( entry )
{
// protect this entry
- if( protectedEntry )
+ if ( protectedEntry )
{
#ifdef __CACHELOG__
- HttpCacheUtil::WriteLogFilenameAndUrl( 0,
+ HttpCacheUtil::WriteLogFilenameAndUrl( 0,
_L("CHttpCacheHandler::ReceivedResponseHeadersL - this is protected item"),
entry->Filename(),
entry->Url(),
- entry->BodySize(),
+ entry->BodySize(),
ELogEntrySize );
#endif
entry->SetProtected();
@@ -528,46 +587,37 @@
__ASSERT_DEBUG( EFalse, PanicCacheHandler( KErrCorrupt ) );
}
}
+
// save headers
- if( entry )
+ if ( entry )
{
- // attach it to the stream handler
- if( iStreamHandler->AttachL( *entry ) )
- {
- entry->SetState( CHttpCacheEntry::ECacheResponding );
- // 1. handle only 304 and 200
- // 2. check if either the header or the body ( or both ) need to be updated
- // 3. update the headers anyway in case of notmodified (304)
- // 4. remove the old body in case of bodyupdate
- TInt httpStatus( aTrans.Response().StatusCode() );
+ entry->SetState( CHttpCacheEntry::ECacheResponding );
+ // 1. handle only 304 and 200
+ // 2. check if either the header or the body ( or both ) need to be updated
+ // 3. update the headers anyway in case of notmodified (304)
+ // 4. remove the old body in case of bodyupdate
+ TInt httpStatus( aTrans.Response().StatusCode() );
#ifdef __CACHELOG__
- HttpCacheUtil::WriteLog( 0, _L("CHttpCacheHandler::ReceivedResponseHeadersL - status code ="), httpStatus );
+ HttpCacheUtil::WriteLog( 0, _L("CHttpCacheHandler::ReceivedResponseHeadersL - status code ="), httpStatus );
#endif
- TBool ok( EFalse );
- if( httpStatus == HTTPStatus::EOk )
- {
- ok = HandleResponseOkL( *entry, aTrans );
- }
- else if( httpStatus == HTTPStatus::ENotModified )
- {
- ok = HandleResponseNotModifiedL( *entry, aTrans );
- }
+ TBool ok( EFalse );
+ if ( httpStatus == HTTPStatus::EOk )
+ {
+ ok = HandleResponseOkL( *entry, aTrans );
+ }
+ else if ( httpStatus == HTTPStatus::ENotModified )
+ {
+ ok = HandleResponseNotModifiedL( *entry, aTrans );
+ }
- // entry could be corrupted at this point
- if( ok )
- {
- // save handler and entry so that
- // on next call we don't have to start a lookup again
- aCacheEntry.iCacheHandler = this;
- aCacheEntry.iCacheEntry = entry;
- }
- else
- {
- iStreamHandler->Detach( *entry );
- DeleteCacheEntry( *entry );
- entry = NULL;
- }
+ // entry could be corrupted at this point
+ if ( ok )
+ {
+ // save handler and entry so that
+ // on next call we don't have to start a lookup again
+ aCacheEntry.iCacheHandler = this;
+ aCacheEntry.iCacheEntry = entry;
}
else
{
@@ -602,23 +652,22 @@
HttpCacheUtil::WriteLog( 0, _L("---> CHttpCacheHandler::ReceivedResponseBodyDataL"), entry->BodySize() );
#endif
HBufC8* bodyStr = HttpCacheUtil::BodyToBufferL( aBodyDataSupplier );
- if ( bodyStr )
+ if( bodyStr )
{
// Do we have old body data to remove first
if ( entry->BodyFileDeleteNeeded() ) {
iStreamHandler->RemoveBodyData( *entry );
entry->SetBodyFileDeleteNeeded( EFalse );
- }
-
+ }
+
// erase entry if we are unable to save it (low disk space)
- if( !SaveBuffer( *entry, bodyStr->Des(), ETrue ) )
+ if ( !SaveBuffer( *entry, bodyStr->Des(), ETrue ) )
{
- // detach it from the stream and erase it
- iStreamHandler->Detach( *entry );
+ // erase it
DeleteCacheEntry( *entry );
-#ifdef __CACHELOG__
+#ifdef __CACHELOG__
HttpCacheUtil::WriteLog( 0, _L( "CHttpCacheHandler::ReceivedResponseBodyDataL - body cannot be saved" ) );
-#endif
+#endif
entry = NULL;
// remove entry
aCacheEntry.iCacheEntry = NULL;
@@ -663,32 +712,59 @@
if ( entry->State() == CHttpCacheEntry::ECacheResponding )
{
- // Flush the entry
- if ( !iStreamHandler->Flush( *entry ) )
+ TBool postponed( EFalse );
+ // flush the entry if necessary
+ if ( iPostponeHandler )
{
- // We failed saving (flush), cleanup
- iStreamHandler->Detach( *entry );
+ CHttpCacheFileWriteHandler::TAddStatus addStatus;
+ TInt err = iPostponeHandler->AddEntry( addStatus, entry );
- // Deleting the entry frees cache buffer
- DeleteCacheEntry( *entry );
- entry = NULL;
- aCacheEntry.iCacheEntry = NULL;
+ switch ( addStatus )
+ {
+ case CHttpCacheFileWriteHandler::EAddedOk:
+ entry->SetState( CHttpCacheEntry::ECacheComplete );
+ postponed = ETrue;
+#ifdef __CACHELOG__
+ HttpCacheUtil::WriteLog( 0, _L(" Added object to postpone list."));
+#endif
+ break;
+ case CHttpCacheFileWriteHandler::EBodySmallerThanThreshold:
+#ifdef __CACHELOG__
+ HttpCacheUtil::WriteLog( 0, _L(" Not postponed. EBodySmallerThanThreshold"));
+#endif
+ break;
+ case CHttpCacheFileWriteHandler::ENotEnoughFreeMemory:
+#ifdef __CACHELOG__
+ HttpCacheUtil::WriteLog( 0, _L(" Not postponed. ENotEnoughFreeMemory"));
+#endif
+ break;
+ case CHttpCacheFileWriteHandler::ECheckReturn:
+#ifdef __CACHELOG__
+ HttpCacheUtil::WriteLog( 0, _L(" Not postponed. ECheckReturn - %d"), err );
+#endif
+ default:
+ break;
+ }
}
- else
+
+ if ( !postponed )
{
- // We successfully saved (flush) body
- entry->SetState( CHttpCacheEntry::ECacheComplete );
- iStreamHandler->Detach( *entry );
-
- // Clear the flushed cache buffer, we were using for incoming body
- TRAP_IGNORE( entry->SetCacheBufferL( KBufferSizeZero ) );
+ if ( !iStreamHandler->Flush( *entry ) )
+ {
+ // remove entry
+ DeleteCacheEntry( *entry );
+ entry = NULL;
+ aCacheEntry.iCacheEntry = NULL;
+ }
+ else
+ {
+ // We successfully saved (flushed) body
+ entry->SetState( CHttpCacheEntry::ECacheComplete );
+ }
}
}
- else if( entry->State() == CHttpCacheEntry::ECacheDestroyed )
+ else if ( entry->State() == CHttpCacheEntry::ECacheDestroyed )
{
- iStreamHandler->Detach( *entry );
-
- // Deleting the entry frees cache buffer
DeleteCacheEntry( *entry, EFalse );
entry = NULL;
aCacheEntry.iCacheEntry = NULL;
@@ -697,7 +773,7 @@
}
// -----------------------------------------------------------------------------
-// Removes all entries in the Cache lookup table, commits table to disk.
+// Removes all entries in the Cache lookup table, commits table to disk.
//
// -----------------------------------------------------------------------------
//
@@ -707,8 +783,16 @@
HttpCacheUtil::WriteLog( 0, _L( "remove all items" ) );
#endif
TInt numberOfBytes;
+
+ // by definition, all entries in the postpone handler aren't active.
+ if ( iPostponeHandler )
+ {
+ iPostponeHandler->RemoveAll();
+ }
+
// clear all the inactive entries
numberOfBytes = iLookupTable->RemoveAll();
+
// and save it. user initiated. no need to do idle save
SaveLookupTableL();
return numberOfBytes;
@@ -778,27 +862,26 @@
TBool saved( EFalse );
// check if entry exist. do not overwrite.
CHttpCacheEntry* entry = iLookupTable->Find( aUrl );
- if( !entry )
+ if ( !entry )
{
entry = iLookupTable->InsertL( aUrl );
// prepare for saving
- if( entry && iStreamHandler->AttachL( *entry ) )
+ if ( entry )
{
// save header and body
saved = SaveBuffer( *entry, aHeader, EFalse ) && SaveBuffer( *entry, aContent, ETrue );
- if( saved )
+ if ( saved )
{
// flush
saved = iStreamHandler->Flush( *entry );
- if( saved )
+ if ( saved )
{
entry->SetState( CHttpCacheEntry::ECacheComplete );
}
}
- iStreamHandler->Detach( *entry );
}
// cleanup
- if( !saved && entry )
+ if ( !saved && entry )
{
DeleteCacheEntry( *entry );
}
@@ -819,24 +902,21 @@
TInt status( KErrNotFound );
//
CHttpCacheEntry* entry = iLookupTable->Find( aUrl );
- if( entry )
+ if ( entry )
{
- TBool attached;
- //
- attached = iStreamHandler->AttachL( *entry );
// get headers
HBufC8* headersStr = iStreamHandler->HeadersL( *entry );
- if( headersStr )
+ if ( headersStr )
{
CleanupStack::PushL( headersStr );
// alter headers and save them
HBufC8* newHeaderStr = HttpCacheUtil::AddHeaderLC( aName, aValue, headersStr->Des() );
- if( newHeaderStr )
+ if ( newHeaderStr )
{
// remove old headers first
iStreamHandler->RemoveHeaders( *entry );
// save new headers
- if( !SaveBuffer( *entry, newHeaderStr->Des(), EFalse ) )
+ if ( !SaveBuffer( *entry, newHeaderStr->Des(), EFalse ) )
{
status = KErrDirFull;
// failed. should we save the original headers?
@@ -844,10 +924,9 @@
// original save should never fail
__ASSERT_DEBUG( saveOk, PanicCacheHandler( KErrCorrupt ) );
- if( !saveOk )
+ if ( !saveOk )
{
// sorry, we made this entry corrupt. remove it
- iStreamHandler->Detach( *entry );
DeleteCacheEntry( *entry );
entry = NULL;
}
@@ -860,11 +939,6 @@
}
CleanupStack::PopAndDestroy(); // headersStr
}
- // detach
- if( attached )
- {
- iStreamHandler->Detach( *entry );
- }
}
return status;
}
@@ -891,75 +965,65 @@
// been validated -- that is when it tries to refetch an entry from
// cache after receiving a 304 response.
// get cached headers
- if( iStreamHandler->AttachL( aCacheEntry ) )
+ HBufC8* headersStr = iStreamHandler->HeadersL( aCacheEntry );
+ CleanupStack::PushL( headersStr );
+ // headersStr == NULL happens if you erase the cache directory
+ // using a file manager
+ if ( headersStr )
{
- HBufC8* headersStr = iStreamHandler->HeadersL( aCacheEntry );
- CleanupStack::PushL( headersStr );
- iStreamHandler->Detach( aCacheEntry );
- // headersStr == NULL happens if you erase the cache directory
- // using a file manager
- if( headersStr )
+ // use response headers for retreiving cached headers
+ RHTTPHeaders responseHeaders = aTrans.Response().GetHeaderCollection();
+ RHTTPHeaders requestHeaders = aTrans.Request().GetHeaderCollection();
+ RStringPool strP = aTrans.Session().StringPool();
+ // convert the buffer to httpHeader
+ HttpCacheUtil::BufferToHeadersL( headersStr->Des(), responseHeaders, strP );
+
+ // check if we need to validate the cahce
+ if ( aCacheMode == TBrCtlDefs::ECacheModeOnlyCache || aCacheMode == TBrCtlDefs::ECacheModeHistory )
{
- // use response headers for retreiving cached headers
- RHTTPHeaders responseHeaders = aTrans.Response().GetHeaderCollection();
- RHTTPHeaders requestHeaders = aTrans.Request().GetHeaderCollection();
- RStringPool strP = aTrans.Session().StringPool();
- // convert the buffer to httpHeader
- HttpCacheUtil::BufferToHeadersL( headersStr->Des(), responseHeaders, strP );
-
- // check if we need to validate the cahce
- if( aCacheMode == TBrCtlDefs::ECacheModeOnlyCache || aCacheMode == TBrCtlDefs::ECacheModeHistory )
+ // no validation required
+#ifdef __CACHELOG__
+ HttpCacheUtil::WriteLog( 0, _L( "prefer cache mode. no need to revalidate" ), aCacheMode );
+#endif
+ mustRevalidate = EFalse;
+ }
+ else
+ {
+ // Get the pragma no-cache header from the headers
+ // no-cache on request header means "do not use cache"
+ if ( !HttpCacheUtil::PragmaNoCache( aTrans ) )
{
- // no validation required
+ if ( !HttpCacheUtil::CacheTimeIsFresh( requestHeaders, responseHeaders, strP ) )
+ {
#ifdef __CACHELOG__
- HttpCacheUtil::WriteLog( 0, _L( "prefer cache mode. no need to revalidate" ), aCacheMode );
-#endif
- mustRevalidate = EFalse;
+ HttpCacheUtil::WriteLog( 0, _L( "cache item is not fresh. needs revalidation" ) );
+#endif
+ // Avoid removing cache entry here
+ mustRevalidate = ETrue;
+ // add headers like EIfModifiedSince, EETag, EIfNoneMatch
+ HttpCacheUtil::AddValidationHeaders( responseHeaders, requestHeaders, strP );
+ }
+ else
+ {
+#ifdef __CACHELOG__
+ HttpCacheUtil::WriteLog( 0, _L( "cache item is fresh. needs no revalidation" ) );
+#endif
+ //
+ mustRevalidate = EFalse;
+ }
}
else
{
- // Get the pragma no-cache header from the headers
- // no-cache on request header means "do not use cache"
- if( !HttpCacheUtil::PragmaNoCache( aTrans ) )
- {
- if( !HttpCacheUtil::CacheTimeIsFresh( requestHeaders, responseHeaders, strP ) )
- {
+ // needs validation
#ifdef __CACHELOG__
- HttpCacheUtil::WriteLog( 0, _L( "cache item is not fresh. needs revalidation" ) );
+ HttpCacheUtil::WriteLog( 0, _L( "no cache/no store header present. need revalidation" ) );
#endif
- // MKLE-7PRD27: Avoid removing cache entry here
- mustRevalidate = ETrue;
- // add headers like EIfModifiedSince, EETag, EIfNoneMatch
- HttpCacheUtil::AddValidationHeaders( responseHeaders, requestHeaders, strP );
- }
- else
- {
-#ifdef __CACHELOG__
- HttpCacheUtil::WriteLog( 0, _L( "cache item is fresh. needs no revalidation" ) );
-#endif
- //
- mustRevalidate = EFalse;
- }
- }
- else
- {
- // needs validation
-#ifdef __CACHELOG__
- HttpCacheUtil::WriteLog( 0, _L( "no cache/no store header present. need revalidation" ) );
-#endif
- mustRevalidate = ETrue;
- }
-
+ mustRevalidate = ETrue;
}
}
- CleanupStack::PopAndDestroy(); // headersStr
}
- else
- {
- DeleteCacheEntry( aCacheEntry );
- // needs validation
- mustRevalidate = ETrue;
- }
+ CleanupStack::PopAndDestroy(); // headersStr
+
return mustRevalidate;
}
@@ -987,10 +1051,10 @@
HttpCacheUtil::WriteLog( 0, _L( "cached items" ) );
const CArrayPtrFlat<CHttpCacheEntry>& entries = iLookupTable->Entries();
- for( TInt i = 0; i < entries.Count(); i++ )
+ for ( TInt i = 0; i < entries.Count(); i++ )
{
CHttpCacheEntry* entry = entries.At( i );
- if( entry && entry != (CHttpCacheEntry*)0xffffffff )
+ if ( entry && entry != (CHttpCacheEntry*)0xffffffff )
{
HttpCacheUtil::WriteUrlToLog( 0, entry->Url(), entry->BodySize() );
size += entry->BodySize();
@@ -1003,40 +1067,28 @@
CArrayPtrFlat<CHttpCacheEntry>* evictedList = iEvictionHandler->EvictL( aSize );
if ( evictedList && evictedList->Count() )
{
- // Delete entry items marked for eviction
+ // destroy items
CHttpCacheEntry* entry;
for ( TInt i = 0; i < evictedList->Count(); i++ )
{
+ //
entry = evictedList->At( i );
-
if ( entry )
{
- // Handle removing valid and invalid entries. Check entry
- // for validity, and if in lookup table. It has been
- // found that the evictList can have invalid entries in it.
- // These invalid entries are not in the lookup table.
- TInt lookupTableIndex( -1 );
- iLookupTable->FindCacheEntryIndex( *entry, &lookupTableIndex );
-
- TInt sizeBody = entry->BodySize();
- if ( sizeBody == 0 && lookupTableIndex >= 0 )
+ if ( iPostponeHandler )
{
- // This is an empty body cache entry that exists
- // in the lookup table, remove it from file system and
- // lookup table.
- // Use CreateNewFilesL() to open file handles, so we can delete
- // the files associated with the cache entry. We don't check
- // return value of RemoveByPosition(), because we already
- // checked for index in FindCacheEntryIndex().
- iStreamHandler->CreateNewFilesL( *entry );
- iStreamHandler->EraseCacheFile( *entry );
- iLookupTable->RemoveByPosition( lookupTableIndex );
+ iPostponeHandler->RemoveEntry( entry );
}
- else if ( lookupTableIndex >= 0 )
- {
- // Remove valid entries that are found in lookup table
- iLookupTable->Remove( entry->Url() );
- }
+
+ // when an item is destroyed, it will attempt to remove itself from the lookup table which will fail and panic
+ // because EvictL already removed it.
+ // In this scenario, we need to tell the item that it's no longer a candidate to prevent that.
+ // we don't want to make lookuptable::remove do that though, because this only applies when we are removing
+ // an item because of eviction and NOT for any other reason.
+ entry->UnsetEvictionCandidate();
+
+ // destroy
+ iLookupTable->Remove( entry->Url() );
}
}
@@ -1050,11 +1102,9 @@
// or the incoming -not yet complete- items take the entire cache?
#ifdef __CACHELOG__
HttpCacheUtil::WriteLog( 0, _L( "NO SPACE can be released!!!" ) );
-#endif
+#endif
ok = EFalse;
}
-
- // Cleanup the evicted list, including any invalid entries
delete evictedList;
}
return ok;
@@ -1077,7 +1127,7 @@
TBool update( ETrue );
// get cached headers to compare
HBufC8* cachedHeaderStr = iStreamHandler->HeadersL( aEntry );
-
+
// we've got some headers to update, check if we really need to update them
if ( cachedHeaderStr )
{
@@ -1095,7 +1145,7 @@
_L("CHttpCacheHandler::HandleResponseOkL - cache UPDATE needed"),
aEntry.Filename(),
aEntry.Url(),
- aEntry.BodySize(),
+ aEntry.BodySize(),
ELogEntrySize );
#endif
if ( aEntry.HeaderSize() )
@@ -1106,27 +1156,22 @@
// save new headerFile
saveOk = SaveBuffer( aEntry, responseHeaderStr->Des() );
-
+
if ( aEntry.BodySize() )
{
// We will remove this body data, after we confirm that we get new
// body data
aEntry.SetBodyFileDeleteNeeded( ETrue );
}
-
- // Setup a cache buffer to hold the incoming body
- aEntry.SetCacheBufferL( KBufferSize32k );
}
else
{
- // if neither the header nor the body need to be updated, then
- // detach entry to protect from being updated
+ // neither the header nor the body need to be updated
#ifdef __CACHELOG__
HttpCacheUtil::WriteLog( 0, _L( "CHttpCacheHandler::HandleResponseOkL - no update needed, ignore response" ) );
-#endif
+#endif
//
aEntry.SetState( CHttpCacheEntry::ECacheComplete );
- iStreamHandler->Detach( aEntry );
// pretend that save was ok.
saveOk = ETrue;
}
@@ -1146,7 +1191,7 @@
CHttpCacheEntry& aEntry,
RHTTPTransaction& aTrans )
{
- // oos? -out of space
+ // Are we out of space ?
TBool saveOk( ETrue );
RHTTPHeaders responseHeader = aTrans.Response().GetHeaderCollection();
RStringPool strP = aTrans.Session().StringPool();
@@ -1156,30 +1201,31 @@
HBufC8* mergedHeadersStr = NULL;
HBufC8* cachedHeaderStr = iStreamHandler->HeadersL( aEntry );
CleanupStack::PushL( cachedHeaderStr );
+
// don't merge with empty headers
- if( cachedHeaderStr )
+ if ( cachedHeaderStr )
{
mergedHeadersStr = HttpCacheUtil::MergeHeadersLC( cachedHeaderStr->Des(), responseHeader, strP );
CleanupStack::Pop(); // mergedHeadersStr
}
// don't update empty headers
- if( mergedHeadersStr || responseHeaderStr )
+ if ( mergedHeadersStr || responseHeaderStr )
{
// remove cached headers first
iStreamHandler->RemoveHeaders( aEntry );
// save merged headers (reponse + cached)
- if( mergedHeadersStr )
+ if ( mergedHeadersStr )
{
saveOk = SaveBuffer( aEntry, mergedHeadersStr->Des() );
}
- else if( responseHeaderStr )
+ else if ( responseHeaderStr )
{
// save responseheader instead
saveOk = SaveBuffer( aEntry, responseHeaderStr->Des() );
}
// if save failed, let's see if we can save old
// headers
- if( !saveOk && cachedHeaderStr )
+ if ( !saveOk && cachedHeaderStr )
{
saveOk = SaveBuffer( aEntry, cachedHeaderStr->Des() );
}
@@ -1189,12 +1235,13 @@
CleanupStack::PopAndDestroy( 2 ); // cachedHeaderStr, responseHeaderStr
// check if save was ok.
// or nothing was not saved at all
- if( saveOk )
+ if ( saveOk )
{
// this item does not need update
aEntry.SetState( CHttpCacheEntry::ECacheComplete );
- iStreamHandler->Detach( aEntry );
+ //iStreamHandler->Detach( aEntry );
}
+
return saveOk;
}
@@ -1205,48 +1252,87 @@
//
void CHttpCacheHandler::OpenLookupTableL()
{
- OpenLookupTableL(iLookupTable);
+ OpenLookupTableL( iLookupTable );
}
// -----------------------------------------------------------------------------
// CHttpCacheHandler::OpenLookupTableL
-// Opens the index*.dat lookup table from file system.
+// Opens the index*.dat lookup table from file system.
// -----------------------------------------------------------------------------
//
void CHttpCacheHandler::OpenLookupTableL(CHttpCacheLookupTable* aLookupTable)
{
+#if 0
// read entries from index.dat
RFileReadStream readStream;
- iRfs.SetSessionPath( iDirectory->Des() );
+ iRfs.SetSessionPath( iDirectory->Des() );
- TInt ret = KErrNone;
- TInt tryCount = 0;
- for (tryCount = 0; tryCount < 5; tryCount++)
+ TInt ret = KErrNone;
+ TInt tryCount = 0;
+ for (tryCount = 0; tryCount < 5; tryCount++)
+ {
+ ret = readStream.Open( iRfs, iIndexFile->Des(), EFileRead | EFileShareAny );
+ if (ret == KErrInUse)
+ {
+ // When the cache is full, it takes 65 - 85 miliseconds to write the index.
+ // So wait 50 miliseconds and try again
+ User::After(50000);
+ }
+ else
{
- ret = readStream.Open( iRfs, iIndexFile->Des(), EFileRead | EFileShareAny );
- if (ret == KErrInUse)
- {
- // When the cache is full, it takes 65 - 85 miliseconds to write the index.
- // So wait 50 miliseconds and try again
- User::After(50000);
- }
- else
- {
- break;
- }
+ break;
+ }
+ }
+ if( ret == KErrNone )
+ {
+ CleanupClosePushL( readStream );
+ aLookupTable->InternalizeL( readStream, iDirectory->Des() );
+ CleanupStack::PopAndDestroy(1); // readStream
+ }
+#else
+ RFile readFile;
+ iRfs.SetSessionPath( iDirectory->Des() );
+
+ TInt ret = KErrNone;
+ TInt tryCount = 0;
+ for (tryCount = 0; tryCount < 5; tryCount++)
+ {
+ ret = readFile.Open( iRfs, iIndexFile->Des(), EFileRead | EFileShareAny );
+ if (ret == KErrInUse)
+ {
+ // When the cache is full, it takes 65 - 85 miliseconds to write the index.
+ // So wait 50 miliseconds and try again
+ User::After(50000);
}
- if( ret == KErrNone )
+ else
+ {
+ break;
+ }
+ }
+
+ if ( ret == KErrNone )
+ {
+ CleanupClosePushL(readFile);
+ TInt size;
+ readFile.Size(size);
+
+ if ( size )
{
- TRAPD ( err, aLookupTable->InternalizeL( readStream, iDirectory->Des() ) );
- readStream.Close();
- if ( err != KErrNone )
- {
- // In case Bad Things Happen (TM), do RemoveAllL() which clears this cache's
- // in-memory data structures + saves an updated lookup table to disk replacing the old one.
- TRAP_IGNORE( RemoveAllL() );
- }
+ HBufC8* buffer = HBufC8::NewLC(size);
+ TPtr8 buf( buffer->Des() );
+ User::LeaveIfError( readFile.Read(buf, size) );
+ RDesReadStream readStream( buf );
+ CleanupClosePushL(readStream);
+ aLookupTable->InternalizeL( readStream, iDirectory->Des() );
+ CleanupStack::PopAndDestroy(3); // read stream, buffer then file
}
+ else
+ {
+ CleanupStack::PopAndDestroy(1); // close the file.
+ }
+ }
+#endif
}
// -----------------------------------------------------------------------------
@@ -1263,12 +1349,10 @@
RFileWriteStream writeStream;
// Don't get notified about own changes
- if ( iHttpCacheObserver )
- iHttpCacheObserver->Cancel();
-
+ iHttpCacheObserver->Cancel();
TInt ret = KErrNone;
TInt tryCount = 0;
- for (tryCount = 0; tryCount < 5; tryCount++)
+ for (tryCount = 0; tryCount < 5; tryCount++)
{
ret = writeStream.Replace( iRfs, iIndexFile->Des(), EFileWrite );
if (ret == KErrInUse)
@@ -1282,16 +1366,14 @@
break;
}
}
- if( ret == KErrNone )
+ if ( ret == KErrNone )
{
CleanupClosePushL( writeStream );
- iLookupTable->ExternalizeL( writeStream );
+ iLookupTable->ExternalizeL( writeStream , iDirectory->Des() );
writeStream.CommitL();
CleanupStack::PopAndDestroy(); // writeStream
}
-
- if ( iHttpCacheObserver )
- iHttpCacheObserver->StartObserver();
+ iHttpCacheObserver->StartObserver();
}
// -----------------------------------------------------------------------------
@@ -1300,27 +1382,26 @@
// -----------------------------------------------------------------------------
//
void CHttpCacheHandler::DeleteCacheEntry(
- CHttpCacheEntry& aEntry,
+ CHttpCacheEntry& aStrayEntry,
TBool aUpdate )
{
- // suppress compiler and PC-lint warnings
- (void)aUpdate;
-
+ (void)aUpdate;//suppress compiler and PC-lint warnings
#ifdef __CACHELOG__
- HttpCacheUtil::WriteLogFilenameAndUrl( 0,
- _L("CHttpCacheHandler::DeleteCacheEntry"),
- aEntry.Filename(),
- aEntry.Url(),
- aEntry.BodySize(),
- ELogEntrySize );
+ HttpCacheUtil::WriteLog( 0, _L( "delete this stray entry" ) );
#endif
- // Remove from the lookuptable
- iLookupTable->EraseCacheEntry( aEntry.Url() );
+ // need to make sure this entry is removed from postpone handler, if it might be there.
+ if ( iPostponeHandler )
+ {
+ iPostponeHandler->RemoveEntry( &aStrayEntry );
+ }
+
+ // remove from the lookuptable
+ iLookupTable->EraseCacheEntry( aStrayEntry.Url() );
}
// -----------------------------------------------------------------------------
-// There used to be a CHttpCacheHandler::FixLookupTableL here.
+// There used to be a CHttpCacheHandler::FixLookupTableL here.
// Go back in SVN to re-discover it :)
//
// -----------------------------------------------------------------------------
@@ -1336,7 +1417,7 @@
TBool aBody )
{
TBool ok( EFalse );
-
+
TRAPD( err, ok = CacheNeedsSpaceL( aBuffer.Length() ) );
if ( err == KErrNone && ok )
{
@@ -1350,10 +1431,10 @@
HttpCacheUtil::WriteUrlToLog( 0, _L( "item cannot be saved. remove it please" ), aEntry.Url() );
}
#endif // __CACHELOG__
+
return ok;
}
-
// -----------------------------------------------------------------------------
// CHttpCacheHandler::UpdateLookupTable
//
@@ -1362,14 +1443,12 @@
void CHttpCacheHandler::UpdateLookupTable()
{
TRAP_IGNORE(UpdateLookupTableL());
-
- if ( iHttpCacheObserver )
- iHttpCacheObserver->StartObserver();
+ iHttpCacheObserver->StartObserver();
}
// -----------------------------------------------------------------------------
// CHttpCacheHandler::UpdateLookupTableL
-// Slow method due to much file-system interaction. Don't call it from performance critical code.
+// Slow method due to much file-system interaction. Don't call it from performance critical code.
// -----------------------------------------------------------------------------
//
void CHttpCacheHandler::UpdateLookupTableL()
@@ -1380,6 +1459,410 @@
CleanupStack::PushL(lookupTable);
OpenLookupTableL(lookupTable);
iLookupTable->MergeL(lookupTable, iRfs);
- CleanupStack::PopAndDestroy(2); // lookupTable, evictionHandler
+ CleanupStack::PopAndDestroy(2); // lookupTable, evictionHandler
+ }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheHandler::GenerateValidationFilename
+// -----------------------------------------------------------------------------
+//
+#ifdef __USE_VALIDATION_FILES__
+ void CHttpCacheHandler::GenerateValidationFilename(TDes& aFilename, const TDesC& aIndexFilename) const
+#else
+ void CHttpCacheHandler::GenerateValidationFilename(TDes& /*aFilename*/, const TDesC& /*aIndexFilename*/) const
+#endif
+ {
+#ifdef __USE_VALIDATION_FILES__
+ _LIT(KValidationExtension, ".val");
+ TParse filenameParser;
+ filenameParser.Set(aIndexFilename, NULL, NULL);
+ aFilename.Copy(filenameParser.DriveAndPath());
+ aFilename.Append(filenameParser.Name());
+ aFilename.Append(KValidationExtension);
+#else
+ PanicCacheHandler(KErrNotSupported);
+#endif
+ }
+
+// -----------------------------------------------------------------------------
+// DestroyBadUrlArray
+// -----------------------------------------------------------------------------
+//
+static void DestroyBadUrlArray(TAny* aPtr)
+ {
+ RPointerArray<HBufC8> *tmp = (RPointerArray<HBufC8>*)aPtr;
+ tmp->ResetAndDestroy();
+ }
+
+// -----------------------------------------------------------------------------
+// CHttpCacheHandler::ValidateCacheEntriesL
+// -----------------------------------------------------------------------------
+//
+void CHttpCacheHandler::ValidateCacheEntriesL()
+ {
+ // iterate through entries and check if file is present.
+ // if not, add URL to a list of bad ones otherwise remove directory entry from list
+ // at the end, go through list of bad entries and remove them from cache,
+ // go through list of unreferenced files and delete them too.
+ THttpCacheLookupTableEntryIterator iter;
+ iLookupTable->BeginEntryIteration(iter);
+#ifdef __CACHELOG__
+ HttpCacheUtil::WriteLog(0, _L("CHttpCacheHandler::ValidateCacheEntriesL"));
+#endif
+ // if the cache contains no items, we should still do this so we detect other files.
+
+ // get list of files on disk
+ CCacheDirectoryFiles *dirFiles = CCacheDirectoryFiles::NewLC(iRfs, *iDirectory);
+
+ // look for bad entries
+ RPointerArray<HBufC8> badEntries;
+ CleanupStack::PushL(TCleanupItem(DestroyBadUrlArray, &badEntries));
+ const CHttpCacheEntry *tmpEntry;
+ while(tmpEntry = iLookupTable->NextEntry(iter), tmpEntry)
+ {
+ if(!dirFiles->ValidateEntryL(*tmpEntry))
+ {
+#ifdef __CACHELOG__
+ HttpCacheUtil::WriteUrlToLog(0, _L("Bad Entry: "), tmpEntry->Url() );
+#endif
+ badEntries.AppendL(tmpEntry->Url().AllocL());
+ }
+ }
+
+ // remove bad entries
+ for(TInt i=0; i < badEntries.Count(); i++)
+ {
+ iLookupTable->Remove(badEntries[i]->Des());
+ }
+ CleanupStack::PopAndDestroy(1); // bad entry list
+
+ // remove orphan files
+ dirFiles->RemoveLeftoverFilesL();
+ CleanupStack::PopAndDestroy(dirFiles);
+ }
+
+// -----------------------------------------------------------------------------
+// CCacheDirectoryFiles::NewL
+// -----------------------------------------------------------------------------
+//
+CCacheDirectoryFiles* CCacheDirectoryFiles::NewL(RFs aRfs, const TDesC& aDir)
+ {
+ CCacheDirectoryFiles* me = CCacheDirectoryFiles::NewLC(aRfs, aDir);
+ CleanupStack::Pop(me);
+ return me;
+ }
+
+// -----------------------------------------------------------------------------
+// CCacheDirectoryFiles::NewLC
+// -----------------------------------------------------------------------------
+//
+CCacheDirectoryFiles* CCacheDirectoryFiles::NewLC(RFs aRfs, const TDesC& aDir)
+ {
+ CCacheDirectoryFiles *me = new (ELeave) CCacheDirectoryFiles(aRfs, aDir);
+ CleanupStack::PushL(me);
+ me->ConstructL();
+ return me;
+ }
+
+// -----------------------------------------------------------------------------
+// CCacheDirectoryFiles::ValidateEntryL
+// -----------------------------------------------------------------------------
+//
+TBool CCacheDirectoryFiles::ValidateEntryL(const CHttpCacheEntry& aEntry)
+ {
+ // check the files associated with the cache entry are present where they should be
+ // if the file is present, then remove it from the dir list
+ // if the file is present AND the size matches the entry, then return ETrue in aPresentAndValid
+ // otherwise, return EFalse there.
+ TBool presentAndValid = EFalse;
+
+ TParse tmpParse;
+ tmpParse.Set(aEntry.Filename(), NULL, NULL);
+ // for this file to be part of the cache it must meet the following rules..
+ // length of name is 8 chars
+ if(tmpParse.Name().Length() != 8)
+ return presentAndValid;
+
+ // this filename has a chance of existing and we can assume correct format from now on
+ TUint32 cacheUintName;
+ if(TCompressedEntry::ConvertANameToUint32(tmpParse.Name(), cacheUintName))
+ {
+ TInt arrayIndex = cacheUintName & 0x0000000F;
+ presentAndValid = iDirContent[arrayIndex]->ValidateCacheEntryL( aEntry );
+ }
+ // after all cache entries have been checked against the list, it should only contain orphaned files
+ // files which match but are corrupt will have been removed from this list
+ // however they should be cleaned up when the 'corrupt' entries are removed at a later date.
+ return presentAndValid;
+ }
+
+// -----------------------------------------------------------------------------
+// CCacheDirectoryFiles::RemoveLeftoverFilesL
+// -----------------------------------------------------------------------------
+//
+void CCacheDirectoryFiles::RemoveLeftoverFilesL()
+ {
+ // delete all the files which are still listed.
+ TFileName tempFilename;
+ for (TInt subDir=0; subDir < 16; subDir++)
+ {
+ for (TInt fileIdx = 0; fileIdx < iDirContent[subDir]->Count(); fileIdx++ )
+ {
+ // each file needs to have the full path prepended in order to delete
+ HBufC *name = iDirContent[subDir]->NameAtL(fileIdx);
+ tempFilename.Format(_L("%S%x\\%S"), &iDir, subDir, name);
+#ifdef __CACHELOG__
+ HttpCacheUtil::WriteFormatLog(0, _L("Deleting file %S"), &tempFilename);
+#endif
+ iRfs.Delete(tempFilename);
+ delete name;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCacheDirectoryFiles::~CCacheDirectoryFiles
+// -----------------------------------------------------------------------------
+//
+CCacheDirectoryFiles::~CCacheDirectoryFiles()
+ {
+ iDirContent.ResetAndDestroy();
+ }
+
+// -----------------------------------------------------------------------------
+// CCacheDirectoryFiles::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CCacheDirectoryFiles::ConstructL()
+ {
+ CDir* baseDirs;
+ User::LeaveIfError(iRfs.GetDir(iDir,KEntryAttDir,ESortByName,baseDirs));
+ CleanupStack::PushL(baseDirs);
+
+ // we know that the cache format is a single letter directory from 0-f
+ // so we ignore any other directories - they might belong to other caches
+ // and our cache will not have written any files out into anywhere except the
+ // 0-f dirs, even if we lost track of something.
+ // See HttpCacheUtil::GenerateNameLC
+ iDirContent.ReserveL(16);
+
+ TInt numdirs = baseDirs->Count();
+ // storage for <c:/system/cache/> + '0/'
+ HBufC* currentDir = HBufC::NewLC( iDir.Length() + KSubdirNameLength );
+ for(TInt i=0; i < numdirs; i++)
+ {
+ TInt arrayIndex = -1;
+ const TEntry& entry = (*baseDirs)[i];
+ if(entry.IsDir() && entry.iName.Length()==1)
+ {
+ TUint16 chr = *(entry.iName.Right(1).Ptr());
+ arrayIndex = TCompressedEntry::ConvertAsciiToIntSingleHexDigit(chr);
+ }
+
+ if(arrayIndex >=0 && arrayIndex <= 15)
+ {
+ // initialise subdir name to base directory
+ currentDir->Des().Copy(iDir);
+ currentDir->Des().AppendFormat(_L("%x\\"), arrayIndex); // if base path wasn't terminated with trailing / we would have blown up at creation time.
+
+ // get subdirectory content
+ CDir *dir;
+ iRfs.GetDir(currentDir->Des(), KEntryAttMatchExclude | KEntryAttDir, ESortByName, dir); // only files this time...
+ if(dir)
+ {
+ iDirContent.Insert( CCustomCacheDirList::NewL( dir ), arrayIndex );
+ }
+ delete dir;
+ }
+ }
+ CleanupStack::PopAndDestroy(2); // baseDirs & currentDir
+ }
+
+// -----------------------------------------------------------------------------
+// CCustomCacheDirList::NewL
+// -----------------------------------------------------------------------------
+//
+CCustomCacheDirList* CCustomCacheDirList::NewL(CDir *aSrc)
+ {
+ CCustomCacheDirList *me = new (ELeave) CCustomCacheDirList;
+ CleanupStack::PushL( me );
+ me->ConstructL( aSrc );
+ CleanupStack::Pop( me );
+ return me;
+ }
+
+// -----------------------------------------------------------------------------
+// CCustomCacheDirList::ValidateCacheEntryL
+// -----------------------------------------------------------------------------
+//
+TBool CCustomCacheDirList::ValidateCacheEntryL( const CHttpCacheEntry& aEntry )
+ {
+ TBool presentAndValid = EFalse;
+ TUint32 shortName;
+ if( TCompressedEntry::ConvertANameToUint32( aEntry.Filename().Right(8), shortName) )
+ {
+ for(TInt i=0; i<iDirList.Count(); i++)
+ {
+ if(iDirList[i]->IsCompressed() &&
+ (iDirList[i]->GetCompressedName() == shortName) &&
+ (iDirList[i]->GetSize() == aEntry.BodySize()))
+ {
+ presentAndValid = ETrue;
+ iDirList.Remove(i);
+ break;
+ }
+ }
+ }
+ return presentAndValid;
+ }
+
+// -----------------------------------------------------------------------------
+// CCustomCacheDirList::Count
+// -----------------------------------------------------------------------------
+//
+TInt CCustomCacheDirList::Count()
+ {
+ return iDirList.Count();
+ }
+
+// -----------------------------------------------------------------------------
+// CCustomCacheDirList::NameAtL
+// -----------------------------------------------------------------------------
+//
+HBufC* CCustomCacheDirList::NameAtL( TInt aIndex )
+ {
+ return iDirList[aIndex]->GetNameL();
+ }
+
+// -----------------------------------------------------------------------------
+// CCustomCacheDirList::CCustomCacheDirList
+// -----------------------------------------------------------------------------
+//
+CCustomCacheDirList::CCustomCacheDirList()
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CCustomCacheDirList::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CCustomCacheDirList::ConstructL(CDir *aSrc)
+ {
+ TInt items = aSrc->Count();
+ if(items)
+ {
+ iDirList.ReserveL(items);
+ for(TInt i=0; i < items; i++)
+ {
+ TCompressedEntry *newDirEntry = TCompressedEntry::NewL( (*aSrc)[i] );
+ iDirList.AppendL( newDirEntry );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// TCompressedEntry::NewL
+// -----------------------------------------------------------------------------
+//
+TCompressedEntry *TCompressedEntry::NewL( const TEntry& aEntry )
+ {
+ TCompressedEntry *newEntry = new (ELeave) TCompressedEntry;
+ CleanupStack::PushL( newEntry );
+ newEntry->ConstructL( aEntry );
+ CleanupStack::Pop( newEntry );
+
+ return newEntry;
+ }
+
+// -----------------------------------------------------------------------------
+// TCompressedEntry::ConstructL
+// -----------------------------------------------------------------------------
+//
+void TCompressedEntry::ConstructL( const TEntry& aEntry )
+ {
+ TUint32 compressedName;
+ if ( ConvertANameToUint32(aEntry.iName, compressedName) )
+ {
+ iFlags |= EFilenameStoredAsUint32;
+ iName.iNameAsUint32 = compressedName;
+ }
+ else
+ {
+ iName.iNameAsHBuf = aEntry.iName.AllocL();
+ }
+ iSize = aEntry.iSize;
+ }
+
+// -----------------------------------------------------------------------------
+// TCompressedEntry::ConvertANameToUint32
+// -----------------------------------------------------------------------------
+//
+TBool TCompressedEntry::ConvertANameToUint32( const TDesC& aName, TUint32& aConverted)
+ {
+ TBool success = EFalse;
+ aConverted = 0;
+
+ if ( aName.Length() == 8 )
+ {
+ TUint32 scratch = 0;
+ for ( TInt i=0; i < 8; i++ )
+ {
+ scratch <<= 4;
+ TInt val = TCompressedEntry::ConvertAsciiToIntSingleHexDigit(aName[i]);
+ if ( val >= 0 )
+ {
+ scratch += val & 0x0F;
+ }
+ else
+ break;
+
+ if ( i==7 )
+ {
+ aConverted = scratch;
+ success = ETrue;
+ }
+ }
+ }
+
+ return success;
+ }
+
+// -----------------------------------------------------------------------------
+// TCompressedEntry::ConvertAsciiToIntSingleHexDigit
+// -----------------------------------------------------------------------------
+//
+TInt TCompressedEntry::ConvertAsciiToIntSingleHexDigit(const TUint16& aDigitChar)
+ {
+ if ( aDigitChar >=48 && aDigitChar <=57 )
+ {
+ return (aDigitChar - 48); //numerals
+ }
+ else if ( aDigitChar >= 65 && aDigitChar <= 70 )
+ {
+ return (aDigitChar - 55); // uppercase hex letters
+ }
+ else if ( aDigitChar >= 97 && aDigitChar <= 102 )
+ {
+ return (aDigitChar - 87); // lowercase hex letters
+ }
+
+ return -1;
+ }
+
+// -----------------------------------------------------------------------------
+// TCompressedEntry::GetNameL
+// -----------------------------------------------------------------------------
+//
+HBufC* TCompressedEntry::GetNameL()
+ {
+ if ( !IsCompressed() )
+ {
+ return iName.iNameAsHBuf->AllocL();
+ }
+
+ HBufC* name = HBufC::NewL(8);
+ name->Des().Format(_L("%08x"), iName.iNameAsUint32);
+
+ return name;
}
// End of File