calendarengines/caldav/src/httpclient.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 14 Sep 2010 21:17:03 +0300
branchRCL_3
changeset 31 97232defd20e
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2010 Sun Microsystems, Inc. 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 Contributor:
* Maximilian Odendahl
*
* Contributors:
* 
* Description: 	basic http/webdav functionality
*				handles all needed internet access for Caldav
*/

#include "httpclient.h"
#include "caldavutils.h"
#include <uri8.h>
#include <http.h>
#include <EIKENV.H>

_LIT8(KTextXml,"text/xml");
_LIT8(KTextCalendar,"text/calendar");
_LIT8(KDepth,"depth");

/**
 * CHttpClient::CHttpClient
 * default constructor
 */
CHttpClient::CHttpClient() :
	iUser(0), iPassword(0), iEtag(0), iCredentialCount(0)
	{
	}

/**
 * CHttpClient::~CHttpClient
 * default destructor
 */
CHttpClient::~CHttpClient()
	{
	delete iUser;
	delete iPassword;
	delete iEtag;

	iSess.Close();
	iRConnection.Close();
	iSocketServ.Close();

	}

/**
 * CHttpClient::NewLC
 * first phase constructor
 */
CHttpClient* CHttpClient::NewLC()
	{
	CHttpClient* me = new (ELeave) CHttpClient;
	CleanupStack::PushL(me);
	me->ConstructL();
	return me;
	}

/**
 * CHttpClient::NewL
 * first phase construction
 */
CHttpClient* CHttpClient::NewL()
	{
	CHttpClient* me = NewLC();
	CleanupStack::Pop(me);
	return me;
	}

/**
 * CHttpClient::OpenSessionL
 * open session and instal authentification
 */
void CHttpClient::OpenSessionL()
	{
	TRAPD(err, iSess.OpenL());

	if (err != KErrNone)
		{
		_LIT(KErrMsg, "Cannot create session. Is internet access point configured?");
		_LIT(KExitingApp, "Exiting app.");
		CEikonEnv::Static()->InfoWinL(KErrMsg, KExitingApp);
		User::Leave(err);
		}

	// Install this class as the callback for authentication requests
	InstallAuthenticationL(iSess);

	// Set the session's connection info...
	RHTTPConnectionInfo connInfo = iSess.ConnectionInfo();
	// ...to use the socket server
	connInfo.SetPropertyL(iSess.StringPool().StringF(HTTP::EHttpSocketServ,
			RHTTPSession::GetTable()), THTTPHdrVal(iSocketServ.Handle()));
	// ...to use the connection
	connInfo.SetPropertyL(
			iSess.StringPool().StringF(HTTP::EHttpSocketConnection,
					RHTTPSession::GetTable()),
			THTTPHdrVal(REINTERPRET_CAST(TInt, &(iRConnection))));

	}

/**
 * CHttpClient::ConstructL
 * second phase construction
 */
void CHttpClient::ConstructL()
	{
	User::LeaveIfError(iSocketServ.Connect());
	User::LeaveIfError(iRConnection.Open(iSocketServ));
	
	iExtPrefs.SetSnapPurpose( CMManager::ESnapPurposeInternet );
	iExtPrefs.SetNoteBehaviour( TExtendedConnPref::ENoteBehaviourConnDisableNotes);
	iPrefList.AppendL(&iExtPrefs);
	iRConnection.Start(iPrefList);

	OpenSessionL();
	}

/**
 * CHttpClient::DeleteL
 * HTTP DELETE
 */
TInt CHttpClient::DeleteL(const TDesC8 &aUrl, const TDesC8 &aETag)
	{
	iReturnCode = ERROR;

	TUriParser8 uri;
	uri.Parse(aUrl);

	iTrans = iSess.OpenTransactionL(uri, *this, iSess.StringPool().StringF(
			HTTP::EDELETE, RHTTPSession::GetTable()));
	if (aETag != KNullDesC8)
		SetHeaderL(iTrans.Request().GetHeaderCollection(), HTTP::EIfMatch,
				aETag);
	SetHeaderL(iTrans.Request().GetHeaderCollection(), HTTP::EUserAgent,
			KUserAgent);
	iTrans.SubmitL();

	CActiveScheduler::Start();
	return iReturnCode;
	}

