calendarengines/caldav/src/httpclient.cpp
branchRCL_3
changeset 31 97232defd20e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calendarengines/caldav/src/httpclient.cpp	Tue Sep 14 21:17:03 2010 +0300
@@ -0,0 +1,687 @@
+/*
+* 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();
+	}