--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/httpfilters/deflatefilter/src/DeflateFilter.cpp Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,533 @@
+/*
+* 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:
+* Deflate decompression filter for HTTP protocol stack.
+*
+*
+*/
+
+
+#include <http/rhttptransaction.h>
+#include <http/rhttpheaders.h>
+#include <http/rhttpresponse.h>
+#include <HttpStringConstants.h>
+#include "DeflateFilter.h"
+#include <bautils.h>
+#include <eikenv.h>
+#include <bldvariant.hrh>
+#include <httpfiltercommonstringsext.h>
+//------------------------------------------------------------------------
+
+_LIT8( KDeflateFilterName, "Deflate");
+
+#ifndef __SERIES60_
+_LIT8(KGzipDeflateStr, "gzip,deflate");
+#else
+_LIT8(KGzipDeflateStr, "gzip, deflate, x-gzip, identity; q=0.9");
+#endif
+//------------------------------------------------------------------------
+
+// format for output of data/time values
+#if defined (_DEBUG) && defined (_LOGGING)
+#define LOG_FILE "deflate.log" //lint !e1923 LOG_FILE only used in debug build
+_LIT(KDateFormat,"%D%M%Y%/0%1%/1%2%/2%3%/3 %:0%H%:1%T%:2%S.%C%:3");
+#endif
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CDeflateFilter::CDeflateFilter
+// Constructor
+// -----------------------------------------------------------------------------
+//
+CDeflateFilter::CDeflateFilter(RHTTPSession aSession)
+ : iSession(aSession)
+{
+ iDataSups.Reset();
+} //lint !e1746 RHTTPSession is a light object, just a wrapper to CHTTPSession
+
+// -----------------------------------------------------------------------------
+// CDeflateFilter::InstallFilterL
+// Initialize the filter and register it to sesssion's filter collection
+// -----------------------------------------------------------------------------
+//
+CHttpDeflateFilter* CDeflateFilter::InstallFilterL(TAny* aSession)
+{
+ RHTTPSession* session = REINTERPRET_CAST(RHTTPSession*, aSession);
+ CDeflateFilter* filter = new (ELeave) CDeflateFilter(*session);
+ CleanupStack::PushL(filter);
+ filter->ConstructL(*session);
+ CleanupStack::Pop(filter);
+ return filter;
+}
+
+// -----------------------------------------------------------------------------
+// CDeflateFilter::ConstructL
+// Memory and resource allocation, leaves
+// -----------------------------------------------------------------------------
+//
+void CDeflateFilter::ConstructL(RHTTPSession aSession)
+{
+ // load resources if UI is available
+ iStringPool = aSession.StringPool();
+ RStringF filterName = iStringPool.OpenFStringL( KDeflateFilterName );
+ CleanupClosePushL( filterName );
+
+ iSession.FilterCollection().AddFilterL( *this,
+ THTTPEvent::ESubmit,
+ MHTTPFilter::EProtocolHandler+5,
+ filterName );
+ iSession.FilterCollection().AddFilterL( *this,
+ THTTPEvent::EGotResponseHeaders,
+ MHTTPFilter::EProtocolHandler+5,
+ filterName );
+ iSession.FilterCollection().AddFilterL( *this,
+ THTTPEvent::EGotResponseBodyData,
+ MHTTPFilter::EProtocolHandler+5,
+ filterName );
+ iSession.FilterCollection().AddFilterL( *this,
+ THTTPEvent::EResponseComplete,
+ MHTTPFilter::EProtocolHandler+5,
+ filterName );
+ iSession.FilterCollection().AddFilterL( *this,
+ THTTPEvent::EClosed,
+ MHTTPFilter::EProtocolHandler+5,
+ filterName );
+ CleanupStack::PopAndDestroy();
+
+ iXGzipVal = iStringPool.StringF(HttpFilterCommonStringsExt::EXGzip, HttpFilterCommonStringsExt::GetTable());
+ // log file
+ __OPEN_LOG( "deflate.log" );
+ __LOG( _L( "--Initialize Deflate Filter---\n" ) );
+} //lint !e1746 RHTTPSession is a light weight class, just wrapper for CHTTPSession
+
+
+//------------------------------------------------------------------------
+// CDeflateFilter::~CDeflateFilter
+// Destructor
+//------------------------------------------------------------------------
+//
+CDeflateFilter::~CDeflateFilter()
+{
+ if (iLoadCount)
+ {
+ iLoadCount = -1;
+ RStringF filterName; //lint !e1551
+ TRAPD( error, ( filterName = iStringPool.OpenFStringL( KDeflateFilterName ) ) ); //lint !e1551
+ if( error == KErrNone ) iSession.FilterCollection().RemoveFilter( filterName ); //lint !e1551
+ filterName.Close(); //lint !e1551
+ }
+
+ CleanupAll(); //lint !e1551
+ iDataSups.Close(); //lint !e1551
+}
+
+//------------------------------------------------------------------------
+// CDeflateFilter::MHFLoad
+// See MHTTPFilterBase::MHFRunL
+//------------------------------------------------------------------------
+//
+void CDeflateFilter::MHFLoad(RHTTPSession, THTTPFilterHandle)
+{
+ __LOG( _L( "--Load Deflate Filter---\n" ) );
+ ++iLoadCount;
+}
+
+//------------------------------------------------------------------------
+// CDeflateFilter::MHFUnload
+// See MHTTPFilterBase::MHFRunError
+//------------------------------------------------------------------------
+//
+void CDeflateFilter::MHFUnload(RHTTPSession , THTTPFilterHandle)
+{
+ __LOG( _L( "--Unload Deflate Filter---\n" ) );
+ if (--iLoadCount)
+ {
+ return;
+ }
+
+ delete this;
+}
+
+//------------------------------------------------------------------------
+// CDeflateFilter::MHFRunL
+// See MHTTPFilterBase::MHFRunL
+//------------------------------------------------------------------------
+//
+void CDeflateFilter::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
+{
+ if (aEvent.iUID != KHTTPUid) return;
+
+ switch(aEvent.iStatus)
+ {
+ case THTTPEvent::ESubmit:
+ {
+ __LOG( _L( "Event: ESubmit\n" ) );
+ AlterRequestHeadersL( aTransaction );
+ }
+ break;
+ case THTTPEvent::EGotResponseHeaders:
+ {
+ __LOG( _L( "Event: EGotResponseHeaders\n" ) );
+ CheckResponseHeadersL( aTransaction );
+ }
+ break;
+ case THTTPEvent::EGotResponseBodyData:
+ {
+ __LOG( _L( "Event: EGotResponseBodyData\n" ) );
+ TInt idx = GetTransIdx( aTransaction );
+ if( idx != KErrNotFound )
+ {
+ iDataSups[idx]->ProcessDataPartL();
+ }
+ }
+ break;
+ case THTTPEvent::EResponseComplete:
+ {
+ __LOG( _L( "Event: EResponseComplete\n" ) );
+ Cleanup( aTransaction );
+ }
+ break;
+ case THTTPEvent::EClosed:
+ {
+ __LOG( _L( "Event: EFailed\n" ) );
+ Cleanup( aTransaction );
+ }
+ break;
+ default:
+ {
+ __LOG1( _L( "Unknow Event: ID - %d\n" ), aEvent.iStatus );
+ }
+ break;
+ }
+}
+
+//------------------------------------------------------------------------
+// CDeflateFilter::MHFRunError
+// See MHTTPFilterBase::MHFRunError
+//------------------------------------------------------------------------
+//
+TInt CDeflateFilter::MHFRunError(TInt /*aError*/, RHTTPTransaction /*aTransaction*/, const THTTPEvent& )
+{
+ // error happened, cleanup the datasupplier related with this transaction
+// Cleanup( aTransaction );
+// aTransaction.SendEventL( THTTPEvent::EFailed, THTTPEvent::EIncoming, THTTPFilterHandle::ECurrentFilter );
+ return KErrNone;
+}
+
+//------------------------------------------------------------------------
+// CDeflateFilter::MHFSessionRunL
+// See MHTTPFilterBase::MHFSessionRunL
+//------------------------------------------------------------------------
+//
+void CDeflateFilter::MHFSessionRunL(const THTTPSessionEvent& )
+{
+ // do nothing
+}
+
+//------------------------------------------------------------------------
+// CDeflateFilter::MHFSessionRunL
+// See MHTTPFilterBase::MHFSessionRunL
+//------------------------------------------------------------------------
+//
+TInt CDeflateFilter::MHFSessionRunError(TInt aError, const THTTPSessionEvent& )
+{
+ // session problem, need to close Deflate engine
+ CleanupAll();
+ return aError;
+}
+
+//------------------------------------------------------------------------
+// CDeflateFilter::DumpResponseHeadersL
+// Dump the response headers to LOG file
+//------------------------------------------------------------------------
+//
+#if defined (_DEBUG) && defined (_LOGGING)
+void CDeflateFilter::DumpHeadersL( RHTTPHeaders aHeaders )
+{
+ __LOG( _L( "Dump the header...\n" ) );
+
+ RStringPool strP = iSession.StringPool();
+ THTTPHdrFieldIter it = aHeaders.Fields();
+
+ while( it.AtEnd() == EFalse )
+ {
+ RStringTokenF fieldName = it();
+ RStringF fieldNameStr = strP.StringF( fieldName );
+
+ THTTPHdrVal fieldVal;
+
+ // how many parts in this field?
+ TInt parts = aHeaders.FieldPartsL( fieldNameStr );
+
+ // dump all parts of a header field
+ for( TInt i=0; i<parts; ++i )
+ {
+ if( aHeaders.GetField( fieldNameStr, i, fieldVal ) == KErrNone )
+ {
+ const TDesC8& fieldNameDesC = fieldNameStr.DesC();
+ if( i==0 )
+ {
+ __DUMPBIN( fieldNameDesC );
+ __LOG( _L ( " : " ) );
+ }
+ else
+ {
+ __LOG( _L ( "," ) );
+ }
+
+ switch( fieldVal.Type() )
+ {
+ case THTTPHdrVal::KTIntVal:
+ {
+ __LOG1( _L("%d"), fieldVal.Int() );
+ }
+ break;
+ case THTTPHdrVal::KStrFVal:
+ {
+ RStringF fieldValStr = strP.StringF( fieldVal.StrF() );
+ const TDesC8& fieldValDesC = fieldValStr.DesC();
+ __DUMPBIN( fieldValDesC );
+ }
+ break;
+ case THTTPHdrVal::KStrVal:
+ {
+ RString fieldValStr = strP.String( fieldVal.Str() );
+ const TDesC8& fieldValDesC = fieldValStr.DesC();
+ __DUMPBIN( fieldValDesC );
+ }
+ break;
+ case THTTPHdrVal::KDateVal:
+ {
+ TDateTime date = fieldVal.DateTime();
+ TBuf<40> dateTimeString;
+ TTime t( date );
+ t.FormatL( dateTimeString, KDateFormat );
+ TBuf8<40> dtStr;
+ dtStr.Copy( dateTimeString.Left( 128 ) );
+ __DUMPBIN( dtStr );
+ }
+ break;
+ case THTTPHdrVal::KNoType:
+ default:
+ {
+ __LOG( _L ( "Unrecognized value type.\n" ) );
+ }
+ break;
+ }
+
+ __LOG( _L ( "\n" ) );
+ }
+ }
+
+ ++it;
+ }
+ __LOG( _L( "Header is Dumped already...\n" ) );
+}//lint !e1746 no need to be const reference, just for debugging
+#endif
+
+//------------------------------------------------------------------------
+// CDeflateFilter::AlterRequestHeadersL
+// Check HTTP headers and extract MIME type
+//------------------------------------------------------------------------
+//
+void CDeflateFilter::AlterRequestHeadersL( const RHTTPTransaction& aTrans )
+{
+#if defined (_DEBUG) && defined (_LOGGING)
+ __LOG( _L( "Dump the request header before modification.\n" ) );
+ DumpHeadersL( aTrans.Request().GetHeaderCollection() );
+#endif
+
+ // remove the original Accept-Encoding field set by HTTP client
+ aTrans.Request().GetHeaderCollection().RemoveField(
+ iStringPool.StringF( HTTP::EAcceptEncoding, RHTTPSession::GetTable()) );
+ SetHeaderL( aTrans.Request().GetHeaderCollection(), HTTP::EAcceptEncoding, KGzipDeflateStr );
+
+#if defined (_DEBUG) && defined (_LOGGING)
+ __LOG( _L( "Dump the request header after modification.\n" ) );
+ DumpHeadersL( aTrans.Request().GetHeaderCollection() );
+#endif
+}
+
+//------------------------------------------------------------------------
+// CDeflateFilter::CheckHeadersL
+// Check HTTP headers and extract MIME type
+//------------------------------------------------------------------------
+//
+void CDeflateFilter::CheckResponseHeadersL( const RHTTPTransaction& aTrans )
+{
+ // read the header data and check the MIME type here
+ // check the status and body
+ RHTTPResponse response = aTrans.Response();
+
+ #if defined (_DEBUG) && defined (_LOGGING)
+ DumpHeadersL( aTrans.Response().GetHeaderCollection() );
+ #endif
+
+ RHTTPHeaders headers = response.GetHeaderCollection();
+ RStringF fieldNameStr = iStringPool.StringF( HTTP::EContentEncoding, RHTTPSession::GetTable() );
+
+ // read the first part of content-encoding field
+ THTTPHdrVal fieldVal;
+
+/*
+ ---------
+ if( headers.GetField( fieldNameStr, 0, fieldVal ) == KErrNone &&
+ ( fieldVal.StrF().Index( RHTTPSession::GetTable() ) == HTTP::EGzip ||
+ fieldVal.StrF().Index( RHTTPSession::GetTable() ) == HTTP::EDeflate ) )
+ {
+ // find gzip/deflate content-decoding header
+ __LOG( _L( "gzip/deflate content-decoding exists...\n" ) );
+
+ // we shouldn't store the same transaction twice
+ TInt idx = GetTransIdx( aTrans );
+ if( idx != KErrNotFound )
+ {
+ // remove the previous one
+ CDeflateDataSupplier* iSup = iDataSups[idx];
+ iDataSups.Remove( idx );
+ delete iSup;
+ }
+
+ CDeflateDataSupplier* pSup = CDeflateDataSupplier::NewL( aTrans.Id(), response.Body(),
+ (1<<15), fieldVal.StrF().Index( RHTTPSession::GetTable() ) == HTTP::EGzip ? 0 : 1 ); //CDecmpStream::EGzip : CDecmpStream::EZlib );
+ iDataSups.Append( pSup );
+ response.SetBody( *pSup );
+
+ // remove the fields of deflate and gzip
+ aTrans.Response().GetHeaderCollection().RemoveField(
+ iStringPool.StringF( HTTP::EContentEncoding, RHTTPSession::GetTable()) );
+ }
+ -----
+*/
+/*********************************************************************/
+ if( headers.GetField( fieldNameStr, 0, fieldVal ) == KErrNone )
+ {
+ if( ( fieldVal.StrF().Index( RHTTPSession::GetTable() ) == HTTP::EGzip ||
+ fieldVal.StrF().Index( RHTTPSession::GetTable() ) == HTTP::EDeflate ||
+ fieldVal.StrF().Index( HttpFilterCommonStringsExt::GetTable() ) == HttpFilterCommonStringsExt::EXGzip ) )
+ {
+ // find gzip/deflate/x-gzip content-decoding header
+ __LOG( _L( "gzip/deflate/x-gzip content-decoding exists...\n" ) );
+
+ /**/
+ // we shouldn't store the same transaction twice
+ TInt idx = GetTransIdx( aTrans );
+ if( idx != KErrNotFound )
+ {
+ // remove the previous one
+ CDeflateDataSupplier* iSup = iDataSups[idx];
+ iDataSups.Remove( idx );
+ delete iSup;
+ }
+ /**/
+
+ CDeflateDataSupplier* pSup = NULL;
+
+ if (fieldVal.StrF().Index( RHTTPSession::GetTable() ) == HTTP::EGzip ||
+ fieldVal.StrF().Index( HttpFilterCommonStringsExt::GetTable() ) == HttpFilterCommonStringsExt::EXGzip )
+ {
+ pSup = CDeflateDataSupplier::NewL( aTrans.Id(), response.Body(), (1<<15), 0 ); // CDecmpStream::EGzip
+ }
+ else // if fieldVal.StrF().Index( RHTTPSession::GetTable() ) == HTTP::EDeflate
+ {
+ pSup = CDeflateDataSupplier::NewL( aTrans.Id(), response.Body(), (1<<15), 1 ); // CDecmpStream::EZlib
+ }
+
+ iDataSups.Append( pSup );
+ response.SetBody( *pSup );
+
+ // remove the fields of deflate and gzip
+ aTrans.Response().GetHeaderCollection().RemoveField(
+ iStringPool.StringF( HTTP::EContentEncoding, RHTTPSession::GetTable()) );
+
+ // Adding Transaction parameter so Download manager knows that content was compressed.
+ RHTTPTransactionPropertySet propSet = aTrans.PropertySet();
+ // Key = "ContentInflated", fieldVal = "gzip" or "deflate" or "x-gzip"
+ propSet.RemoveProperty( iStringPool.StringF(HttpFilterCommonStringsExt::EContentInflated, HttpFilterCommonStringsExt::GetTable()));
+ propSet.SetPropertyL( iStringPool.StringF(HttpFilterCommonStringsExt::EContentInflated, HttpFilterCommonStringsExt::GetTable()), fieldVal );
+ }
+ }
+ else
+ {
+ TInt idx = GetTransIdx( aTrans );
+ if( idx != KErrNotFound )
+ {
+ // remove the previous one
+ CDeflateDataSupplier* iSup = iDataSups[idx];
+ iDataSups.Remove( idx );
+ delete iSup;
+ iSup = NULL;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// CDeflateFilter::GetDeflateTransIdx
+// Retrieve the Deflate datasupplier
+//-----------------------------------------------------------------------------
+//
+TInt CDeflateFilter::GetTransIdx( const RHTTPTransaction& aTrans ) const
+{
+ for( TInt i=0; i<iDataSups.Count(); ++i )
+ if( iDataSups[i]->GetTransId() == aTrans.Id() )
+ return i;
+ return KErrNotFound;
+}
+
+
+//-----------------------------------------------------------------------------
+// CDeflateFilter::Cleanup
+// Cleanup the resource related with a transaction
+//-----------------------------------------------------------------------------
+//
+void CDeflateFilter::Cleanup( const RHTTPTransaction& aTrans )
+{
+ TInt idx = GetTransIdx( aTrans );
+ if( idx != KErrNotFound )
+ {
+ // remove the problematic data supplier
+ CDeflateDataSupplier* iSup = iDataSups[idx];
+ iDataSups.Remove( idx );
+ delete iSup;
+ iSup = NULL;
+ }
+
+ // shutdown the Deflate session
+ if( iDataSups.Count()==0 ) CleanupAll();
+}
+
+//-----------------------------------------------------------------------------
+// CDeflateFilter::CleanupAll
+// Cleanup all the Deflate transactions, in case a session error happens or a session
+// is closed.
+//-----------------------------------------------------------------------------
+//
+void CDeflateFilter::CleanupAll()
+{
+ iDataSups.ResetAndDestroy();
+}
+
+//-----------------------------------------------------------------------------
+// CDeflateFilter::SetHeaderL
+// Add string to the header
+//-----------------------------------------------------------------------------
+//
+void CDeflateFilter::SetHeaderL(RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8& aHdrValue) const
+{
+ RStringF valStr = iStringPool.OpenFStringL(aHdrValue);
+ THTTPHdrVal val(valStr);
+ aHeaders.SetFieldL(iStringPool.StringF(aHdrField,RHTTPSession::GetTable()), val);
+ valStr.Close();
+}