applayerpluginsandutils/httpprotocolplugins/httpclient/chttprequestbatcher.cpp
changeset 0 b16258d2340f
child 5 337070b4fa18
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerpluginsandutils/httpprotocolplugins/httpclient/chttprequestbatcher.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,319 @@
+// Copyright (c) 2003-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:
+//
+
+#include <x509cert.h>
+
+#include "chttprequestbatcher.h"
+
+
+const TInt KBatchingTimeoutMicroSeconds = 100000;
+
+
+CHttpRequestBatcher* CHttpRequestBatcher::NewL(MOutputStream& aOutputStream, const TInt aBufferSize)
+	{
+	CHttpRequestBatcher* self = new (ELeave) CHttpRequestBatcher(aOutputStream, aBufferSize);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CHttpRequestBatcher::CHttpRequestBatcher(MOutputStream& aOutputStream, const TInt aBufferSize)
+: CActive(CActive::EPriorityStandard + 1), iDataToSend(TPtr8(NULL, 0)), iExcessData(TPtrC8(NULL, 0)), iMaxBufferSize(aBufferSize)
+	{
+	__FLOG_OPEN("http", "httpclienthandler.txt");
+
+	CActiveScheduler::Add(this);
+	iOutputStream = &aOutputStream;
+	iOutputStream->Bind(*this);
+
+	iFuncPtr = &CHttpRequestBatcher::SendRequestImmediatelyL;
+	}
+
+void CHttpRequestBatcher::ConstructL()
+	{
+	iBuffer = HBufC8::NewL(iMaxBufferSize);
+	iDataToSend.Set(iBuffer->Des());
+
+	iTimer.CreateLocal();
+	iTimerCompleted = EFalse;
+
+	}
+
+
+CHttpRequestBatcher::~CHttpRequestBatcher()
+	{
+	Cancel();
+	delete iBuffer;
+	iTimer.Close();
+
+	__FLOG_CLOSE;
+	}
+
+
+void CHttpRequestBatcher::SendRequestImmediatelyL(const TDesC8& aBuffer)
+	{
+#if defined (_DEBUG) && defined (_LOGGING)
+		__FLOG_0(_T8("!! Send the first request i.e. not batching"));
+#endif
+
+	iOutputStream->SendDataReqL(aBuffer);
+	}
+
+void CHttpRequestBatcher::SendRequestsBatchedL(const TDesC8& aBuffer)
+	{
+	StartTimer();
+
+	BatchRequestsL(aBuffer);
+	}
+
+void CHttpRequestBatcher::BatchRequestsL(const TDesC8& aBuffer)
+	{
+	if (iTimerCompleted)
+		iExcessData.Set(aBuffer);
+
+	else if ((aBuffer.Length() + iDataToSend.Length()) < iMaxBufferSize)
+		{
+		iDataToSend.Append(aBuffer);
+		
+		// Buffer is not yet full, so request observer to send more data
+		iObserver->SendDataCnfL();
+		}
+	else
+		{
+		TInt pos = iMaxBufferSize - iDataToSend.Length();
+
+		// Fill up the buffer
+		iDataToSend.Append(aBuffer.Left(pos));
+
+		// Cancel the timer
+		Cancel();
+
+#if defined (_DEBUG) && defined (_LOGGING)
+		__FLOG_0(_T8("!! Buffer has been filled - cancel timer and send batched requests now"));
+#endif
+
+		// Send the request with a filled-up buffer
+		iOutputStream->SendDataReqL(iDataToSend);
+
+		// Save the excess data from this request
+		iExcessData.Set(aBuffer.Mid(pos));
+		}
+	}
+
+void CHttpRequestBatcher::StartTimer()
+	{
+	if(!IsActive())
+		{
+#if defined (_DEBUG) && defined (_LOGGING)
+		__FLOG_0(_T8("!! Start the batching timer"));
+#endif
+
+		SetActive();
+		iTimer.After(iStatus, KBatchingTimeoutMicroSeconds);
+		}
+	}
+
+
+/*
+ *	Methods from MOutputStream
+ */
+
+void CHttpRequestBatcher::Bind(MOutputStreamObserver& aObserver)
+	{
+	// Bind to the output stream observer
+	iObserver = &aObserver;
+	}
+
+void CHttpRequestBatcher::SendDataReqL(const TDesC8& aBuffer)
+	{
+	// Call the appropriate function depending on what the function pointer has been set to.
+	// For the first request, the pointer will be set to the SendRequestImmediately() function.
+	// For subsequent requests, i.e. when batching, the pointer will be set to the
+	// SendRequestsBatched() function.
+
+	(*this.*iFuncPtr)(aBuffer);
+	}
+
+void CHttpRequestBatcher::ShutdownReq()
+	{
+	iOutputStream->ShutdownReq();
+	}
+
+void CHttpRequestBatcher::SecureClientReq(const TDesC8& aHostName)
+	{
+	iOutputStream->SecureClientReq(aHostName);
+	}
+
+void CHttpRequestBatcher::Close()
+	{
+	iOutputStream->Close();
+	}
+
+const CX509Certificate* CHttpRequestBatcher::ServerCert()
+ 	{
+	return iOutputStream->ServerCert();
+ 	}
+	
+TInt CHttpRequestBatcher::CipherSuite(TDes8& aCipherSuite)
+	{
+	return iOutputStream->CipherSuite(aCipherSuite);
+	}
+
+void CHttpRequestBatcher::MOutputStream_Reserved()
+	{
+	User::Invariant();
+	}
+
+void CHttpRequestBatcher::Reset ()
+	{
+	iOutputStream->Reset ();
+	}
+
+/*
+ *	Methods from MOutputStreamObserver
+ */
+
+void CHttpRequestBatcher::SendDataCnfL()
+	{
+	// If this is the first request send a confirmation to the observer that the data
+	// has been sent and then set the function pointer to the SendRequestBatched() method.
+	if (iFuncPtr == &CHttpRequestBatcher::SendRequestImmediatelyL)
+		{
+#if defined (_DEBUG) && defined (_LOGGING)
+		__FLOG_0(_T8("!! Received conf back for first request i.e. not batching"));
+#endif
+
+		iObserver->SendDataCnfL();
+		iFuncPtr = &CHttpRequestBatcher::SendRequestsBatchedL;
+		}
+
+	// If the timer did not complete then by implication a filled-up buffer was sent in the request.
+	else if (!iTimerCompleted)
+		{
+#if defined (_DEBUG) && defined (_LOGGING)
+		__FLOG_0(_T8("!! Received conf back for batched requests"));
+#endif
+
+		iDataToSend.Zero();
+		HandleExcessDataL();
+		}
+	else	// Timer did complete
+		{
+		iDataToSend.Zero();
+
+		// Check for any requests that may have been sent by the observer after the RunL fired
+		// i.e. the timer completed, but before we received a conf from the output stream.
+		if (iExcessData.Length() > 0)
+			HandleExcessDataL();
+
+		// Reset the flag
+		iTimerCompleted = EFalse;
+		}
+	}
+
+void CHttpRequestBatcher::HandleExcessDataL()
+	{
+	if (iExcessData.Length() > iMaxBufferSize)
+		{
+#if defined (_DEBUG) && defined (_LOGGING)
+		__FLOG_0(_T8("!! Handling excess data - have enough data to fill up another buffer so send it"));
+#endif
+
+		// It's possible that the excess data is larger than the maximum allowable size of the buffer in
+		// which case this excess data is used to fill up another buffer and a request made.
+		iDataToSend.Append(iExcessData.Left(iMaxBufferSize));
+		iOutputStream->SendDataReqL(iDataToSend);
+		iExcessData.Set(iExcessData.Mid(iMaxBufferSize));
+		}
+	else
+		{
+		// Not enough data to fill up a buffer therefore store the data
+		iDataToSend.Append(iExcessData);
+		iExcessData.Set(KNullDesC8());
+		iObserver->SendDataCnfL();
+
+#if defined (_DEBUG) && defined (_LOGGING)
+		__FLOG_0(_T8("!! Handling excess data - but not enough data to fill up buffer"));
+#endif
+
+		// start the timer again
+		StartTimer();			
+		}
+	}
+
+
+void CHttpRequestBatcher::SecureClientCnf()
+	{
+	iObserver->SecureClientCnf();
+	}
+
+void CHttpRequestBatcher::OutputStreamCloseInd(TInt aError)
+	{
+	Cancel();
+	iObserver->OutputStreamCloseInd(aError);
+	}
+
+void CHttpRequestBatcher::MOutputStreamObserver_Reserved()
+	{
+	User::Invariant();
+	}
+
+
+/*
+ * Methods from CActive
+ */
+
+void CHttpRequestBatcher::RunL()
+	{
+	if (iDataToSend.Length() > 0)
+		{
+#if defined (_DEBUG) && defined (_LOGGING)
+		__FLOG_0(_T8("!! Timer has completed before buffer has been filled - send request now"));
+#endif
+
+		// Timer has completed before the buffer has been filled, therefore send the request now.
+		iOutputStream->SendDataReqL(iDataToSend);
+		}
+	iTimerCompleted = ETrue;
+	}
+
+void CHttpRequestBatcher::DoCancel()
+	{
+	iTimer.Cancel();
+	}
+
+TInt CHttpRequestBatcher::RunError(TInt /*aError*/)
+	{
+	// The RunL() cannot leave - nothing to do here.
+	return KErrNone;
+	}
+
+void CHttpRequestBatcher::OnSendTimeOut()
+	{
+	iObserver->OnSendTimeOut();
+	}
+ 
+TInt CHttpRequestBatcher::SendTimeOutVal()
+	{
+	return iObserver->SendTimeOutVal();
+	}
+
+void CHttpRequestBatcher::SetTCPCorking(TBool /* aValue */)
+    {
+    
+    }
+
+