diff -r 000000000000 -r 3ce708148e4d pnpmobileservices/pnpms/PnpPaosFilter/src/PnpPaosFilter.cpp --- /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 +#include +#include // for RApaLsSession +#include // for CApaCommandLine +#include // 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, "" ); +_LIT8( KHttp, "http://" ); +_LIT8( KHttps, "https://" ); + +CEComFilter* CPnpPaosFilter::InstantiateL( TAny* aSession ) + { + LOGSTRING("CPnpPaosFilter::InstantiateL()"); + // Cast TAny to RHTTPSession + RHTTPSession* pSession = static_cast(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 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; + }