diff -r 000000000000 -r f5a58ecadc66 upnp/upnpstack/serviceframework/src/upnphttpmessagesender.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/upnp/upnpstack/serviceframework/src/upnphttpmessagesender.cpp Tue Feb 02 01:12:20 2010 +0200 @@ -0,0 +1,486 @@ +/** @file +* Copyright (c) 2008 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: Definition of the CUpnpHttpMessageSender class +* +*/ + + +#include +#include +#include +#include + +#include "upnphttpmessagesender.h" +#include "upnphttpmessagesenderowner.h" +#include "upnphttptransaction.h" + +#ifdef _DEBUG +#define KLogFile _L("HttpClientEngine.txt") +#endif +#include "upnpcustomlog.h" + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::NewL +// Two-phased constructor. +// ---------------------------------------------------------------------------- +// +CUpnpHttpMessageSender* CUpnpHttpMessageSender::NewL( CUpnpHttpTransaction& aUpnpTransaction, + RHTTPSession aSession, MUpnpHttpMessageSenderOwner& aOwner ) + { + CUpnpHttpMessageSender* self = CUpnpHttpMessageSender::NewLC( aUpnpTransaction, + aSession, aOwner ); + CleanupStack::Pop( self ); + return self; + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::NewLC +// Two-phased constructor. +// ---------------------------------------------------------------------------- +// +CUpnpHttpMessageSender* CUpnpHttpMessageSender::NewLC( CUpnpHttpTransaction& aUpnpTransaction, + RHTTPSession aSession, MUpnpHttpMessageSenderOwner& aOwner ) + { + CUpnpHttpMessageSender* self = new (ELeave) CUpnpHttpMessageSender( aUpnpTransaction, + aSession, aOwner ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::CUpnpHttpMessageSender +// Constructor. +// ---------------------------------------------------------------------------- +// +CUpnpHttpMessageSender::CUpnpHttpMessageSender( CUpnpHttpTransaction& aUpnpTransaction, + RHTTPSession aSession, MUpnpHttpMessageSenderOwner& aOwner ) : + iUpnpTransaction( aUpnpTransaction ), + iSession( aSession ), + iOwner( aOwner ) + { + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::ConstructL +// Constructor of CUpnpHttpMessageSender +// ---------------------------------------------------------------------------- +// +void CUpnpHttpMessageSender::ConstructL() + { + iTimer = CUpnpNotifyTimer::NewL( this ); + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::~CUpnpHttpMessageSender +// Destructor. +// ---------------------------------------------------------------------------- +// +CUpnpHttpMessageSender::~CUpnpHttpMessageSender() + { + delete iBody; + delete iTimer; + iTransaction.Close(); + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::UpnpTransaction +// Returns upnp transaction object that is maintained by the object. +// ---------------------------------------------------------------------------- +// +CUpnpHttpTransaction& CUpnpHttpMessageSender::UpnpTransaction() + { + return iUpnpTransaction; + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::StartTransactionL +// Start a new HTTP transaction maintained by the object. It will start +// asynchronous sending of request message. +// ---------------------------------------------------------------------------- +// +void CUpnpHttpMessageSender::StartTransactionL() + { + ASSERT( !iTimer->IsActive() && NULL == iBody ); //check if this method is called only once + LOG_FUNC_NAME; + + PrepareRequestTransactionL(); + PrepareRequestHeadersL(); + PrepareRequestBody(); + StartRequestTimer(); + iTransaction.SubmitL(); + + ASSERT( iTimer->IsActive() ); //timer is set + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::PrepareRequestTransactionL +// Opens RHTTPTransaction with request method and uri, subscribe +// for transaction's events +// ---------------------------------------------------------------------------- +// +void CUpnpHttpMessageSender::PrepareRequestTransactionL() + { + HBufC8* uri = DestinationUriL( iUpnpTransaction.Request() ); + CleanupStack::PushL( uri ); + TUriParser8 uriParser; + uriParser.Parse( *uri ); + RStringF method = iSession.StringPool().OpenFStringL( iUpnpTransaction.Request()->Method() ); + CleanupClosePushL( method ); + iTransaction = iSession.OpenTransactionL( uriParser, *this, method ); + CleanupStack::PopAndDestroy( &method ); + //synchronize ids of both transactions + iUpnpTransaction.Request()->SetSessionId( iTransaction.Id() ); + CleanupStack::PopAndDestroy( uri ); + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::PrepareRequestHeadersL +// Sets http headers from UpnpHttpTransaction to RHTTPTransaction +// ---------------------------------------------------------------------------- +// +void CUpnpHttpMessageSender::PrepareRequestHeadersL() + { + RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection(); + hdr.RemoveAllFields(); + CUpnpHttpHeaderList& headerList = *(iUpnpTransaction.Request()->HeaderList()); + CUpnpHttpHeader* upnphdr = headerList.First(); + upnphdr = headerList.Next(upnphdr); // first header is a method + while ( upnphdr ) + { + RStringF valStr = iSession.StringPool().OpenFStringL( upnphdr->Value() ); + CleanupClosePushL( valStr ); + RStringF namStr = iSession.StringPool().OpenFStringL( upnphdr->Name() ); + CleanupClosePushL( namStr ); + + hdr.SetFieldL( namStr, THTTPHdrVal( valStr ) ); + upnphdr = headerList.Next(upnphdr); + + CleanupStack::PopAndDestroy( &namStr ); + CleanupStack::PopAndDestroy( &valStr ); + } + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::CopyResponseHeadersL +// Copies http headers from RHTTPTransaction to UpnpHttpTransaction +// ---------------------------------------------------------------------------- +// +void CUpnpHttpMessageSender::CopyResponseHeadersL() + { + CUpnpHttpMessage* msg = iUpnpTransaction.Response(); + RStringPool strPool = iSession.StringPool(); + RHTTPHeaders headers = iTransaction.Response().GetHeaderCollection(); + + THTTPHdrFieldIter iter = headers.Fields(); + while ( !iter.AtEnd() ) + { + RStringTokenF fieldName = iter(); + RStringF fieldNameStr = strPool.StringF( fieldName ); + const TDesC8& fieldNameDesC = fieldNameStr.DesC(); + + TPtrC8 rawFieldData; + if ( headers.GetRawField( fieldNameStr, rawFieldData ) == KErrNone ) + { + msg->AddPairL( fieldNameDesC, rawFieldData ); + } + + ++iter; + } + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::PrepareRequestBodyL +// Sets http message body from UpnpHttpTransaction to RHTTPTransaction +// ---------------------------------------------------------------------------- +// +void CUpnpHttpMessageSender::PrepareRequestBody() + { + if ( iUpnpTransaction.Request()->Method().Compare( KHttpPost ) == 0 + || ( iUpnpTransaction.Request()->Method().Compare( UpnpGENA::KGenaNotify ) == 0 ) ) + { + iTransaction.Request().SetBody( *this ); + } + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::StartRequestTimer +// Starts timer of request sending with TcpTimeout value. +// ---------------------------------------------------------------------------- +// +void CUpnpHttpMessageSender::StartRequestTimer() + { + iTimer->After( iUpnpTransaction.Request()->TcpTimeout(), EFalse ); + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::TimerEventL +// From MNotifyTimerObserver function which indicate that request timeout +// expired, so transaction failed. +// ---------------------------------------------------------------------------- +// +void CUpnpHttpMessageSender::TimerEventL( CUpnpNotifyTimer* /*aTimer*/ ) + { + LOG_FUNC_NAME; + TransactionFailed( EHttpRequestTimeout ); + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::MHFRunL +// Called by Symbian OS HTTP client framework to notify about transaction events. +// ---------------------------------------------------------------------------- +// +void CUpnpHttpMessageSender::MHFRunL( RHTTPTransaction aTransaction, const THTTPEvent& aEvent ) + { + ASSERT( aTransaction == iTransaction ); + switch ( aEvent.iStatus ) + { + case THTTPEvent::EGotResponseHeaders: + { + LOGS1( "THTTPEvent::EGotResponseHeaders trans id: %d", + aTransaction.Id() ); + } + break; + case THTTPEvent::EGotResponseBodyData: + { + GotResponseBodyDataL( *(aTransaction.Response().Body()) ); + } + break; + case THTTPEvent::EResponseComplete: + { + LOGS( "THTTPEvent::EResponseComplete"); + // Indicates that header & body of response is completely received. + } + break; + //note: there is a guarantee that THTTPEvent::ESucceeded XOR THTTPEvent::EFailed + //event will be provided, and it will be the last event for a transaction + //so ESucceeded and EFailed are the only legal states + //in which we can call TransactionSucceeded/TransactionFailed + case THTTPEvent::ESucceeded: + { + LOGS( "THTTPEvent::ESucceeded"); + TransactionSucceeded(); + } + break; + case THTTPEvent::EFailed: + { + LOGS( "THTTPEvent::EFailed"); + if ( KErrNone != iCurrentErrorNumber ) + { + TransactionFailed( EHttpRequestTimeout, iCurrentErrorNumber ); + } + else + { + TransactionFailed( aTransaction.Response().StatusCode() ); + } + } + break; + default: + // There are more events in THTTPEvent, but they are not usually + // needed. However, event status smaller than zero should be handled + // correctly since it's error. + { + LOGS1( "Other THTTPEvent::%d", aEvent.iStatus ); + if ( aEvent.iStatus < 0 ) + { + iCurrentErrorNumber = aEvent.iStatus; + } + } + break; + } + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::MHFRunError +// Called by Symbian OS HTTP client framework when *leave* occurs in handling +// of transaction event +// ---------------------------------------------------------------------------- +// +TInt CUpnpHttpMessageSender::MHFRunError( TInt aError, + RHTTPTransaction /*aTransaction*/, + const THTTPEvent& /*aEvent*/ ) + { + LOGS1( "Run error %d", aError ); + //in case of serious errors we are receiving here we have to notify + //error immediatly (we probably won't receive THTTPEvent::EFailed) + TransactionFailed( EHttpRequestTimeout, aError ); + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CUpnpHTTPMessageSender::TransactionSucceededL +// Called when transaction succeeded. +// Closes RHTTPTransaction, and forward result message to observer. +// ----------------------------------------------------------------------------- +void CUpnpHttpMessageSender::TransactionSucceeded() + { + //there is nothing we can do about error during notification upper layer + //except retry (risky), or ignore + TRAP_IGNORE( DoTransactionSucceededL() ); + } + +// ----------------------------------------------------------------------------- +// CUpnpHttpMessageSender::TransactionFailedL +// Called in case of every fail of transaction. +// Closes RHTTPTransaction, creates error message with given status, and forward it +// to observer. +// ----------------------------------------------------------------------------- +void CUpnpHttpMessageSender::TransactionFailed( TInt aStatus, TInt aError ) + { + //see comment in TransactionSucceeded + TRAP_IGNORE( DoTransactionFailedL( aStatus, aError ) ); + } + +// ----------------------------------------------------------------------------- +// CUpnpHTTPMessageSender::DoTransactionSucceededL +// Internal, leaving code to notify that transaction succeeded +// Do NOT use this method directly, but via TransactionSucceded +// ----------------------------------------------------------------------------- +void CUpnpHttpMessageSender::DoTransactionSucceededL() + { + LOG_FUNC_NAME; + iTimer->Cancel(); + iUpnpTransaction.CreateOkResponseL( iBody ? *iBody : KNullDesC8() ); + CopyResponseHeadersL(); //to copy SID from service subscription http response + iTransaction.Close(); + delete iBody; + iBody = NULL; + iOwner.SenderFinishedLD( this ); + } + +// ----------------------------------------------------------------------------- +// CUpnpHTTPMessageSender::DoTransactionFailedL +// Internal, leaving code to notify that transaction failed +// Do NOT use this method directly, but via TransactionFailed +// ----------------------------------------------------------------------------- +void CUpnpHttpMessageSender::DoTransactionFailedL( TInt aStatus, TInt aError ) + { + LOG_FUNC_NAME; + iTimer->Cancel(); + iTransaction.Close(); + if ( KErrNone != aError ) //in case of internal symbian error colected body isn't meaningful + { + delete iBody; + iBody = NULL; + } + iUpnpTransaction.CreateFaultResponseL( iBody ? *iBody : KNullDesC8(), + aStatus, + aError ); + delete iBody; + iBody = NULL; + iOwner.SenderFinishedLD( this ); + } + +// ----------------------------------------------------------------------------- +// CUpnpHttpMessageSender::GotResponseBodyDataL +// Called when transaction got another part of body data. +// Data is concatenated to iBody and when the last part of body is received +// request message is created witin transaction. +// ----------------------------------------------------------------------------- +void CUpnpHttpMessageSender::GotResponseBodyDataL( + MHTTPDataSupplier& aResponseBodySupplier ) + { + LOG_FUNC_NAME; + + TPtrC8 dataChunk; + aResponseBodySupplier.GetNextDataPart( dataChunk ); + + if (!iBody) + { + iBody = dataChunk.AllocL(); + } + else + { + iBody = iBody->ReAllocL( iBody->Length() + dataChunk.Length() ); + iBody->Des().Append( dataChunk ); + } + + aResponseBodySupplier.ReleaseData(); + } + +// ----------------------------------------------------------------------------- +// CUpnpHTTPMessageSender::DestinationUriL +// Helper method that allocate descriptor object with destination uri of message +// passed as a parameter. +// ----------------------------------------------------------------------------- +HBufC8* CUpnpHttpMessageSender::DestinationUriL( CUpnpHttpMessage* aMessage ) + { + TInetAddr add( aMessage->Receiver() ); + HBufC8* address = UpnpString::InetToStringL( add ); + CleanupStack::PushL( address ); + TPtrC8 path( aMessage->SenderPathFromHeader() ) ; + HBufC8* uriBuf = HBufC8::NewL( + UpnpHTTP::KHTTPUrl().Length() + address->Length() + path.Length() ); + TPtr8 uri( uriBuf->Des() ); + uri.Append( UpnpHTTP::KHTTPUrl ); + uri.Append( *address ); + uri.Append( path ); + CleanupStack::PopAndDestroy( address ); + return uriBuf; + } + +// ----------------------------------------------------------------------------- +// CUpnpHttpMessageSender::GetNextDataPart +// Method from MHTTPDataSupplier used to supply body of request from +// our UpnpMessage to Symian RHTTPRequest +// ----------------------------------------------------------------------------- +TBool CUpnpHttpMessageSender::GetNextDataPart( TPtrC8& aDataChunk ) + { + aDataChunk.Set( iUpnpTransaction.Request()->Body() ); + return ETrue; + } + +// ----------------------------------------------------------------------------- +// CUpnpHttpMessageSender::ReleaseData() +// Method from from MHTTPDataSupplier to supply body of request from +// our UpnpMessage to Symian RHTTPRequest +// ----------------------------------------------------------------------------- +void CUpnpHttpMessageSender::ReleaseData() + { + } + +// ----------------------------------------------------------------------------- +// CUpnpHttpMessageSender::OverallDataSize +// Method from MHTTPDataSupplier used to supply body of request from +// our UpnpMessage to Symian RHTTPRequest +// ----------------------------------------------------------------------------- +TInt CUpnpHttpMessageSender::OverallDataSize() + { + return iUpnpTransaction.Request()->Body().Length(); + } + +// ----------------------------------------------------------------------------- +// CUpnpHttpMessageSender::Reset +// Method from MHTTPDataSupplier used to supply body of request from +// our UpnpMessage to Symian RHTTPRequest +// ----------------------------------------------------------------------------- +TInt CUpnpHttpMessageSender::Reset() + { + return KErrNone; + } + +// ---------------------------------------------------------------------------- +// CUpnpHttpMessageSender::CancelTransaction +// Cancels transaction +// ---------------------------------------------------------------------------- +// +void CUpnpHttpMessageSender::CancelTransaction() + { + LOG_FUNC_NAME; + iTransaction.Cancel(); + iTimer->Cancel(); + TransactionFailed( EHttpRequestTimeout );//no need to wait, notify timeout + } + +//end of file