|         |      1 /* | 
|         |      2 * Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies). | 
|         |      3 * All rights reserved. | 
|         |      4 * This component and the accompanying materials are made available | 
|         |      5 * under the terms of the License "Eclipse Public License v1.0" | 
|         |      6 * which accompanies this distribution, and is available | 
|         |      7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". | 
|         |      8 * | 
|         |      9 * Initial Contributors: | 
|         |     10 * Nokia Corporation - initial contribution. | 
|         |     11 * | 
|         |     12 * Contributors: | 
|         |     13 * | 
|         |     14 * Description:   Implementation of HttpCacheUtil | 
|         |     15 * | 
|         |     16 */ | 
|         |     17  | 
|         |     18  | 
|         |     19 // INCLUDE FILES | 
|         |     20 #include "HttpCacheUtil.h" | 
|         |     21 #include <http/rhttpheaders.h> | 
|         |     22 #include <http/RHTTPTransaction.h> | 
|         |     23 #include <http.h> | 
|         |     24 #include <stdlib.h> | 
|         |     25 #include <string.h> | 
|         |     26 #include <stringpool.h> | 
|         |     27 #include <flogger.h> | 
|         |     28 #include "TInternetdate.h" | 
|         |     29 #include "HttpFilterCommonStringsExt.h" | 
|         |     30 #include "HttpCacheEntry.h" | 
|         |     31  | 
|         |     32 // EXTERNAL DATA STRUCTURES | 
|         |     33  | 
|         |     34 // EXTERNAL FUNCTION PROTOTYPES | 
|         |     35  | 
|         |     36 // CONSTANTS | 
|         |     37 _LIT8( KHttpNewLine, "\r\n" ); | 
|         |     38 // if you change it here, change in HeadersToBufferL too | 
|         |     39 _LIT8( KHttpFieldSeparator, ": " ); | 
|         |     40 _LIT8( KHttpValueSep, "," ); | 
|         |     41 const TInt KMaxHeaderStrLen = 1024; | 
|         |     42 _LIT8( KHttpContentType, "Content-Type" ); | 
|         |     43  | 
|         |     44 #ifdef __CACHELOG__ | 
|         |     45 _LIT( KDateString,"%D%M%Y%/0%1%/1%2%/2%3%/3 %-B%:0%J%:1%T%:2%S%.%*C4%:3%+B"); | 
|         |     46 _LIT( KHttpCacheGeneralFileName, "cachehandler.txt" ); | 
|         |     47 _LIT( KHttpCacheHashFileName, "hash.txt" ); | 
|         |     48 const TInt KCurrentLogLevel = 0; | 
|         |     49 #endif // __CACHELOG__ | 
|         |     50  | 
|         |     51 // MACROS | 
|         |     52  | 
|         |     53 // LOCAL CONSTANTS AND MACROS | 
|         |     54  | 
|         |     55 // MODULE DATA STRUCTURES | 
|         |     56  | 
|         |     57 // LOCAL FUNCTION PROTOTYPES | 
|         |     58  | 
|         |     59 // FORWARD DECLARATIONS | 
|         |     60  | 
|         |     61 // ============================= LOCAL FUNCTIONS =============================== | 
|         |     62  | 
|         |     63 // ============================ MEMBER FUNCTIONS =============================== | 
|         |     64  | 
|         |     65 // ============================ MEMBER FUNCTIONS =============================== | 
|         |     66  | 
|         |     67 // ----------------------------------------------------------------------------- | 
|         |     68 // HttpCacheUtil::SetEntryOnTransL | 
|         |     69 // | 
|         |     70 // ----------------------------------------------------------------------------- | 
|         |     71 // | 
|         |     72 void HttpCacheUtil::SetEntryOnTransL( | 
|         |     73     CHttpCacheEntry& aEntry, | 
|         |     74     RHTTPTransaction& aTrans, | 
|         |     75     RStringF& aCacheEntryStr ) | 
|         |     76     { | 
|         |     77     RHTTPTransactionPropertySet propSet = aTrans.PropertySet(); | 
|         |     78  | 
|         |     79     // set transaction property with the event handler callback functions' pointer | 
|         |     80     THTTPHdrVal tokenVal = (TInt)(CHttpCacheEntry*)&aEntry; | 
|         |     81     aTrans.PropertySet().RemoveProperty( aCacheEntryStr ); | 
|         |     82     aTrans.PropertySet().SetPropertyL( aCacheEntryStr, tokenVal ); | 
|         |     83     } | 
|         |     84  | 
|         |     85 // ----------------------------------------------------------------------------- | 
|         |     86 // HttpCacheUtil::EntryOnTransL | 
|         |     87 // | 
|         |     88 // ----------------------------------------------------------------------------- | 
|         |     89 // | 
|         |     90 CHttpCacheEntry* HttpCacheUtil::EntryOnTransL( | 
|         |     91     RHTTPTransaction& aTrans, | 
|         |     92     RStringF& aCacheEntryStr ) | 
|         |     93     { | 
|         |     94     // | 
|         |     95     CHttpCacheEntry* entry = NULL; | 
|         |     96     // | 
|         |     97     THTTPHdrVal entryPtr; | 
|         |     98     RHTTPTransactionPropertySet propSet = aTrans.PropertySet(); | 
|         |     99     // this is a transaction, already forwarded to download manager | 
|         |    100     if( propSet.Property( aCacheEntryStr, entryPtr ) ) | 
|         |    101         { | 
|         |    102         entry = REINTERPRET_CAST( CHttpCacheEntry*, entryPtr.Int() ); | 
|         |    103         } | 
|         |    104     return entry; | 
|         |    105     } | 
|         |    106  | 
|         |    107 // ----------------------------------------------------------------------------- | 
|         |    108 // HttpCacheUtil::HeadersToBufferLC | 
|         |    109 // | 
|         |    110 // ----------------------------------------------------------------------------- | 
|         |    111 // | 
|         |    112 HBufC8* HttpCacheUtil::HeadersToBufferLC( | 
|         |    113     RHTTPHeaders& aHttpHeaders, | 
|         |    114     RStringPool& aStrP ) | 
|         |    115     { | 
|         |    116     // Get an iterator for the collection of response headers | 
|         |    117     HBufC8* headerString = HBufC8::NewL( KMaxHeaderStrLen ); | 
|         |    118     TPtr8 headerPtr( headerString->Des() ); | 
|         |    119     TInt newLength( 0 ); | 
|         |    120     THTTPHdrFieldIter it = aHttpHeaders.Fields(); | 
|         |    121  | 
|         |    122     while( it.AtEnd() == EFalse ) | 
|         |    123         { | 
|         |    124         TPtrC8 rawData; | 
|         |    125         // Get name of next header field | 
|         |    126         RStringTokenF fieldName = it(); | 
|         |    127         RStringF fieldNameStr = aStrP.StringF( fieldName ); | 
|         |    128         aHttpHeaders.GetRawField( fieldNameStr, rawData ); | 
|         |    129  | 
|         |    130         newLength+=( fieldNameStr.DesC().Length() + KHttpFieldSeparator().Length() + rawData.Length() + | 
|         |    131             KHttpNewLine().Length() ); | 
|         |    132  | 
|         |    133         if( headerPtr.MaxLength() < newLength ) | 
|         |    134             { | 
|         |    135             // realloc | 
|         |    136             HBufC8* temp = HBufC8::New( newLength + KMaxHeaderStrLen ); | 
|         |    137             if( !temp ) | 
|         |    138                 { | 
|         |    139                 delete headerString; | 
|         |    140                 User::LeaveNoMemory(); | 
|         |    141                 } | 
|         |    142             temp->Des().Copy( headerPtr ); | 
|         |    143             delete headerString; | 
|         |    144             headerString = temp; | 
|         |    145             headerPtr.Set( headerString->Des() ); | 
|         |    146             } | 
|         |    147         // append | 
|         |    148         headerPtr.Append( fieldNameStr.DesC() ); | 
|         |    149         headerPtr.Append( KHttpFieldSeparator ); | 
|         |    150         headerPtr.Append( rawData ); | 
|         |    151         headerPtr.Append( KHttpNewLine ); | 
|         |    152         ++it; | 
|         |    153         } | 
|         |    154     CleanupStack::PushL( headerString ); | 
|         |    155     return headerString; | 
|         |    156     } | 
|         |    157  | 
|         |    158 // ----------------------------------------------------------------------------- | 
|         |    159 // HttpCacheUtil::BufferToHeadersL | 
|         |    160 // | 
|         |    161 // ----------------------------------------------------------------------------- | 
|         |    162 // | 
|         |    163 void HttpCacheUtil::BufferToHeadersL( | 
|         |    164     const TDesC8& aHeaderStr, | 
|         |    165     RHTTPHeaders& aHttpHeaders, | 
|         |    166     RStringPool& aStrP ) | 
|         |    167     { | 
|         |    168     // take header str line by line | 
|         |    169     TInt sepPos( 0 ); | 
|         |    170     TInt lineEnd( 0 ); | 
|         |    171     TPtrC8 headerStr( aHeaderStr ); | 
|         |    172  | 
|         |    173     while( lineEnd != KErrNotFound ) | 
|         |    174         { | 
|         |    175         lineEnd = headerStr.Find( KHttpNewLine ); | 
|         |    176         sepPos = headerStr.Find( KHttpFieldSeparator ); | 
|         |    177  | 
|         |    178         if( lineEnd != KErrNotFound && sepPos != KErrNotFound && | 
|         |    179             lineEnd > sepPos ) | 
|         |    180             { | 
|         |    181             // ETag: "9be043c1-175-793-41419a44" | 
|         |    182             TPtrC8 line( headerStr.Left( lineEnd ) ); | 
|         |    183             // ETag | 
|         |    184             TPtrC8 key( line.Left( sepPos ) ); | 
|         |    185             // "9be043c1-175-793-41419a44" | 
|         |    186             TInt sepEnd( sepPos + KHttpFieldSeparator().Length() ); | 
|         |    187             TPtrC8 value( line.Mid( sepEnd ) ); | 
|         |    188             // add it to the http header | 
|         |    189             RStringF nameStr = aStrP.OpenFStringL( key ); | 
|         |    190             CleanupClosePushL( nameStr ); | 
|         |    191             // remove if exists | 
|         |    192             THTTPHdrVal headerValue; | 
|         |    193             if( aHttpHeaders.GetField( nameStr, 0, headerValue ) == KErrNone ) | 
|         |    194                 { | 
|         |    195                 // | 
|         |    196                 aHttpHeaders.RemoveField( nameStr ); | 
|         |    197                 } | 
|         |    198             TRAPD( err, aHttpHeaders.SetRawFieldL( nameStr, value, KHttpValueSep ) ); | 
|         |    199             // leave OOM only | 
|         |    200             if( err == KErrNoMemory ) | 
|         |    201                 { | 
|         |    202                 User::Leave( err ); | 
|         |    203                 } | 
|         |    204             CleanupStack::PopAndDestroy(); // namestr | 
|         |    205  | 
|         |    206             // move string to the end of the line | 
|         |    207             headerStr.Set( headerStr.Mid( lineEnd + KHttpNewLine().Length() ) ); | 
|         |    208             } | 
|         |    209         } | 
|         |    210     } | 
|         |    211  | 
|         |    212 // ----------------------------------------------------------------------------- | 
|         |    213 // HttpCacheUtil::BodyToBufferL | 
|         |    214 // | 
|         |    215 // ----------------------------------------------------------------------------- | 
|         |    216 // | 
|         |    217 HBufC8* HttpCacheUtil::BodyToBufferL( | 
|         |    218     MHTTPDataSupplier& aBodySupplier ) | 
|         |    219     { | 
|         |    220     // get it from the transaction | 
|         |    221     TPtrC8 ptr; | 
|         |    222     aBodySupplier.GetNextDataPart( ptr ); | 
|         |    223     // | 
|         |    224     return ptr.AllocL(); | 
|         |    225     } | 
|         |    226  | 
|         |    227 // ----------------------------------------------------------------------------- | 
|         |    228 // HttpCacheUtil::MergeHeadersLC | 
|         |    229 // | 
|         |    230 // ----------------------------------------------------------------------------- | 
|         |    231 // | 
|         |    232 HBufC8* HttpCacheUtil::MergeHeadersLC( | 
|         |    233     const TDesC8& aCachedHeaderStr, | 
|         |    234     RHTTPHeaders& aResponseHeaders, | 
|         |    235     RStringPool& aStrP ) | 
|         |    236     { | 
|         |    237     // FYI: it uses the response header to merge | 
|         |    238     // take header str line by line | 
|         |    239     TInt sepPos( 0 ); | 
|         |    240     TInt lineEnd( 0 ); | 
|         |    241     TPtrC8 headerStr( aCachedHeaderStr ); | 
|         |    242  | 
|         |    243     while( lineEnd != KErrNotFound ) | 
|         |    244         { | 
|         |    245         lineEnd = headerStr.Find( KHttpNewLine ); | 
|         |    246         sepPos = headerStr.Find( KHttpFieldSeparator ); | 
|         |    247  | 
|         |    248         if( lineEnd != KErrNotFound && sepPos != KErrNotFound && | 
|         |    249             lineEnd > sepPos ) | 
|         |    250             { | 
|         |    251             // ETag: "9be043c1-175-793-41419a44" | 
|         |    252             TPtrC8 line( headerStr.Left( lineEnd ) ); | 
|         |    253             // ETag | 
|         |    254             TPtrC8 key( line.Left( sepPos ) ); | 
|         |    255             // "9be043c1-175-793-41419a44" | 
|         |    256             TInt sepEnd( sepPos + KHttpFieldSeparator().Length() ); | 
|         |    257             TPtrC8 value( line.Mid( sepEnd ) ); | 
|         |    258             // add it to the http header | 
|         |    259             RStringF nameStr = aStrP.OpenFStringL( key ); | 
|         |    260             CleanupClosePushL( nameStr ); | 
|         |    261             // avoid corrupted content type from the stack in case of 304 | 
|         |    262             if(key == KHttpContentType) | 
|         |    263                 { | 
|         |    264                 aResponseHeaders.RemoveField(nameStr); | 
|         |    265                 } | 
|         |    266             THTTPHdrVal tempVal; | 
|         |    267             // add this field unless it already exists | 
|         |    268             if( aResponseHeaders.GetField( nameStr, 0, tempVal ) == KErrNotFound ) | 
|         |    269                 { | 
|         |    270                 TRAPD( err, aResponseHeaders.SetRawFieldL( nameStr, value, KHttpValueSep ) ); | 
|         |    271                 // leave OOM only | 
|         |    272                 if( err == KErrNoMemory ) | 
|         |    273                     { | 
|         |    274                     User::Leave( err ); | 
|         |    275                     } | 
|         |    276                 } | 
|         |    277             CleanupStack::PopAndDestroy(); // namestr | 
|         |    278             // move string to the end of the line | 
|         |    279             headerStr.Set( headerStr.Mid( lineEnd + KHttpNewLine().Length() ) ); | 
|         |    280             } | 
|         |    281         } | 
|         |    282     // we've got the merged headers, let's covert it to buffer | 
|         |    283     return HeadersToBufferLC( aResponseHeaders, aStrP ); | 
|         |    284     } | 
|         |    285  | 
|         |    286 // ----------------------------------------------------------------------------- | 
|         |    287 // HttpCacheUtil::AddHeaderLC | 
|         |    288 // | 
|         |    289 // ----------------------------------------------------------------------------- | 
|         |    290 // | 
|         |    291 HBufC8* HttpCacheUtil::AddHeaderLC( | 
|         |    292     const TDesC8& aName, | 
|         |    293     const TDesC8& aValue, | 
|         |    294     const TDesC8& aHeaders ) | 
|         |    295     { | 
|         |    296     HBufC8* newHeaders = NULL; | 
|         |    297     // first check if the header exists so | 
|         |    298     // then all we need to do is to update the value | 
|         |    299     TInt pos( aHeaders.FindF( aName ) ); | 
|         |    300     // | 
|         |    301     newHeaders = HBufC8::NewLC( aHeaders.Length() + aName.Length() + KHttpFieldSeparator().Length() + | 
|         |    302         aValue.Length() + KHttpNewLine().Length() ); | 
|         |    303     // | 
|         |    304     if( pos != KErrNotFound ) | 
|         |    305         { | 
|         |    306         // replace old header with this new one | 
|         |    307         TPtr8 newHeadersPtr( newHeaders->Des() ); | 
|         |    308         // copy headers | 
|         |    309         newHeadersPtr.Copy( aHeaders ); | 
|         |    310         // check what we need to replace | 
|         |    311         TPtrC8 leftover( aHeaders.Mid( pos ) ); | 
|         |    312         // headers are terminated by \r\n | 
|         |    313         TInt endPos( leftover.Find( KHttpNewLine ) ); | 
|         |    314         if( endPos != KErrNotFound ) | 
|         |    315             { | 
|         |    316             // value pos | 
|         |    317             TInt valuePos( pos + aName.Length() + KHttpFieldSeparator().Length() ); | 
|         |    318             newHeadersPtr.Replace( valuePos, pos + endPos - valuePos, aValue ); | 
|         |    319             } | 
|         |    320         } | 
|         |    321     else | 
|         |    322         { | 
|         |    323         // add new header | 
|         |    324         // new header = old header\r\n aName: aValue\r\n | 
|         |    325         TPtr8 newHeadersPtr( newHeaders->Des() ); | 
|         |    326         // old headers | 
|         |    327         newHeadersPtr.Copy( aHeaders ); | 
|         |    328         // Cache Control | 
|         |    329         newHeadersPtr.Append( aName ); | 
|         |    330         // : | 
|         |    331         newHeadersPtr.Append( KHttpFieldSeparator ); | 
|         |    332         // max age=180 | 
|         |    333         newHeadersPtr.Append( aValue ); | 
|         |    334         // \r\n | 
|         |    335         newHeadersPtr.Append( KHttpNewLine ); | 
|         |    336         } | 
|         |    337     return newHeaders; | 
|         |    338     } | 
|         |    339  | 
|         |    340 // ----------------------------------------------------------------------------- | 
|         |    341 // HttpCacheUtil::HeaderFieldFromBufferLC | 
|         |    342 // | 
|         |    343 // ----------------------------------------------------------------------------- | 
|         |    344 // | 
|         |    345 HBufC8* HttpCacheUtil::HeaderFieldFromBufferLC( | 
|         |    346     const TDesC8& aHeaders, | 
|         |    347     const TDesC8& aKey ) | 
|         |    348     { | 
|         |    349     HBufC8* value = NULL; | 
|         |    350     // | 
|         |    351     TInt pos( aHeaders.Find( aKey ) ); | 
|         |    352     if( pos != KErrNotFound ) | 
|         |    353         { | 
|         |    354         // line: Cache-Control: max-age=180 | 
|         |    355         TPtrC8 linePtr = aHeaders.Mid( pos ); | 
|         |    356         // line end \r\n | 
|         |    357         TInt lineEnd( linePtr.Find( KHttpNewLine ) ); | 
|         |    358         // separator : | 
|         |    359         TInt sepPos( linePtr.Find( KHttpFieldSeparator ) ); | 
|         |    360         // | 
|         |    361         if( sepPos != KErrNotFound ) | 
|         |    362             { | 
|         |    363             // fix line end | 
|         |    364             lineEnd = lineEnd == KErrNotFound ? linePtr.Length(): lineEnd; | 
|         |    365             // max-age=180 | 
|         |    366             TInt valueLen( lineEnd - ( sepPos + KHttpFieldSeparator().Length() ) ); | 
|         |    367             value = HBufC8::NewLC( valueLen ); | 
|         |    368             value->Des().Copy( linePtr.Mid( sepPos + KHttpFieldSeparator().Length(), valueLen ) ); | 
|         |    369             } | 
|         |    370         } | 
|         |    371     return value; | 
|         |    372     } | 
|         |    373  | 
|         |    374 // ----------------------------------------------------------------------------- | 
|         |    375 // HttpCacheUtil::MethodFromStr | 
|         |    376 // | 
|         |    377 // ----------------------------------------------------------------------------- | 
|         |    378 // | 
|         |    379  | 
|         |    380 TCacheLoadMethod HttpCacheUtil::MethodFromStr( | 
|         |    381     RStringF aMethodStr, | 
|         |    382     RStringPool aStrP ) | 
|         |    383     { | 
|         |    384     if( aMethodStr == aStrP.StringF( HTTP::EGET, RHTTPSession::GetTable() ) ) | 
|         |    385         { | 
|         |    386         return EMethodGet; | 
|         |    387         } | 
|         |    388     if( aMethodStr == aStrP.StringF(HTTP::ECONNECT, RHTTPSession::GetTable() ) ) | 
|         |    389         { | 
|         |    390         return EMethodConnect; | 
|         |    391         } | 
|         |    392     if( aMethodStr == aStrP.StringF(HTTP::EDELETE, RHTTPSession::GetTable() ) ) | 
|         |    393         { | 
|         |    394         return EMethodDelete; | 
|         |    395         } | 
|         |    396     if( aMethodStr == aStrP.StringF(HTTP::EHEAD, RHTTPSession::GetTable() ) ) | 
|         |    397         { | 
|         |    398         return EMethodHead; | 
|         |    399         } | 
|         |    400     if( aMethodStr == aStrP.StringF(HTTP::EOPTIONS, RHTTPSession::GetTable() ) ) | 
|         |    401         { | 
|         |    402         return EMethodOptions; | 
|         |    403         } | 
|         |    404     if( aMethodStr == aStrP.StringF(HTTP::EPUT, RHTTPSession::GetTable() ) ) | 
|         |    405         { | 
|         |    406         return EMethodPut; | 
|         |    407         } | 
|         |    408     if( aMethodStr == aStrP.StringF(HTTP::EPOST, RHTTPSession::GetTable() ) ) | 
|         |    409         { | 
|         |    410         return EMethodPost; | 
|         |    411         } | 
|         |    412     if( aMethodStr == aStrP.StringF(HTTP::ETRACE, RHTTPSession::GetTable() ) ) | 
|         |    413         { | 
|         |    414         return EMethodTrace; | 
|         |    415         } | 
|         |    416     return EMethodGet; | 
|         |    417     } | 
|         |    418  | 
|         |    419  | 
|         |    420 // ----------------------------------------------------------------------------- | 
|         |    421 // HttpCacheUtil::ProtectedEntry | 
|         |    422 // | 
|         |    423 // Returns true if the entry is protected | 
|         |    424 // | 
|         |    425 // ----------------------------------------------------------------------------- | 
|         |    426 // | 
|         |    427 TBool HttpCacheUtil::ProtectedEntry( | 
|         |    428     RHTTPHeaders& aHttpHeaders, | 
|         |    429     RStringPool& aStrP ) | 
|         |    430     { | 
|         |    431     TBool protectedEntry( EFalse ); | 
|         |    432     // | 
|         |    433     THTTPHdrVal contType; | 
|         |    434     RStringF fieldName = aStrP.StringF( HTTP::EContentType, RHTTPSession::GetTable() ); | 
|         |    435     // | 
|         |    436     if( aHttpHeaders.GetField( fieldName, 0, contType ) == KErrNone ) | 
|         |    437         { | 
|         |    438         if( contType.Type() == THTTPHdrVal::KStrFVal ) | 
|         |    439             { | 
|         |    440             RStringF fieldValStr = aStrP.StringF( contType.StrF() ); | 
|         |    441             // css and javascrip are protected entries | 
|         |    442             protectedEntry = fieldValStr.DesC().Find( _L8("text/css") ) != KErrNotFound || | 
|         |    443                 fieldValStr.DesC().Find( _L8("javascript") ) != KErrNotFound; | 
|         |    444             } | 
|         |    445         } | 
|         |    446     return protectedEntry; | 
|         |    447     } | 
|         |    448  | 
|         |    449 // ----------------------------------------------------------------------------- | 
|         |    450 // HttpCacheUtil::CacheTimeIsFresh | 
|         |    451 // | 
|         |    452 // Returns true if the entry is fresh. | 
|         |    453 // | 
|         |    454 // ----------------------------------------------------------------------------- | 
|         |    455 // | 
|         |    456 TBool HttpCacheUtil::CacheTimeIsFresh( | 
|         |    457     const RHTTPHeaders& aRequestHeaders, | 
|         |    458     const RHTTPHeaders& aCachedHeaders, | 
|         |    459     RStringPool aStrP ) | 
|         |    460     { | 
|         |    461     TInt status( KErrNone ); | 
|         |    462     TBool isFresh( EFalse ); | 
|         |    463     TInt64 freshness; | 
|         |    464     TInt64 age; | 
|         |    465     TInt64 maxAge; | 
|         |    466     TInt64 minFresh; | 
|         |    467     TInt64 maxStale; | 
|         |    468     TTime cachedRequestTime; | 
|         |    469     TTime cachedResponseTime; | 
|         |    470  | 
|         |    471     TTime date; | 
|         |    472     TInt err; | 
|         |    473     THTTPHdrVal dateValue; | 
|         |    474     RStringF fieldName; | 
|         |    475  | 
|         |    476     // Get the date from the headers | 
|         |    477     fieldName = aStrP.StringF( HTTP::EDate, RHTTPSession::GetTable() ); | 
|         |    478     err = aCachedHeaders.GetField( fieldName, 0, dateValue ); | 
|         |    479     if( err == KErrNotFound || dateValue.Type() != THTTPHdrVal::KDateVal ) | 
|         |    480         { | 
|         |    481         date = 0; | 
|         |    482         } | 
|         |    483     else | 
|         |    484         { | 
|         |    485         date = TTime( dateValue.DateTime() ); | 
|         |    486         } | 
|         |    487     cachedRequestTime = date; | 
|         |    488     cachedResponseTime = date; | 
|         |    489  | 
|         |    490     // Get Max Age header. If maxAge = 0, then must revalidate. | 
|         |    491     status = GetCacheControls( aCachedHeaders, &maxAge, NULL, NULL, NULL, NULL, NULL, aStrP ); | 
|         |    492     if( status == KErrNone &&  maxAge == 0 ) | 
|         |    493         { | 
|         |    494         return EFalse; //Must revalidate | 
|         |    495         } | 
|         |    496  | 
|         |    497     // Get the freshness and age of the cachedHeaders | 
|         |    498     freshness = Freshness( aCachedHeaders, cachedResponseTime, aStrP ); | 
|         |    499     age = Age( aCachedHeaders, cachedRequestTime, cachedResponseTime, aStrP ); | 
|         |    500 #ifdef __CACHELOG__ | 
|         |    501         TBuf<50> dateString; | 
|         |    502         TTime fr( freshness ); | 
|         |    503  | 
|         |    504         fr.FormatL( dateString, KDateString ); | 
|         |    505         HttpCacheUtil::WriteLog( 0, _L( "fresness" ) ); | 
|         |    506         HttpCacheUtil::WriteLog( 0, dateString ); | 
|         |    507  | 
|         |    508         TTime ca( age ); | 
|         |    509         ca.FormatL( dateString, KDateString ); | 
|         |    510         HttpCacheUtil::WriteLog( 0, _L( "age" ) ); | 
|         |    511         HttpCacheUtil::WriteLog( 0, dateString ); | 
|         |    512 #endif // __CACHELOG__ | 
|         |    513  | 
|         |    514     // Get useful cache-control directives from the requestHeaders | 
|         |    515     status = GetCacheControls( aRequestHeaders, &maxAge, &minFresh, &maxStale, NULL, NULL, NULL, aStrP ); | 
|         |    516     if( status == KErrNone ) | 
|         |    517         { | 
|         |    518         // Above values for maxAge, minFresh and maxStale are in seconds | 
|         |    519         // Convert to micro seconds before using it. | 
|         |    520  | 
|         |    521         // If maxStale is present it means that it is willing to | 
|         |    522         // accept a response maxStale seconds after it expires.  To | 
|         |    523         // allow this freshness is extended by maxStale seconds. | 
|         |    524         if( maxStale != -1 ) | 
|         |    525             { | 
|         |    526             if( maxStale == MAKE_TINT64( KMaxTInt, KMaxTInt ) ) | 
|         |    527                 { | 
|         |    528                 freshness = MAKE_TINT64( KMaxTInt, KMaxTInt ); | 
|         |    529                 } | 
|         |    530             else | 
|         |    531                 { | 
|         |    532                 freshness += maxStale * 1000 * 1000; | 
|         |    533                 } | 
|         |    534             } | 
|         |    535         // If minFresh is present reject it if it would expire | 
|         |    536         // within minFresh seconds. | 
|         |    537         if( minFresh != -1 ) | 
|         |    538             { | 
|         |    539             if( ( age + minFresh * 1000 * 1000 ) > freshness ) | 
|         |    540                 { | 
|         |    541                 return EFalse; | 
|         |    542                 } | 
|         |    543             } | 
|         |    544         // If the age > request's maxAge, reject it | 
|         |    545         if( maxAge != -1 ) | 
|         |    546             { | 
|         |    547             if( age > maxAge * 1000 * 1000 ) | 
|         |    548                 { | 
|         |    549                 return EFalse; | 
|         |    550                 } | 
|         |    551             } | 
|         |    552         // If age is less than freshness its fresh | 
|         |    553     // If age == 0 and freshness == 0 - revalidation is needed | 
|         |    554         if( freshness && age <= freshness ) | 
|         |    555     { | 
|         |    556     isFresh = ETrue; | 
|         |    557     } | 
|         |    558     } | 
|         |    559     return isFresh; | 
|         |    560     } | 
|         |    561  | 
|         |    562 // ----------------------------------------------------------------------------- | 
|         |    563 // HttpCacheUtil::AddValidationHeaders | 
|         |    564 // | 
|         |    565 // Adds appropriate headers to make the given "request" conditional. | 
|         |    566 // | 
|         |    567 // ----------------------------------------------------------------------------- | 
|         |    568 // | 
|         |    569 void HttpCacheUtil::AddValidationHeaders( | 
|         |    570     const RHTTPHeaders aCachedHeaders, | 
|         |    571     RHTTPHeaders& aRequestHeaders, | 
|         |    572     RStringPool& aStrP ) | 
|         |    573     { | 
|         |    574     THTTPHdrVal lastMod; | 
|         |    575     THTTPHdrVal eTag; | 
|         |    576     RStringF fieldName; | 
|         |    577     TInt err; | 
|         |    578  | 
|         |    579     // Get the entry's last-modified header | 
|         |    580     fieldName = aStrP.StringF( HTTP::ELastModified, RHTTPSession::GetTable() ); | 
|         |    581     err = aCachedHeaders.GetField( fieldName, 0, lastMod ); | 
|         |    582  | 
|         |    583     // If last-Modified is present add an If-Modified-Since header | 
|         |    584     if( err != KErrNotFound ) | 
|         |    585         { | 
|         |    586         fieldName = aStrP.StringF( HTTP::EIfModifiedSince, RHTTPSession::GetTable() ); | 
|         |    587         TRAP_IGNORE( aRequestHeaders.SetFieldL( fieldName, lastMod ) ); | 
|         |    588         } | 
|         |    589  | 
|         |    590     // Get the entry's ETag header | 
|         |    591     fieldName = aStrP.StringF( HTTP::EETag, RHTTPSession::GetTable() ); | 
|         |    592     err = aCachedHeaders.GetField( fieldName, 0, eTag ); | 
|         |    593  | 
|         |    594     // If etag is present add an etag header | 
|         |    595     if( err != KErrNotFound ) | 
|         |    596         { | 
|         |    597         fieldName = aStrP.StringF( HTTP::EIfNoneMatch, RHTTPSession::GetTable() ); | 
|         |    598         TRAP_IGNORE( aRequestHeaders.SetFieldL( fieldName, eTag ) ); | 
|         |    599         } | 
|         |    600     } | 
|         |    601  | 
|         |    602 // ----------------------------------------------------------------------------- | 
|         |    603 // HttpCacheUtil::OperatorCacheContent | 
|         |    604 // This function checks if aUrl is part of the operator domain. for examp: if aUrl->http://www.opdomain.com/pub/index.html | 
|         |    605 // and operator domain is http://www.opdomain.com/pub then it returns ETrue. | 
|         |    606 // ----------------------------------------------------------------------------- | 
|         |    607 // | 
|         |    608 TBool HttpCacheUtil::OperatorCacheContent( | 
|         |    609     const TDesC8& aOpDomain, | 
|         |    610     const TDesC8& aUrl ) | 
|         |    611     { | 
|         |    612     TUriParser8 opDomain; | 
|         |    613     TUriParser8 url; | 
|         |    614     TBool found( EFalse ); | 
|         |    615  | 
|         |    616     // check if both URIs are correct. | 
|         |    617     if( opDomain.Parse( aOpDomain ) == KErrNone && url.Parse( aUrl ) == KErrNone ) | 
|         |    618         { | 
|         |    619         // host value must be the same. for examp: www.operator.co is different from www.operator.com | 
|         |    620         // note: check if compare is case sensitive! | 
|         |    621         // note2: if http:// is missing from operator domain then TUriParser8 takes the host part as path. | 
|         |    622         if( opDomain.Compare( url, EUriHost ) == 0 ) | 
|         |    623             { | 
|         |    624             // further checking on the path value. domain path must be a substring of the given url. | 
|         |    625             // for examp: op path: /news | 
|         |    626             // url path: /news/local_news.html | 
|         |    627             const TDesC8& opPath = opDomain.Extract( EUriPath ); | 
|         |    628             if( opPath.Length() ) | 
|         |    629                 { | 
|         |    630                 const TDesC8& urlPath = url.Extract( EUriPath ); | 
|         |    631                 // we don't take the content if the url path is not defined (while domain path is) or the | 
|         |    632                 // domain path is not a substring of url path. actually url path must start with domain path | 
|         |    633                 // op path: /news url path: /media/news/local_news.html is not valid. | 
|         |    634                 found = ( urlPath.Length() && urlPath.FindF( opPath ) == 0 ); | 
|         |    635                 } | 
|         |    636             else | 
|         |    637                 { | 
|         |    638                 // no opPath means that we take every content on this host. | 
|         |    639                 found = ETrue; | 
|         |    640                 } | 
|         |    641             } | 
|         |    642         } | 
|         |    643     return found; | 
|         |    644     } | 
|         |    645  | 
|         |    646  | 
|         |    647 // ----------------------------------------------------------------------------- | 
|         |    648 // HttpCacheUtil::VSSCacheContent | 
|         |    649 // | 
|         |    650 // ----------------------------------------------------------------------------- | 
|         |    651 // | 
|         |    652 TBool HttpCacheUtil::VSSCacheContent( const TDesC8& aUrl, const HBufC8* aWhiteList ) | 
|         |    653   { | 
|         |    654     TBool found( EFalse ); | 
|         |    655   if( aWhiteList ) | 
|         |    656     { | 
|         |    657     TUint8* bufPtr = (TUint8* ) aWhiteList->Ptr(); | 
|         |    658     TUint8* startBufPtr = bufPtr; | 
|         |    659     TUint len = aWhiteList->Length(); | 
|         |    660     TInt i, startUri, uriLen; | 
|         |    661     TPtrC8 uri ( aUrl ); | 
|         |    662     for(i=0; i < len; i++) | 
|         |    663       { | 
|         |    664       startUri = i; | 
|         |    665       for( ;( ( *bufPtr != ';' ) && ( i<len ) ) ; i++, bufPtr++ ) ; | 
|         |    666       uriLen = i - startUri; | 
|         |    667       if( i == len )  | 
|         |    668           { | 
|         |    669           uriLen += 2; //For getting total length  | 
|         |    670           } | 
|         |    671       TPtrC8 uriDomain( startBufPtr, uriLen); | 
|         |    672       if ( OperatorCacheContent( uriDomain, uri ) ) | 
|         |    673         { | 
|         |    674         found = ETrue; | 
|         |    675         break; | 
|         |    676         } | 
|         |    677       startBufPtr = ++bufPtr; | 
|         |    678       i++; | 
|         |    679       } //end for() | 
|         |    680      } //end for() | 
|         |    681      return found; | 
|         |    682     } | 
|         |    683  | 
|         |    684 // ----------------------------------------------------------------------------- | 
|         |    685 // HttpCacheUtil::PragmaNoCache | 
|         |    686 // | 
|         |    687 // ----------------------------------------------------------------------------- | 
|         |    688 // | 
|         |    689 TBool HttpCacheUtil::PragmaNoCache( | 
|         |    690     RHTTPTransaction& aTrans ) | 
|         |    691     { | 
|         |    692     // | 
|         |    693     RHTTPHeaders requestHeaders = aTrans.Request().GetHeaderCollection(); | 
|         |    694     RStringPool strP = aTrans.Session().StringPool(); | 
|         |    695     RStringF fieldName = strP.StringF( HTTP::ENoCache, RHTTPSession::GetTable() ); | 
|         |    696  | 
|         |    697     // check no-cache | 
|         |    698     THTTPHdrVal headerVal; | 
|         |    699     TInt noCacheField( requestHeaders.GetField( fieldName, 0, headerVal ) ); | 
|         |    700     // check no-store | 
|         |    701     fieldName = strP.StringF( HTTP::ENoStore, RHTTPSession::GetTable() ); | 
|         |    702     TInt noStoreField( requestHeaders.GetField( fieldName, 0, headerVal ) ); | 
|         |    703     // | 
|         |    704     return( noCacheField == KErrNone || noStoreField == KErrNone ); | 
|         |    705     } | 
|         |    706  | 
|         |    707 // ----------------------------------------------------------------------------- | 
|         |    708 // HttpCacheUtil::GetHeaderFileName | 
|         |    709 // | 
|         |    710 // ----------------------------------------------------------------------------- | 
|         |    711 // | 
|         |    712 void HttpCacheUtil::GetHeaderFileName( | 
|         |    713     const TDesC& aBodyFileName, | 
|         |    714     TDes& aHeaderFileName ) | 
|         |    715     { | 
|         |    716     // body file name = foo | 
|         |    717     // header file name = foo.h | 
|         |    718     aHeaderFileName.Copy( aBodyFileName ); | 
|         |    719     // take the filename and append the new extension | 
|         |    720     aHeaderFileName.Append( KHttpCacheHeaderExt() ); | 
|         |    721     } | 
|         |    722  | 
|         |    723 // ----------------------------------------------------------------------------- | 
|         |    724 // HttpCacheUtil::AdjustExpirationTime | 
|         |    725 // | 
|         |    726 // ----------------------------------------------------------------------------- | 
|         |    727 // | 
|         |    728 void HttpCacheUtil::AdjustExpirationTimeL( | 
|         |    729     RHTTPHeaders& aResponseHeaders, | 
|         |    730     RStringPool& aStrP ) | 
|         |    731     { | 
|         |    732     const TStringTable& stringTable = RHTTPSession::GetTable(); | 
|         |    733     THTTPHdrVal hdrVal; | 
|         |    734  | 
|         |    735     if( aResponseHeaders.GetField( aStrP.StringF( HTTP::EExpires, stringTable ), 0, hdrVal ) == KErrNone ) | 
|         |    736         { | 
|         |    737         HttpCacheUtil::WriteLog( 0, _L( "adjust expiration time from" ) ); | 
|         |    738  | 
|         |    739         TTime expDate( hdrVal.DateTime() ); | 
|         |    740 #ifdef __CACHELOG__ | 
|         |    741         TBuf<50> dateString; | 
|         |    742         TTime expTime( hdrVal.DateTime() ); | 
|         |    743  | 
|         |    744         expTime.FormatL( dateString, KDateString ); | 
|         |    745         HttpCacheUtil::WriteLog( 0, dateString ); | 
|         |    746 #endif // __CACHELOG__ | 
|         |    747         // double it | 
|         |    748         TTimeIntervalMinutes minutes; | 
|         |    749         TTimeIntervalHours hours; | 
|         |    750         TTime now; | 
|         |    751         now.UniversalTime(); | 
|         |    752  | 
|         |    753         if( expDate.MinutesFrom( now, minutes ) == KErrNone ) | 
|         |    754             { | 
|         |    755 #ifdef __CACHELOG__ | 
|         |    756         // | 
|         |    757         now.FormatL( dateString, KDateString ); | 
|         |    758         HttpCacheUtil::WriteLog( 0, _L( "current time" ) ); | 
|         |    759         HttpCacheUtil::WriteLog( 0, dateString ); | 
|         |    760         // | 
|         |    761         now.FormatL( dateString, KDateString ); | 
|         |    762         HttpCacheUtil::WriteLog( 0, _L( "expires in (minutes)" ), minutes.Int() ); | 
|         |    763 #endif // __CACHELOG__ | 
|         |    764             // | 
|         |    765             expDate+=minutes; | 
|         |    766             } | 
|         |    767         // minutes owerflow? take hours instead | 
|         |    768         else if( expDate.HoursFrom( now, hours ) == KErrNone ) | 
|         |    769             { | 
|         |    770             expDate+=hours; | 
|         |    771             } | 
|         |    772         else | 
|         |    773             { | 
|         |    774             // last resort | 
|         |    775             TTimeIntervalDays days( expDate.DaysFrom( now ) ); | 
|         |    776             expDate+=days; | 
|         |    777             } | 
|         |    778         // set new date on the response header | 
|         |    779         aResponseHeaders.RemoveField( aStrP.StringF( HTTP::EExpires, stringTable ) ); | 
|         |    780         // add it | 
|         |    781         hdrVal.SetDateTime( expDate.DateTime() ); | 
|         |    782 #ifdef __CACHELOG__ | 
|         |    783         HttpCacheUtil::WriteLog( 0, _L( "to" ) ); | 
|         |    784         // | 
|         |    785         TTime newExptime( hdrVal.DateTime() ); | 
|         |    786         newExptime.FormatL( dateString, KDateString ); | 
|         |    787         HttpCacheUtil::WriteLog( 0, dateString ); | 
|         |    788  | 
|         |    789         TTimeIntervalMinutes min; | 
|         |    790  | 
|         |    791         newExptime.MinutesFrom( now, min ); | 
|         |    792  | 
|         |    793         HttpCacheUtil::WriteLog( 0, _L( "now it expires in (minutes)" ), min.Int() ); | 
|         |    794 #endif // __CACHELOG__ | 
|         |    795         aResponseHeaders.SetFieldL( aStrP.StringF( HTTP::EExpires, stringTable ), hdrVal ); | 
|         |    796         } | 
|         |    797     } | 
|         |    798  | 
|         |    799 // ----------------------------------------------------------------------------- | 
|         |    800 // HttpCacheUtil::CacheNeedsUpdateL | 
|         |    801 // | 
|         |    802 // ----------------------------------------------------------------------------- | 
|         |    803 // | 
|         |    804 TBool HttpCacheUtil::CacheNeedsUpdateL( | 
|         |    805     RHTTPHeaders& aResponseHeaders, | 
|         |    806     const TDesC8& aCachedHeadersStr, | 
|         |    807     RStringPool& aStrP ) | 
|         |    808     { | 
|         |    809     HBufC8* valueStr; | 
|         |    810     TTime cachedDate( 0 ); | 
|         |    811     TTime responseDate( 0 ); | 
|         |    812     TTime cachedLastModified( 0 ); | 
|         |    813     TTime responseLastModified( 0 ); | 
|         |    814     RStringF cachedETag; | 
|         |    815     RStringF responseETag; | 
|         |    816     RStringF fieldName; | 
|         |    817     TInternetDate value; | 
|         |    818     THTTPHdrVal hdrValue; | 
|         |    819     TBool eTag( EFalse ); | 
|         |    820     TBool eLastModified( EFalse ); | 
|         |    821     TBool eDate( EFalse ); | 
|         |    822     TInt status; | 
|         |    823     TBool update( ETrue ); | 
|         |    824  | 
|         |    825      // date | 
|         |    826     fieldName = aStrP.StringF( HTTP::EDate, RHTTPSession::GetTable() ); | 
|         |    827     // new | 
|         |    828     status = aResponseHeaders.GetField( fieldName, 0, hdrValue ); | 
|         |    829     if( status == KErrNone ) | 
|         |    830         { | 
|         |    831         responseDate = TTime( hdrValue.DateTime() ); | 
|         |    832         // orig | 
|         |    833         valueStr = HttpCacheUtil::HeaderFieldFromBufferLC( aCachedHeadersStr, fieldName.DesC() ); | 
|         |    834         if( valueStr ) | 
|         |    835             { | 
|         |    836             eDate = ETrue; | 
|         |    837             value.SetDateL( valueStr->Des() ); | 
|         |    838             cachedDate = TTime( value.DateTime() ); | 
|         |    839             CleanupStack::PopAndDestroy(); // valueStr | 
|         |    840             } | 
|         |    841         } | 
|         |    842  | 
|         |    843  | 
|         |    844     // last modified | 
|         |    845     fieldName = aStrP.StringF( HTTP::ELastModified, RHTTPSession::GetTable() ); | 
|         |    846     // new | 
|         |    847     status = aResponseHeaders.GetField( fieldName, 0, hdrValue ); | 
|         |    848     if( status == KErrNone ) | 
|         |    849         { | 
|         |    850         responseLastModified = TTime( hdrValue.DateTime() ); | 
|         |    851         // orig | 
|         |    852         valueStr = HttpCacheUtil::HeaderFieldFromBufferLC( aCachedHeadersStr, fieldName.DesC() ); | 
|         |    853         if( valueStr ) | 
|         |    854             { | 
|         |    855             eLastModified = ETrue; | 
|         |    856             value.SetDateL( valueStr->Des() ); | 
|         |    857             cachedLastModified  = TTime( value.DateTime() ); | 
|         |    858             CleanupStack::PopAndDestroy(); // valueStr | 
|         |    859             } | 
|         |    860         } | 
|         |    861  | 
|         |    862     // Etag | 
|         |    863     fieldName = aStrP.StringF( HTTP::EETag, RHTTPSession::GetTable() ); | 
|         |    864     // new | 
|         |    865     status = aResponseHeaders.GetField( fieldName, 0, hdrValue ); | 
|         |    866     if( status == KErrNone ) | 
|         |    867         { | 
|         |    868         responseETag = hdrValue.StrF(); | 
|         |    869         // orig | 
|         |    870         valueStr = HttpCacheUtil::HeaderFieldFromBufferLC( aCachedHeadersStr, fieldName.DesC() ); | 
|         |    871         if( valueStr ) | 
|         |    872             { | 
|         |    873             TRAP( status, cachedETag = aStrP.OpenFStringL( valueStr->Des() ) ); | 
|         |    874             CleanupStack::PopAndDestroy(); // valueStr | 
|         |    875             eTag = ( status == KErrNone ); | 
|         |    876             // | 
|         |    877             if( eTag ) | 
|         |    878                 { | 
|         |    879                 CleanupClosePushL( cachedETag ); | 
|         |    880                 } | 
|         |    881             } | 
|         |    882         } | 
|         |    883  | 
|         |    884     // If the entry's date is greater than the responses's date, | 
|         |    885     // ignore the response. | 
|         |    886     if( eDate && cachedDate > responseDate ) | 
|         |    887         { | 
|         |    888         update  = EFalse; | 
|         |    889         } | 
|         |    890     // If the entry's ETag does not equal the responses's ETag, | 
|         |    891     // replace the cached entry with the response. | 
|         |    892     else if( eTag && cachedETag != responseETag ) | 
|         |    893         { | 
|         |    894         update  = ETrue; | 
|         |    895         } | 
|         |    896     // If the entry's lastMod is greater than the responses's lastMod, | 
|         |    897     // ignore the response. | 
|         |    898     else if( eLastModified && cachedLastModified > responseLastModified ) | 
|         |    899         { | 
|         |    900         update  = EFalse; | 
|         |    901         } | 
|         |    902     // If the entry's lastMod is equal to the responses's lastMod, | 
|         |    903     // update the cached headers with the new response headers. | 
|         |    904     else if( eLastModified && cachedLastModified == responseLastModified ) | 
|         |    905         { | 
|         |    906         update  = ETrue; | 
|         |    907         } | 
|         |    908     // If the entry's lastMod is less than the responses's lastMod, | 
|         |    909     // replace the cached entry with the response. | 
|         |    910     else if( eLastModified && cachedLastModified < responseLastModified ) | 
|         |    911         { | 
|         |    912         update  = ETrue; | 
|         |    913         } | 
|         |    914     else | 
|         |    915         { | 
|         |    916         // If we get here the headers need to be replaced | 
|         |    917         update  = ETrue; | 
|         |    918         } | 
|         |    919     // | 
|         |    920     if( eTag ) | 
|         |    921         { | 
|         |    922         CleanupStack::PopAndDestroy(); // cachedETag | 
|         |    923         } | 
|         |    924     return update; | 
|         |    925     } | 
|         |    926  | 
|         |    927 // ----------------------------------------------------------------------------- | 
|         |    928 // HttpCacheUtil::IsCacheable | 
|         |    929 // | 
|         |    930 // ----------------------------------------------------------------------------- | 
|         |    931 // | 
|         |    932 TBool HttpCacheUtil::IsCacheable( | 
|         |    933     RHTTPTransaction& aTrans, | 
|         |    934     TUint aMaxSize, | 
|         |    935     TBool& aProtectedEntry ) | 
|         |    936     { | 
|         |    937     TBool isCacheable( ETrue ); | 
|         |    938     TBool hasExplicitCache( EFalse ); | 
|         |    939     TInt64 maxAge; | 
|         |    940     TBool noCache; | 
|         |    941     TBool noStore; | 
|         |    942     TTime now; | 
|         |    943     TTime expires; | 
|         |    944     RStringF fieldName; | 
|         |    945     THTTPHdrVal expiresVal; | 
|         |    946     TInt err; | 
|         |    947     RStringPool strP = aTrans.Session().StringPool(); | 
|         |    948     RHTTPHeaders respHeaders = aTrans.Response().GetHeaderCollection(); | 
|         |    949  | 
|         |    950     // not protected by default | 
|         |    951     aProtectedEntry = EFalse; | 
|         |    952     // 1. do not cache sesnitive content (DRM) | 
|         |    953     // 2. do not cache content bigger than the cache | 
|         |    954     // 3. check if the content is protected | 
|         |    955     // 4. check normal cache directives | 
|         |    956  | 
|         |    957     // init the field name | 
|         |    958     THTTPHdrVal contType; | 
|         |    959     fieldName = strP.StringF( HTTP::EContentType, RHTTPSession::GetTable() ); | 
|         |    960  | 
|         |    961     // check if this is a noncacheable content type | 
|         |    962     if( respHeaders.GetField( fieldName, 0, contType ) == KErrNone && | 
|         |    963         contType.StrF() == strP.StringF( HttpFilterCommonStringsExt::EApplicationVndOmaDrm, | 
|         |    964         HttpFilterCommonStringsExt::GetTable() ) ) | 
|         |    965         { | 
|         |    966         HttpCacheUtil::WriteLog( 0, _L( "sensitive content. do not cache" ) ); | 
|         |    967         // drm == nocache | 
|         |    968         isCacheable = EFalse; | 
|         |    969         } | 
|         |    970     else | 
|         |    971         { | 
|         |    972         // check if the content is bigger than the cache | 
|         |    973         THTTPHdrVal contLen; | 
|         |    974         fieldName = strP.StringF( HTTP::EContentLength, RHTTPSession::GetTable() ); | 
|         |    975  | 
|         |    976         if( respHeaders.GetField( fieldName, 0, contLen ) != KErrNotFound && | 
|         |    977             ( contLen.Type() == THTTPHdrVal::KTIntVal && contLen.Int() > aMaxSize ) ) | 
|         |    978             { | 
|         |    979             HttpCacheUtil::WriteLog( 0, _L( "oversized content. do not cache" ) ); | 
|         |    980             // oversized content | 
|         |    981             return EFalse; | 
|         |    982             } | 
|         |    983         // check if this is a proteced entry | 
|         |    984         aProtectedEntry = ProtectedEntry( respHeaders, strP ); | 
|         |    985         // check various cache controls | 
|         |    986         if( GetCacheControls( respHeaders, &maxAge, NULL, NULL, NULL, | 
|         |    987             &noCache, &noStore, strP ) == KErrNone ) | 
|         |    988             { | 
|         |    989             // There are several header "conditions" that make a resource | 
|         |    990             // non-cachable.  Reject if they are present. | 
|         |    991             // | 
|         |    992             // If no-cache or no-store directives exist -> don't cache. | 
|         |    993             if( noCache || noStore ) | 
|         |    994                 { | 
|         |    995                 HttpCacheUtil::WriteLog( 0, _L( "no cache/no store header. do not cache" ) ); | 
|         |    996                 // no protection on this entry | 
|         |    997                 aProtectedEntry = EFalse; | 
|         |    998                 return EFalse; | 
|         |    999                 } | 
|         |   1000             // Get the current time | 
|         |   1001             now.UniversalTime(); | 
|         |   1002  | 
|         |   1003             // Get the expires from the respHeaders | 
|         |   1004             fieldName = strP.StringF( HTTP::EExpires, RHTTPSession::GetTable() ); | 
|         |   1005             err = respHeaders.GetField( fieldName, 0, expiresVal ); | 
|         |   1006             if( err == KErrNone ) | 
|         |   1007                 { | 
|         |   1008                 expires = TTime( expiresVal.DateTime() ); | 
|         |   1009                 } | 
|         |   1010             else | 
|         |   1011                 { | 
|         |   1012                 expires = now; | 
|         |   1013                 } | 
|         |   1014              | 
|         |   1015             // if past-expire date do not cache. According to RFC2616, section 13.2.4/14.9.3, | 
|         |   1016             // if maxage is present, then ignore expires | 
|         |   1017             if (!maxAge && now > expires) | 
|         |   1018                 { | 
|         |   1019                 return EFalse; | 
|         |   1020                 } | 
|         |   1021              | 
|         |   1022             if( err == KErrNone || maxAge > 0 ) | 
|         |   1023                 { | 
|         |   1024                 hasExplicitCache = ETrue; | 
|         |   1025                 } | 
|         |   1026             // Reject if the http status code doesn't equal 200, 304, 301, 410. | 
|         |   1027             // Note: We accept status codes, 307, 302 if some cache | 
|         |   1028             //       control directives exist. | 
|         |   1029             switch( aTrans.Response().StatusCode() ) | 
|         |   1030                 { | 
|         |   1031                 case HTTPStatus::EOk: | 
|         |   1032                 case HTTPStatus::ENotModified: | 
|         |   1033                 case HTTPStatus::EMovedPermanently: | 
|         |   1034                 case HTTPStatus::EGone: | 
|         |   1035                     { | 
|         |   1036                     break; | 
|         |   1037                     } | 
|         |   1038                 case HTTPStatus::EFound: | 
|         |   1039                 case HTTPStatus::ETemporaryRedirect: | 
|         |   1040                     { | 
|         |   1041                     if( !hasExplicitCache ) | 
|         |   1042                         { | 
|         |   1043                         isCacheable = EFalse; | 
|         |   1044                         } | 
|         |   1045                     break; | 
|         |   1046                     } | 
|         |   1047                 default: | 
|         |   1048                     { | 
|         |   1049                     isCacheable = EFalse; | 
|         |   1050                     break; | 
|         |   1051                     } | 
|         |   1052                 } | 
|         |   1053  | 
|         |   1054             // Check method specific conditions. | 
|         |   1055             switch( HttpCacheUtil::MethodFromStr( aTrans.Request().Method(), strP ) ) | 
|         |   1056                 { | 
|         |   1057                 case EMethodGet: | 
|         |   1058                     { | 
|         |   1059                     // Reject if the url contains a "query" part unless there | 
|         |   1060                     // are caching directives. | 
|         |   1061                     TBool isQuery; | 
|         |   1062                     isQuery = aTrans.Request().URI().IsPresent( EUriQuery ); | 
|         |   1063  | 
|         |   1064                     if( isQuery && !hasExplicitCache ) | 
|         |   1065                         { | 
|         |   1066                         isCacheable = EFalse; | 
|         |   1067                         } | 
|         |   1068                     break; | 
|         |   1069                     } | 
|         |   1070                 case EMethodPost: | 
|         |   1071                     { | 
|         |   1072                     // Reject unless there are caching directives | 
|         |   1073                     if( !hasExplicitCache ) | 
|         |   1074                         { | 
|         |   1075                         isCacheable = EFalse; | 
|         |   1076                         } | 
|         |   1077                     break; | 
|         |   1078                     } | 
|         |   1079                 case EMethodHead: | 
|         |   1080                     { | 
|         |   1081                     // Don't cache Head responses...we don't need to, and the | 
|         |   1082                     // cache implementation can't currently handle it anyway. | 
|         |   1083                     // So just fall through to the default case. | 
|         |   1084                     // Reject all other methods | 
|         |   1085                     } | 
|         |   1086                 default: | 
|         |   1087                     { | 
|         |   1088                     isCacheable = EFalse; | 
|         |   1089                     break; | 
|         |   1090                     } | 
|         |   1091                 } | 
|         |   1092             } | 
|         |   1093         } | 
|         |   1094     return isCacheable; | 
|         |   1095     } | 
|         |   1096  | 
|         |   1097 // ----------------------------------------------------------------------------- | 
|         |   1098 // HttpCacheUtil::WriteLog | 
|         |   1099 // | 
|         |   1100 // ----------------------------------------------------------------------------- | 
|         |   1101 // | 
|         |   1102 void HttpCacheUtil::WriteLog( | 
|         |   1103     TInt aLogLevel, | 
|         |   1104     TPtrC aBuf, | 
|         |   1105     TInt aAny ) | 
|         |   1106     { | 
|         |   1107 #ifdef __CACHELOG__ | 
|         |   1108     TBool log( aLogLevel <= KCurrentLogLevel ); | 
|         |   1109     TPtrC fileName( KHttpCacheGeneralFileName ); | 
|         |   1110  | 
|         |   1111     if( aLogLevel == 1 ) | 
|         |   1112         { | 
|         |   1113         // hash | 
|         |   1114         fileName.Set( KHttpCacheHashFileName ); | 
|         |   1115         log = ETrue; | 
|         |   1116         } | 
|         |   1117     if( log ) | 
|         |   1118         { | 
|         |   1119         if( aAny != 0xffff ) | 
|         |   1120             { | 
|         |   1121             RFileLogger::WriteFormat(_L("Browser"), fileName, EFileLoggingModeAppend, | 
|         |   1122                     _L("%S %d"), &aBuf, aAny ); | 
|         |   1123             } | 
|         |   1124         else | 
|         |   1125             { | 
|         |   1126             RFileLogger::WriteFormat(_L("Browser"), fileName, EFileLoggingModeAppend, | 
|         |   1127                     _L("%S"), &aBuf ); | 
|         |   1128             } | 
|         |   1129         } | 
|         |   1130 #else // __CACHELOG__ | 
|         |   1131     (void)aLogLevel; | 
|         |   1132     (void)aBuf; | 
|         |   1133     (void)aAny; | 
|         |   1134 #endif // __CACHELOG__ | 
|         |   1135     } | 
|         |   1136  | 
|         |   1137 // ----------------------------------------------------------------------------- | 
|         |   1138 // HttpCacheUtil::WriteUrlToLog | 
|         |   1139 // | 
|         |   1140 // Get the freshness of the "entry". | 
|         |   1141 // | 
|         |   1142 // ----------------------------------------------------------------------------- | 
|         |   1143 // | 
|         |   1144 void HttpCacheUtil::WriteUrlToLog( | 
|         |   1145     TInt aLogLevel, | 
|         |   1146     const TDesC8& aUrl, | 
|         |   1147     TInt aAny ) | 
|         |   1148     { | 
|         |   1149 #ifdef __CACHELOG__ | 
|         |   1150     HBufC* tmp = HBufC::New( aUrl.Length() ); | 
|         |   1151     if( tmp ) | 
|         |   1152         { | 
|         |   1153         TPtr tmpPtr( tmp->Des() ); | 
|         |   1154         tmpPtr.Copy( aUrl ); | 
|         |   1155         HttpCacheUtil::WriteLog( aLogLevel, tmpPtr, aAny ); | 
|         |   1156         delete tmp; | 
|         |   1157         } | 
|         |   1158 #else // __CACHELOG__ | 
|         |   1159     (void)aLogLevel; | 
|         |   1160     (void)aUrl; | 
|         |   1161     (void)aAny; | 
|         |   1162 #endif // __CACHELOG__ | 
|         |   1163     } | 
|         |   1164  | 
|         |   1165 // ----------------------------------------------------------------------------- | 
|         |   1166 // HttpCacheUtil::WriteUrlToLog | 
|         |   1167 // | 
|         |   1168 // Get the freshness of the "entry". | 
|         |   1169 // | 
|         |   1170 // ----------------------------------------------------------------------------- | 
|         |   1171 // | 
|         |   1172 void HttpCacheUtil::WriteUrlToLog( | 
|         |   1173     TInt aLogLevel, | 
|         |   1174     const TDesC& aTxt, | 
|         |   1175     const TDesC8& aUrl, | 
|         |   1176     TInt aAny ) | 
|         |   1177     { | 
|         |   1178 #ifdef __CACHELOG__ | 
|         |   1179     TBool log( aLogLevel <= KCurrentLogLevel ); | 
|         |   1180     TPtrC fileName( KHttpCacheGeneralFileName ); | 
|         |   1181  | 
|         |   1182     if( aLogLevel == 1 ) | 
|         |   1183         { | 
|         |   1184         // hash | 
|         |   1185         fileName.Set( KHttpCacheHashFileName ); | 
|         |   1186         log = ETrue; | 
|         |   1187         } | 
|         |   1188     if( log ) | 
|         |   1189         {    // | 
|         |   1190         HBufC* tmp = HBufC::New( aUrl.Length() ); | 
|         |   1191         if( tmp ) | 
|         |   1192             { | 
|         |   1193             TPtr tmpPtr( tmp->Des() ); | 
|         |   1194             tmpPtr.Copy( aUrl ); | 
|         |   1195             if( aAny != 0xffff ) | 
|         |   1196                 { | 
|         |   1197                 RFileLogger::WriteFormat( _L("Browser"), fileName, EFileLoggingModeAppend, | 
|         |   1198                         _L("%S %S %d"), &aTxt, &tmpPtr, aAny ); | 
|         |   1199                 } | 
|         |   1200             else | 
|         |   1201                 { | 
|         |   1202                 RFileLogger::WriteFormat(_L("Browser"), fileName, EFileLoggingModeAppend, | 
|         |   1203                         _L("%S %S"), &aTxt, &tmpPtr ); | 
|         |   1204                 } | 
|         |   1205             delete tmp; | 
|         |   1206             } | 
|         |   1207         } | 
|         |   1208 #else // __CACHELOG__ | 
|         |   1209     (void)aLogLevel; | 
|         |   1210     (void)aTxt; | 
|         |   1211     (void)aUrl; | 
|         |   1212     (void)aAny; | 
|         |   1213 #endif // __CACHELOG__ | 
|         |   1214     } | 
|         |   1215  | 
|         |   1216 // ----------------------------------------------------------------------------- | 
|         |   1217 // HttpCacheUtil::GenerateNameLC | 
|         |   1218 // Given a URL, generates fully qualified Symbian path for storing HTTP response.  | 
|         |   1219 // The format is <cache base dir> + <subdirectory> + <file name>.  | 
|         |   1220 // Caller must free the returned HBufC* when done.  | 
|         |   1221 // ----------------------------------------------------------------------------- | 
|         |   1222 HBufC* HttpCacheUtil::GenerateNameLC( | 
|         |   1223         const TDesC8& aUrl, const TDesC& aBaseDir) | 
|         |   1224         { | 
|         |   1225  | 
|         |   1226     TUint32 crc (0); | 
|         |   1227  | 
|         |   1228     //use the entire URL for CRC calculation: maximizes source entropy/avoids collisions | 
|         |   1229     Mem::Crc32(crc, aUrl.Ptr(), aUrl.Size());  | 
|         |   1230     TUint32 nibble (crc & (KCacheSubdirCount-1)); // extract least significant 4 bits (nibble) for subdirectory | 
|         |   1231  | 
|         |   1232     HBufC* fileName = HBufC::NewLC( KMaxPath ); // e.g E\078AFEFE | 
|         |   1233     _LIT(KFormat,"%S%x%c%08x"); // Note the %08x : a 32-bit value can represented as 0xFFFFFFFF  | 
|         |   1234     fileName->Des().Format(KFormat, &aBaseDir, nibble, KPathDelimiter, crc); | 
|         |   1235     return fileName; | 
|         |   1236  | 
|         |   1237     } | 
|         |   1238  | 
|         |   1239  | 
|         |   1240 // ----------------------------------------------------------------------------- | 
|         |   1241 // HttpCacheUtil::Freshness | 
|         |   1242 // | 
|         |   1243 // Get the freshness of the "entry". | 
|         |   1244 // | 
|         |   1245 // ----------------------------------------------------------------------------- | 
|         |   1246 // | 
|         |   1247 TInt64 HttpCacheUtil::Freshness( | 
|         |   1248     const RHTTPHeaders& aHeaders, | 
|         |   1249     TTime aResponseTime, | 
|         |   1250     RStringPool aStrP ) | 
|         |   1251     { | 
|         |   1252     TInt status( KErrNone ); | 
|         |   1253     TInt64 maxAge; | 
|         |   1254     TTime expires; | 
|         |   1255     TTime lastModified( 0 ); | 
|         |   1256     TTime date; | 
|         |   1257     RStringF fieldName; | 
|         |   1258     THTTPHdrVal hdrValue; | 
|         |   1259     TInt err; | 
|         |   1260     TInt64 freshness( 0 ); | 
|         |   1261  | 
|         |   1262     // Get the date from the headers | 
|         |   1263     fieldName = aStrP.StringF( HTTP::EDate, RHTTPSession::GetTable() ); | 
|         |   1264     err = aHeaders.GetField( fieldName, 0, hdrValue ); | 
|         |   1265     if( err == KErrNotFound || hdrValue.Type() != THTTPHdrVal::KDateVal ) | 
|         |   1266         { | 
|         |   1267         date = aResponseTime; | 
|         |   1268         } | 
|         |   1269     else | 
|         |   1270         { | 
|         |   1271         date = TTime( hdrValue.DateTime() ); | 
|         |   1272         } | 
|         |   1273  | 
|         |   1274     // Get useful cache-control directives | 
|         |   1275     status = GetCacheControls( aHeaders, &maxAge, NULL, NULL, NULL, NULL, NULL, aStrP ); | 
|         |   1276     if( status == KErrNone ) | 
|         |   1277         { | 
|         |   1278         // max-age is in delta-seconds. Convert it to micro seconds. | 
|         |   1279         // All our calculations are in micro-seconds | 
|         |   1280         // If maxAge is present, use it | 
|         |   1281         if( maxAge != -1 ) | 
|         |   1282             { | 
|         |   1283             freshness = maxAge * 1000 * 1000; | 
|         |   1284  | 
|         |   1285             return freshness; | 
|         |   1286             } | 
|         |   1287  | 
|         |   1288         // Get the expires from the headers | 
|         |   1289         fieldName = aStrP.StringF( HTTP::EExpires, RHTTPSession::GetTable() ); | 
|         |   1290         err = aHeaders.GetField( fieldName, 0, hdrValue ); | 
|         |   1291         if( err == KErrNotFound || hdrValue.Type() != THTTPHdrVal::KDateVal ) | 
|         |   1292             { | 
|         |   1293             expires = 0; | 
|         |   1294             } | 
|         |   1295         else | 
|         |   1296             { | 
|         |   1297             expires = TTime( hdrValue.DateTime() ); | 
|         |   1298             } | 
|         |   1299  | 
|         |   1300         // Otherwise, if the expires is present use it | 
|         |   1301         if( err != KErrNotFound ) | 
|         |   1302             { | 
|         |   1303             freshness = expires.Int64() - date.Int64(); | 
|         |   1304             return freshness; | 
|         |   1305             } | 
|         |   1306  | 
|         |   1307         // Get the last modified from the headers | 
|         |   1308         fieldName = aStrP.StringF( HTTP::ELastModified, RHTTPSession::GetTable() ); | 
|         |   1309         err = aHeaders.GetField( fieldName, 0, hdrValue ); | 
|         |   1310         if( err == KErrNotFound || hdrValue.Type() != THTTPHdrVal::KDateVal ) | 
|         |   1311             { | 
|         |   1312             hdrValue = 0; | 
|         |   1313             } | 
|         |   1314         else | 
|         |   1315             { | 
|         |   1316             lastModified = TTime( hdrValue.DateTime() ); | 
|         |   1317             } | 
|         |   1318  | 
|         |   1319         // Otherwise, if last-modified is present use it | 
|         |   1320         if( err != KErrNotFound ) | 
|         |   1321             { | 
|         |   1322             if( aResponseTime > lastModified ) | 
|         |   1323                 { | 
|         |   1324                 freshness = aResponseTime.Int64() - lastModified.Int64(); | 
|         |   1325                 freshness += ((TInt64)( freshness * 0.10 ) ); | 
|         |   1326                 } | 
|         |   1327             return freshness; | 
|         |   1328             } | 
|         |   1329         // If it get here then we have no way to determine if it is | 
|         |   1330         // fresh.  So we set freshness to zero, which will most likely | 
|         |   1331         // cause the resource to be validated. | 
|         |   1332         freshness = 0; | 
|         |   1333         } | 
|         |   1334     return freshness; | 
|         |   1335     } | 
|         |   1336  | 
|         |   1337 // ----------------------------------------------------------------------------- | 
|         |   1338 // HttpCacheUtil::Age | 
|         |   1339 // | 
|         |   1340 // Get the age of the "entry". | 
|         |   1341 // | 
|         |   1342 // ----------------------------------------------------------------------------- | 
|         |   1343 // | 
|         |   1344 TInt64 HttpCacheUtil::Age( | 
|         |   1345     const RHTTPHeaders& aHeaders, | 
|         |   1346     TTime aRequestTime, | 
|         |   1347     TTime aResponseTime, | 
|         |   1348     RStringPool aStrP ) | 
|         |   1349     { | 
|         |   1350     TTime now; | 
|         |   1351     TDateTime date; | 
|         |   1352     TTime time; | 
|         |   1353  | 
|         |   1354     // Int64 timeinsec; | 
|         |   1355     TInt64 correctedRecvAge; | 
|         |   1356     TInt64 apparentAge; | 
|         |   1357     TInt64 responseDelay; | 
|         |   1358     TInt64 correctedInitialAge; | 
|         |   1359     TInt64 residentTime; | 
|         |   1360     TInt64 currentAge; | 
|         |   1361     TInt64 age; | 
|         |   1362  | 
|         |   1363  | 
|         |   1364     RStringF fieldName; | 
|         |   1365     THTTPHdrVal dateValue; | 
|         |   1366     TInt err; | 
|         |   1367  | 
|         |   1368     // Get the current time. All internet dates are GMT | 
|         |   1369     now.UniversalTime(); | 
|         |   1370 #ifdef __CACHELOG__ | 
|         |   1371     TBuf<50> dateString; | 
|         |   1372     // | 
|         |   1373     now.FormatL( dateString, KDateString ); | 
|         |   1374     HttpCacheUtil::WriteLog( 0, _L( "current time" ) ); | 
|         |   1375     HttpCacheUtil::WriteLog( 0, dateString ); | 
|         |   1376 #endif // __CACHELOG__ | 
|         |   1377  | 
|         |   1378     // The aRequestTime is same as that of headers time. | 
|         |   1379  | 
|         |   1380     time = aRequestTime; | 
|         |   1381  | 
|         |   1382     // Do a sanity check | 
|         |   1383     if( aRequestTime > now ) | 
|         |   1384         { | 
|         |   1385         aRequestTime = now; | 
|         |   1386         } | 
|         |   1387     if( aResponseTime > now ) | 
|         |   1388         { | 
|         |   1389         aResponseTime = now; | 
|         |   1390         } | 
|         |   1391     if( aRequestTime > aResponseTime ) | 
|         |   1392         { | 
|         |   1393         aRequestTime = aResponseTime; | 
|         |   1394         } | 
|         |   1395     if( time > aResponseTime ) | 
|         |   1396         { | 
|         |   1397         time = aResponseTime; | 
|         |   1398         } | 
|         |   1399  | 
|         |   1400     // Get the age from the headers.  If age is missing it equals | 
|         |   1401     // 0, which is a safe value to use below. | 
|         |   1402     fieldName = aStrP.StringF( HTTP::EAge, RHTTPSession::GetTable() ); | 
|         |   1403     err = aHeaders.GetField( fieldName, 0, dateValue ); | 
|         |   1404     if( err == KErrNotFound ) | 
|         |   1405         { | 
|         |   1406         age = 0; | 
|         |   1407         } | 
|         |   1408     else | 
|         |   1409         { | 
|         |   1410         // Age should be in delta seconds | 
|         |   1411         if( dateValue.Type() == THTTPHdrVal::KTIntVal ) | 
|         |   1412             { | 
|         |   1413             age = dateValue; | 
|         |   1414             } | 
|         |   1415         else | 
|         |   1416             { | 
|         |   1417             age = 0; | 
|         |   1418             } | 
|         |   1419         } | 
|         |   1420  | 
|         |   1421     // Get the "current" age | 
|         |   1422     apparentAge = Max( TInt64( 0 ), aResponseTime.Int64() - time.Int64() ); | 
|         |   1423     // The TTime::Int64() gives the time in micro seconds. And the age field is in | 
|         |   1424     // delta seconds. | 
|         |   1425     correctedRecvAge = Max( apparentAge, age * 1000 * 1000 ); | 
|         |   1426     responseDelay = aResponseTime.Int64() - aRequestTime.Int64(); | 
|         |   1427     correctedInitialAge = correctedRecvAge + responseDelay; | 
|         |   1428     residentTime = now.Int64() - aResponseTime.Int64(); | 
|         |   1429  | 
|         |   1430     currentAge = correctedInitialAge + residentTime; | 
|         |   1431  | 
|         |   1432     //the current age in micro seconds. | 
|         |   1433     return currentAge; | 
|         |   1434     } | 
|         |   1435  | 
|         |   1436 // ----------------------------------------------------------------------------- | 
|         |   1437 // HttpCacheUtil::GetCacheControls | 
|         |   1438 // | 
|         |   1439 // Description: Returns various cache controls. | 
|         |   1440 // | 
|         |   1441 // ----------------------------------------------------------------------------- | 
|         |   1442 // | 
|         |   1443 TInt HttpCacheUtil::GetCacheControls( | 
|         |   1444     const RHTTPHeaders& aHeaders, | 
|         |   1445     TInt64* aMaxAge, | 
|         |   1446     TInt64* aMinFresh, | 
|         |   1447     TInt64* aMaxStale, | 
|         |   1448     TBool* aMustRevalidate, | 
|         |   1449     TBool* aNoCache, | 
|         |   1450     TBool* aNoStore, | 
|         |   1451     RStringPool aStrP ) | 
|         |   1452     { | 
|         |   1453     TInt status( KErrNone ); | 
|         |   1454     TInt i; | 
|         |   1455     TInt cacheCount( 0 ); | 
|         |   1456     RStringF directive; | 
|         |   1457     TInt64 value; | 
|         |   1458     char* extraValues = NULL; | 
|         |   1459     RStringF fieldName; | 
|         |   1460  | 
|         |   1461  | 
|         |   1462     if( aMaxAge ) | 
|         |   1463         { | 
|         |   1464         *aMaxAge = -1; | 
|         |   1465         } | 
|         |   1466     if( aMinFresh ) | 
|         |   1467         { | 
|         |   1468         *aMinFresh = -1; | 
|         |   1469         } | 
|         |   1470     if( aMaxStale ) | 
|         |   1471         { | 
|         |   1472         *aMaxStale = -1; | 
|         |   1473         } | 
|         |   1474     if( aMustRevalidate ) | 
|         |   1475         { | 
|         |   1476         *aMustRevalidate = EFalse; | 
|         |   1477         } | 
|         |   1478     if( aNoCache ) | 
|         |   1479         { | 
|         |   1480         *aNoCache = EFalse; | 
|         |   1481         } | 
|         |   1482     if( aNoStore ) | 
|         |   1483         { | 
|         |   1484         *aNoStore = EFalse; | 
|         |   1485         } | 
|         |   1486  | 
|         |   1487     // init the field name | 
|         |   1488     fieldName = aStrP.StringF( HTTP::ECacheControl, RHTTPSession::GetTable() ); | 
|         |   1489     TRAP( status, cacheCount = aHeaders.FieldPartsL( fieldName ) ); | 
|         |   1490     if( status == KErrNone ) | 
|         |   1491         { | 
|         |   1492         for( i = 0; i < cacheCount; i++ ) | 
|         |   1493             { | 
|         |   1494             status = GetCacheControlDirective( aHeaders, i, directive, &value, &extraValues, aStrP ); | 
|         |   1495             if( status == KErrNone ) | 
|         |   1496                 { | 
|         |   1497                 if( directive == aStrP.StringF( HTTP::EMaxAge, RHTTPSession::GetTable() ) ) | 
|         |   1498                     { | 
|         |   1499                     if( aMaxAge ) | 
|         |   1500                         { | 
|         |   1501                         *aMaxAge = value; | 
|         |   1502                         } | 
|         |   1503                     } | 
|         |   1504                 else if( directive == aStrP.StringF( HTTP::EMinFresh, RHTTPSession::GetTable() ) ) | 
|         |   1505                     { | 
|         |   1506                     if( aMinFresh ) | 
|         |   1507                         { | 
|         |   1508                         *aMinFresh = value; | 
|         |   1509                         } | 
|         |   1510                     } | 
|         |   1511                 else if( directive == aStrP.StringF( HTTP::EMaxStale, RHTTPSession::GetTable() ) ) | 
|         |   1512                     { | 
|         |   1513                     if( aMaxStale ) | 
|         |   1514                         { | 
|         |   1515                         *aMaxStale = value; | 
|         |   1516                         } | 
|         |   1517                     } | 
|         |   1518                 else if( directive == aStrP.StringF( HTTP::EMustRevalidate, RHTTPSession::GetTable() ) ) | 
|         |   1519                     { | 
|         |   1520                     if( aMustRevalidate ) | 
|         |   1521                         { | 
|         |   1522                         *aMustRevalidate = ETrue; | 
|         |   1523                         } | 
|         |   1524                     } | 
|         |   1525                 else if( directive == aStrP.StringF( HTTP::ENoCache, RHTTPSession::GetTable() ) ) | 
|         |   1526                     { | 
|         |   1527                     if( aNoCache ) | 
|         |   1528                         { | 
|         |   1529                         *aNoCache = ETrue; | 
|         |   1530                         } | 
|         |   1531                     } | 
|         |   1532                 else if( directive == aStrP.StringF( HTTP::ENoStore, RHTTPSession::GetTable() ) ) | 
|         |   1533                     { | 
|         |   1534                     if( aNoStore ) | 
|         |   1535                         { | 
|         |   1536                         *aNoStore = ETrue; | 
|         |   1537                         } | 
|         |   1538                     } | 
|         |   1539                 directive.Close(); | 
|         |   1540                 // It ignores extraValues, just free it | 
|         |   1541                 User::Free( extraValues ); | 
|         |   1542                 extraValues = NULL; | 
|         |   1543                 } | 
|         |   1544             else | 
|         |   1545                 { | 
|         |   1546                 break; | 
|         |   1547                 } | 
|         |   1548             } | 
|         |   1549         } | 
|         |   1550     return status; | 
|         |   1551     } | 
|         |   1552  | 
|         |   1553 // ----------------------------------------------------------------------------- | 
|         |   1554 // HttpCacheUtil::GetCacheControlDirective | 
|         |   1555 // | 
|         |   1556 // ----------------------------------------------------------------------------- | 
|         |   1557 // | 
|         |   1558 TInt HttpCacheUtil::GetCacheControlDirective( | 
|         |   1559     const RHTTPHeaders& aHeaders, | 
|         |   1560     TInt aIndex, | 
|         |   1561     RStringF& aDirective, | 
|         |   1562     TInt64* aDirectiveValue, | 
|         |   1563     char** aExtraValue, | 
|         |   1564     RStringPool aStrP ) | 
|         |   1565     { | 
|         |   1566     RStringF fieldName; | 
|         |   1567     THTTPHdrVal hdrVal; | 
|         |   1568     TInt err; | 
|         |   1569  | 
|         |   1570     // Get the cache-control from the headers | 
|         |   1571     fieldName = aStrP.StringF( HTTP::ECacheControl, RHTTPSession::GetTable() ); | 
|         |   1572     aHeaders.GetField( fieldName, aIndex, hdrVal ); | 
|         |   1573  | 
|         |   1574     if( hdrVal.Type() == THTTPHdrVal::KStrVal || hdrVal.Type() == THTTPHdrVal::KStrFVal ) | 
|         |   1575         { | 
|         |   1576         RStringF cacheDir = hdrVal.StrF(); | 
|         |   1577  | 
|         |   1578         TInt endPos; | 
|         |   1579         _LIT8(KFind, "="); | 
|         |   1580  | 
|         |   1581         endPos = cacheDir.DesC().Find( KFind ); | 
|         |   1582         if( endPos != -1 ) | 
|         |   1583             { | 
|         |   1584             TRAP( err, aDirective = aStrP.OpenFStringL( cacheDir.DesC().Left( endPos ) ) ); | 
|         |   1585             if( err != KErrNone ) | 
|         |   1586                 { | 
|         |   1587                 return err; | 
|         |   1588                 } | 
|         |   1589             TPtrC8 value = cacheDir.DesC().Right( cacheDir.DesC().Length() - endPos - 1 ); | 
|         |   1590             err = ExtractCacheControlDirectiveValue( aStrP, aDirective, value, aDirectiveValue, aExtraValue ); | 
|         |   1591             if( err != KErrNone ) | 
|         |   1592                 { | 
|         |   1593                 aDirective.Close(); | 
|         |   1594                 return err; | 
|         |   1595                 } | 
|         |   1596             } | 
|         |   1597         else | 
|         |   1598             { | 
|         |   1599             aDirective = cacheDir.Copy(); | 
|         |   1600             // Directives which MUST have values; | 
|         |   1601             if( ( aDirective == aStrP.StringF( HTTP::EMaxAge, RHTTPSession::GetTable() ) ) || | 
|         |   1602                 ( aDirective == aStrP.StringF( HTTP::EMinFresh, RHTTPSession::GetTable() ) ) || | 
|         |   1603                 ( aDirective == aStrP.StringF( HTTP::ESMaxAge, RHTTPSession::GetTable() ) ) ) | 
|         |   1604                 { | 
|         |   1605                 aDirective.Close(); | 
|         |   1606                 return KErrGeneral; | 
|         |   1607                 } | 
|         |   1608             } | 
|         |   1609         } | 
|         |   1610     return KErrNone; | 
|         |   1611     } | 
|         |   1612  | 
|         |   1613 // ----------------------------------------------------------------------------- | 
|         |   1614 // HttpCacheUtil::ExtractCacheControlDirectiveValue | 
|         |   1615 // | 
|         |   1616 // ----------------------------------------------------------------------------- | 
|         |   1617 // | 
|         |   1618 TInt HttpCacheUtil::ExtractCacheControlDirectiveValue( | 
|         |   1619     RStringPool aStrP, | 
|         |   1620     RStringF& aDirective, | 
|         |   1621     TDesC8& aValue, | 
|         |   1622     TInt64* aDirectiveValue, | 
|         |   1623     char** aExtraValue ) | 
|         |   1624     { | 
|         |   1625     TInt status( KErrNone ); | 
|         |   1626     TInt temp; | 
|         |   1627     char* errorIfNull; | 
|         |   1628  | 
|         |   1629     *aDirectiveValue = -1; | 
|         |   1630     *aExtraValue = NULL; | 
|         |   1631     char* valuestr = (char*)User::Alloc( aValue.Length() + 1 ); | 
|         |   1632     if( !valuestr ) | 
|         |   1633         { | 
|         |   1634         return KErrNoMemory; | 
|         |   1635         } | 
|         |   1636     memcpy( valuestr, aValue.Ptr(), aValue.Length() ); | 
|         |   1637     valuestr[ aValue.Length() ] = '\0'; | 
|         |   1638  | 
|         |   1639  | 
|         |   1640     if( ( aDirective == aStrP.StringF( HTTP::EMaxAge, RHTTPSession::GetTable() ) ) || | 
|         |   1641         ( aDirective == aStrP.StringF( HTTP::EMinFresh, RHTTPSession::GetTable() ) ) || | 
|         |   1642         ( aDirective == aStrP.StringF( HTTP::ESMaxAge, RHTTPSession::GetTable() ) ) ) | 
|         |   1643         { | 
|         |   1644         // Cases with directiveValues | 
|         |   1645         temp = strtoul( valuestr, &errorIfNull, 10 ); | 
|         |   1646         if( !errorIfNull ) | 
|         |   1647             { | 
|         |   1648             status = KErrGeneral; | 
|         |   1649             } | 
|         |   1650         else | 
|         |   1651             { | 
|         |   1652             *aDirectiveValue = temp; | 
|         |   1653             } | 
|         |   1654         User::Free( valuestr ); | 
|         |   1655         return status; | 
|         |   1656         } | 
|         |   1657  | 
|         |   1658     if( ( aDirective == aStrP.StringF( HTTP::EMaxStale, RHTTPSession::GetTable() ) ) ) | 
|         |   1659         { | 
|         |   1660         // Cases with optional directiveValues | 
|         |   1661         temp = strtoul( valuestr, &errorIfNull, 10 ); | 
|         |   1662         if( errorIfNull ) | 
|         |   1663             { | 
|         |   1664             *aDirectiveValue = temp; | 
|         |   1665             } | 
|         |   1666         User::Free( valuestr ); | 
|         |   1667         return status; | 
|         |   1668         } | 
|         |   1669  | 
|         |   1670     if( ( aDirective == aStrP.StringF( HTTP::ENoCache, RHTTPSession::GetTable() ) ) || | 
|         |   1671         ( aDirective == aStrP.StringF( HTTP::EPrivate, RHTTPSession::GetTable() ) ) ) | 
|         |   1672         { | 
|         |   1673         *aExtraValue = valuestr; | 
|         |   1674         return status; | 
|         |   1675         } | 
|         |   1676     User::Free( valuestr ); | 
|         |   1677     return status; | 
|         |   1678     } | 
|         |   1679  | 
|         |   1680 //  End of File |