omadrm/drmplugins/drmfilter/src/HTTPFilterDRM.cpp
changeset 0 95b198f216e5
child 12 8a03a285ab14
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omadrm/drmplugins/drmfilter/src/HTTPFilterDRM.cpp	Thu Dec 17 08:52:27 2009 +0200
@@ -0,0 +1,737 @@
+/*
+ * Copyright (c) 2006 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:  Implementation of the DRM Filter HTTP Filter
+ *
+ */
+
+#include <http/rhttptransaction.h>
+#include <http/rhttpheaders.h>
+#include <http/rhttpresponse.h>
+#include <httpstringconstants.h>
+#include <httperr.h>
+#include <bautils.h>
+#include <drmmessageparser.h>
+
+#include "httpfilterdrm.h"
+
+// LOCAL CONSTANTS
+_LIT8( KDRMString1, "application/vnd.oma.drm.message" );
+// FL or CD
+
+_LIT8( KDRMString3, "application/vnd.oma.drm.content" );
+// SD only
+
+_LIT8( KJADString, "text/vnd.sun.j2me.app-descriptor" );
+// Jad files
+
+_LIT8( KXOmaFieldName, "x-oma-drm-separate-delivery");
+// Estimated arrival time for rights of the SD content
+
+_LIT8( KDRMOldContentType, "x-drm-old-content-type");
+// old content type header to be added
+
+_LIT8( KHTTPFilterDRMName, "DRM");
+// Name of filter
+
+_LIT8( KCFMRingtoneStr, "ringtone");
+// cfm ringtone string
+
+_LIT8( KCFMFwdStr, "fwd");
+// cfm forward string
+
+_LIT8( KCFMValStr, "no");
+// cfm negative value string
+
+const TInt KXOmaDefaultValue = 25;
+//default value for the 'x-oma-drm-separate-delivery' header
+
+const TInt KCFMFieldMaxLength( 200 );
+const TInt KBadMimeType( -12002 ); // common error code
+const TInt NW_STAT_FAILURE( -20000 ); // common error code
+
+// format for output of data/time values
+#if defined (_DEBUG) && defined (_LOGGING)
+_LIT(KDateFormat,"%D%M%Y%/0%1%/1%2%/2%3%/3 %:0%H%:1%T%:2%S.%C%:3");
+#endif
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CHTTPFilterDRM::CHTTPFilterDRM
+// Constructor
+// -----------------------------------------------------------------------------
+//
+CHTTPFilterDRM::CHTTPFilterDRM( RHTTPSession aSession ) :
+    iSession( aSession )
+    {
+    iDataSups.Reset();
+    }
+
+// -----------------------------------------------------------------------------
+// CHTTPFilterDRM::InstallFilterL
+// Initialize the filter and register it to sesssion's filter collection
+// -----------------------------------------------------------------------------
+//
+CEComFilter* CHTTPFilterDRM::InstallFilterL( TAny* aSession )
+    {
+    RHTTPSession* session = REINTERPRET_CAST(RHTTPSession*, aSession);
+    CHTTPFilterDRM* filter = new ( ELeave ) CHTTPFilterDRM( *session );
+    CleanupStack::PushL( filter );
+
+    filter->ConstructL( *session );
+    CleanupStack::Pop( filter );
+
+    return filter;
+    }
+
+// -----------------------------------------------------------------------------
+// CHTTPFilterDRM::ConstructL
+// Memory and resource allocation, leaves
+// -----------------------------------------------------------------------------
+//
+void CHTTPFilterDRM::ConstructL( RHTTPSession aSession )
+    {
+    iStringPool = aSession.StringPool();
+
+    const TInt KPriorityDelta( 10 );
+    // register the filter
+    RStringF filterName = iStringPool.OpenFStringL( KHTTPFilterDRMName );
+    CleanupClosePushL( filterName );
+    iSession.FilterCollection().AddFilterL( *this,
+        THTTPEvent::EGotResponseHeaders, // Any transaction event
+        MHTTPFilter::EProtocolHandler + KPriorityDelta, // Priority of filter
+        filterName ); // Name of filter
+    iSession.FilterCollection().AddFilterL( *this,
+        THTTPEvent::EGotResponseBodyData,
+        MHTTPFilter::EProtocolHandler + KPriorityDelta,
+        filterName );
+    iSession.FilterCollection().AddFilterL( *this,
+        THTTPEvent::EResponseComplete,
+        MHTTPFilter::EProtocolHandler + KPriorityDelta,
+        filterName );
+    iSession.FilterCollection().AddFilterL( *this,
+        THTTPEvent::EFailed,
+        MHTTPFilter::EProtocolHandler + KPriorityDelta,
+        filterName );
+    iSession.FilterCollection().AddFilterL( *this,
+        THTTPEvent::EClosed,
+        MHTTPFilter::EProtocolHandler + KPriorityDelta,
+        filterName );
+    CleanupStack::PopAndDestroy( &filterName );
+
+    // log file
+    __OPEN_LOG( "DRM.LOG" );
+    __LOG( _L ( "--Initialize DRM Filter---\n" ) );
+
+    }
+
+//------------------------------------------------------------------------
+// CHTTPFilterDRM::~CHTTPFilterDRM
+// Destructor
+//------------------------------------------------------------------------
+//
+CHTTPFilterDRM::~CHTTPFilterDRM()
+    {
+    // If we've been destroyed from the cleanup stack during creation
+    // of the object, it might still be loaded. So check. (Normaly the
+    // delete is initiated by the 'delete this' in MHFUnload)
+    if ( iLoadCount )
+        {
+        // As we're already in a destructor, MHFUnload must not delete us again
+        iLoadCount = -1;
+        RStringF filterName;
+        TRAPD( error, ( filterName = iStringPool.OpenFStringL( KHTTPFilterDRMName ) ) );
+        if ( error == KErrNone )
+            iSession.FilterCollection().RemoveFilter( filterName );
+        filterName.Close();
+        }
+
+    CleanupAll();
+    iDataSups.Close();
+    }
+
+//------------------------------------------------------------------------
+// CHTTPFilterDRM::DeleteDataSupplier
+//------------------------------------------------------------------------
+//
+void CHTTPFilterDRM::DeleteDataSupplier( TInt aTransId )
+    {
+    __LOG( _L ( "CHTTPFilterDRM::DeleteDataSupplier" ) );
+    TInt idx( KErrNotFound );
+    for ( TInt i = 0; idx == KErrNotFound && i < iDataSups.Count(); ++i )
+        {
+        if ( iDataSups[i]->GetTransId() == aTransId )
+            {
+            idx = i;
+            }
+        }
+
+    if ( idx != KErrNotFound )
+        {
+        __LOG1( _L ( "CHTTPFilterDRM::DeleteDataSupplier: deleting transaction %d." ), aTransId );
+        // remove the problematic data supplier
+        CHTTPFilterDRMDataSupplier* sup = iDataSups[idx];
+        iDataSups.Remove( idx );
+        delete sup;
+        sup = NULL;
+        }
+    }
+
+//------------------------------------------------------------------------
+// CHTTPFilterDRM::MHFLoad
+// See MHTTPFilterBase::MHFRunL
+//------------------------------------------------------------------------
+//
+void CHTTPFilterDRM::MHFLoad( RHTTPSession, THTTPFilterHandle )
+    {
+    __LOG( _L ( "--Load DRM Filter---\n" ) );
+    ++iLoadCount;
+    }
+
+//------------------------------------------------------------------------
+// CHTTPFilterDRM::MHFUnload
+// See MHTTPFilterBase::MHFRunError
+//------------------------------------------------------------------------
+//
+void CHTTPFilterDRM::MHFUnload( RHTTPSession, THTTPFilterHandle )
+    {
+    __LOG( _L ( "--Unload DRM Filter---\n" ) );
+    if ( --iLoadCount )
+        {
+        return;
+        }
+
+    delete this;
+    }
+
+//------------------------------------------------------------------------
+// CHTTPFilterDRM::MHFRunL
+// See MHTTPFilterBase::MHFRunL 
+//------------------------------------------------------------------------
+//
+void CHTTPFilterDRM::MHFRunL( RHTTPTransaction aTransaction,
+    const THTTPEvent& aEvent )
+    {
+    if ( aEvent.iUID != KHTTPUid )
+        return;
+
+    switch ( aEvent.iStatus )
+        {
+        case THTTPEvent::EGotResponseHeaders:
+            {
+            __LOG( _L ( "Event: EGotResponseHeaders\n" ) );
+            CheckHeadersL( aTransaction );
+            }
+            break;
+        case THTTPEvent::EGotResponseBodyData:
+            {
+            __LOG( _L ( "Event: EGotResponseBodyData\n" ) );
+            TInt idx = GetDRMTransIdx( aTransaction );
+            if ( idx != KErrNotFound )
+                {
+                // for x-oma-drm-separate-delivery purpose
+                if ( iXOmaHeaderVal )
+                    {
+                    iDataSups[idx]->SetEstimatedArrivalTime( iXOmaHeaderVal );
+                    iXOmaHeaderVal = 0;
+
+                    //remove the DataSuuplier
+                    delete iDataSups[idx];
+                    iDataSups.Remove( idx );
+                    }
+                else
+                    {
+                    iDataSups[idx]->ProcessDataPartL();
+                    }
+                }
+            }
+            break;
+        case THTTPEvent::EResponseComplete:
+            {
+            __LOG( _L ( "Event: EResponseComplete\n" ) );
+            }
+            break;
+        case THTTPEvent::EFailed:
+            {
+            __LOG( _L ( "Event: EFailed\n" ) );
+            Cleanup( aTransaction );
+            }
+            break;
+        case THTTPEvent::EClosed:
+            {
+            __LOG( _L ( "Event: EClosed\n" ) );
+            }
+            break;
+        default:
+            {
+            __LOG1( _L ( "Unknow Event: ID - %d\n" ), aEvent.iStatus );
+            }
+            break;
+        }
+    }
+
+const static TInt KGlobalErrs[] =
+    {
+        NW_STAT_FAILURE,
+        KBadMimeType,
+        KBadMimeType,
+        NW_STAT_FAILURE,
+        KBadMimeType,
+        KBadMimeType,
+        KBadMimeType,
+        KBadMimeType,
+        KBadMimeType
+    };
+
+//------------------------------------------------------------------------
+// CHTTPFilterDRM::MHFRunError
+// See MHTTPFilterBase::MHFRunError
+//------------------------------------------------------------------------
+//
+TInt CHTTPFilterDRM::MHFRunError( TInt aError, RHTTPTransaction aTransaction,
+    const THTTPEvent& )
+    {
+    TInt error = 0;
+    TInt error2 = KErrNone;
+    // map aError to global error message
+
+    if ( aError >= DRMCommon::EInvalidRights && aError
+        <= DRMCommon::EGeneralError )
+        error = KGlobalErrs[DRMCommon::EGeneralError - aError];
+    else
+        error = aError;
+
+    //to map caf errors and KErrCorrupt to display
+    switch ( aError )
+        {
+        case KErrCANotSupported:
+        case KErrCANoPermission:
+        case KErrCANoRights:
+        case KErrCorrupt:
+            {
+            error = NW_STAT_FAILURE; //Unable to perform operation   
+            }
+            break;
+        case KErrArgument:
+            {
+            error = KBadMimeType;
+            }
+            break;
+        case KErrCANoAgent:
+        case KErrCAOutOfRange:
+        case KErrCAPendingRights:
+        case KErrCASizeNotDetermined:
+        case KErrCANewFileHandleRequired:
+            {
+            error = NW_STAT_FAILURE;
+            }
+            break;
+        default:
+            {
+            error = NW_STAT_FAILURE;
+            }
+            break;
+        }
+
+    // pass the errorcode forward
+    THTTPEvent httpEvent( error );
+        TRAP( error2, aTransaction.SendEventL(httpEvent, THTTPEvent::EIncoming, THTTPFilterHandle::ECurrentFilter ));
+
+    return error2;
+    }
+
+//------------------------------------------------------------------------
+// CHTTPFilterDRM::MHFSessionRunL
+// See MHTTPFilterBase::MHFSessionRunL
+//------------------------------------------------------------------------
+//
+void CHTTPFilterDRM::MHFSessionRunL( const THTTPSessionEvent& )
+    {
+    // do nothing
+    }
+
+//------------------------------------------------------------------------
+// CHTTPFilterDRM::MHFSessionRunL
+// See MHTTPFilterBase::MHFSessionRunL
+//------------------------------------------------------------------------
+//
+TInt CHTTPFilterDRM::MHFSessionRunError( TInt aError,
+    const THTTPSessionEvent& )
+    {
+    // session problem, need to close DRM engine
+    CleanupAll();
+    return aError;
+    }
+
+//------------------------------------------------------------------------
+// CHTTPFilterDRM::DumpResponseHeadersL
+// Dump the response headers to LOG file
+//------------------------------------------------------------------------
+//
+#if defined (_DEBUG) && defined (_LOGGING)
+void CHTTPFilterDRM::DumpResponseHeadersL( RHTTPResponse& aResponse )
+    {
+    __LOG( _L ( "Dump the header...\n" ) );
+
+    RHTTPHeaders headers = aResponse.GetHeaderCollection();
+    RStringPool strP = iSession.StringPool();
+    THTTPHdrFieldIter it = headers.Fields();
+
+    while ( it.AtEnd() == EFalse )
+        {
+        RStringTokenF fieldName = it();
+        RStringF fieldNameStr = strP.StringF( fieldName );
+        THTTPHdrVal fieldVal;
+        TInt fieldParts = 0; // For the case if next the call fails.
+        TRAPD( ignoreErr, fieldParts = headers.FieldPartsL( fieldNameStr ) );
+
+        // dump the first part of  a  header field
+        for ( TInt ii = 0; ii < fieldParts; ii++ )
+            {
+            if ( headers.GetField( fieldNameStr, ii, fieldVal ) == KErrNone )
+                {
+                const TDesC8& fieldNameDesC = fieldNameStr.DesC();
+                __DUMPBIN( fieldNameDesC );
+                __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:
+                        {
+                        const TInt KDateTimeMaxLength( 40 );
+                        TDateTime date = fieldVal.DateTime();
+                        TBuf<KDateTimeMaxLength> dateTimeString;
+                        TTime t( date );
+                        t.FormatL( dateTimeString, KDateFormat );
+                        TBuf8<KDateTimeMaxLength> dtStr;
+                        dtStr.Copy( dateTimeString.Left( KDateTimeMaxLength ) );
+                        __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" ) );
+
+    }
+#endif
+
+//------------------------------------------------------------------------
+// CHTTPFilterDRM::CheckHeadersL
+// Check HTTP headers and extract MIME type
+//------------------------------------------------------------------------
+// 
+void CHTTPFilterDRM::CheckHeadersL( const RHTTPTransaction& aTrans )
+    {
+    // read the header data and check the MIME type here	
+    // check the status and body
+    RHTTPResponse response = aTrans.Response();
+    TInt status = response.StatusCode();
+
+#if defined (_DEBUG) && defined (_LOGGING)
+    DumpResponseHeadersL( response );
+#endif
+
+    THTTPHdrVal fieldVal;
+    // check if the content type is application/vnd.oma.drm.message
+    if ( ( status >= HTTPStatus::EOk ) &&
+        ( status < HTTPStatus::EMultipleChoices ) &&
+        ( status != HTTPStatus::ENoContent ) )
+        {
+        const TBuf8<sizeof( KDRMString1 )> DRMStringBuf1( KDRMString1 );
+        const TBuf8<sizeof( KDRMString3 )> DRMStringBuf3( KDRMString3 );
+        const TBuf8<sizeof( KDRMOldContentType )> DRMHeaderName(
+            KDRMOldContentType );
+
+        RHTTPHeaders headers = response.GetHeaderCollection();
+        RStringPool strP = iSession.StringPool();
+        RStringF fieldNameStr = strP.StringF( HTTP::EContentType,
+            RHTTPSession::GetTable() );
+
+        if ( headers.GetField( fieldNameStr, 0, fieldVal ) == KErrNone )
+            {
+            RStringF fieldValStr = strP.StringF( fieldVal.StrF() );
+
+            RStringF DRMValue1 = strP.OpenFStringL( DRMStringBuf1 );
+            CleanupClosePushL( DRMValue1 );
+
+            RStringF DRMValue3 = strP.OpenFStringL( DRMStringBuf3 );
+            CleanupClosePushL( DRMValue3 );
+
+            RStringF DRMHeaderNameF = strP.OpenFStringL( DRMHeaderName );
+            CleanupClosePushL( DRMHeaderNameF );
+
+            // DRM message
+            if ( DRMValue1 == fieldValStr )
+                {
+                __LOG( _L ("DRM content exists, a new dummy data supplier is created!\n" ) );
+
+                CHTTPFilterDRMDataSupplier* drmData = 0;
+
+                drmData = CHTTPFilterDRMDataSupplier::NewL( aTrans.Id(),
+                    response.Body(), const_cast<CHTTPFilterDRM*> ( this ) );
+                /** Support for Hutchinson's content protection scheme, CFM
+                 *  
+                 */
+                drmData->SetProcessedContentType( EStandardDRMContent );
+                /**
+                 *
+                 */
+                iDataSups.Append( drmData );
+                response.SetBody( *drmData );
+
+                // change the mime type to "application/vnd.oma.drm.content"
+                headers.RemoveField( fieldNameStr );
+                headers.SetFieldL( fieldNameStr, THTTPHdrVal( DRMValue3 ) );
+
+                // add the new header
+                headers.SetFieldL( DRMHeaderNameF, THTTPHdrVal( DRMValue1 ) );
+
+                }
+            else if ( DRMValue3 == fieldValStr )
+                {
+                RStringF xOmaFieldName = strP.OpenFStringL( KXOmaFieldName );
+                if ( headers.GetField( xOmaFieldName, 0, fieldVal )
+                    == KErrNone )
+                    {
+                    iXOmaHeaderVal = KXOmaDefaultValue;
+
+                    switch ( fieldVal.Type() )
+                        {
+                        case THTTPHdrVal::KStrFVal:
+                            {
+                            TLex8 lexer( fieldVal.StrF().DesC() );
+                            lexer.Val( iXOmaHeaderVal );
+                            }
+                            break;
+                        case THTTPHdrVal::KStrVal:
+                            {
+                            TLex8 lexer( fieldVal.Str().DesC() );
+                            lexer.Val( iXOmaHeaderVal );
+                            }
+                            break;
+                        case THTTPHdrVal::KTIntVal:
+                            {
+                            iXOmaHeaderVal = fieldVal.Int();
+                            }
+                            break;
+                        }
+                    }
+                xOmaFieldName.Close();
+                if ( iXOmaHeaderVal ) //if header has value of 0 then will be ignored
+                    {
+                    CHTTPFilterDRMDataSupplier* drmData = 0;
+                    drmData
+                        = CHTTPFilterDRMDataSupplier::NewL( aTrans.Id(),
+                            response.Body(),
+                            const_cast<CHTTPFilterDRM*> ( this ) );
+                    iDataSups.Append( drmData );
+                    }
+
+                }
+
+            CleanupStack::PopAndDestroy( &DRMHeaderNameF );
+            CleanupStack::PopAndDestroy( &DRMValue3 );
+            CleanupStack::PopAndDestroy( &DRMValue1 );
+
+            // dump the header after modification
+#if defined (_DEBUG) && defined (_LOGGING)
+            __LOG( _L ("--- HEADER AFTER CHANGE ---\n") );
+            DumpResponseHeadersL( response );
+#endif
+            }
+
+        // CFM Content protection:
+        //========================
+
+        TInt idx = GetDRMTransIdx( aTrans );
+        if ( idx != KErrNotFound )
+            return;
+
+        TProcessedContentType currentContentType = EUnknownContent;
+
+        RStringF cfmValStr = strP.OpenFStringL( KCFMValStr );
+        CleanupClosePushL( cfmValStr );
+
+        // check "fwd=no"
+        RStringF cfmFwdStr = strP.OpenFStringL( KCFMFwdStr );
+        CleanupClosePushL( cfmFwdStr );
+        if ( headers.GetParam( fieldNameStr, cfmFwdStr, fieldVal )
+            != KErrNotFound )
+            {
+            RStringF fieldValStr = strP.StringF( fieldVal.StrF() );
+            TBufC8<KCFMFieldMaxLength> buf1 = fieldValStr.DesC();
+            if ( fieldValStr == cfmValStr )
+                {
+                currentContentType = EHutchinsonCFMNoFirstChunk;
+                }
+            }
+        CleanupStack::PopAndDestroy( &cfmFwdStr );
+
+        // check "ringtone=no"
+        RStringF cfmRingtoneStr = strP.OpenFStringL( KCFMRingtoneStr );
+        CleanupClosePushL( cfmRingtoneStr );
+
+        if ( headers.GetParam( fieldNameStr, cfmRingtoneStr, fieldVal )
+            != KErrNotFound )
+            {
+            RStringF fieldValStr = strP.StringF( fieldVal.StrF() );
+            TBufC8<KCFMFieldMaxLength> buf1 = fieldValStr.DesC();
+            if ( fieldValStr == cfmValStr )
+                {
+                currentContentType
+                    = EHutchinsonCFMWithRingingToneNoFirstChunk;
+                }
+            }
+        CleanupStack::PopAndDestroy( &cfmRingtoneStr );
+        CleanupStack::PopAndDestroy( &cfmValStr );
+
+        // Do not encrypt JAD files:
+        if ( headers.GetField( fieldNameStr, 0, fieldVal ) == KErrNone )
+            {
+            // If it is a JAD always ignore any of the above:	
+            const TBuf8<sizeof( KJADString )> JADStringBuf( KJADString );
+            RStringF JADValue = strP.OpenFStringL( JADStringBuf );
+            CleanupClosePushL( JADValue );
+
+            RStringF jadFieldValStr = strP.StringF( fieldVal.StrF() );
+            if ( JADValue == jadFieldValStr )
+                {
+                currentContentType = EUnknownContent;
+                }
+            CleanupStack::PopAndDestroy( &JADValue );
+            }
+
+        // Protect the content
+        if ( currentContentType != EUnknownContent ) // content protected
+            {
+            CHTTPFilterDRMDataSupplier* drmData = 0;
+            drmData = CHTTPFilterDRMDataSupplier::NewL( aTrans.Id(),
+                response.Body(), EHutchinsonCFMWithRingingToneNoFirstChunk,
+                const_cast<CHTTPFilterDRM*> ( this ) );
+            drmData->SetProcessedContentType( currentContentType );
+
+            if ( headers.GetField( fieldNameStr, 0, fieldVal ) == KErrNone )
+                {
+                drmData->SetContentMimeTypeL( fieldVal.StrF().DesC() );
+                }
+            else
+                {
+                delete drmData;
+                User::Leave( KErrUnknown );
+                }
+
+            iDataSups.Append( drmData );
+            response.SetBody( *drmData );
+
+            ///			
+            RStringF DRMValue1 = strP.OpenFStringL( DRMStringBuf1 );
+            CleanupClosePushL( DRMValue1 );
+
+            RStringF DRMValue3 = strP.OpenFStringL( DRMStringBuf3 );
+            CleanupClosePushL( DRMValue3 );
+
+            RStringF DRMHeaderNameF = strP.OpenFStringL( DRMHeaderName );
+            CleanupClosePushL( DRMHeaderNameF );
+
+            // change the mime type to "application/vnd.oma.drm.content"
+
+            headers.RemoveField( fieldNameStr );
+            headers.SetFieldL( fieldNameStr, THTTPHdrVal( DRMValue3 ) );
+
+            // add the new header
+            headers.SetFieldL( DRMHeaderNameF, THTTPHdrVal( DRMValue1 ) );
+
+            CleanupStack::PopAndDestroy( &DRMHeaderNameF );
+            CleanupStack::PopAndDestroy( &DRMValue3 );
+            CleanupStack::PopAndDestroy( &DRMValue1 );
+            }
+        }
+    }
+
+//-----------------------------------------------------------------------------
+// CHTTPFilterDRM::GetDRMTransIdx
+// Retrieve the DRM datasupplier
+//-----------------------------------------------------------------------------
+//
+TInt CHTTPFilterDRM::GetDRMTransIdx( const RHTTPTransaction& aTrans ) const
+    {
+    for ( TInt i = 0; i < iDataSups.Count(); ++i )
+        {
+        if ( iDataSups[i]->GetTransId() == aTrans.Id() )
+            {
+            return i;
+            }
+        }
+    return KErrNotFound;
+    }
+
+//-----------------------------------------------------------------------------
+// CHTTPFilterDRM::Cleanup
+// Cleanup the resource related with a transaction
+//-----------------------------------------------------------------------------
+//
+void CHTTPFilterDRM::Cleanup( const RHTTPTransaction& aTrans )
+    {
+    TInt idx = GetDRMTransIdx( aTrans );
+    if ( idx != KErrNotFound )
+        {
+        // remove the problematic data supplier
+        CHTTPFilterDRMDataSupplier* sup = iDataSups[idx];
+        iDataSups.Remove( idx );
+        delete sup;
+        sup = NULL;
+        }
+    }
+
+//-----------------------------------------------------------------------------
+// CHTTPFilterDRM::CleanupAll
+// Cleanup all the DRM transactions, in case a session error happens or a session
+// is closed.
+//-----------------------------------------------------------------------------
+//
+void CHTTPFilterDRM::CleanupAll()
+    {
+    iDataSups.ResetAndDestroy();
+    }