--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/httpfilters/httpfilteracceptheader/Src/HttpFilterAcceptHeader.cpp Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,591 @@
+/*
+* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: HTTP filter for handling dynamic accept headers
+*
+*/
+
+
+
+// INCLUDE FILES
+#include <http.h>
+
+#include <bldvariant.hrh>
+
+#include "FeatMgr.h"
+
+// User Includes
+#include "HttpFilterAcceptHeader.h"
+#include "httpfiltercommonstringsext.h"
+
+#include "HttpFilterAcceptHeaderVariant.hrh"
+#include <SysLangUtil.h>
+
+#include <centralrepository.h>
+#include <HttpFilterAcceptHeaderPrivateCRKeys.h>
+#include <BrowserUiSDKCRKeys.h>
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+_LIT8(KFieldSeparator, "\n");
+_LIT8(KCommaSeperator, ", ");
+_LIT8(KQHalfValue, ";q=0.5");
+_LIT8(KQWholeValue, ";q=1.0");
+
+// Initial number of MIME types. This is just for setting the granuality.
+const TUint8 KNumDefaultNumOfTypes = 20;
+
+// Initial size for mime type buffer.
+const TUint KSizeofMimeTypeBuffer = 512;
+
+// List of MIME types supported by the browser
+_LIT8(KBrowserMimeTypeList,"text/html,application/vnd.wap.xhtml+xml,application/xhtml+xml,text/css,multipart/mixed,text/vnd.wap.wml,application/vnd.wap.wmlc,application/vnd.wap.wmlscriptc");
+
+_LIT8( KStarSlashStar, "*/*" );
+
+_LIT8(KCssStr, "text/css" );
+
+_LIT8(KAppJavaScript, "application/x-javascript");
+
+_LIT8(KECMAScript, "text/ecmascript");
+
+_LIT8(KJavaScript, "text/javascript");
+
+// LOCAL FUNCTIONS
+
+// -----------------------------------------------------------------------------
+// PanicHttpFilter
+// Returns: void
+// -----------------------------------------------------------------------------
+//
+void PanicHttpFilter( TInt aErr = KErrUnknown )
+ {
+ User::Panic( _L( "HTTP FILTER ACCEPT HEADER" ), aErr );
+ }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::CHttpFilterAcceptHeader
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CHttpFilterAcceptHeader::CHttpFilterAcceptHeader( RHTTPSession* aSession ):
+ iSession( aSession )
+ {
+ __ASSERT_DEBUG( aSession != NULL, PanicHttpFilter( KErrArgument ) );
+ }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::ReadFeatureBitmaskL
+// Read feature bitmask into member variable
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAcceptHeader::ReadFeatureBitmaskL( )
+ {
+ //Create a new repository with KSDUidCacheManager
+ CRepository* repository = CRepository::NewL(KCRUidAcceptHeaderLV);
+ User::LeaveIfNull(repository);
+
+ //Read the setting for CacheEnabled
+ repository->Get(KAcceptHeaderLV, iFeatureBitmask);
+
+ //delete the repository
+ delete repository;
+ repository = NULL;
+ }
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::ConstructL
+// Epoc Constructor
+//-----------------------------------------------------------------------------
+//
+void CHttpFilterAcceptHeader::ConstructL()
+ {
+
+ iSession->StringPool().OpenL( HttpFilterCommonStringsExt::GetTable() );
+
+ iDataTypes = new ( ELeave ) CDataTypeArray( KNumDefaultNumOfTypes );
+
+ // Add hardcoded data types that the browser supports to the array
+ AddBrowserSupportedTypesL();
+
+ ReadFeatureBitmaskL();
+ // Try adding external data types from shared data
+ ReadMimeTypesL();
+
+ FeatureManager::InitializeLibL();
+ if (( iFeatureBitmask & KHttpAcceptMultipleAcceptLanguagesSupport))
+ { // Compose Multiple Languages String
+ ComposeMultipleLanguagesStringL();
+ }
+
+ iAcceptStr = iSession->StringPool().StringF(
+ HTTP::EAccept,
+ RHTTPSession::GetTable() );
+
+ iLoadTypeStr = iSession->StringPool().StringF(
+ HttpFilterCommonStringsExt::ELoadType,
+ HttpFilterCommonStringsExt::GetTable() );
+
+ iDone = iSession->StringPool().StringF(
+ HttpFilterCommonStringsExt::EAcceptHeadersDone,
+ HttpFilterCommonStringsExt::GetTable() );
+
+ // Register the filter. we are interested in transaction event
+ // ESubmit.
+ iSession->FilterCollection().AddFilterL( *this,
+ THTTPEvent::ESubmit,
+ RStringF(),
+ KAnyStatusCode,
+ EClientFilters,
+ iAcceptStr );
+ }
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+CHttpFilterAcceptHeader::~CHttpFilterAcceptHeader()
+ {
+ FeatureManager::UnInitializeLib();
+ delete iDataTypes;
+ }
+
+// Install filter
+CHttpFilterAcceptHeader* CHttpFilterAcceptHeader::InstallFilterL(
+ TAny* aSession )
+ {
+ __ASSERT_DEBUG( aSession != NULL, PanicHttpFilter() );
+ RHTTPSession* session = REINTERPRET_CAST( RHTTPSession*, aSession );
+ CHttpFilterAcceptHeader* filter =
+ new ( ELeave ) CHttpFilterAcceptHeader( session );
+ CleanupStack::PushL( filter );
+ filter->ConstructL();
+ CleanupStack::Pop();
+ return filter;
+ }
+
+void CHttpFilterAcceptHeader::MHFLoad( RHTTPSession, THTTPFilterHandle )
+ {
+ ++iLoadCount;
+ }
+
+void CHttpFilterAcceptHeader::MHFUnload(
+ RHTTPSession /*aSession*/,
+ THTTPFilterHandle /*aFilterHandler*/ )
+ {
+ __ASSERT_DEBUG( iLoadCount >= 0, PanicHttpFilter() );
+ if ( --iLoadCount )
+ {
+ return;
+ }
+
+ delete this;
+ }
+
+
+void CHttpFilterAcceptHeader::MHFRunL(
+ RHTTPTransaction aTransaction,
+ const THTTPEvent& aEvent )
+ {
+ switch (aEvent.iStatus)
+ {
+ case THTTPEvent::ESubmit:
+ AddHeadersL( aTransaction );
+ AddLanguageHeaderL( aTransaction );
+ break;
+ default:
+ break;
+ }
+ }
+
+TInt CHttpFilterAcceptHeader::MHFRunError(
+ TInt aError,
+ RHTTPTransaction /*aTransaction*/,
+ const THTTPEvent& /*aEvent*/ )
+ {
+ return aError;
+ }
+
+void CHttpFilterAcceptHeader::MHFSessionRunL(
+ const THTTPSessionEvent& /*aEvent*/ )
+ {}
+
+TInt CHttpFilterAcceptHeader::MHFSessionRunError(
+ TInt aError,
+ const THTTPSessionEvent& /*aEvent*/ )
+ {
+ return aError;
+ }
+
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::AddBrowserSupportedTypesL
+// Add hardcoded MIME types into the array.
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::AddBrowserSupportedTypesL()
+ {
+ HBufC8* buf8 = HBufC8::NewLC( KBrowserMimeTypeList.iTypeLength);
+ TPtr8 ptr8 = buf8->Des();
+ ptr8.Copy(KBrowserMimeTypeList);
+ ParseAndStoreMimeListL(ptr8);
+ CleanupStack::PopAndDestroy(); // buf8
+ }
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::ReadMimeTypesL
+// Query the supported MIME types from the shared data and store the result array.
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::ReadMimeTypesL()
+ {
+ TInt error = KErrNone;
+
+ //Create a new repository with KSDUidCacheManager
+ CRepository* repository = CRepository::NewL(KCRUidBrowser);
+ User::LeaveIfNull(repository);
+
+ if (error == KErrNone)
+ {
+ // Allocate wide buffer for data types
+ HBufC16* buf16 = HBufC16::NewLC( KSizeofMimeTypeBuffer );
+ TPtr16 ptr16 = buf16->Des();
+
+ // Read the data types from SharedData, increase the buffer
+ // if the initial size not enough.
+ do
+ {
+ // SharedData Key should be included from the variant.hrh when available
+ error = repository->Get(KBrowserNGMimeTypes, ptr16);
+ if (error == KErrNotFound || (ptr16.Length() < 3))
+ {
+ CleanupStack::PopAndDestroy(); // buf16
+ return;
+ }
+ if (error == KErrTooBig || error == KErrOverflow)
+ {
+ buf16->ReAllocL(ptr16.MaxLength() + KSizeofMimeTypeBuffer);
+ ptr16.Set(buf16->Des());
+ }
+ }
+ while (error != KErrNone);
+
+ delete repository;
+ repository = NULL;
+
+ // Allocate narrow buffer and copy data types there
+ HBufC8* buf8 = HBufC8::NewLC( buf16->Length() );
+ TPtr8 ptr8 = buf8->Des();
+ ptr8.Copy(ptr16);
+
+ // Clean up the list and store it to array
+ ParseAndStoreMimeListL( ptr8 );
+
+ CleanupStack::PopAndDestroy(2); // buf16, buf8
+ } //if
+ }
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::AddToArrayL
+// Store individual result to an array after some sanity checking
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::AddToArrayL( TPtr8& aPtr )
+ {
+ aPtr.Trim();
+ if ( aPtr.Length() > 3)
+ {
+ iDataTypes->AppendL(TDataType(aPtr));
+ }
+ }
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::ParseAndStoreMimeListL
+// Parse comma separate list of data types and store them.
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::ParseAndStoreMimeListL( TPtr8& aPtr )
+ {
+ TInt left = 0;
+ TInt right = 0;
+
+ if (aPtr.Length() == 0)
+ return;
+ // Start from left to right until no commas found
+ do
+ {
+ aPtr = aPtr.Mid(left, aPtr.Length() - left);
+ right = aPtr.LocateF(TChar(','));
+ if (right > 0 )
+ {
+ HBufC8* mimestr = HBufC8::NewLC(right);
+ TPtr8 ptr = mimestr->Des();
+ ptr = aPtr.Left(right);
+ AddToArrayL(ptr);
+ CleanupStack::PopAndDestroy(); // mimestr
+ }
+ left = right+1;
+ }
+ while ( right >= 0 );
+
+ // Handle remaining or the only part
+ HBufC8* mimestr = HBufC8::NewLC(aPtr.Length());
+ TPtr8 ptr = mimestr->Des();
+ ptr.Copy(aPtr);
+ AddToArrayL(ptr);
+ CleanupStack::PopAndDestroy(); // mimestr
+ }
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::AddAllHeadersL
+// Add all MIME types from the array to the headers
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::AddAllHeadersL(
+ RHTTPHeaders& aHeaders,
+ RStringF aAcceptStr )
+ {
+ TDataType type;
+ for ( TInt i= 0; i < iDataTypes->Count() ; i++ )
+ {
+ type = iDataTypes->At(i);
+ SetHeaderL( aHeaders, aAcceptStr, type.Des8() );
+ }
+ TPtrC8 strStarSlashStar(KStarSlashStar);
+// SetHeaderL( aHeaders, aAcceptStr, TPtrC8( KJavaScript));
+// SetHeaderL( aHeaders, aAcceptStr, TPtrC8( KAppJavaScript));
+// SetHeaderL( aHeaders, aAcceptStr, TPtrC8( KECMAScript) );
+ SetHeaderL( aHeaders, aAcceptStr, strStarSlashStar );
+ }
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::AddNpiHeadersL
+// We just add */* because the response goes directly to the plugin
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::AddNpiHeadersL(
+ RHTTPHeaders& aHeaders,
+ RStringF aAcceptStr )
+ {
+ TPtrC8 strNpi(KStarSlashStar);
+ SetHeaderL( aHeaders, aAcceptStr, strNpi );
+ }
+
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::AddHeaders
+// Decide which subset of the MIME types we should add to the headers.
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::AddHeadersL(RHTTPTransaction aTransaction)
+ {
+ RHTTPTransactionPropertySet properties = aTransaction.PropertySet();
+
+ THTTPHdrVal hdrVal;
+
+ if ( properties.Property( iDone, hdrVal ) )
+ {
+ return;
+ }
+ else
+ {
+ AllHeadersSetL( properties );
+ }
+
+
+ if (iDataTypes->Count() > 0)
+ {
+ RHTTPHeaders requestHeaders(
+ aTransaction.Request().GetHeaderCollection() );
+
+ if ( !properties.Property( iLoadTypeStr, hdrVal ) )
+ {
+ AddAllHeadersL( requestHeaders, iAcceptStr );
+ return;
+ }
+
+ if ( hdrVal.Type() == THTTPHdrVal::KTIntVal )
+ {
+ switch ( hdrVal.Int() )
+ {
+ case ( EAcceptNone ) :
+ break;
+ case ( EAcceptImages ) :
+ AddImageHeadersL( requestHeaders, iAcceptStr );
+ break;
+ case ( EAcceptCss ) :
+ AddCssHeadersL( requestHeaders, iAcceptStr );
+ break;
+ case ( EAcceptJavaScript) :
+ AddJavaScriptHeadersL( requestHeaders, iAcceptStr );
+ break;
+ case EAcceptAll:
+ default:
+ AddAllHeadersL( requestHeaders, iAcceptStr );
+ break;
+ }
+ }
+ else
+ {
+ AddAllHeadersL( requestHeaders, iAcceptStr );
+ }
+ }
+ }
+
+
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::AllHeadersSetL
+// We have processed this transaction already once. In case of redirects
+// we don't have to do it again. Set the value of "ahd" to one. Next time we
+// will check if the properity is already there.
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::AllHeadersSetL(RHTTPTransactionPropertySet& aProperties)
+ {
+ aProperties.SetPropertyL( iDone, THTTPHdrVal(1) );
+ }
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::AddImageHeadersL
+// We just add */* so that we can concatenate as many image requests
+// possible.
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::AddImageHeadersL(
+ RHTTPHeaders& aHeaders,
+ RStringF aAcceptStr )
+ {
+ TPtrC8 strImages(KStarSlashStar);
+ SetHeaderL( aHeaders, aAcceptStr, strImages );
+ }
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::AddCssHeadersL
+// Add text/css to the headers.
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::AddCssHeadersL(
+ RHTTPHeaders& aHeaders,
+ RStringF aAcceptStr )
+ {
+ TPtrC8 strCss( KCssStr );
+ SetHeaderL( aHeaders, aAcceptStr, strCss );
+ }
+
+//-----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::AddJavaScriptHeadersL
+// Add "application/x-javascript and text/ecmascript"
+//-----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::AddJavaScriptHeadersL(
+ RHTTPHeaders& aHeaders,
+ RStringF aAcceptStr )
+ {
+ SetHeaderL( aHeaders, aAcceptStr, TPtrC8( KJavaScript));
+ SetHeaderL( aHeaders, aAcceptStr, TPtrC8( KAppJavaScript));
+ SetHeaderL( aHeaders, aAcceptStr, TPtrC8( KECMAScript) );
+ }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::SetHeaderL()
+// -----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::SetHeaderL(
+ RHTTPHeaders aHeaders,
+ const RStringF aKey,
+ const TPtrC8& aValue )
+ {
+ RStringF headerValue = iSession->StringPool().OpenFStringL( aValue );
+ THTTPHdrVal val( headerValue );
+ aHeaders.SetFieldL( aKey, val );
+ headerValue.Close(); // close headerValue
+ }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::AddLanguageHeaderL()
+// -----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::AddLanguageHeaderL(RHTTPTransaction aTransaction)
+ {
+ RHTTPHeaders requestHeaders( aTransaction.Request().GetHeaderCollection() );
+ RStringPool aStringPool = iSession->StringPool();
+
+ if (( iFeatureBitmask & KHttpAcceptMultipleAcceptLanguagesSupport))
+ { // If KHttpAcceptMultipleAcceptLanguagesSupport enabled
+ // need to put user selected Language and other installed language in the format as below:
+ // en;q=1.0, es;q=0.5, fr;q=0.5
+
+ // Get User current selected language
+ TLanguage aCurrentUserSelectedLang = User::Language();
+ if ( aCurrentUserSelectedLang != iUserSelectedLang )
+ { // If User current selected language is not User selected language at contructor time
+ // Compose Multiple Languages String again
+ ComposeMultipleLanguagesStringL();
+ }
+
+ RStringF acceptLangStr = aStringPool.StringF(HTTP::EAcceptLanguage, RHTTPSession::GetTable());
+
+ // First check if EAcceptLanguage field is already added
+ const TInt parts = requestHeaders.FieldPartsL( acceptLangStr );
+ if( !parts )
+ {
+ requestHeaders.SetRawFieldL( acceptLangStr, iInstalledLangBuf, KFieldSeparator );
+ } // else: If EAcceptLanguage field is is already added, do nothing
+ }
+ else
+ { //If KHttpAcceptMultipleAcceptLanguagesSupport not enabled, only put "en"
+ requestHeaders.SetFieldL(aStringPool.StringF(HTTP::EAcceptLanguage,
+ RHTTPSession::GetTable()),
+ HttpFilterCommonStringsExt::GetLocaleLanguage(aStringPool));
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAcceptHeader::ComposeMultipleLanguagesStringL()
+// -----------------------------------------------------------------------------
+void CHttpFilterAcceptHeader::ComposeMultipleLanguagesStringL()
+ {
+ RStringPool aStringPool = iSession->StringPool();
+
+ // Declare a language arrays
+ CArrayFixFlat<TInt>* systemEpocLanguageCodes = 0;
+ // Get installed language codes
+ User::LeaveIfError( SysLangUtil::GetInstalledLanguages(systemEpocLanguageCodes) );
+ CleanupStack::PushL( systemEpocLanguageCodes );
+
+ // Compose the String such as "en;q=1.0, es;q=0.5, fr;q=0.5"
+ // Get user selected language
+ iUserSelectedLang = User::Language();
+ // Get user selected language string
+ iUserSelectedLangString = HttpFilterCommonStringsExt::GetLocaleLanguage(aStringPool);
+ // Compose the Installed Languages Buf
+ iInstalledLangBuf.Copy(iUserSelectedLangString.DesC());
+
+ if ( systemEpocLanguageCodes->Count() > 1)
+ { // If we have more than one one language installed, do...
+ iInstalledLangBuf.Append(KQWholeValue); // _LIT8(KQWholeValue, ";q=1.0");
+
+ // Append the other installed languages
+ for ( TInt i = 0; i < systemEpocLanguageCodes->Count(); ++i )
+ {
+ TLanguage language = (TLanguage) systemEpocLanguageCodes->At( i );
+ {
+ if ( language != iUserSelectedLang)
+ {
+ RStringF extraLang = HttpFilterCommonStringsExt::GetLanguageString(aStringPool, language);
+ iInstalledLangBuf.Append(KCommaSeperator); // _LIT8(KCommaSeperator, ", ");
+ iInstalledLangBuf.Append(extraLang.DesC());
+ iInstalledLangBuf.Append(KQHalfValue); // _LIT8(KQHalfValue, ";q=0.5");
+ }
+ }
+ }
+ } // else: Don't append q value if we only have one language installed
+
+ // clean up
+ CleanupStack::PopAndDestroy( 1 ); // systemEpocLanguageCodes
+ }
+
+// End of File
+