/**
 * CHttpClient::HeadL
 * HTTP HEAD
 */
TInt CHttpClient::HeadL(const TDesC8 &aUrl)
	{
	iReturnCode = ERROR;

	TUriParser8 uri;
	uri.Parse(aUrl);

	iTrans = iSess.OpenTransactionL(uri, *this, iSess.StringPool().StringF(
			HTTP::EHEAD, RHTTPSession::GetTable()));
	SetHeaderL(iTrans.Request().GetHeaderCollection(), HTTP::EUserAgent,
			KUserAgent);
	iTrans.SubmitL();
	CActiveScheduler::Start();
	return iReturnCode;
	}

/**
 * CHttpClient::GetL
 * HTTP Get
 */
TInt CHttpClient::GetL(const TDesC8 &aUrl, CBufFlat *aResponse)
	{
	iReturnCode = ERROR;

	iBodyResponse = aResponse;

	TUriParser8 uri;
	uri.Parse(aUrl);

	iTrans = iSess.OpenTransactionL(uri, *this, iSess.StringPool().StringF(
			HTTP::EGET, RHTTPSession::GetTable()));
	SetHeaderL(iTrans.Request().GetHeaderCollection(), HTTP::EUserAgent,
			KUserAgent);
	iTrans.SubmitL();
	CActiveScheduler::Start();
	iBodyResponse = NULL;
	return iReturnCode;
	}

/**
 * CHttpClient::MkCalendarL
 * Caldav MKCALENDAR
 */
TInt CHttpClient::MkCalendarL(const TDesC8 &aUrl, const TDesC8 &aBody,
		CBufFlat *aResponse)
	{
	iReturnCode = ERROR;

	if (aBody != KNullDesC8)
		{
		iBodyRequest = aBody.Alloc();
		iTrans.Request().SetBody(*this);
		}

	iBodyResponse = aResponse;

	TUriParser8 uri;
	uri.Parse(aUrl);

	RStringF mkcalendar = iSess.StringPool().OpenFStringL(MKCALENDAR);
	iTrans = iSess.OpenTransactionL(uri, *this, mkcalendar);
	RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();

	SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
	SetHeaderL(hdr, HTTP::EContentType, KTextXml);

	iTrans.SubmitL();
	CActiveScheduler::Start();

	mkcalendar.Close();
	if (iBodyRequest)
		{
		delete iBodyRequest;
		iBodyRequest = NULL;
		}
	iBodyResponse = NULL;

	return iReturnCode;
	}

/**
 * CHttpClient::PutL
 * HTTP PUT
 */
TInt CHttpClient::PutL(const TDesC8 &aUrl, const TDesC8 &aIcs,
		CBufFlat *aResponse, const TDesC8 &aEtag)
	{
	iReturnCode = ERROR;

	iBodyRequest = aIcs.Alloc();
	iBodyResponse = aResponse;

	TUriParser8 uri;
	uri.Parse(aUrl);

	iTrans = iSess.OpenTransactionL(uri, *this, iSess.StringPool().StringF(
			HTTP::EPUT, RHTTPSession::GetTable()));
	RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();

	iTrans.Request().SetBody(*this);

	if (aEtag == KNullDesC8)
		{
		_LIT8(KStar, "*");
		SetHeaderL(hdr, HTTP::EIfNoneMatch, KStar);
		}
	else
		{
#ifdef ETAG
		 SetHeaderL(hdr,HTTP::EIfMatch,aEtag);
#endif
		}

	SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
	SetHeaderL(hdr, HTTP::EContentType, KTextCalendar);

	iTrans.SubmitL();
	CActiveScheduler::Start();

	delete iBodyRequest;
	iBodyRequest = NULL;
	iBodyResponse = NULL;

	return iReturnCode;
	}

