--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pnpmobileservices/pnpms/PnpPaosFilter/src/PnpPaosFilter.cpp Thu Dec 17 08:40:12 2009 +0200
@@ -0,0 +1,817 @@
+/*
+* Copyright (c) 2005-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: PnP Paos filter implementation
+*
+*/
+
+
+#include <e32std.h>
+#include <http.h>
+#include <apgcli.h> // for RApaLsSession
+#include <apacmdln.h> // for CApaCommandLine
+#include <centralrepository.h> // link against centralrepository.lib
+
+#include "PnpPaosFilter.h"
+#include "PnpPaosLogger.h"
+#include "PnpPaosXml.h"
+#include "PnpPaosFilterPrivateCRKeys.h"
+
+
+
+_LIT8( KPaosContentType, "application/vnd.paos+xml" );
+_LIT8( KPnpPaosFilterName, "PnpPaosFilter" );
+_LIT8( KPaosHeaderName, "PAOS" );
+_LIT8( KPaosHeader, "ver=\"urn:liberty:paos:2003-08\"; urn:\"http://pnpms.nokia.com/signkey\"" );
+_LIT8( KDummyResponse, "<!-- Dummy -->" );
+_LIT8( KHttp, "http://" );
+_LIT8( KHttps, "https://" );
+
+CEComFilter* CPnpPaosFilter::InstantiateL( TAny* aSession )
+ {
+ LOGSTRING("CPnpPaosFilter::InstantiateL()");
+ // Cast TAny to RHTTPSession
+ RHTTPSession* pSession = static_cast<RHTTPSession*>(aSession);
+ CPnpPaosFilter* filter = CPnpPaosFilter::NewL( pSession );
+ LOGSTRING("CPnpPaosFilter::InstantiateL() - done");
+ return filter;
+ }
+
+CPnpPaosFilter* CPnpPaosFilter::NewL( RHTTPSession* pSession )
+ {
+ LOGSTRING("CPnpPaosFilter::NewL()");
+ CPnpPaosFilter* pNew = new (ELeave) CPnpPaosFilter( pSession);
+ CleanupStack::PushL(pNew);
+ pNew->ConstructL();
+ CleanupStack::Pop();
+ LOGSTRING("CPnpPaosFilter::NewL() - done");
+ return pNew;
+ }
+
+CPnpPaosFilter::CPnpPaosFilter( RHTTPSession* pSession ) :
+ iTransactionId(-1),
+ iSession( pSession ),
+ iMakePaosResponse( EFalse )
+#ifndef __SERIES60_
+ ,iHdcPaosPostDone( EFalse )
+#endif
+ {
+ LOGSTRING("constructor CPnpPaosFilter()");
+ }
+
+void CPnpPaosFilter::ReadAllowedDomainsL()
+ {
+ LOGSTRING("CPnpPaosFilter::ReadAllowedDomainsL()");
+ RLibrary library;
+ const TUidType hdcuid( KNullUid, KNullUid, KHdcUtilDllUid );
+ TInt result = library.Load( KHdcDllFileName, hdcuid );
+ LOGSTRING2( "Hdc Library load result: %i", result );
+ // If there is no HDC installed, cannot add allowed HDC domains
+ if( result == KErrNone )
+ {
+ CleanupClosePushL( library );
+ LOGSTRING("CPnpPaosFilter::ReadAllowedDomainsL() 2");
+ // Function at ordinal 1 is NewLC
+ TLibraryFunction entry = library.Lookup(1);
+ // Call the function to create new hdc dll object
+ LOGSTRING("CPnpPaosFilter::ReadAllowedDomainsL() 3");
+ CHdcToPaosInterface* hdcUtil = ( CHdcToPaosInterface* ) entry();
+ hdcUtil->TrustedDomainsL( iTrustedHdcDomains );
+ LOGSTRING("CPnpPaosFilter::ReadAllowedDomainsL() 4");
+ CleanupStack::PopAndDestroy( hdcUtil );
+ CleanupStack::PopAndDestroy(); // library.Close()
+ LOGSTRING("CPnpPaosFilter::ReadAllowedDomainsL() 5");
+ }
+
+ // PnP trusted domains could be handled as in HDC case, by maintaining
+ // a list of trusted domains as browser bookmarks (changeable only
+ // in a Device Managament session, not by the user)
+ //AllowedDomainsArray pnpDomains = pnpUtil->AllowedDomainsL();
+ LOGSTRING("CPnpPaosFilter::ReadAllowedDomainsL() - done");
+ }
+
+void CPnpPaosFilter::ReadAllowedPnpDomainsL()
+ {
+ LOGSTRING("CPnpPaosFilter::ReadAllowedPnpDomainsL()");
+ // Create PnP-MS home domain filter
+ // Read allowed pnp domains from cenrep
+ CRepository* repository = CRepository::NewLC( KCRUidPnpPaosFilter );
+
+ TBuf<KMaxURLLength> buffer;
+ TUint32 domainNbr;
+ TrustedDomain domain;
+ for (domainNbr = KPnPPaosFilterHomeDomain1; domainNbr <= KPnPPaosFilterHomeDomainLast; domainNbr++)
+ {
+ User::LeaveIfError( repository->Get( domainNbr, buffer ) );
+ if(buffer.Length() > 0)
+ {
+ domain.Copy( buffer );
+ iTrustedPnpDomains.Append( domain );
+ }
+ }
+ CleanupStack::PopAndDestroy( repository );
+ LOGSTRING("CPnpPaosFilter::ReadAllowedPnpDomainsL() - done");
+ }
+
+void CPnpPaosFilter::ConstructL()
+ {
+ LOGSTRING("CPnpPaosFilter::ConstructL()");
+
+ iSessionStringPool = iSession->StringPool();
+ iFilterName = iSessionStringPool.OpenFStringL( KPnpPaosFilterName );
+ TInt err( KErrNone );
+ TRAP( err, iPnpPaosXml = CPnpPaosXml::NewL() );
+ LOGSTRING2( "iPnpPaosXml err: %i", err );
+
+ TRAP( err, ReadAllowedDomainsL() );
+ if( err != KErrNone )
+ {
+ LOGSTRING2( "Could not read allowed domains for HelpDeskConnect PAOS: %i", err );
+ }
+
+ TRAP( err, ReadAllowedPnpDomainsL() );
+ if( err != KErrNone )
+ {
+ LOGSTRING2( "Could not read allowed domains for PnP PAOS: %i", err );
+ }
+
+
+ LOGSTRING("CPnpPaosFilter::ConstructL() add filters");
+
+ // Add the filter to the queue and register for selected incoming and
+ // outgoing events.
+ iSession->FilterCollection().AddFilterL(
+ *this,
+ THTTPEvent::ESubmit, // Transaction event
+ RStringF(), // Any header field
+ KAnyStatusCode, // HTTP status code
+ MHTTPFilter::EClientFilters, // Position in filter chain
+ //MHTTPFilter::EProtocolHandler, // Position in filter chain
+ iFilterName ); // Filter name
+
+ iSession->FilterCollection().AddFilterL(
+ *this,
+ THTTPEvent::EGotResponseHeaders,
+ RStringF(),
+ 200,
+ MHTTPFilter::EClientFilters, // Position in filter chain
+ //MHTTPFilter::EProtocolHandler, // Position in filter chain
+ iFilterName );
+
+ iSession->FilterCollection().AddFilterL(
+ *this,
+ THTTPEvent::EGotResponseBodyData,
+ RStringF(),
+ 200,
+ MHTTPFilter::EClientFilters, // Position in filter chain
+ //MHTTPFilter::EProtocolHandler, // Position in filter chain
+ iFilterName );
+
+ iSession->FilterCollection().AddFilterL(
+ *this,
+ THTTPEvent::EResponseComplete,
+ RStringF(),
+ 200,
+ MHTTPFilter::EClientFilters, // Position in filter chain
+ //MHTTPFilter::EProtocolHandler, // Position in filter chain
+ iFilterName );
+
+ LOGSTRING("CPnpPaosFilter::ConstructL() - done");
+ }
+
+CPnpPaosFilter::~CPnpPaosFilter()
+ {
+ LOGSTRING("CPnpPaosFilter::~CPnpPaosFilter()");
+
+ if( iLoadCount )
+ {
+ // As we're already in a destructor, MHFUnload must not delete us again
+ iLoadCount = -1;
+ if (iSession)
+ {
+ // Removes all registrations of this filter:
+ iSession->FilterCollection().RemoveFilter( iFilterName );
+ }
+ }
+ iFilterName.Close();
+ iTrustedPnpDomains.Close();
+
+ delete iPaosPostUrl;
+ delete iPnpPaosXml;
+
+ // RArray must be closed before destructing
+ iTrustedHdcDomains.Close();
+
+ // we do not own iSessionStringPool, we do not close it.
+ // we do not own iSession
+
+ LOGSTRING("CPnpPaosFilter::~CPnpPaosFilter() - done");
+ }
+
+void CPnpPaosFilter::HostFromUriL( CUri8* aUri )
+ {
+ LOGSTRING( "Original URI:" );
+ LOGTEXT( aUri->Uri().UriDes() );
+
+ /** The userinfo component specifier */
+ aUri->RemoveComponentL( EUriUserinfo );
+ LOGTEXT( aUri->Uri().UriDes() );
+ /** The path component specifier */
+ aUri->RemoveComponentL( EUriPath );
+ LOGTEXT( aUri->Uri().UriDes() );
+ /** The query component specifier */
+ aUri->RemoveComponentL( EUriQuery );
+ LOGTEXT( aUri->Uri().UriDes() );
+ /** The fragment component specifier */
+ aUri->RemoveComponentL( EUriFragment );
+ LOGTEXT( aUri->Uri().UriDes() );
+
+ // Only EUriHost (The host component specifier) and
+ // EUriPort (The port component specifier) are left
+ }
+
+void CPnpPaosFilter::MHFRunL( RHTTPTransaction aTransaction,
+ const THTTPEvent& aEvent)
+ {
+ LOGSTRING3( "CPnpPaosFilter::MHFRunL( TxnId: %d, event: %d )", aTransaction.Id(), aEvent.iStatus );
+ switch( aEvent.iStatus )
+ {
+ case THTTPEvent::ESubmit:
+ {
+ LOGSTRING( "CPnpPaosFilter::MHFRunL:ESubmit");
+
+ // Generate as little overhead as possible:
+
+ // If this is the case maybe PAOS requests should be allowed only from certain URLs...
+ // Now only nokia.com or help-portal.com are allowed URLs
+ CUri8* uri = CUri8::NewLC( aTransaction.Request().URI() );
+ HostFromUriL( uri );
+ TPtrC8 host = uri->Uri().UriDes();
+
+ // Check if a PAOS query is allowed from the domain
+
+ if( IsPaosHomeDomainL( host ) )
+ {
+ LOGSTRING("PnP Mobile Services Allows PAOS-requests from the domain");
+ RHTTPHeaders headers = aTransaction.Request().GetHeaderCollection();
+ AddPaosHeadersL( headers );
+ // From HTTP stack documentation:
+ // It's important to note that a filter object is per-session, and so might be shared by several
+ // transactions. This means that if you have per-transaction state that you need to store, it
+ // must be stored in the transaction's property set. DO NOT STORE ANY PER-TRANSACTION INFORMATION
+ // IN THE FILTER OBJECT.
+
+ iMakePaosResponse = ETrue;
+ }
+ else
+ {
+ if( host.Size() <= 255)
+ {
+ if( iTrustedHdcDomains.Find( host ) != KErrNotFound )
+ {
+ LOGSTRING("HelpDeskConnect Allows PAOS-requests from the domain");
+ RHTTPHeaders headers = aTransaction.Request().GetHeaderCollection();
+ AddPaosHeadersL( headers );
+ iMakePaosResponse = ETrue;
+ }
+ else
+ {
+ iMakePaosResponse = EFalse;
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy( uri );
+ break;
+ }
+ case THTTPEvent::EGotResponseHeaders:
+ {
+ LOGSTRING( "CPnpPaosFilter::MHFRunL:EGotResponseHeaders" );
+
+ if( !iMakePaosResponse ) break;
+
+ RHTTPHeaders headers = aTransaction.Response().GetHeaderCollection();
+ if( IsPaosContentTypeL( headers ) )
+ {
+ iTransactionId = aTransaction.Id();
+
+ delete iPaosPostUrl;
+ iPaosPostUrl = 0;
+ iPaosPostUrl = CUri8::NewL( aTransaction.Request().URI() );
+ HostFromUriL( iPaosPostUrl );
+ }
+ else
+ {
+ iMakePaosResponse = EFalse;
+ }
+ break;
+ }
+ case THTTPEvent::EGotResponseBodyData:
+ {
+ LOGSTRING( "CPnpPaosFilter::MHFRunL:EGotResponseBodyData" );
+
+ // Check if we are allowed to make a PAOS response
+ if( iMakePaosResponse && aTransaction.Id() == iTransactionId )
+ {
+ if( !iPnpPaosXml )
+ {
+ User::Leave( KErrGeneral );
+ }
+ TBool lastPart( EFalse );
+ // Received another body data chunk
+ MHTTPDataSupplier* pBody = aTransaction.Response().Body();
+ if( pBody )
+ {
+ lastPart = iPnpPaosXml->CollectResponseBodyL( *pBody );
+ }
+
+ // check if more data is expected
+ if( lastPart )
+ {
+ PostPaosResponseL( aTransaction );
+ }
+ }
+#ifndef __SERIES60_
+ // check if expecting a HDC trigger file
+ else if( iHdcPaosPostDone )
+ {
+ // Received another body data chunk
+ MHTTPDataSupplier* pBody = aTransaction.Response().Body();
+ if( pBody )
+ {
+ iPnpPaosXml->CollectResponseBodyL( *pBody );
+ }
+ }
+#endif
+ break;
+ }
+ case THTTPEvent::EResponseComplete:
+ {
+ LOGSTRING( "CPnpPaosFilter::MHFRunL:EResponseComplete" );
+
+#ifndef __SERIES60_
+ // if( contenttype == trigger )
+ if( iHdcPaosPostDone )
+ {
+ HandleHdcTriggerL();
+ aTransaction.Cancel( THTTPFilterHandle::ECurrentFilter );
+ }
+#endif
+ break;
+ }
+ default:
+ {
+ // We ignore other events. We shouldn't receive other events though.
+ break;
+ }
+ }
+ LOGSTRING( "CPnpPaosFilter::MHFRunL - done" );
+ }
+
+
+void CPnpPaosFilter::PostPaosResponseL( RHTTPTransaction& aTransaction )
+ {
+ // For some mysterious reason the http transaction has to be cancelled here (EGotResponseBodyData),
+ // otherwise browser will have the PAOS request concatenated with the resulting
+ // html page (or at least the resulting html page shows an extra text "setOfKeys"
+ // so it seems to concatenate at least part of the PAOS request)
+
+ // Since transaction is cancelled in EGotResponseBodyData event, there is no
+ // point in listening for EResponseComplete event anymore
+
+ CPnpPaosXml::TPaosStates status( CPnpPaosXml::EPaosStatusUnknown );
+
+ TRAPD( err, iPnpPaosXml->ParseL( status ) );
+ if( err == KErrNone )
+ {
+ iMakePaosResponse = EFalse;
+ iTransactionId = -1;
+ LOGSTRING( "PAOS post URL:" );
+ /*
+ "responseConsumerURL attribute, with a URL as its value.This URL SHOULD be relative to the URL that
+ was requested by the user agent (in the HTTP request that resulted in the creation of the SOAP message). If the
+ URL nevertheless is absolute it MUST have http or https as the protocol and SHOULD have a domain that is
+ owned by the same party as the owner of the domain in the URL of the HTTP request."
+ [Liberty Reverse HTTP binding for SOAP Specification]
+ */
+ const TDesC8& paosPostUrl = iPnpPaosXml->GetPaosPostUrlL();
+ if( paosPostUrl.Find( KHttp ) != KErrNotFound || paosPostUrl.Find( KHttps ) != KErrNotFound )
+ {
+ LOGSTRING( "Absolute URL" );
+ delete iPaosPostUrl;
+ iPaosPostUrl = 0;
+ TUriParser8 uriParser;
+ User::LeaveIfError( uriParser.Parse( paosPostUrl ) );
+ iPaosPostUrl = CUri8::NewL( uriParser );
+ }
+ else
+ {
+ LOGSTRING( "Relative URL" );
+ iPaosPostUrl->SetComponentL( paosPostUrl, EUriPath );
+ }
+ LOGTEXT( iPaosPostUrl->Uri().UriDes() );
+
+ switch( status )
+ {
+ case CPnpPaosXml::EPaosStatusUnknown:
+ LOGSTRING( "EPaosStatusUnknown" );
+ // Do nothing, was: User::Leave( KErrArgument );
+ break;
+ case CPnpPaosXml::EPaosStatusRequestingPnPKeys:
+ {
+ LOGSTRING( "EPaosStatusRequestingPnPKeys" );
+ CUri8* uri = CUri8::NewLC( aTransaction.Request().URI() );
+ HostFromUriL( uri );
+ // Also remove scheme
+ uri->RemoveComponentL( EUriScheme );
+ LOGTEXT( uri->Uri().UriDes() );
+
+ TPtrC8 host = uri->Uri().UriDes();
+ // check the domain was an allowed domain of PnP-MS home domain filter
+ if( IsPaosHomeDomainL( host ) )
+ {
+ PaosPostL( aTransaction );
+ }
+ CleanupStack::PopAndDestroy( uri );
+ break;
+ }
+ case CPnpPaosXml::EPaosStatusRequestingHdcKeys:
+ {
+ LOGSTRING( "EPaosStatusRequestingHdcKeys" );
+ CUri8* uri = CUri8::NewLC( aTransaction.Request().URI() );
+ HostFromUriL( uri );
+ TPtrC8 host = uri->Uri().UriDes();
+
+ TBool isTrusted( EFalse );
+ for( TInt i(0); i < iTrustedHdcDomains.Count(); i++ )
+ {
+ HdcTrustedDomain trustedDomain = iTrustedHdcDomains[i];
+ if( host.Find( trustedDomain ) != KErrNotFound )
+ isTrusted = ETrue;
+ }
+ // check the domain was an allowed domain of HDC home domain filter
+ if( isTrusted )
+ {
+ PaosPostL( aTransaction );
+#ifndef __SERIES60_
+ iHdcPaosPostDone = ETrue;
+#endif
+ }
+#ifdef _DEBUG
+ else
+ {
+ LOGSTRING("Not an allowed domain!");
+ LOGTEXT( host );
+ LOGSTRING("domains:");
+ for( TInt j(0); j < iTrustedHdcDomains.Count(); j++ )
+ {
+ LOGTEXT( iTrustedHdcDomains[j] );
+ }
+ }
+#endif
+ CleanupStack::PopAndDestroy( uri );
+ break;
+ }
+ default:
+ {
+ // We ignore other events. We shouldn't receive other events though.
+ break;
+ }
+ }
+ }
+ else
+ {
+ LOGSTRING2( "Error in ParseL: %i", err );
+ }
+
+ LOGSTRING("iPnpPaosXml->ResetPaosRequest()");
+ iPnpPaosXml->ResetPaosRequest();
+ }
+
+#ifndef __SERIES60_
+void CPnpPaosFilter::HandleHdcTriggerL()
+ {
+ LOGSTRING("Create file");
+ iHdcPaosPostDone = EFalse;
+
+ _LIT( KTempDocumentName, "C:\\Temp\\trigger.trg" );
+
+ RFs rfs;
+ User::LeaveIfError( rfs.Connect() );
+ CleanupClosePushL( rfs );
+ TInt err = rfs.MkDir( KTempDocumentName );
+ // The folder may already exist, do not leave in that case
+ if( err != KErrNone && err != KErrAlreadyExists )
+ {
+ User::Leave( err );
+ }
+
+ RFile file;
+ User::LeaveIfError( file.Replace( rfs, KTempDocumentName, EFileWrite ) );
+ CleanupClosePushL( file );
+ LOGSTRING("File created");
+ // A HDC PAOS post was made and we expect the response to be a HDC trigger file
+ const TPtrC8 hdcTriggerData = iPnpPaosXml->ResponseBodyL();
+ file.Write( hdcTriggerData );
+ LOGSTRING("File written");
+ iPnpPaosXml->ResetPaosRequest();
+
+ CleanupStack::PopAndDestroy(); // rfs
+ CleanupStack::PopAndDestroy(); // file
+
+ LOGSTRING("Starting app");
+ RApaLsSession appArcSession;
+ User::LeaveIfError( appArcSession.Connect() );
+ CleanupClosePushL( appArcSession );
+
+ CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
+ TApaAppInfo info;
+ const TUid KHdcUid = { 0x1020433F };
+ User::LeaveIfError( appArcSession.GetAppInfo( info, KHdcUid ) );
+#ifdef RD_APPS_TO_EXES
+ cmdLine->SetExecutableNameL( info.iFullName );
+#else
+ cmdLine->SetLibraryNameL( info.iFullName );
+#endif
+ cmdLine->SetCommandL( EApaCommandOpen );
+ cmdLine->SetDocumentNameL( KTempDocumentName );
+ err = appArcSession.StartApp( *cmdLine );
+ if( err != KErrNone )
+ {
+ LOGSTRING2( "StartApp err %i", err );
+ User::Leave( err );
+ }
+ LOGSTRING("Cancel transaction");
+ CleanupStack::PopAndDestroy( cmdLine );
+ CleanupStack::PopAndDestroy(); // appArcSession
+ LOGSTRING("done");
+ }
+#endif
+
+
+TBool CPnpPaosFilter::GetNextDataPart( TPtrC8& aDataPart )
+ {
+ LOGSTRING("CPnpPaosFilter::GetNextDataPart");
+ aDataPart.Set( KDummyResponse );
+ return ETrue;
+ }
+
+void CPnpPaosFilter::ReleaseData()
+ {
+ LOGSTRING("CPnpPaosFilter::ReleaseData");
+ }
+
+TInt CPnpPaosFilter::OverallDataSize()
+ {
+ LOGSTRING("CPnpPaosFilter::OverallDataSize");
+ return KDummyResponse().Length();
+ }
+
+TInt CPnpPaosFilter::Reset()
+ {
+ LOGSTRING("CPnpPaosFilter::Reset");
+ return KErrNone;
+ }
+
+void CPnpPaosFilter::AddPaosHeadersL( RHTTPHeaders& requestHeaders )
+ {
+ LOGSTRING( "CPnpPaosFilter::AddPaosHeadersL" );
+
+ // Add PAOS header
+ THTTPHdrVal paosVer;
+ RStringF paosVerStr = iSessionStringPool.OpenFStringL( KPaosHeader );
+ CleanupClosePushL( paosVerStr );
+ paosVer.SetStrF( paosVerStr );
+ RStringF paosStr = iSessionStringPool.OpenFStringL( KPaosHeaderName );
+ CleanupClosePushL( paosStr );
+ requestHeaders.SetFieldL( paosStr, paosVerStr );
+ CleanupStack::PopAndDestroy(); // paosStr.Close()
+ CleanupStack::PopAndDestroy(); // paosVerStr.Close()
+
+ // Add PAOS content type to accept header
+ THTTPHdrVal acceptHdr;
+ requestHeaders.GetField(
+ iSessionStringPool.StringF( HTTP::EAccept, RHTTPSession::GetTable() ), 0, acceptHdr );
+
+ if (acceptHdr.Type() == 0x04) //Worst case scenario, if transaction does not have accept header.
+ {
+ RStringF valStr = iSessionStringPool.OpenFStringL(_L8("*/*"));
+ THTTPHdrVal val(valStr);
+ requestHeaders.SetFieldL(iSessionStringPool.StringF(HTTP::EAccept, RHTTPSession::GetTable() ), val);
+ valStr.Close();
+ requestHeaders.GetField(
+ iSessionStringPool.StringF( HTTP::EAccept, RHTTPSession::GetTable() ), 0, acceptHdr );
+
+ }
+
+
+ RStringF acceptStr = acceptHdr.StrF();
+ TPtrC8 accept = acceptStr.DesC();
+ if( accept.Find( KPaosContentType ) == KErrNotFound )
+ {
+ HBufC8* acceptBuf = HBufC8::NewLC( KPaosContentType().Length() );
+ TPtr8 acceptBufPtr = acceptBuf->Des();
+ acceptBufPtr.Append( KPaosContentType );
+ SetHttpHeaderL( requestHeaders, HTTP::EAccept, *acceptBuf );
+
+#ifdef LOGGING_ENABLED
+ LOGSTRING( "Accept header:" );
+ for( TInt i(0); i < acceptBufPtr.Length(); i += 128 )
+ {
+ TPtrC8 logText = acceptBufPtr.Right( acceptBufPtr.Length() - i );
+ LOGTEXT( logText );
+ }
+#endif
+ CleanupStack::PopAndDestroy( acceptBuf );
+ }
+#ifdef LOGGING_ENABLED
+ else
+ {
+ LOGSTRING( "Accept header already includes PAOS:" );
+ for( TInt i(0); i < accept.Length(); i += 128 )
+ {
+ TPtrC8 logText = accept.Right( accept.Length() - i );
+ LOGTEXT( logText );
+ }
+ }
+#endif
+
+ LOGSTRING( "CPnpPaosFilter::AddPaosHeadersL - done" );
+ }
+
+TBool CPnpPaosFilter::IsPaosContentTypeL( RHTTPHeaders& aHeaders )
+ {
+ LOGSTRING( "CPnpPaosFilter::IsPaosContentTypeL" );
+
+ // get the Content-Type string
+ RStringF content = iSessionStringPool.StringF( HTTP::EContentType,
+ RHTTPSession::GetTable() );
+
+ THTTPHdrVal fieldVal;
+ // now retrieve the Content-Type field
+ if( KErrNone == aHeaders.GetField( content, 0, fieldVal ) )
+ {
+ TPtrC8 contentType;
+ // get the field value
+ if( THTTPHdrVal::KStrFVal == fieldVal.Type() )
+ {
+ contentType.Set( fieldVal.StrF().DesC() );
+ LOGSTRING( "ContentType:" );
+ LOGTEXT( contentType );
+ }
+ else if( THTTPHdrVal::KStrVal == fieldVal.Type() )
+ {
+ contentType.Set( fieldVal.Str().DesC() );
+ LOGSTRING( "ContentType:" );
+ LOGTEXT( contentType );
+ }
+ else
+ {
+ return EFalse;
+ }
+
+ if( contentType.Compare( KPaosContentType ) == 0 )
+ {
+ LOGSTRING("Content type matches");
+
+ // 3.0 does not handle the resulting html right, it is stored by DL manager.
+ // This means that it does not recognize the incoming text/html data correctly.
+ // So try replacing content type field with text/html, maybe PAOS content type is
+ // cached somewhere even if the transaction has been canceled.
+ LOGSTRING("Resetting Content type to text/html");
+ aHeaders.RemoveField( iSessionStringPool.StringF( HTTP::EContentType , RHTTPSession::GetTable() ) );
+ SetHttpHeaderL( aHeaders, HTTP::EContentType, _L8("text/html") );
+
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+void CPnpPaosFilter::PaosPostL( RHTTPTransaction& aTransaction )
+ {
+ LOGSTRING( "CPnpPaosFilter::PaosPostL" );
+
+ RHTTPRequest request = aTransaction.Request();
+
+ aTransaction.Cancel( THTTPFilterHandle::ECurrentFilter );
+ RHTTPHeaders requestHeaders = request.GetHeaderCollection();
+ request.RemoveBody();
+ // Remove Content-Type header
+ requestHeaders.RemoveField( iSessionStringPool.StringF( HTTP::EContentType, RHTTPSession::GetTable() ) );
+ // Remove Content-Length header
+ requestHeaders.RemoveField( iSessionStringPool.StringF( HTTP::EContentLength, RHTTPSession::GetTable() ) );
+ // Remove Host header
+ requestHeaders.RemoveField( iSessionStringPool.StringF( HTTP::EHost, RHTTPSession::GetTable() ) );
+
+ // PAOS header
+ THTTPHdrVal paosVer;
+ RStringF paosVerStr = iSessionStringPool.OpenFStringL( KPaosHeader );
+ CleanupClosePushL( paosVerStr );
+ paosVer.SetStrF( paosVerStr );
+ RStringF paosStr = iSessionStringPool.OpenFStringL( KPaosHeaderName );
+ CleanupClosePushL( paosStr );
+ requestHeaders.SetFieldL( paosStr, paosVerStr );
+ CleanupStack::PopAndDestroy(); // paosStr
+ CleanupStack::PopAndDestroy(); // paosVerStr
+
+ // Content headers
+ SetHttpHeaderL( requestHeaders, HTTP::EContentType, _L8("application/vnd.paos+xml") );
+
+ request.SetMethod( iSessionStringPool.StringF( HTTP::EPOST, RHTTPSession::GetTable() ) );
+
+ // Set the URI of the request
+ request.SetURIL( iPaosPostUrl->Uri() );
+
+ LOGSTRING( "Uri:" );
+ LOGTEXT( iPaosPostUrl->Uri().UriDes() );
+
+ // Provide Response
+ if( !iPnpPaosXml )
+ {
+ User::Leave( KErrGeneral );
+ }
+ request.SetBody( *iPnpPaosXml );
+
+ aTransaction.Cancel();
+ aTransaction.SubmitL();
+ LOGSTRING( "CPnpPaosFilter::PaosPostL - done" );
+ }
+
+void CPnpPaosFilter::SetHttpHeaderL( RHTTPHeaders& aMessage, const HTTP::TStrings aIndex, const TDesC8& aString )
+ {
+ LOGSTRING( "CPnpPaosFilter::SetHttpHeaderL" );
+
+ THTTPHdrVal hdrVal;
+ RStringF str = iSessionStringPool.OpenFStringL( aString );
+ CleanupClosePushL( str );
+ hdrVal.SetStrF( str );
+ aMessage.SetFieldL( iSessionStringPool.StringF( aIndex, RHTTPSession::GetTable() ), hdrVal );
+ CleanupStack::PopAndDestroy();
+
+ LOGSTRING( "CPnpPaosFilter::SetHttpHeaderL - done" );
+ }
+
+TInt CPnpPaosFilter::MHFRunError( TInt aError,
+ RHTTPTransaction aTransaction,
+ const THTTPEvent& aEvent )
+ {
+ LOGSTRING( "CPnpPaosFilter::MHFRunError()" );
+
+ LOGSTRING3( "error: %d, event: %d", aError, aEvent.iStatus );
+ // If anything left, we've run out of memory or something
+ // similarly catastrophic has gone wrong.
+ // Remove the body to prevent other client from accessing
+ // the contents.
+ aTransaction.Response().RemoveBody();
+ // Set the transaction to failed
+ aTransaction.Fail();
+ // Keep compiler happy
+ (void)aError;
+ (void)aEvent;
+ LOGSTRING( "CPnpPaosFilter::MHFRunError() - done" );
+ return KErrNone;
+ }
+
+void CPnpPaosFilter::MHFLoad(RHTTPSession /*aSession*/,
+ THTTPFilterHandle /*aHandle*/)
+ {
+ LOGSTRING("CPnpPaosFilter::MHFLoad");
+ iLoadCount++;
+ }
+
+void CPnpPaosFilter::MHFUnload(RHTTPSession /*aSession*/,
+ THTTPFilterHandle /*aHandle*/)
+ {
+ LOGSTRING("CPnpPaosFilter::MHFUnload");
+ if( --iLoadCount > 0 )
+ {
+ LOGSTRING("CPnpPaosFilter::MHFUnload - done");
+ return;
+ }
+ delete this; // Delete object itself
+ LOGSTRING("CPnpPaosFilter::MHFUnload - done");
+ }
+
+TBool CPnpPaosFilter::IsPaosHomeDomainL( const TPtrC8 aHost )
+ {
+ LOGSTRING("CPnpPaosFilter::IsPaosHomeDomainL");
+ // check is the host in trusted domains list
+ for (TInt i=0; i < iTrustedPnpDomains.Count(); i++)
+ {
+ if (aHost.Find(iTrustedPnpDomains[i]) != KErrNotFound )
+ {
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }