upnp/upnpstack/serviceframework/src/upnphttpmessagesender.cpp
changeset 0 f5a58ecadc66
--- /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 <upnphttpmessage.h>
+#include <upnplist.h>
+#include <upnpcons.h>
+#include <upnpstring.h>
+
+#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