diff -r 000000000000 -r 62f9d29f7211 webservices/wsibasicplugin/src/senbasicwebservicesession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webservices/wsibasicplugin/src/senbasicwebservicesession.cpp Thu Jan 07 16:19:19 2010 +0200 @@ -0,0 +1,529 @@ +/* +* Copyright (c) 2002-2005 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: +* +*/ + + + + + + + + + + + +// INCLUDE FILES +#include "senbasicwebservicesession.h" +#include "SenHttpTransportProperties.h" // could be system included (ADO task) +#include "senservicesession.h" +#include "SenSoapMessage.h" +#include "SenSoapConstants.h" // KSenSoapActionHeaderName +#include "senwsdescription.h" +#include "msencoreservicemanager.h" +#include "msenremoteserviceconsumer.h" +#include "SenXmlUtils.h" +#include "SenDateUtils.h" +#include "msentransport.h" +#include "SenServiceConnection.h" +#include "sendebug.h" +#include "senlogger.h" +#include + + +CSenBasicWebServiceSession* CSenBasicWebServiceSession::NewL(MSIF& aFramework) + { + CSenBasicWebServiceSession* pNew = + CSenBasicWebServiceSession::NewLC(aFramework); + CleanupStack::Pop(); + return pNew; + } + +CSenBasicWebServiceSession* CSenBasicWebServiceSession::NewLC(MSIF& aFramework) + { + CSenBasicWebServiceSession* pNew = + new (ELeave) CSenBasicWebServiceSession(EBasicWebServiceSession, + aFramework); + CleanupStack::PushL(pNew); + // bugfix 2004-09-08, + // removed faulty call to CSenServiceSession::BaseConstructL + pNew->ConstructL(); + return pNew; + } + +CSenBasicWebServiceSession::CSenBasicWebServiceSession( + TDescriptionClassType aType, + MSIF& aFramework) +: +CSenWebServiceSession(aType, aFramework) + { + } + +void CSenBasicWebServiceSession::ConstructL() + { + // Sets the local name to "ServiceDescription" and initiates the inner ipElement + CSenWebServiceSession::ConstructL(); + } + +CSenBasicWebServiceSession::~CSenBasicWebServiceSession() + { + } + +// Override compute status to make BWS sessions to be ALWAYS valid (ready) +TInt CSenBasicWebServiceSession::ComputeStatusL() + { + // session is ready, if an endpoint is defined + return CSenServiceSession::ComputeStatusL(); + } + +TInt CSenBasicWebServiceSession::InitializeFromL(MSenServiceDescription& aServiceDescription) + { + TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CSenWebServiceSession::InitializeFromL"))); + + // Call superclass method to initialize facets, transport (endpoint) cue, etc.. + TInt retVal = CSenWebServiceSession::InitializeFromL(aServiceDescription); + CSenWSDescription& xmlSD = (CSenWSDescription&)aServiceDescription; + TPtrC8 transportCue = xmlSD.TransportCue(); + if( transportCue.Length() > 0 ) + { + SetTransportCueL( transportCue ); + } + return retVal; + } + + +TInt CSenBasicWebServiceSession::SubmitSoapL( const TDesC8& aSoapMessage, + const TDesC8& aTransportProperties, + MSenRemoteServiceConsumer& aConsumer, + HBufC8*& aResponse ) + { + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenWsiPlugin::RegisterServiceDescriptionL"); + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenBasicWebServiceSession::SubmitSoapL(TDesC8&)"); + TPtrC8 endpoint = Endpoint(); +#ifdef _SENDEBUG + CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////"); + CSLOG_FORMAT((aConsumer.ConnectionId() , KMinLogLevel, _L8("- Endpoint: %S"), &endpoint)); + CSLOG_FORMAT((aConsumer.ConnectionId() , KMaxLogLevel, _L8("- Message (%d bytes):"), aSoapMessage.Length())); + CSLOG_ALL(aConsumer.ConnectionId() , KMaxLogLevel,( aSoapMessage )); + CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////"); +#endif + + MSenTransport& transport = aConsumer.TransportL(); + SetFrameworkPropertiesL( transport ); + TInt retVal = transport.SubmitL( endpoint, aSoapMessage, aTransportProperties, aResponse, aConsumer); + + if(!aResponse) + { + // response was NULL: probably either out + // of heap or some transport malfunction. + return retVal; + } + else if(aResponse->Length() < KSenSoapEnvelopeName().Length()*2) + { + // no use parsing, Envelope -root element not there + // deliver non-soap body to consumer + return retVal; + } + + CleanupStack::PushL(aResponse); + + CSenSoapMessage* pResponseSoapMsg = NULL; + TInt leaveCode(KErrNone); + + // attempt to parse the response + // here. SOAP faults are to be + // searched after, + + TInt parseRetCode(KErrNone); + TRAP( leaveCode, (parseRetCode = + ParseResponseL(*aResponse, pResponseSoapMsg)) ); + + if(leaveCode!=KErrNone) + { + // THE RESPONSE could not be parsed + delete pResponseSoapMsg; + + // THE RESPONSE IS NOT SOAP + if(retVal==KErrNone) + { + // indicate with return value, that response is + // invalid - even though submit was ok, the + // response could NOT be parsed! + retVal = leaveCode; + } + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"(NOK) Response is not a SOAP message"); + } + else + { + + if (parseRetCode != KErrNone) + { + CSLOG_FORMAT((aConsumer.ConnectionId() , KMinLogLevel, _L8("(NOK) Parsing SOAP msg failed (%d)"), + parseRetCode)); + + if(retVal==KErrNone) // submit was ok + { + // indicate with return value, that response is + // invalid - even though submit was ok, the + // response could NOT be parsed! + retVal = parseRetCode; + } + + // THE RESPONSE could not be parsed + delete pResponseSoapMsg; + } + else + { + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"WS-I: (OK) Response is a SOAP message"); + CleanupStack::PushL(pResponseSoapMsg); + + TBool completeServerMessages(ETrue); + HasFacetL(KCompleteMessagesFacet, completeServerMessages); + + // response is OK and in SOAP form. + if(pResponseSoapMsg) + { + if (pResponseSoapMsg->IsFault()) + { + // response is SOAP fault + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"WS-I: Response is a SOAP fault."); + retVal = KErrSenSoapFault; + + if (!completeServerMessages) + { + CleanupStack::Pop(pResponseSoapMsg); + // try to detach the SOAP fault + HBufC8* pDetached = NULL; + retVal = HandleSoapFaultL(pResponseSoapMsg, pDetached); + if(retVal == KErrSenSoapFault || retVal == KErrNone) + { + // KErrNone means that original fault was handled + // properly and we now have the wanted result + // and consumer may receive it (message body) + + // Note: currently we don't handle any SOAP faults + // in WebServiceSession class, so KErrNone should + // not be returned. The OR clause (||) here is + // only for future extensions. + delete aResponse; + aResponse = NULL; + aResponse = pDetached; + pDetached = NULL; + } + else if(retVal == KErrNotFound) + { + + // SOAP fault element could not be found + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"WS-I: Major; SOAP fault element not found \ + even though assumed SOAP fault."); + retVal = KErrSenInternal; + } + + } + else + { + CleanupStack::PopAndDestroy(pResponseSoapMsg); + } + } + else + { + // Check complete server messages on/off + if (!completeServerMessages) + { + HBufC8* pBody = pResponseSoapMsg->BodyAsStringL(); + if(pBody) + { + delete aResponse; + aResponse = NULL; + aResponse = pBody; + pBody = NULL; + CSLOG_L(aConsumer.ConnectionId() , KNormalLogLevel,"- Detached SOAP message body."); + } + } + CleanupStack::PopAndDestroy(pResponseSoapMsg); + } + } + } + } +#ifdef _SENDEBUG + if(aResponse) + { + CleanupStack::PushL(aResponse); + CSLOG_L(aConsumer.ConnectionId() , KNormalLogLevel,"- Detached SOAP message body."); + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenBasicWebServiceSession::SubmitSoapL:"); + CSLOG_FORMAT((aConsumer.ConnectionId() , KNormalLogLevel, _L8("- Response (%d bytes):"), + aResponse->Length())); + CSLOG_ALL(aConsumer.ConnectionId() , KMaxLogLevel,(*aResponse)); + CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"--------------------------------------------------"); + CleanupStack::Pop(); // aResponse + } +#endif + CleanupStack::Pop(); // aResponse + return retVal; + } + +TInt CSenBasicWebServiceSession::SendSoapL( const TDesC8& aSoapMessage, + const TDesC8& aTransportProperties, + MSenRemoteServiceConsumer& aConsumer, + TInt& aTxnId, + HBufC8*& /*aRevalidationError*/ ) + { + TPtrC8 endpoint = Endpoint(); +#ifdef _SENDEBUG + CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////"); + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenBasicWebServiceSession::SendSoapL:"); + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"- Endpoint:"); + TLSLOG(aConsumer.ConnectionId() , KMinLogLevel,( endpoint )); + CSLOG_FORMAT((aConsumer.ConnectionId() , KMaxLogLevel, _L8("- Message (%d bytes):"), aSoapMessage.Length())); + CSLOG_ALL(aConsumer.ConnectionId() , KMaxLogLevel,(aSoapMessage)); + CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////"); +#endif + MSenTransport& transport = aConsumer.TransportL(); + SetFrameworkPropertiesL( transport ); + TInt retVal = transport.SendL( endpoint, + aSoapMessage, + aTransportProperties, + *this, + aConsumer, + aTxnId ); + CSLOG_FORMAT((aConsumer.ConnectionId() , KNormalLogLevel, _L8("- Transaction id: %d"), aTxnId)); + return retVal; + } + +TInt CSenBasicWebServiceSession::HttpMethodFromPropertiesL( const TDesC8& aProperties, + CSenHttpTransportProperties::TSenHttpMethod& aMethod ) + { + TInt retVal(KErrNotFound); + if ( aProperties.Length() > 0 && aProperties.Find(KHttpMethodLocalName)!= KErrNotFound && + (aProperties.Find(KHttpGet)!= KErrNotFound || aProperties.Find(KHttpDelete)!= KErrNotFound) ) + { + // Properties strings are found, now use CSenHttpProperties instance to validate that HTTP + // method really is either HTTP GET or HTTP DELETE: + CSenHttpTransportProperties* pHttpProperties = CSenHttpTransportProperties::NewLC(); // push tp + + // Parse aProperties into HTTP transport properties object: + TInt leaveCode( KErrNone ); + TRAP( leaveCode, pHttpProperties->ReadFromL( aProperties ); ) + if ( leaveCode == KErrNone ) + { + CSenHttpTransportProperties::TSenHttpMethod method; + retVal = pHttpProperties->HttpMethodL( method ); + if ( retVal == KErrNone ) + { + aMethod = method; + } +#ifdef _SENDEBUG + else + { + // HttpMethodL failed: + TLSLOG_FORMAT((KSenCoreServiceManagerLogChannelBase , KMinLogLevel, _L8("- HttpMethodL call failed. Error code: (%d)"), retVal)); + } +#endif // _SENDEBUG + } +#ifdef _SENDEBUG + else + { + // ReadFromL leaved: + TLSLOG_FORMAT((KSenCoreServiceManagerLogChannelBase , KMinLogLevel, _L8("- Reading (parsing) of HTTP properties failed. Leave code: (%d)"), leaveCode)); + + } +#endif // _SENDEBUG + CleanupStack::PopAndDestroy( pHttpProperties ); // de-alloc tp + } + return retVal; + } + + + +/* +* @param aMessage contains request which is parsed into a SoapEnvelope object using +* CSenWebServiceSession::MessageForSendingL and then SendSoapL is called +*/ +TInt CSenBasicWebServiceSession::SendL( const TDesC8& aMessage, + const TDesC8& aTransportProperties, + MSenRemoteServiceConsumer& aConsumer, + TInt& aTxnId, + HBufC8*& aRevalidationError ) + { + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenBasicWebServiceSession::SendL(TDesC8&, ...)"); +#ifdef _SENDEBUG + CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////"); + TPtrC8 endpoint = Endpoint(); + CSLOG_FORMAT((aConsumer.ConnectionId() , KMinLogLevel, _L8("- Endpoint: %S"), &endpoint)); + CSLOG_FORMAT((aConsumer.ConnectionId() , KMaxLogLevel, _L8("- Message (%d bytes):"), aMessage.Length())); + CSLOG_ALL(aConsumer.ConnectionId() , KMaxLogLevel,( aMessage )); + CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////"); +#endif + TInt retVal(KErrNone); + + // First check if HTTP GET or DELETE has been spesified via transport properties: + // -- in such case, the raw descriptor should be sent "as it is", without wrapping + // it inside SOAP Body. This way WS-I can support HTTP GET and DELETE and still + // validate that response(s) are SOAP (unlike REST, which does no response validation). + + CSenHttpTransportProperties::TSenHttpMethod httpMethod; + TInt readHttpMethodRetVal = HttpMethodFromPropertiesL( aTransportProperties, httpMethod ); + + if ( readHttpMethodRetVal == KErrNone && + httpMethod == CSenHttpTransportProperties::ESenHttpGet || + httpMethod == CSenHttpTransportProperties::ESenHttpDelete ) + { + // Perform direct call to service session (and not to web service session!) + retVal = CSenServiceSession::SendL( aMessage, aTransportProperties, aConsumer, aTxnId, aRevalidationError); + } + else + { + // The request data (UTF-8 descriptor) is expected to be serialized content + // for SOAP Body and HTTP GET/DELETE is not taking place. + // Proceed in standard way and parse the request with SOAP-ENV: + CSenSoapMessage* pMsg = NULL; + retVal = CSenWebServiceSession::MessageForSendingL( aMessage, aConsumer.Id(), pMsg ); + CleanupStack::PushL( pMsg ); + if ( retVal!=KErrNone ) + { + CSLOG_FORMAT((aConsumer.ConnectionId() , KMinLogLevel, _L8("- MessageForSendingL returned an error: %d"), retVal)); + CleanupStack::PopAndDestroy( pMsg ); + } + else // no error + { + HBufC8* pSoapMsg = pMsg->AsXmlL(); + CleanupStack::PopAndDestroy( pMsg ); + CleanupStack::PushL( pSoapMsg ); + retVal = SendSoapL( *pSoapMsg, aTransportProperties, aConsumer, aTxnId, aRevalidationError); + CleanupStack::PopAndDestroy( pSoapMsg ); + } + } + return retVal; + } + +/* +* aMessage contains request which is parsed into a SoapEnvelope object using +* CSenWebServiceSession::MessageForSendingL and then SubmitSoapL is called +*/ +TInt CSenBasicWebServiceSession::SubmitL( const TDesC8& aMessage, + const TDesC8& aTransportProperties , + MSenRemoteServiceConsumer& aConsumer , + HBufC8*& aResponse ) + { + CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenBasicWebServiceSession::SubmitL(TDesC8&, ...)"); +#ifdef _SENDEBUG + CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////"); + TPtrC8 endpoint = Endpoint(); + CSLOG_FORMAT((aConsumer.ConnectionId() , KMinLogLevel, _L8("- Endpoint: %S"), &endpoint)); + CSLOG_FORMAT((aConsumer.ConnectionId() , KMaxLogLevel, _L8("- Message (%d bytes) about to submit:"), aMessage.Length())); + CSLOG_ALL(aConsumer.ConnectionId() , KMaxLogLevel,( aMessage )); + CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////"); +#endif + TInt retVal(KErrNone); + CSenHttpTransportProperties::TSenHttpMethod httpMethod; + TInt readHttpMethodRetVal = HttpMethodFromPropertiesL( aTransportProperties, httpMethod ); + + if ( readHttpMethodRetVal == KErrNone && + httpMethod == CSenHttpTransportProperties::ESenHttpGet || + httpMethod == CSenHttpTransportProperties::ESenHttpDelete ) + { + // Perform direct call to service session (and not to web service session!) + retVal = CSenServiceSession::SubmitL( aMessage, aTransportProperties, aConsumer, aResponse); + } + else + { + CSenSoapMessage* pMsg = NULL; + retVal = CSenWebServiceSession::MessageForSendingL( aMessage, aConsumer.Id(), pMsg ); + CleanupStack::PushL(pMsg); + if ( retVal!=KErrNone ) + { + CSLOG_FORMAT((aConsumer.ConnectionId() , KMinLogLevel, _L8("- MessageForSendingL returned an error: %d"), retVal)); + CleanupStack::PopAndDestroy( pMsg ); + } + else // no error + { + HBufC8* pSoapMsg = pMsg->AsXmlL(); + CleanupStack::PopAndDestroy( pMsg ); // de-alloc SOAP object after de-serialization + CleanupStack::PushL( pSoapMsg ); + retVal = SubmitSoapL( *pSoapMsg, aTransportProperties, aConsumer, aResponse ); + CleanupStack::PopAndDestroy( pSoapMsg ); + } + } + return retVal; + } + + +TBool CSenBasicWebServiceSession::HasSuperClass( TDescriptionClassType aType ) + { + if( aType == MSenServiceDescription::EWebServiceSession ) // direct superclass! + { + // If asked type is the know *direct* father/mother, return true: + return ETrue; + } + else + { + // Otherwise, ask from direct superclass (may invoke chain of recursive calls) + return CSenWebServiceSession::HasSuperClass( aType ); + } + } + + +// TEMPORARY: remove when "message context"- and "transport factory taking +// properties from all layers"- tasks are ready +TInt CSenBasicWebServiceSession::SetFrameworkPropertiesL(MSenTransport& aTransport) + { + return iFramework.SetTransportPropertiesL(aTransport); + } +TInt CSenBasicWebServiceSession::HandleSoapFaultL(CSenSoapMessage* apSOAPMessage, + const TInt aErrorCode, + const TInt aTxnId, + MSenRemoteServiceConsumer& aConsumer, + MSenProperties* aResponseTransportProperties) + { + LOG_WRITE_L("CSenBasicWebServiceSession::HandleSoapFaultL "); + + TInt retVal(KErrNone); + + if ( apSOAPMessage ) + { + CleanupStack::PushL( apSOAPMessage ); + CSenSoapFault* pDetached = apSOAPMessage->DetachFaultL(); + if(pDetached) + { + LOG_WRITE_L("Detached a SOAP fault"); + CleanupStack::PushL(pDetached); + HBufC8* pAsXml = pDetached->AsXmlL(); + if(pAsXml) + { + aConsumer.HandleErrorL(pAsXml, KErrSenSoapFault, aTxnId, aResponseTransportProperties); + } + CleanupStack::PopAndDestroy(); + retVal = KErrNone; + } + else + { + LOG_WRITE_L("No SOAP fault was received."); + aConsumer.HandleErrorL(NULL, aErrorCode, aTxnId, aResponseTransportProperties); + retVal = KErrSenInternal; + } + CleanupStack::PopAndDestroy( apSOAPMessage ); + } + + + + return retVal; + } +TInt CSenBasicWebServiceSession::HandleSoapFaultL(CSenSoapMessage* apSOAPMessage, + HBufC8*& aResponse) +{ + return(CSenWebServiceSession::HandleSoapFaultL(apSOAPMessage,aResponse)); +} + +// End of File