/**
 * CHttpClient::ReportL
 * Caldav REPORT 
 */
TInt CHttpClient::ReportL(const TDesC8 &aUrl, const TDesC8 &aBodyRequest,
		CBufFlat *aResponse)
	{
	iReturnCode = ERROR;
	iBodyResponse = aResponse;

	TUriParser8 uri;
	uri.Parse(aUrl);

	RStringF report = iSess.StringPool().OpenFStringL(REPORT);
	iTrans = iSess.OpenTransactionL(uri, *this, report);
	if (aBodyRequest.Length())
		{
		iBodyRequest = aBodyRequest.Alloc();
		iTrans.Request().SetBody(*this);
		}

	RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();
	SetHeaderL(hdr, HTTP::EContentType, KTextXml);
	SetHeaderL(hdr, KDepth, ONE);
	SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
	iTrans.SubmitL();
	CActiveScheduler::Start();

	report.Close();

	delete iBodyRequest;
	iBodyRequest = NULL;
	iBodyResponse = NULL;

	return iReturnCode;
	}

/**
 * CHttpClient::PropfindL
 * WebDAV PROPFIND
 */
TInt CHttpClient::PropfindL(const TDesC8 &aUrl, const TDesC8 &aBodyRequest,
		CBufFlat *aResponse, TBool depth)
	{
	iReturnCode = ERROR;
	iBodyResponse = aResponse;

	TUriParser8 uri;
	uri.Parse(aUrl);

	RStringF propfind = iSess.StringPool().OpenFStringL(PROPFIND);
	iTrans = iSess.OpenTransactionL(uri, *this, propfind);
	if (aBodyRequest.Length())
		{
		iBodyRequest = aBodyRequest.Alloc();
		iTrans.Request().SetBody(*this);
		}

	RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();
	SetHeaderL(hdr, HTTP::EContentType, KTextXml);
	SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
	if (depth)
		SetHeaderL(hdr, KDepth, ZERO);
	else
		SetHeaderL(hdr, KDepth, ONE);

	iTrans.SubmitL();
	CActiveScheduler::Start();

	propfind.Close();

	delete iBodyRequest;
	iBodyRequest = NULL;
	iBodyResponse = NULL;

	return iReturnCode;
	}

/**
 * CHttpClient::ProppatchL
 * Webdav PROPPATCH
 */
TInt CHttpClient::ProppatchL(const TDesC8 &aUrl, const TDesC8 &aBodyRequest, CBufFlat *aResponse)
	{
	iReturnCode = ERROR;
	iBodyResponse = aResponse;

	TUriParser8 uri;
	uri.Parse(aUrl);

	RStringF proppatch = iSess.StringPool().OpenFStringL(PROPPATCH);
	iTrans = iSess.OpenTransactionL(uri, *this, proppatch);
	RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();
	SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
	SetHeaderL(hdr, HTTP::EContentType, KTextXml);
	
	iBodyRequest = aBodyRequest.Alloc();
	iTrans.Request().SetBody(*this);
	
	iTrans.SubmitL();
	CActiveScheduler::Start();

	proppatch.Close();

	delete iBodyRequest;
	iBodyRequest = NULL;
	iBodyResponse = NULL;

	return iReturnCode;
	}

/**
 * CHttpClient::GetServerOptionsL
 * HTTP OPTIONS
 */
