--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerpluginsandutils/httpprotocolplugins/WspProtocolHandler/CWspCOProtocolHandler.cpp Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,1237 @@
+// 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 <http/framework/crxdata.h>
+#include <http/rhttpheaders.h>
+#include <http/thttpevent.h>
+#include <httpstringconstants.h>
+#include <wsp/wsptypes.h>
+#include <wsp/cwsptransporthandler.h>
+#include <wsp/mwspcosessioninvoker.h>
+#include <wsp/mwspcomethodinvoker.h>
+#include <wspstringconstants.h>
+#include <wspstdconstants.h>
+#include <wsperror.h>
+
+// User includes
+#include "cwspcotransaction.h"
+#include "cwspcapabilityinfo.h"
+#include "cwspproxyinfoprovider.h"
+#include "cconnectiontimer.h"
+#include "cwspprimitivesender.h"
+#include "wsppanic.h"
+#include "cwspheaderutils.h"
+#include "cwspheadercodec.h"
+
+// Class signature
+#include "cwspcoprotocolhandler.h"
+
+const TInt KDefaultConnectionTimeMicroSeconds = 180000000; // 3 minutes
+
+/*
+ * CWspCOProtocolHandler
+ */
+
+CWspCOProtocolHandler* CWspCOProtocolHandler::NewL(TAny* aSession)
+ {
+ RHTTPSession* session = REINTERPRET_CAST(RHTTPSession*, aSession);
+ CWspCOProtocolHandler* self = new (ELeave) CWspCOProtocolHandler(*session);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CWspCOProtocolHandler::~CWspCOProtocolHandler()
+ {
+
+ if( iConnectionTimer )
+ iConnectionTimer->Cancel();
+ delete iConnectionTimer;
+
+ delete iClientSessionHeaders;
+ delete iTransportHandler;
+ delete iClientCapInfo;
+ delete iNegotiatedCapInfo;
+ delete iProxyInfoProvider;
+ delete iPrimitiveSender;
+ delete iHdrUtils;
+ }
+
+CWspCOProtocolHandler::CWspCOProtocolHandler(RHTTPSession aSession)
+: CProtocolHandler(aSession), /*iSessionState(ENull),*/ iTimedOutValue(KDefaultConnectionTimeMicroSeconds)
+ {
+ __OPEN_LOG("WspProtocolHandler.txt")
+ }
+
+void CWspCOProtocolHandler::ConstructL()
+ {
+ CProtocolHandler::ConstructL(iSession);
+
+ // Open the WSP header field names table
+ iSession.StringPool().OpenL(WSP::Table);
+
+ // Create the proposed client capability object and the negotiated session capability object
+ iClientCapInfo = CWspCapabilityInfo::NewL();
+ iNegotiatedCapInfo = CWspCapabilityInfo::NewL();
+
+ // Create the proxy info provider
+ iProxyInfoProvider = CWspProxyInfoProvider::NewL(iSession);
+
+ // Create the connection timer object
+ iConnectionTimer = CConnectionTimer::NewL(*this);
+
+ // Create the primitive sender active object
+ iPrimitiveSender = CWspPrimitiveSender::NewL(*this);
+
+ // Create the transport handler
+ CreateWspTransportHandlerL();
+
+ // Create the WSP header utilities
+ iHdrUtils = CWspHeaderUtils::NewL(*STATIC_CAST(CWspHeaderCodec*, iCodec));
+ }
+
+void CWspCOProtocolHandler::CreateWspTransportHandlerL()
+ {
+ // Assert that the transport handler doesn't already exist
+ __ASSERT_DEBUG(iTransportHandler == NULL, Panic(KWspPanicTransportHandlerAlreadyExists));
+
+ // Pass through the session string pool when creating the transport handler
+ RStringPool stringPool = iSession.StringPool();
+ iTransportHandler = CWspTransportHandler::NewL(
+ stringPool,
+ iSecurityPolicy,
+ *this, // Session CB
+ *iProxyInfoProvider, // Proxy info
+ *this, // Capability info
+ *this // Session headers info
+ );
+
+ // Check the supported services
+ CWspTransportHandler::TWspSupportedServices suppSvc = iTransportHandler->SupportedServices();
+ TBool sessionSupport = suppSvc & CWspTransportHandler::ECOSessionService;
+ TBool methodSupport = suppSvc & CWspTransportHandler::ECOMethodInvocationService;
+ if( !sessionSupport || !methodSupport )
+ {
+ __LOG(_L("Session management facility or method invoke facility not supported by transport handler"));
+ User::Leave(KWspErrRequiredServicesNotSupported);
+ }
+ // Configure the session invoker object
+ iSessionInvoker = &iTransportHandler->COSessionInvoker();
+ }
+
+
+void CWspCOProtocolHandler::CheckClientCapabilities()
+ {
+ // Reset the proposed client properties - sets the capabilities to the
+ // default values.
+ iClientCapInfo->Reset();
+
+ // Check the session properties...
+ RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
+ RStringPool stringPool = iSession.StringPool();
+
+ // ...client message size...
+ THTTPHdrVal clientMessageSize;
+ TBool hasClientMessageSize = connInfo.Property(stringPool.StringF(HTTP::EWspCapClientMessageSize, RHTTPSession::GetTable()), clientMessageSize);
+ if( hasClientMessageSize )
+ {
+ // Initial attempt to negotiate message size and SDU size will attempt to go
+ // for a single PDU transfers, so set them the same
+ __ASSERT_DEBUG( clientMessageSize.Type() == THTTPHdrVal::KTIntVal, Panic(KWspPanicBadClientMessageSize) );
+ iClientCapInfo->SetClientMessageSize(clientMessageSize.Int());
+ iClientCapInfo->SetClientSDUSize(clientMessageSize.Int());
+ }
+ // ... server message size...
+ THTTPHdrVal serverMessageSize;
+ TBool hasServerMessageSize = connInfo.Property(stringPool.StringF(HTTP::EWspCapServerMessageSize, RHTTPSession::GetTable()), serverMessageSize);
+ if( hasServerMessageSize )
+ {
+ // Initial attempt to negotiate message size and SDU size will attempt to go
+ // for a single PDU transfers, so set them the same
+ __ASSERT_DEBUG( serverMessageSize.Type() == THTTPHdrVal::KTIntVal, Panic(KWspPanicBadServerMessageSize) );
+ iClientCapInfo->SetServerMessageSize(serverMessageSize.Int());
+ iClientCapInfo->SetServerSDUSize(serverMessageSize.Int());
+ }
+ // ...method MOR...
+ THTTPHdrVal methodMOR;
+ TBool hasMethodMOR = connInfo.Property(stringPool.StringF(HTTP::EWspCapMaxOutstandingRequests, RHTTPSession::GetTable()), methodMOR);
+ if( hasMethodMOR )
+ {
+ __ASSERT_DEBUG( methodMOR.Type() == THTTPHdrVal::KTIntVal, Panic(KWspPanicBadMethodMOR) );
+ __ASSERT_DEBUG( STATIC_CAST(TUint8, methodMOR.Int()) <= KMaxTUint8, Panic(KWspPanicBadMethodMOR) );
+ __ASSERT_DEBUG( STATIC_CAST(TUint8, methodMOR.Int()) > 0, Panic(KWspPanicBadMethodMOR) );
+ iClientCapInfo->SetMethodMOR( STATIC_CAST(TUint8, methodMOR.Int()) );
+ }
+ // Sort out the protocol options - by default try to use Large Data Transfer
+ TUint8 protocolOptions = ELargeDataTransfer;
+ THTTPHdrVal notUsed;
+ // ...use acknowledgements...
+ TBool hasUseAcknowledgements = connInfo.Property(stringPool.StringF(HTTP::EWspCapUseAcknowledgements, RHTTPSession::GetTable()), notUsed);
+ if( hasUseAcknowledgements )
+ {
+ protocolOptions |= EAcknowledgementHeaders;
+ }
+ // ...support suspend resume facilty...
+ TBool hasSuspendResume = connInfo.Property(stringPool.StringF(HTTP::EWspCapSupportSuspendResume, RHTTPSession::GetTable()), notUsed);
+ if( hasSuspendResume )
+ {
+ protocolOptions |= ESessionResumeFacility;
+ }
+ iClientCapInfo->SetProtocolOptions(protocolOptions);
+
+ // Get the connection time-out value
+ THTTPHdrVal connectionTimeout;
+ TBool hasConnectionTimeout = connInfo.Property(stringPool.StringF(HTTP::EWspProxyConnectionTimeout, RHTTPSession::GetTable()), connectionTimeout);
+ if( hasConnectionTimeout )
+ {
+ __ASSERT_DEBUG((connectionTimeout.Type() == THTTPHdrVal::KTIntVal), Panic(KWspPanicBadConenctionTimeout));
+ iTimedOutValue = connectionTimeout.Int();
+ }
+ else
+ {
+ // Use the default value
+ iTimedOutValue = KDefaultConnectionTimeMicroSeconds;
+ }
+ }
+
+TBool CWspCOProtocolHandler::UpdateNegotiatedCapabilitiesL()
+ {
+ // Check the capabilities proposed by the client
+ TBool capabilitiesReduced = EFalse;
+
+ RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
+ RStringPool stringPool = iSession.StringPool();
+
+ // ...client message size...
+ TUint32 clientMessageSize = iNegotiatedCapInfo->GetClientMessageSize();
+ if( clientMessageSize != iClientCapInfo->GetClientMessageSize() )
+ {
+ // The server has reduced the client message size - update the return flag...
+ capabilitiesReduced = ETrue;
+
+ // ...and the session property...
+ THTTPHdrVal clientMessageSizeProperty = clientMessageSize;
+ connInfo.SetPropertyL(stringPool.StringF(HTTP::EWspCapClientMessageSize, RHTTPSession::GetTable()), clientMessageSizeProperty);
+ }
+ // ...server message size...
+ TUint32 serverMessageSize = iNegotiatedCapInfo->GetServerMessageSize();
+ if( serverMessageSize != iClientCapInfo->GetServerMessageSize() )
+ {
+ // The server has reduced the server message size - update the return flag...
+ capabilitiesReduced = ETrue;
+
+ // ...and the session property...
+ THTTPHdrVal serverMessageSizeProperty = serverMessageSize;
+ connInfo.SetPropertyL(stringPool.StringF(HTTP::EWspCapServerMessageSize, RHTTPSession::GetTable()), serverMessageSizeProperty);
+ }
+ // ...method MOR...
+ TUint32 methodMOR = iNegotiatedCapInfo->GetMethodMOR();
+ if( methodMOR != iClientCapInfo->GetMethodMOR() )
+ {
+ // The server has reduced the method MOR - update the return flag...
+ capabilitiesReduced = ETrue;
+
+ // ...and the session property...
+ THTTPHdrVal methodMORProperty = methodMOR;
+ connInfo.SetPropertyL(stringPool.StringF(HTTP::EWspCapMaxOutstandingRequests, RHTTPSession::GetTable()), methodMORProperty);
+ }
+ // Check the protocol options
+ TUint8 protocolOptions = iNegotiatedCapInfo->GetProtocolOptions();
+
+ // ...acknowledgements...
+ if( (protocolOptions & EAcknowledgementHeaders) != (iClientCapInfo->GetProtocolOptions() & EAcknowledgementHeaders) )
+ {
+ // The server has cleared the use acknowledgement headers flag - update
+ // the return flag...
+ capabilitiesReduced = ETrue;
+
+ // ...and the session property...
+ THTTPHdrVal notUsed = 0;
+ connInfo.SetPropertyL(stringPool.StringF(HTTP::EWspCapUseAcknowledgements, RHTTPSession::GetTable()), notUsed);
+ }
+ // ...suspend resume facility...
+ if( (protocolOptions & ESessionResumeFacility) != (iClientCapInfo->GetProtocolOptions() & ESessionResumeFacility) )
+ {
+ // The server has cleared the support suspend/resume facility flag -
+ // update the return flag...
+ capabilitiesReduced = ETrue;
+
+ // ...and the session property...
+ THTTPHdrVal notUsed = 0;
+ connInfo.SetPropertyL(stringPool.StringF(HTTP::EWspCapSupportSuspendResume, RHTTPSession::GetTable()), notUsed);
+ }
+
+ return capabilitiesReduced;
+ }
+
+TBool CWspCOProtocolHandler::SupportSuspendResume() const
+ {
+ return (iNegotiatedCapInfo->GetProtocolOptions() & ESessionResumeFacility);
+ }
+
+TBool CWspCOProtocolHandler::CanResume() const
+ {
+ TBool canResume = SupportSuspendResume();
+
+ if( canResume && (iSessionState != EConnected && iSessionState != ESuspending && iSessionState != ESuspended) )
+ {
+ // In the wrong state
+ canResume = EFalse;
+ }
+ return canResume;
+ }
+
+TBool CWspCOProtocolHandler::CanSuspend() const
+ {
+ TBool canSuspend = SupportSuspendResume();
+
+ if( canSuspend && (iSessionState != EConnected && iSessionState != EResuming) )
+ {
+ // In the wrong state
+ canSuspend = EFalse;
+ }
+ return canSuspend;
+ }
+
+#if defined (_DEBUG)
+void CWspCOProtocolHandler::ResetAll()
+ {
+ // Delete helper objects and reset state
+ delete iClientSessionHeaders;
+ iClientSessionHeaders = NULL;
+ //
+ if (iClientCapInfo)
+ iClientCapInfo->Reset();
+ if (iNegotiatedCapInfo)
+ iNegotiatedCapInfo->Reset();
+ if (iConnectionTimer)
+ iConnectionTimer->Cancel();
+ if (iProxyInfoProvider)
+ iProxyInfoProvider->ResetProxyInfo();
+ //
+ iSessionState = ENull;
+ iTimedOutValue = 0;
+ iConnectTimedOut = EFalse;
+ iWaitingMethod = EFalse;
+ iDisconnectRequested = EFalse;
+ iPendingCompletingMethods = 0;
+ //
+ // Reset the transport handler (stub only)
+ iSessionInvoker->DisconnectReq((TWspReason)(-999));
+ }
+#endif
+
+void CWspCOProtocolHandler::SessionConnectL()
+ {
+ __ASSERT_DEBUG( iSessionState == ENull, Panic(KWspPanicSessionNotInValidState) );
+
+ __LOG(_L("Initiating a session connect."));
+
+ // Check for any client proposed capabilities
+ CheckClientCapabilities();
+
+ // Update the client session headers
+ UpdateClientSessionHeadersL();
+
+ // Update the proxy info
+ iProxyInfoProvider->UpdateProxyInfoL();
+
+ // Start connection timed-out timer
+ iConnectionTimer->Start(iTimedOutValue);
+
+ // Send S-Connect.req primitive to transport handler
+ __LOG(_L("---Sending S-Connect.req primitive."));
+ iSessionInvoker->ConnectReq();
+
+ // Update session state
+ __LOG(_L("---WSP Session in Connecting state."));
+ iSessionState = EConnecting;
+
+ // Check to see if there is a method transactions waiting.
+ CheckWaitingMethod();
+ }
+
+void CWspCOProtocolHandler::SessionResumeL()
+ {
+ __ASSERT_DEBUG( CanResume(), Panic(KWspPanicSessionNotInValidState) );
+
+ __LOG(_L("Initiating a session resume."));
+
+ // Check to see if the proxy info has not changed.
+ if( iProxyInfoProvider->ProxyInfoChangedAndUpdateL() )
+ {
+ __LOG(_L("---Proxy has changed. Disconnect from the old proxy and connect to the new one."));
+
+ // The client has specified a different - disconnect this session
+ SessionDisconnect(EChangedProxyInSuspendedSession);
+ }
+ else
+ {
+ // Check for any client proposed capabilities
+ CheckClientCapabilities();
+
+ // Update the client session headers
+ UpdateClientSessionHeadersL();
+
+ // Start connection timed-out timer
+ iConnectionTimer->Start(iTimedOutValue);
+
+ // Send S-Resume.req primitive to transport handler
+ __LOG(_L("---Sending S-Resume.req primitive."));
+ iSessionInvoker->ResumeReq();
+
+ // Update session state
+ __LOG(_L("---WSP Session in Resuming state."));
+ iSessionState = EResuming;
+
+ // Check to see if there is a method transactions waiting.
+ CheckWaitingMethod();
+ }
+ }
+
+void CWspCOProtocolHandler::SessionDisconnect(TWspReason aReason)
+ {
+ __ASSERT_DEBUG( iSessionState != ENull && iSessionState != EClosing, Panic(KWspPanicSessionNotInValidState) );
+
+ // Are there any methods waiting to send their final .res primitive
+ if( iPendingCompletingMethods > 0 )
+ {
+ // Yep, need to wait until there are done.
+ iDisconnectRequested = ETrue;
+ return;
+ }
+ __LOG(_L("Disconnecting session."));
+
+ // Need to cancel the connection timer
+ iConnectionTimer->Cancel();
+
+ // Send S-Disconnect.req primitive to transport handler
+ __LOG1(_L("---Sending S-Disconnect.req primitive. Reason code : %d"), aReason);
+ iSessionInvoker->DisconnectReq(aReason);
+
+ // Update session state
+ __LOG(_L("---WSP Session in Closing state."));
+ iSessionState = EClosing;
+ }
+
+void CWspCOProtocolHandler::SessionSuspend()
+ {
+ __ASSERT_DEBUG( CanSuspend(), Panic(KWspPanicSessionNotInValidState) );
+
+ // Are there any methods waiting to send their final .res primitive
+ if( iPendingCompletingMethods > 0 )
+ {
+ // Yep, need to wait until there are done.
+ iDisconnectRequested = ETrue;
+ return;
+ }
+ __LOG(_L("Suspending session."));
+
+ // Need to cancel the connection timer
+ iConnectionTimer->Cancel();
+
+ // Send S-Suspend.req primitive to transport handler
+ __LOG(_L("---Sending S-Suspend.req primitive."));
+ iSessionInvoker->SuspendReq();
+
+ // Update session state
+ __LOG(_L("---WSP Session in Suspending state."));
+ iSessionState = ESuspending;
+ }
+
+void CWspCOProtocolHandler::DoSessionConnectedL()
+ {
+ // Cancel the connection timer
+ iConnectionTimer->Cancel();
+
+ // Check for the Encoding-Version header in the server session headers
+ RHTTPHeaders headers = iSession.ResponseSessionHeadersL();
+ THTTPHdrVal negotiatedVersion;
+ TInt err = headers.GetField(
+ iSession.StringPool().StringF(WSP::EEncodingVersion, WSP::Table),
+ 0, // Zero index -> first part
+ negotiatedVersion
+ );
+
+ // Default version is 1.2 - this is the case if the header is missing.
+ CWspHeaderCodec::TWspVersion version = CWspHeaderCodec::EVersion1_2;
+
+ if( (err != KErrNotFound) && (negotiatedVersion.Type() == THTTPHdrVal::KStrFVal) )
+ {
+ // Check what version the encoding is and set it accordingly in the codec
+ switch(negotiatedVersion.StrF().Index(WSPStdConstants::Table) )
+ {
+ case WSPStdConstants::EWspVersion11:
+ version = CWspHeaderCodec::EVersion1_1;
+ break;
+ case WSPStdConstants::EWspVersion13:
+ version = CWspHeaderCodec::EVersion1_3;
+ break;
+ case WSPStdConstants::EWspVersion14:
+ version = CWspHeaderCodec::EVersion1_4;
+ break;
+ default:
+ // If the version is 1.2 or anything else, stay at 1.2
+ break;
+ }
+ }
+ // Set the encoding value in the codec
+ STATIC_CAST(CWspHeaderCodec*, iCodec)->SetWspVersion(version);
+
+ // Inform client that the session is connected - check negotiated capabilities
+ THTTPSessionEvent connectEvent = THTTPSessionEvent::EConnectedOK;
+
+ // Check the negotiated capabilities
+ TBool capabilitiesReduced = UpdateNegotiatedCapabilitiesL();
+
+ if( capabilitiesReduced )
+ {
+ // At least one of the proposed client capabilities has been negotiated
+ // down or rejected - need to inform client of this event.
+ connectEvent = THTTPSessionEvent::EConnectedWithReducedCapabilities;
+ }
+ SendSessionEvent(connectEvent);
+
+ // WSP session is connected - update state
+ __LOG(_L("---WSP Session in Connected state"));
+ iSessionState = EConnected;
+ }
+
+void CWspCOProtocolHandler::SendSessionEvent(THTTPSessionEvent aEvent)
+ {
+ // Send the event to the client - need to TRAPD
+ TRAPD(error, iSession.SendSessionEventL(aEvent, THTTPSessionEvent::EIncoming, THTTPFilterHandle::EProtocolHandler));
+ if( error != KErrNone )
+ {
+ __LOG1(_L("Error - Could not send event to the client, error code %d"), error);
+ iSession.FailSessionEvent(THTTPFilterHandle::EProtocolHandler);
+ }
+ }
+
+void CWspCOProtocolHandler::UpdateClientSessionHeadersL()
+ {
+ // Check for Encoding-Version header
+ RStringPool stringPool = iSession.StringPool();
+ RHTTPHeaders headers = iSession.RequestSessionHeadersL();
+ THTTPHdrVal version;
+ RStringF encodingVersionField = stringPool.StringF(WSP::EEncodingVersion, WSP::Table);
+ TInt err = headers.GetField(encodingVersionField, 0 /* Zero index -> first part*/, version);
+ TBool foundHeader = EFalse;
+
+ // If the encoding-version header exists, check that it is valid
+ if( err == KErrNone )
+ {
+ if( version.Type() == THTTPHdrVal::KStrFVal )
+ {
+ switch( version.StrF().Index(WSPStdConstants::Table) )
+ {
+ case WSPStdConstants::EWspVersion11:
+ case WSPStdConstants::EWspVersion12:
+ case WSPStdConstants::EWspVersion13:
+ case WSPStdConstants::EWspVersion14:
+ foundHeader = ETrue;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // If the header is not found or is invalid, then use WSP encoding v1.4
+ if(!foundHeader)
+ {
+ // Remove existing header first if its invalid, this won't do anything if it doesn't exist
+ headers.RemoveField(encodingVersionField);
+ THTTPHdrVal encodingVersionValue(stringPool.StringF(WSPStdConstants::EWspVersion14, WSPStdConstants::Table));
+ headers.SetFieldL(encodingVersionField, encodingVersionValue);
+ __LOG(_L("---Updated WSP encoding version request to 1.4"));
+ }
+
+ // Encode the headers...
+ HBufC8* buf = iHdrUtils->EncodeHeadersL(stringPool, headers);
+
+ // Update the client session headers buffer;
+ delete iClientSessionHeaders;
+ iClientSessionHeaders = buf;
+ }
+
+void CWspCOProtocolHandler::HandleConnectRequestL()
+ {
+ // Check the WSP session state
+ switch( iSessionState )
+ {
+ case ENull:
+ {
+ // Initiate a session connect
+ SessionConnectL();
+ } break;
+ case ESuspended:
+ case ESuspending:
+ {
+ // In suspending or suspended state - this implies that the WSP
+ // session supports the Suspend Resume facility and was suspended
+ // rather than disconnected for a more efficient re-connection.
+
+ // Initiate a session resume
+ SessionResumeL();
+ } break;
+ case EConnecting:
+ case EResuming:
+ {
+ // A connect request has already been sent - inform the client
+ SendSessionEvent(THTTPSessionEvent::EAlreadyConnecting);
+ } break;
+ case EConnected:
+ {
+ // A connect request has already been sent and the session is
+ // connected - inform the client
+ SendSessionEvent(THTTPSessionEvent::EAlreadyConnected);
+ } break;
+ case EClosing:
+ {
+ // A disconnect request has already been sent - inform the client
+ SendSessionEvent(THTTPSessionEvent::EAlreadyDisconnecting);
+ } break;
+ default:
+ Panic(KWspPanicIllegalSessionState);
+ break;
+ }
+ }
+
+void CWspCOProtocolHandler::HandleDisconnectRequest()
+ {
+ // Disconnect has been requestd. Action depends of the WSP session state.
+ switch( iSessionState )
+ {
+ case ENull:
+ case ESuspended:
+ {
+ // A disconnect request has already been fulfilled - inform the client
+ SendSessionEvent(THTTPSessionEvent::EAlreadyDisconnected);
+ } break;
+ case EClosing:
+ case ESuspending:
+ {
+ // A disconnect request has already been sent - inform the client
+ SendSessionEvent(THTTPSessionEvent::EAlreadyDisconnecting);
+ } break;
+ case EConnecting:
+ {
+ // The WSP session is in the Connecting state, then the session should be
+ // disconnected - do SessionDisconnect. This will issue the
+ // S-Disconnect.req primitive and tell the transport handler to stop the
+ // connection. The transport handler will send the S-Disconnect.ind
+ // primitive which results in the client being notified.
+ SessionDisconnect(EUserReq);
+ } break;
+ case EResuming:
+ {
+ // If the WSP session is resuming, then the Suspend Resume facility is
+ // supported - can suspend the WSP session. This will issue the
+ // S-Suspend.req primitive and tell the transport handler to stop the
+ // session resume. The transport handler will send the S-Suspend.ind
+ // primitive to the protocol handler who will then inform the client.
+ SessionSuspend();
+ } break;
+ case EConnected:
+ {
+ // Check if the Suspend Resume facility is supported. If so, then
+ // suspend the WSP session, rather then disconnect it.
+ if( SupportSuspendResume() )
+ {
+ // Suspend the WSP session
+ SessionSuspend();
+ }
+ else
+ {
+ // Disconnect the WSP session
+ SessionDisconnect(EUserReq);
+ }
+ } break;
+ default:
+ Panic(KWspPanicIllegalSessionState);
+ break;
+ }
+ }
+
+void CWspCOProtocolHandler::CheckWaitingMethod()
+ {
+ if( iWaitingMethod )
+ {
+ // Self-complete the base class - this will start servicing the pending
+ // transaction.
+ CompleteSelf();
+
+ // Clear the flag
+ iWaitingMethod = EFalse;
+ }
+ }
+
+/*
+ * Methods from CProtocolHandler
+ */
+
+void CWspCOProtocolHandler::CreateCodecL()
+ {
+ iCodec = CWspHeaderCodec::NewL(iSession.StringPool(), WSP::Table);
+ }
+
+CProtTransaction* CWspCOProtocolHandler::CreateProtTransactionL(RHTTPTransaction aTransaction)
+ {
+ return CWspCOTransaction::NewL(aTransaction, iTransportHandler->COTransactionInvoker(), *iNegotiatedCapInfo, *this, *iHdrUtils);
+ }
+
+TBool CWspCOProtocolHandler::ServiceL(CProtTransaction& aTrans)
+ {
+ __LOG(_L("Attempting to invoke request."));
+
+ // Check the WSP session state
+ if( iSessionState == EClosing || iSessionState == ESuspending )
+ {
+ __LOG(_L("---Session is Closing or Suspending - cannot invoke methods."));
+
+ // The WSP session is either disconnecting or suspending - leave
+ User::Leave(KWspErrSessionClosingOrSuspending);
+ }
+ if( iSessionState == ENull || iSessionState == ESuspended )
+ {
+ __LOG(_L("---Session is Null or Suspended - cannot invoke methods. Wait for session connect initiation."));
+
+ // Send back an event saying that session is not connected yet
+ SendSessionEvent(THTTPSessionEvent::ENotConnected);
+
+ // Set a flag to indicate that there is a transaction waiting to be
+ // serviced - need to self-complete once connected.
+ iWaitingMethod = ETrue;
+
+ // Cannot service the method transaction now.
+ return EFalse;
+ }
+ // Check to see if the method MOR has been reached.
+ TUint32 activeTransactions = NumActiveTransactions();
+ if( activeTransactions == iNegotiatedCapInfo->GetMethodMOR() )
+ {
+ __LOG1(_L("---Have reached method MOR (=%d) - cannot invoke request."), iNegotiatedCapInfo->GetMethodMOR());
+
+ // Have reached the method MOR - cannot service this method transaction.
+ return EFalse;
+ }
+ // Have not yet reached the negotiated method MOR - can service this
+ // transaction.
+
+ // Create the Tx Data object for this transaction
+ aTrans.CreateTxDataL();
+
+ // Do the method invocation
+ STATIC_CAST(CWspCOTransaction&, aTrans).InitRequestL();
+
+ __LOG1(_L("---Initiated request - trans %d is active"), aTrans.Transaction().Id() );
+
+ return ETrue;
+ }
+
+void CWspCOProtocolHandler::ClosedTransactionHook(CProtTransaction* aTrans)
+ {
+ __LOG1(_L("Trans %d has been closed"), aTrans->Transaction().Id() );
+
+ // Down-cast the CProtTransaction
+ CWspCOTransaction& wspTransaction = *STATIC_CAST(CWspCOTransaction*, aTrans);
+
+ // Abort this transaction
+ wspTransaction.AbortRequest();
+
+ // Tell the method transaction to suicide - the transaction will ensure that
+ // it deletes itself at the appropriate time.
+ wspTransaction.Suicide();
+ }
+
+void CWspCOProtocolHandler::CancelTransactionHook(CProtTransaction& aTransaction)
+ {
+ __LOG1(_L("Trans %d has been cancelled"), aTransaction.Transaction().Id() );
+
+ // Abort this transaction
+ STATIC_CAST(CWspCOTransaction&, aTransaction).AbortRequest();
+ }
+
+void CWspCOProtocolHandler::NotifyNewRequestBodyPart(CProtTransaction& aTransaction)
+ {
+ __LOG(_L("Client has more request data..."));
+
+ // Send the S-MethodInvokeData primitive
+ STATIC_CAST(CWspCOTransaction&, aTransaction).NotifyMoreRequestData();
+ }
+
+void CWspCOProtocolHandler::GetInterfaceL(TUid aInterfaceId, MProtHandlerInterface*& aInterfacePtr)
+ {
+ switch(aInterfaceId.iUid)
+ {
+ case KProtHandlerSessionServerCertUid:
+ {
+ aInterfacePtr = this;
+ break;
+ }
+ default:
+ {
+ CProtocolHandler::GetInterfaceL(aInterfaceId, aInterfacePtr);
+ break;
+ }
+ }
+ }
+
+/*
+ * Methods from MHTTPFilterBase
+ */
+
+void CWspCOProtocolHandler::MHFSessionRunL(const THTTPSessionEvent& aEvent)
+ {
+ __ASSERT_DEBUG( iTransportHandler, Panic(KWspPanicTransportHandlerDoesNotExist) );
+
+ // Check the session event
+ switch(aEvent.iStatus)
+ {
+ case THTTPSessionEvent::EConnect:
+ {
+ __LOG(_L("Processing EConnect session event"));
+
+ // Handle the connect request
+ HandleConnectRequestL();
+ } break;
+ case THTTPSessionEvent::EDisconnect:
+ {
+ __LOG(_L("Processing EDisconnect session event"));
+
+ // Handle the disconnect request
+ HandleDisconnectRequest();
+ } break;
+#if defined (_DEBUG)
+ case -999:
+ {
+ // This unpublished value is used in testing to cause a whole protocol
+ // handler reset and to reset the transport handler. It should be used with caution!
+ __LOG(_L("PROTOCOL HANDLER RESETTING!"));
+ ResetAll();
+
+ // Ack the owner
+ SendSessionEvent(-999);
+ } break;
+#endif
+ default:
+ // Ignore the unknown session event.
+ __LOG1(_L("Received unknown session event : %d"), aEvent.iStatus);
+ break;
+ }
+ }
+
+TInt CWspCOProtocolHandler::MHFSessionRunError(TInt aError, const THTTPSessionEvent& /*aEvent*/)
+ {
+ // Send the error as a session event.
+ SendSessionEvent(aError);
+ return KErrNone;
+ }
+
+/*
+ * Methods from MWspCOSessionCallback
+ */
+
+void CWspCOProtocolHandler::ConnectCnf()
+ {
+ __LOG(_L("Received S-Connect.cnf primitive"));
+
+ // Did we connect to a secure proxy? If so, send the 'authenticated OK' session event
+ MWspProxyInfoProvider& proxyInfo = STATIC_CAST(MWspProxyInfoProvider&, *iProxyInfoProvider);
+ if( proxyInfo.SecureConnection() )
+ {
+ __LOG(_L("---WTLS authentication was successful."));
+
+ // Send EAuthenticatedOK event...
+ SendSessionEvent(THTTPSessionEvent::EAuthenticatedOK);
+ }
+
+ // Process the session connected event
+ DoSessionConnected();
+ }
+
+void CWspCOProtocolHandler::ResumeCnf()
+ {
+ __LOG(_L("Received S-Resume.cnf primitive"));
+
+ // Process the session connected event
+ DoSessionConnected();
+ }
+
+void CWspCOProtocolHandler::DoSessionConnected()
+ {
+ // Process the session connected event
+ TRAPD(error, DoSessionConnectedL());
+ if( error != KErrNone )
+ {
+ __LOG(_L("Error - Could not process S-Connect.cnf/S-Resume.cnf. Disconnect the WSP session."));
+
+ // Disconnect this session
+ SessionDisconnect(EPeerReq);
+ }
+ }
+
+void CWspCOProtocolHandler::DisconnectInd(TWspReason aReason,
+ TBool /*aRedirectSecurity*/,
+ TWspRedirectedAddress& aRedirectAddress,
+ const TDesC8& /*aErrorHeader*/,
+ const TDesC8& /*aErrorBody*/)
+ {
+ __ASSERT_DEBUG( NumActiveTransactions() == 0, Panic(KWspPanicMethodsStillOutstanding) );
+
+ __LOG(_L("Received S-Disconnect.ind primitive"));
+ __LOG1(_L("---Reason code : %d"), aReason);
+
+ // Cancel the connection timer
+ iConnectionTimer->Cancel();
+
+ // Check the reason for the disconnect
+ switch( aReason )
+ {
+ case EPermanentRedirectedProxy:
+ {
+ __LOG(_L("---Permanent proxy redirection"));
+
+ // Update the proxy info with the redirected proxy addresses. This will
+ // place the new address in the EWspProxyAddress session property.
+ TRAPD(error, iProxyInfoProvider->SetPermanentRedirectedProxyL(aRedirectAddress) );
+
+ if( error != KErrNone )
+ {
+ // Something went wrong - just disconnect
+ SendSessionEvent(THTTPSessionEvent::EDisconnected);
+ }
+ else
+ {
+ // Need to inform client that the proxy has been redirected permanently.
+ SendSessionEvent(THTTPSessionEvent::ERedirected);
+
+ // Send the S-Connect primitive
+ iPrimitiveSender->InitiateSend(ESConnect);
+ }
+ } break;
+ case ETemporaryRedirectedProxy:
+ {
+ __LOG(_L("---Temporary proxy redirection"));
+
+ // Update the proxy info with the redirected proxy addresses.
+ TRAPD(error, iProxyInfoProvider->SetTemporaryRedirectedProxyL(aRedirectAddress) );;
+
+ if( error != KErrNone )
+ {
+ // Something went wrong - just disconnect
+ SendSessionEvent(THTTPSessionEvent::EDisconnected);
+ }
+ else
+ {
+ // Send the S-Connect primitive
+ iPrimitiveSender->InitiateSend(ESConnect);
+ }
+ } break;
+ case EChangedProxyInSuspendedSession:
+ {
+ __LOG(_L("---Client changed proxy whilst suspended"));
+ __LOG(_L("---Forced disconnect, then connection to new proxy"));
+
+ // The client had disconnected the session (resulting in the session
+ // being suspended) and then did a connect, but with a different
+ // proxy. This resulted in the suspended session being disconnected.
+ // Now need to initiate a session connect to the new proxy.
+ iPrimitiveSender->InitiateSend(ESConnect);
+ } break;
+ case EWtlsConfigurationFailed:
+ case EWtlsPhase1HandshakeFailed:
+ case EWtlsPhase2HandshakeFailed:
+ case EWtlsInvalidServerCert:
+ case EWtlsUntrustedServerCert:
+ case EWtlsNegotiatedConfigRejected:
+ {
+ __LOG(_L("---WTLS handshake failure"));
+
+ // Various failure modes for the WTLS handshake. All result in a
+ // 'authentication failure' event being sent to the client, followed by
+ // a 'disconnected' event.
+ SendSessionEvent(THTTPSessionEvent::EAuthenticationFailure);
+ SendSessionEvent(THTTPSessionEvent::EDisconnected);
+ } break;
+ case EOutOfMemory:
+ {
+ // There was a memory allocation failure in the transport handler - inform
+ // the client.
+ SendSessionEvent(KErrNoMemory);
+
+ // Inform the client that the sesion is disconnected
+ SendSessionEvent(THTTPSessionEvent::EDisconnected);
+ } break;
+ case ESessionStateFailure:
+ {
+ // The session is effectively disconnected
+ SendSessionEvent(THTTPSessionEvent::EDisconnected);
+
+ // The transport handler has entered an invalid or indeterminate state - possibly due
+ // to a memory allocation failure - the session is no longer valid and should be
+ // discontinued by the client - inform the client.
+ __LOG(_L("Transport Handler has signalled a session state failure"));
+ iSession.FailSessionEvent(THTTPFilterHandle::EProtocolHandler);
+ } break;
+ case EUserReq:
+ {
+ // This is ind to a S-Disconnect.req. Was it due to a connect time-out?
+ if( iConnectTimedOut )
+ {
+ __LOG(_L("---Connection has timed-out"));
+
+ // Inform the client that the resume timed-out
+ SendSessionEvent(THTTPSessionEvent::EConnectionTimedOut);
+ iConnectTimedOut = EFalse;
+ break;
+ }
+ // Drop-through if there was no connect time-out
+ }
+ default:
+ // Session disconnected for some other reason. Inform the client, but
+ // ignore the information in aErrorHeader and aErrorBody. The WSP
+ // Specification states that the provider MAY choose not to communicate
+ // this information - the protocol handler is making that choice!!
+ SendSessionEvent(THTTPSessionEvent::EDisconnected);
+ break;
+ }
+ // WSP session is disconnected - update state
+ __LOG(_L("---WSP Session in Null state"));
+ iSessionState = ENull;
+ }
+
+void CWspCOProtocolHandler::SuspendInd(TWspReason /*aReason*/)
+ {
+ __ASSERT_DEBUG( NumActiveTransactions() == 0, Panic(KWspPanicMethodsStillOutstanding) );
+
+ __LOG(_L("Received S-Suspend.ind primitive"));
+
+ // Do not care about the reason, just inform the client. First check if this
+ // suspend is the result of a session resume timed-out.
+ if( iConnectTimedOut )
+ {
+ __LOG(_L("---Resume has timed-out"));
+
+ // Inform the client that the resume timed-out
+ SendSessionEvent(THTTPSessionEvent::EConnectionTimedOut);
+ iConnectTimedOut = EFalse;
+ }
+ else
+ {
+ // Inform the client that the session is disconnected - this event is
+ // sent as the the client does not understand suspend/resume and the
+ // Suspend Resume facility is being used for efficiency.
+ SendSessionEvent(THTTPSessionEvent::EDisconnected);
+ }
+ // WSP session is suspended - update state
+ __LOG(_L("---WSP Session in Suspended state"));
+ iSessionState = ESuspended;
+ }
+
+void CWspCOProtocolHandler::ExceptionInd(const TDesC8& aExceptionData)
+ {
+ RStringPool stringPool = iSession.StringPool();
+
+ // Generic handling for exception data
+ __LOG(_L("Have received exception information."));
+
+ // Add the exception data as the EWspProxyExceptionInfo property
+ RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
+ TRAP_IGNORE(
+ RStringF exceptionData = stringPool.OpenFStringL(aExceptionData);
+ CleanupClosePushL(exceptionData);
+ THTTPHdrVal exceptionProperty = exceptionData;
+ connInfo.SetPropertyL(stringPool.StringF(HTTP::EWspProxyExceptionInfo, RHTTPSession::GetTable()), exceptionProperty);
+ CleanupStack::PopAndDestroy(&exceptionData);
+ );
+
+ // Send the exception info event
+ SendSessionEvent(THTTPSessionEvent::EExceptionInfo);
+ }
+
+/*
+ * Methods from MWspCapabilityInfoProvider
+ */
+
+const MWspCapabilityViewer& CWspCOProtocolHandler::ClientCapabilities() const
+ {
+ return *iClientCapInfo;
+ }
+
+MWspCapabilitySetter& CWspCOProtocolHandler::ServerCapabilities() const
+ {
+ return *iNegotiatedCapInfo;
+ }
+
+/*
+ * Methods from MWspSessionHeadersProvider
+ */
+
+const TDesC8& CWspCOProtocolHandler::ClientHeaders() const
+ {
+ return *iClientSessionHeaders;
+ }
+
+void CWspCOProtocolHandler::SetServerHeadersL(const TDesC8& aBuffer)
+ {
+ RHTTPHeaders serverHeaders = iSession.ResponseSessionHeadersL();
+ iHdrUtils->DecodeHeadersL(iSession.StringPool(), aBuffer, serverHeaders);
+ }
+
+/*
+ * Methods from MConnectionTimerCallback
+ */
+
+void CWspCOProtocolHandler::HandleConnectionTimedOut()
+ {
+ __LOG(_L("Connection timed-out - appropriate action taken"));
+
+ // The connection has timed-out - flag
+ iConnectTimedOut = ETrue;
+
+ // Request a disconnect.
+ HandleDisconnectRequest();
+ }
+
+/*
+ * Methods from MWspPrimitiveSenderCallback
+ */
+
+void CWspCOProtocolHandler::SendPrimitiveL(TWspPrimitive aPrimitive)
+ {
+ // Check that the primitive is one that is supported
+ switch( aPrimitive )
+ {
+ case ESConnect:
+ {
+ SessionConnectL();
+ } break;
+ case ESDisconnect:
+ case ESSuspend:
+ {
+ HandleDisconnectRequest();
+ } break;
+ default:
+ // Unsupported primitive
+ User::Leave(KWspErrUnsupportedSendPrimitive);
+ break;
+ }
+ }
+
+TInt CWspCOProtocolHandler::WspPrimitiveSenderCallbackError(TInt /*aError*/)
+ {
+ // The initiate session connect has failed. Need to unlock the proxy info.
+ iProxyInfoProvider->UnlockProxyInfo();
+
+ // Inform the client - send disconnected signal
+ SendSessionEvent(THTTPSessionEvent::EDisconnected);
+
+ return KErrNone;
+ }
+
+/*
+ * Methods from MWspCOMethodObserver
+ */
+
+void CWspCOProtocolHandler::HandleMethodAbort(CWspCOTransaction& aTransaction)
+ {
+ // The CWspCOTransaction has failed the transaction - inform the base class
+ // protocol handler to change the state of this transaction.
+ TransactionFailed(aTransaction.Transaction());
+
+ __LOG1(_L("Transaction %d has failed."), aTransaction.Transaction().Id() );
+ }
+
+void CWspCOProtocolHandler::NotifyPendingCompletingMethod()
+ {
+ // Increment the number of pending methods waiting to move from Completing
+ // to Null state.
+ ++iPendingCompletingMethods;
+
+ __LOG1(_L("Number of methods waiting to send final .res primitive : %d"), iPendingCompletingMethods);
+ }
+
+void CWspCOProtocolHandler::NotifyMethodComplete()
+ {
+ // The final .res primitive has been sent for one of the methods - decrement
+ // count.
+ --iPendingCompletingMethods;
+
+ __LOG1(_L("Number of methods waiting to send final .res primitive : %d"), iPendingCompletingMethods);
+
+ if( iPendingCompletingMethods == 0 && iDisconnectRequested )
+ {
+ __LOG(_L("---All methods have sent final .res primitive. Requesting disconnect."));
+
+ // No more methods waiting to send the final .res primitive and the
+ // client has requested the session be disconnected - request it now.
+ iPrimitiveSender->InitiateSend(ESDisconnect);
+ }
+ }
+
+
+/*
+ * Methods from MRxDataObserver
+ */
+
+void CWspCOProtocolHandler::SetStatusL(CRxData& aRxData, TInt aStatus)
+ {
+ // Have received a status message from an Rx data object - check the status.
+ switch( aStatus )
+ {
+ case THTTPEvent::EResponseComplete:
+ {
+ __LOG1(_L("Transaction %d has completed"), aRxData.ProtTrans().Transaction().Id() );
+ // The response is complete - the client has been passed all the data
+ // and released it. It has no further use for the Rx data object. The
+ // transaction is now complete - inform the base class.
+ TransactionCompletedL(aRxData.ProtTrans().Transaction(), THTTPEvent::EResponseComplete);
+ } break;
+ default:
+ // Unknown status - do nothing.
+ __LOG1(_L("Received unknown status %d"), aStatus);
+ break;
+ }
+ }
+
+TInt CWspCOProtocolHandler::SessionServerCert(TCertInfo& aServerCert)
+ {
+ return iTransportHandler->ServerCert(aServerCert);
+ }
+
+const CCertificate* CWspCOProtocolHandler::SessionServerCert()
+ {
+ return iTransportHandler->ServerCert();
+ }
+
+/*
+ * Methods from MProtHandlerInterface
+ */
+
+TInt CWspCOProtocolHandler::TransactionServerCert(TCertInfo& /*aServerCert*/, RHTTPTransaction /*aTransaction*/)
+ {
+ // Transaction Server certificate does not make sense for WSP
+ return KErrNotSupported;
+ }
+
+const CCertificate* CWspCOProtocolHandler::TransactionServerCert(RHTTPTransaction /*aTransaction*/)
+
+ {
+ return NULL;
+ }