diff -r 000000000000 -r b16258d2340f applayerpluginsandutils/httpprotocolplugins/WspProtocolHandler/CWspCOTransaction.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/applayerpluginsandutils/httpprotocolplugins/WspProtocolHandler/CWspCOTransaction.cpp Tue Feb 02 01:09:52 2010 +0200 @@ -0,0 +1,662 @@ +// Copyright (c) 2001-2009 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: +// + +// System includes +#include +#include +#include +#include + +// User includes +#include +#include "cwspcotxdata.h" +#include "cwspcorxdata.h" +#include "cwspprimitivesender.h" +#include "mwspcomethodobserver.h" +#include "wsppanic.h" + +// Class signature +#include "cwspcotransaction.h" + +CWspCOTransaction* CWspCOTransaction::NewL( + RHTTPTransaction aTransaction, + MWspCOMethodInvoker& aMethodInvoker, + MWspCapabilityViewer& aNegotiatedCapInfo, + MWspCOMethodObserver& aObserver, + CWspHeaderUtils& aHdrUtils + ) + { + CWspCOTransaction* self = new (ELeave) CWspCOTransaction(aTransaction, aMethodInvoker, aNegotiatedCapInfo, aObserver, aHdrUtils); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CWspCOTransaction::~CWspCOTransaction() + { + if( iPrimitiveSender ) + iPrimitiveSender->Cancel(); + delete iPrimitiveSender; + } + +CWspCOTransaction::CWspCOTransaction( + RHTTPTransaction aTransaction, + MWspCOMethodInvoker& aMethodInvoker, + MWspCapabilityViewer& aNegotiatedCapInfo, + MWspCOMethodObserver& aObserver, + CWspHeaderUtils& aHdrUtils + ) +: CProtTransaction(aTransaction), iMethodInvoker(aMethodInvoker), + iNegotiatedCapInfo(aNegotiatedCapInfo), + iObserver(aObserver), + iHdrUtils(aHdrUtils), + iMethodState(ENullMethod) + { + __OPEN_LOG("WspProtocolHandler.txt") + } + +void CWspCOTransaction::ConstructL() + { + iPrimitiveSender = CWspPrimitiveSender::NewL(*this); + } + +void CWspCOTransaction::InitRequestL() + { + __ASSERT_DEBUG( iMethodState == ENullMethod, Panic(KWspPanicMethodAlreadyActive) ); + + // Reset all the flags + ResetFlags(); + + // Set the request data + STATIC_CAST(CWspCOTxData*, iTxData)->SetRequestDataL(); + } + +void CWspCOTransaction::NotifyMoreRequestData() + { + __ASSERT_DEBUG( iMethodState == ENullMethod || iMethodState == ERequesting, Panic(KWspPanicBadMethodState) ); + + // Inform the Tx data object that there is more data + STATIC_CAST(CWspCOTxData*, iTxData)->NotifyMoreRequestData(); + } + +void CWspCOTransaction::AbortRequest() + { + // Check the state - ignore if in the WSP method transaction is in the Null + // or Aborting state. + if( iMethodState != ENullMethod && iMethodState != EAborting && !iFinalResPending ) + { + // The client has cancelled the method - set flag. + iClientMethodAbort = ETrue; + + // Do abort... + MethodAbort(); + } + } + +void CWspCOTransaction::Suicide() + { + // Check the WSP method transaction state + if( iMethodState == EAborting || iFinalResPending ) + { + // Waiting for the S-MethodAbort.ind primitive or the final .res primitive + // to be sent. Need to flag self-destruction suicide when the primitive + // is received/sent. + iSuicide = ETrue; + } + else + { + __ASSERT_DEBUG( iMethodState == ENullMethod, Panic(KWspPanicBadMethodState) ); + + // The WSP method transaction is finished or not started - safe to + // delete now. + delete this; + } + } + +void CWspCOTransaction::ResetFlags() + { + iMoreRequestData = EFalse; + iSentMethodResultRes = EFalse; + iClientMethodAbort = EFalse; + iSuicide = EFalse; + iFinalResPending = EFalse; + } + +CWspHeaderUtils& CWspCOTransaction::GetWspHeaderUtils() const + { + return iHdrUtils; + } + +void CWspCOTransaction::MethodInvoke() + { + __ASSERT_DEBUG( iMethodState == ENullMethod, Panic(KWspPanicMethodAlreadyActive) ); + + __LOG1(_L("Trans %d - Sending S-MethodInvoke.req"), Transaction().Id()); + + // Down-cast to derived CTxData object + CWspCOTxData* txData = STATIC_CAST(CWspCOTxData*, iTxData); + + // Get the request body data supplier + MHTTPDataSupplier& dataSupplier = txData->RequestBodyData(); + TPtrC8 bodyData; + iMoreRequestData = !dataSupplier.GetNextDataPart(bodyData); + + // Send the S-MethodInvoke.req primitive + RHTTPRequest request = iTrans.Request(); + iMethodInvoker.MethodInvokeReq( + *this, + request.Method(), + request.URI(), + txData->RequestHeadersData(), + bodyData, + iMoreRequestData + ); + // WSP method transaction is requesting - update state + iMethodState = ERequesting; + + __LOG(_L("---Method in Requesting state")); + + // Release request body data + dataSupplier.ReleaseData(); + } + +void CWspCOTransaction::MethodInvokeData() + { + __ASSERT_DEBUG( iNegotiatedCapInfo.GetProtocolOptions() & ELargeDataTransfer, Panic(KWspPanicLDTNotSuppoted) ); + __ASSERT_DEBUG( iMethodState == ERequesting, Panic(KWspPanicNotExpectingMoreRequestData) ); + + __LOG1(_L("Trans %d - Sending S-MethodInvokeData.req"), Transaction().Id()); + + // Down-cast to derived CTxData object + CWspCOTxData* txData = STATIC_CAST(CWspCOTxData*, iTxData); + + // Get the request body data supplier + MHTTPDataSupplier& dataSupplier = txData->RequestBodyData(); + TPtrC8 bodyData; + iMoreRequestData = !dataSupplier.GetNextDataPart(bodyData); + + // Send the S-MethodInvoke.req primitive + iMethodInvoker.MethodInvokeDataReq( + *this, + bodyData, + txData->RequestHeadersData(), + iMoreRequestData + ); + + __LOG(_L("---Method in Requesting state")); + + // WSP method transaction remains in requesting state - do nothing. + // Release request body data + dataSupplier.ReleaseData(); + } + +void CWspCOTransaction::MethodAbort() + { + __ASSERT_DEBUG( iMethodState != EAborting && iMethodState != ENullMethod, Panic(KWspPanicBadMethodState) ); + + __LOG1(_L("Trans %d - Sending S-MethodAbort.req"), Transaction().Id()); + + // Cancel any pending primitives that are waiting to be sent + iPrimitiveSender->Cancel(); + + // Abort the method - send the S-MethodAbort.req + iMethodInvoker.MethodAbortReq(*this); + + // WSP method transaction is aborting - update state + iMethodState = EAborting; + + __LOG(_L("---Method in Aborting state")); + } + +void CWspCOTransaction::MethodResultRes() + { + // Send the S-MethodResult.res primitive + iMethodInvoker.MethodResultRes(*this, KNullDesC8()); + + // Ensure the S-MethodResultData.res is not sent again + iSentMethodResultRes = ETrue; + + // Sent the .res primitive - update. + PostResProcessing(); + } + +void CWspCOTransaction::MethodResultDataRes() + { + // Send the S-MethodResultData.cnf primitive + iMethodInvoker.MethodResultDataRes(*this, KNullDesC8()); + + // Sent the .res primitive - update. + PostResProcessing(); + } + +void CWspCOTransaction::PostResProcessing() + { + // Check the WSP method transaction state + if( iMethodState == ECompleting ) + { + __ASSERT_DEBUG( iFinalResPending, Panic(KWspPanicBadMethodState) ); + + // WSP method state is in the Null state - update state + iMethodState = ENullMethod; + + __LOG(_L("---Method in Null state")); + + // Reset the final .res pending flag + iFinalResPending = EFalse; + + // Need to inform observer that this method has sent the final .res + // primitive. + iObserver.NotifyMethodComplete(); + + // Check to see if the transaction has been closed. + if( iSuicide ) + { + __LOG(_L("---Transaction has been closed - suiciding!")); + + // Transaction is closed - self-destruct + delete this; + } + } +#ifdef _DEBUG + else + { + __ASSERT_DEBUG( iMethodState == EWaiting2, Panic(KWspPanicBadMethodState) ); + __LOG(_L("---Method in Waiting2 state")); + } +#endif + } + +void CWspCOTransaction::ProcessResponseDataL(const TDesC8& aResponseHeaders, MHTTPDataSupplier& aResponseBody, TBool aMoreData) + { + // Create the rx data object + CreateRxDataL(iObserver); + + // Set-up the response data object + STATIC_CAST(CWspCORxData*, iRxData)->SetResponseDataL(aResponseHeaders, aResponseBody, aMoreData); + } + +/* + * Methods from CProtTransaction + */ + +void CWspCOTransaction::CreateTxDataL() + { + __ASSERT_DEBUG( iTxData == NULL, Panic(KWspPanicTxDataObjectNotReset) ); + + iTxData = CWspCOTxData::NewL(*this, *this, iNegotiatedCapInfo); + } + +void CWspCOTransaction::CreateRxDataL(MRxDataObserver& aObserver) + { + __ASSERT_DEBUG( iRxData == NULL, Panic(KWspPanicRxDataObjectNotReset) ); + + iRxData = CWspCORxData::NewL(*this, aObserver, *this); + } + +/* + * Methods from MWspCOMethodCallback + */ + +void CWspCOTransaction::MethodInvokeCnf() + { + __ASSERT_DEBUG( iMethodState == ERequesting, Panic(KWspPanicBadMethodState) ); + + __LOG1(_L("Trans %d - Received S-MethodInvoke.cnf"), Transaction().Id()); + __LOG1(_L("---More Data flag : %d."), iMoreRequestData); + + // Inform the Tx data object that cnf has been received. + STATIC_CAST(CWspCOTxData*, iTxData)->ReceivedCnf(); + + // Is the requst complete? Stay in requesting if not. + if( !iMoreRequestData ) + { + // The request is complete - all the request body data has been received + // and, as iMoreRequestData is cleared, all the headers and body data + // have been sent. Can delete the Tx data object. + ResetTxData(); + + // WSP method transaction is waiting - update state + iMethodState = EWaiting; + + __LOG(_L("---Method in Waiting state")); + } +#if defined (_DEBUG) && defined (_LOGGING) + else + __LOG(_L("---Method in Requesting state")); +#endif + } + +void CWspCOTransaction::MethodInvokeDataCnf() + { + __ASSERT_DEBUG( iMethodState == ERequesting, Panic(KWspPanicBadMethodState) ); + + __LOG1(_L("Trans %d - Received S-MethodInvokeData.cnf"), Transaction().Id()); + __LOG1(_L("---More Data flag : %d."), iMoreRequestData); + + // Inform the Tx data object that cnf has been received. + STATIC_CAST(CWspCOTxData*, iTxData)->ReceivedCnf(); + + // Is the requst complete? Stay in requesting if not. + if( !iMoreRequestData ) + { + // The request is complete - all the request body data has been received + // and, as iMoreRequestData is cleared, all the headers and body data + // have been sent. Can delete the Tx data object. + ResetTxData(); + + // WSP method transaction is waiting - update state + iMethodState = EWaiting; + + __LOG(_L("---Method in Waiting state")); + } +#if defined (_DEBUG) && defined (_LOGGING) + else + __LOG(_L("---Method in Requesting state")); +#endif + } + +void CWspCOTransaction::MethodAbortInd(TWspReason aReason) + { + __ASSERT_DEBUG( iMethodState != ENullMethod, Panic(KWspPanicBadMethodState) ); + + __LOG1(_L("Trans %d - Received S-MethodAbort.ind"), Transaction().Id()); + __LOG1(_L("---Abort reason : %d"), aReason); + + // Cancel any pending primitives that are waiting to be sent + iPrimitiveSender->Cancel(); + if( iFinalResPending ) + { + // Reset the final .res pending flag + iFinalResPending = EFalse; + + // Need to inform observer that this method has sent the final .res + // primitive. + iObserver.NotifyMethodComplete(); + } + + // The method has been aborted - check to see if the client initiated the + // abort or not. + if( !iClientMethodAbort ) + { + __LOG(_L("---Method was aborted by the proxy - need to inform the client.")); + + // The method was NOT aborted by the client - need to fail the + // transaction. Check the abort reason for EOutOfMemory. + THTTPEvent event = THTTPEvent::EFailed; + if( aReason == EOutOfMemory ) + { + // Send KErrNoMemory event - the validation filter will ensure an + // EFailed event is also sent. + event = KErrNoMemory; + } + TRAPD(err, Transaction().SendEventL(event, + THTTPEvent::EIncoming, + THTTPFilterHandle::EProtocolHandler)); + + // Get the protocol handler to deal with the method abort. + iObserver.HandleMethodAbort(*this); + + // If the event could not be sent, we must take more drastic action. Note that + // this _must_ follow the observer's handling of method abort, since the use + // of RHTTPTransaction::Fail() is drastic, and could result in the whole + // transaction having been deleted by the time we get back here. + if (err != KErrNone) + Transaction().Fail(THTTPFilterHandle::EProtocolHandler); + } + + // WSP method transaction is now Null - update state + iMethodState = ENullMethod; + + __LOG(_L("---Method in Null state")); + + // Check to see if the client has closed the transaction. In this case the + // suicide flag is set and need to self-destruct. + if( iSuicide ) + { + __LOG(_L("---Transaction has been closed - suiciding!")); + + // Transaction is closed - self-destruct + delete this; + } + } + +void CWspCOTransaction::MethodResultInd( + TInt aStatus, + const TDesC8& aResponseHeaders, + MHTTPDataSupplier& aResponseBody, + TBool aMoreData + ) + { + __ASSERT_DEBUG( iMethodState == EWaiting, Panic(KWspPanicBadMethodState) ); + + __LOG1(_L("Trans %d - Received S-MethodResult.ind"), Transaction().Id()); + __LOG1(_L("---More Data flag : %d."), aMoreData); + + // Are there more S-MethodResultData primitives to follow? + if( aMoreData ) + { + // WSP method transaction is in Waiting2 state - update state + iMethodState = EWaiting2; + + __LOG(_L("---Method in Waiting2 state")); + } + else + { + // WSP method transaction is in Completing state - update state + iMethodState = ECompleting; + + __LOG(_L("---Method in Completing state")); + } + + // Decode response status code from WSP binary representation + TInt httpStatus = 0; + if ((aStatus >= 0x10) && (aStatus <= 0x65)) + { + // Calculate this status code in decimal + httpStatus = 100*(aStatus/0x10); + if (httpStatus == 500) + httpStatus = 416; + if (httpStatus == 600) + httpStatus = 500; + httpStatus += aStatus & 0xf; + } + + // Set the response status + iTrans.Response().SetStatusCode(httpStatus); + + // Process the response header and body data. + TRAPD(error, ProcessResponseDataL(aResponseHeaders, aResponseBody, aMoreData)); + + // Check everything went ok + if( error != KErrNone ) + { + // Ok the S-MethodResult primitive was not dealt with correctly - abort + // the method + iPrimitiveSender->InitiateSend(ESMethodAbort); + + __LOG1(_L("---Could not deal with S-MethodResult.ind primitive. Error : %d"), error); + __LOG( _L("---Aborting the method.")); + } + } + +void CWspCOTransaction::MethodResultDataInd(const TDesC8& aTrailerHeaders, TBool aMoreData) + { + __ASSERT_DEBUG( iMethodState == EWaiting2, Panic(KWspPanicBadMethodState) ); + + __LOG1(_L("Trans %d - Received S-MethodResultData.ind"), Transaction().Id()); + __LOG1(_L("---More Data flag : %d."), aMoreData); + + // Are there more S-MethodResultData primitives to follow? If there are + // more S-MethodResultData primitives to follow then the WSP method + // transaction remains in Waiting2 state - no need to update the state. + if( !aMoreData ) + { + // No more S-MethodResultData primitives to follow. WSP method + // transaction is in Completing state - update state + iMethodState = ECompleting; + + __LOG(_L("---Method in Completing state")); + } +#if defined (_DEBUG) && defined (_LOGGING) + else + __LOG(_L("---Method in EWaiting2 state")); +#endif + + // Update the response data object + TRAPD(error, + STATIC_CAST(CWspCORxData*, iRxData)->UpdateResponseDataL(aTrailerHeaders, aMoreData)); + + // Check everything went ok + if( error != KErrNone ) + { + // Ok the S-MethodResultData primitive was not dealt with correctly - + // abort the method + iPrimitiveSender->InitiateSend(ESMethodAbort); + + __LOG1(_L("---Could not deal with S-MethodResultData.ind primitive. Error : %d"), error); + __LOG( _L("---Aborting the method.")); + } + } + +/* + * Methods from MWspPrimitiveSenderCallback + */ + +void CWspCOTransaction::SendPrimitiveL(TWspPrimitive aPrimitive) + { + // Check that the primitive is one that is supported + switch( aPrimitive ) + { + case ESMethodInvokeData: + { + MethodInvokeData(); + } break; + case ESMethodResult: + { + MethodResultRes(); + } break; + case ESMethodResultData: + { + MethodResultDataRes(); + } break; + case ESMethodAbort: + { + MethodAbort(); + } break; + default: + // Unsupported primitive + User::Leave(KWspErrUnsupportedSendPrimitive); + break; + } + } + +TInt CWspCOTransaction::WspPrimitiveSenderCallbackError(TInt /*aError*/) + { + // Ok, sending one of the primitives failed. Abort the method + iPrimitiveSender->InitiateSend(ESMethodAbort); + + // Signal that this leave has been dealt with. + return KErrNone; + } + +/* + * Methods from MWspCORxDataCallback + */ + +void CWspCOTransaction::AbortResponse() + { + iPrimitiveSender->InitiateSend(ESMethodAbort); + } + +void CWspCOTransaction::SendResponsePrimitive() + { + // Set the pending last response primitive flag + iFinalResPending = iMethodState == ECompleting; + + // Is this the final .res? + if( iFinalResPending ) + { + // Inform the observer that this method needs to send the final .res primitive + iObserver.NotifyPendingCompletingMethod(); + } + + // Check to see if the S-MethodResult primitive has already been responded. + if( iSentMethodResultRes ) + { + // Need to send the S-MethodResultData.res + iPrimitiveSender->InitiateSend(ESMethodResultData); + } + else + { + // Need to send the S-MethodResult.res + iPrimitiveSender->InitiateSend(ESMethodResult); + } + } + +/* + * Methods from MWspCOTxDataCallback + */ + +void CWspCOTransaction::SendInvokePrimitive() + { + // Need to check the state to see what primitive to send. + if( iMethodState == ENullMethod ) + { + // Need to send S-MethodInvoke.req primitive - ok to send here as this + // would have been caused either by InitRequestL() or by + // otifyMoreRequestData() + MethodInvoke(); + } + else + { + __ASSERT_DEBUG( iMethodState == ERequesting, Panic(KWspPanicBadMethodState) ); + + // Need to send S-MethodInvokeData.req - defer sending as could be in + // callstack from either MethodInvokeCnf() or MethodInvokeDataCnf(). + iPrimitiveSender->InitiateSend(ESMethodInvokeData); + } + } + +void CWspCOTransaction::AbortInvoke() + { + // Check the state - no need to send S-MethodAbort primitive if the method + // is still in the null state. + if( iMethodState == ENullMethod ) + { + // Inform the client that the tranaction has failed. + TRAPD(err, Transaction().SendEventL(THTTPEvent::EFailed, + THTTPEvent::EIncoming, + THTTPFilterHandle::EProtocolHandler)); + + // Get the protocol handler to deal with the method abort. + iObserver.HandleMethodAbort(*this); + + // If the event could not be sent, we must take more drastic action. Note that + // this _must_ follow the observer's handling of method abort, since the use + // of RHTTPTransaction::Fail() is drastic, and could result in the whole + // transaction having been deleted by the time we get back here. + if (err != KErrNone) + Transaction().Fail(THTTPFilterHandle::EProtocolHandler); + } + else + { + __ASSERT_DEBUG( iMethodState == ERequesting, Panic(KWspPanicBadMethodState) ); + + // Send MethodAbort.req primitive - defer sending as could be in + // callstack from either MethodInvokeCnf() or MethodInvokeDataCnf(). + iPrimitiveSender->InitiateSend(ESMethodAbort); + } + }