TInt CHttpClient::GetServerOptionsL(const TDesC8 &aUrl,
		TCalDAVOptions &aOptions)
	{
	iReturnCode = ERROR;
	iAction = EActionOption;
	iOptions = &aOptions;

	TUriParser8 uri;
	uri.Parse(aUrl);

	RStringF options = iSess.StringPool().OpenFStringL(OPTIONS);
	iTrans = iSess.OpenTransactionL(uri, *this, options);
	SetHeaderL(iTrans.Request().GetHeaderCollection(), HTTP::EUserAgent,
			KUserAgent);
	iTrans.SubmitL();

	CActiveScheduler::Start();

	options.Close();

	iAction = EActionNone;
	return iReturnCode;
	}

/**
 * CHttpClient::GetNextDataPart
 * GetNextDataPart callback
 */
TBool CHttpClient::GetNextDataPart(TPtrC8& aDataPart)
	{
	aDataPart.Set(iBodyRequest->Des());
	return ETrue;
	}

/**
 * CHttpClient::ReleaseData
 * ReleaseData callback
 */
void CHttpClient::ReleaseData()
	{
	}

/**
 * CHttpClient::OverallDataSize
 * OverallDataSize callback
 */
TInt CHttpClient::OverallDataSize()
	{
	if (iBodyRequest)
		return iBodyRequest->Length();
	else
		return 0;
	}

/**
 * CHttpClient::Reset
 * Reset callback
 */
TInt CHttpClient::Reset()
	{
	return KErrNone;
	}

/**
 * CHttpClient::SetHeaderL
 * sets int header at session headers 
 */
void CHttpClient::SetHeaderL(RHTTPHeaders aHeaders, TInt aHdrField,
		const TDesC8& aHdrValue)
	{
	RStringF valStr = iSess.StringPool().OpenFStringL(aHdrValue);
	CleanupClosePushL(valStr);
	THTTPHdrVal val(valStr);
	aHeaders.SetFieldL(iSess.StringPool().StringF(aHdrField,
			RHTTPSession::GetTable()), val);
	CleanupStack::PopAndDestroy(&valStr);
	}

/**
 * CHttpClient::SetHeaderL
 * set string header at session headers
 */
void CHttpClient::SetHeaderL(RHTTPHeaders aHeaders, const TDesC8 &aField,
		const TDesC8 &aValue)
	{
	RStringF FieldVal = iSess.StringPool().OpenFStringL(aField);
	CleanupClosePushL(FieldVal);
	RStringF valStr = iSess.StringPool().OpenFStringL(aValue);
	CleanupClosePushL(valStr);
	THTTPHdrVal val(valStr);
	aHeaders.SetFieldL(FieldVal, val);
	CleanupStack::PopAndDestroy(&valStr);
	CleanupStack::PopAndDestroy(&FieldVal);
	}

/**
 * CHttpClient::GetCredentialsL
 * ask for username and password for authentification
 */
TBool CHttpClient::GetCredentialsL(const TUriC8& /*aURI*/, RString aRealm,
		RStringF /*aAuthenticationType*/, RString& aUsername,
		RString& aPassword)
	{
	if (iCredentialCount)
		{
		iCredentialCount = 0;
		User::Leave(KErrAccessDenied);
		}
	iCredentialCount++;
	aUsername = aRealm.Pool().OpenStringL(*iUser);
	aPassword = aRealm.Pool().OpenStringL(*iPassword);
	return ETrue;
	}

/**
 * CHttpClient::GetEtagHeaderL
 * check for ETag and save it
 */
void CHttpClient::GetEtagHeaderL(RHTTPTransaction &aTransaction)
	{
	RStringF Header = aTransaction.Session().StringPool().StringF(HTTP::EETag,
			RHTTPSession::GetTable());
	THTTPHdrVal HeaderVal;
	if (aTransaction.Response().GetHeaderCollection().GetField(Header, 0,
			HeaderVal) == KErrNone)
		{
		RStringF FieldValStr = aTransaction.Session().StringPool().StringF(
				HeaderVal.StrF());
		const TDesC8 &FieldValDesC = FieldValStr.DesC();
		delete iEtag;
		iEtag = NULL;
		iEtag = FieldValDesC.AllocL();
		}
	}

