diff -r 000000000000 -r b16258d2340f applayerpluginsandutils/httpprotocolplugins/WspProtocolHandler/CWspCOProtocolHandler.cpp --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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; + }