/**
 * CHttpClient::MHFRunL
 * http state machine callback
 */
void CHttpClient::MHFRunL(RHTTPTransaction aTransaction,
		const THTTPEvent& aEvent)
	{
	switch (aEvent.iStatus)
		{
		case THTTPEvent::EGotResponseHeaders:
			{
			// HTTP response headers have been received. We can determine now if there is
			// going to be a response body to save.
			RHTTPResponse resp = aTransaction.Response();
			iReturnCode = resp.StatusCode();

			if (iAction == EActionOption)
				{
				CalDavUtils::ScanAllowHeaderL(aTransaction, *iOptions);
				CalDavUtils::ScanDAVHeaderL(aTransaction, *iOptions);
				}

			GetEtagHeaderL(aTransaction);
			
			TBool cancelling = ETrue;
			if (resp.HasBody() && (iReturnCode >= OK) && (iReturnCode
					< MUTIPLECHOICES))
				cancelling = EFalse;

			if (cancelling)
				{
				aTransaction.Close();
				CActiveScheduler::Stop();
				}
			}
			break;
		case THTTPEvent::EGotResponseBodyData:
			{
			// Get the body data supplier
			MHTTPDataSupplier* body = aTransaction.Response().Body();
			TPtrC8 dataChunk;
			TBool isLast = body->GetNextDataPart(dataChunk);
			if (iBodyResponse)
				iBodyResponse->InsertL(iBodyResponse->Size(), dataChunk);
			// Done with that bit of body data
			body->ReleaseData();
			}
			break;
		case THTTPEvent::EResponseComplete:
			{
			// The transaction's response is complete
			}
			break;
		case THTTPEvent::ESucceeded:
			{
			aTransaction.Close();
			CActiveScheduler::Stop();
			}
			break;
		case THTTPEvent::EFailed:
			{
			aTransaction.Close();
			CActiveScheduler::Stop();
			}
			break;
		case THTTPEvent::ERedirectedPermanently:
			{
			}
			break;
		case THTTPEvent::ERedirectedTemporarily:
			{
			}
			break;
		default:
			{
			// close off the transaction if it's an error
			if (aEvent.iStatus < 0)
				{
				iReturnCode = aEvent.iStatus;
				aTransaction.Close();
				CActiveScheduler::Stop();
				}
			}
			break;
		}
	}

/**
 * CHttpClient::MHFRunError
 * http stack erros
 */
TInt CHttpClient::MHFRunError(TInt aError, RHTTPTransaction /*aTransaction*/,
		const THTTPEvent& /*aEvent*/)
	{
	iReturnCode = aError;
	return KErrNone;
	}

/**
 * CHttpClient::SetUserL
 * set username for authentification
 */
void CHttpClient::SetUserL(const TDesC8 &aUser)
	{
	if (iUser)
		delete iUser;
	iUser = aUser.Alloc();
	iSess.Close();
	OpenSessionL();
	}

/**
 * CHttpClient::SetPasswordL
 * Set Password for authentification
 */
void CHttpClient::SetPasswordL(const TDesC8 &aPassword)
	{
	if (iPassword)
		delete iPassword;
	iPassword = aPassword.Alloc();
	iSess.Close();
	OpenSessionL();
	}

/**
 * CHttpClient::User
 * get username
 */
TPtrC8 CHttpClient::User()
	{
	return iUser ? *iUser : KNullDesC8();
	}

/**
 * CHttpClient::Password
 * get password
 */
TPtrC8 CHttpClient::Password()
	{
	return iPassword ? *iPassword : KNullDesC8();
	}

/**
 * CHttpClient::ReturnCode
 * get returned HTTP code
 */
TInt CHttpClient::ReturnCode()
	{
	return iReturnCode;
	}

/**
 * CHttpClient::ETag
 * get ETag
 */
TPtrC8 CHttpClient::ETag()
	{
	return iEtag ? *iEtag : KNullDesC8();
	}