engine/src/HttpClient.cpp
author Sebastian Brannstrom <sebastianb@symbian.org>
Sun, 24 Oct 2010 01:27:31 +0100
branchRCL_3
changeset 285 4d42a5e09930
parent 126 c2f1ea38ec70
child 310 2e0299e13cbf
permissions -rw-r--r--
Significant robustness improvements for ConnectionEngine

// HttpClient.cpp


#include <e32base.h>
#include <http/rhttpheaders.h>
#include <http.h>
#include <commdb.h>
#include <eikenv.h>
#include <es_sock.h>
#include <bautils.h>
#include <CommDbConnPref.h>
#include "debug.h"
#include "constants.h"
#include "HttpClient.h"
#include "connectionengine.h"
#include "settingsengine.h"
#include "Podcatcher.pan"

const TInt KTempBufferSize = 100;

CHttpClient::~CHttpClient()
  {
	
	iPodcastModel.ConnectionEngine().RemoveObserver(this);
	 
  if (iHandler)
  	{
  	iHandler->CloseSaveFile();
	delete iHandler;
  	}
  
  iSession.Close();
  }

CHttpClient* CHttpClient::NewL(CPodcastModel& aPodcastModel, MHttpClientObserver& aObserver)
  {
  CHttpClient* me = NewLC(aPodcastModel, aObserver);
  CleanupStack::Pop(me);
  return me;
  }

CHttpClient::CHttpClient(CPodcastModel& aPodcastModel, MHttpClientObserver& aObserver) : iPodcastModel(aPodcastModel), iObserver(aObserver)
  {
  iResumeEnabled = EFalse;
  }

CHttpClient* CHttpClient::NewLC(CPodcastModel& aPodcastModel, MHttpClientObserver& aObserver)
  {
  CHttpClient* me = new (ELeave) CHttpClient(aPodcastModel, aObserver);
  CleanupStack::PushL(me);
  me->ConstructL();
  return me;
  }

void CHttpClient::ConstructL()
  {
  iPodcastModel.ConnectionEngine().AddObserver(this);
  }

void CHttpClient::SetHeaderL(RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8& aHdrValue)
	{
	RStringF valStr = iSession.StringPool().OpenFStringL(aHdrValue);
	THTTPHdrVal val(valStr);
	aHeaders.SetFieldL(iSession.StringPool().StringF(aHdrField, RHTTPSession::GetTable()), val);
	valStr.Close();
	}

TBool CHttpClient::IsActive()
	{
	return iIsActive;
	}

void CHttpClient::SetResumeEnabled(TBool aEnabled)
	{
	iResumeEnabled = aEnabled;
	}


void CHttpClient::ConnectHttpSessionL()
{
	DP("ConnectHttpSessionL START");	
	CConnectionEngine::TConnectionState connState = iPodcastModel.ConnectionEngine().ConnectionState();
	if(connState == CConnectionEngine::EConnected)
		{
		DP("ConnectionState == CConnectionEngine::EConnected");
		// Session already connected, call connect complete directly but return status since URLs or so might be faulty
		ConnectCompleteL(KErrNone);		
		return;
		}

	if(connState == CConnectionEngine::ENotConnected)
		{
		DP1("SpecificIAP() == %d",iPodcastModel.SettingsEngine().SpecificIAP());

		if(iPodcastModel.SettingsEngine().SpecificIAP() == -1)
			{
			iPodcastModel.ConnectionEngine().StartL(CConnectionEngine::EUserSelectConnection);	
			}
		else if ( iPodcastModel.SettingsEngine().SpecificIAP() == 0 )
			{
			iPodcastModel.ConnectionEngine().StartL(CConnectionEngine::EDefaultConnection);	
			}
		else if( (iPodcastModel.SettingsEngine().SpecificIAP()&KUseIAPFlag))
			{
			iPodcastModel.ConnectionEngine().StartL(CConnectionEngine::EIAPConnection);
			}
		else
			{
			iPodcastModel.ConnectionEngine().StartL(CConnectionEngine::EMobilityConnection);
			}
		}
	DP("ConnectHttpSessionL END");	
}

void CHttpClient::ConnectCompleteL(TInt aErrorCode)
	{
	DP1("CHttpClient::ConnectCompleteL BEGIN, aErrorCode=%d", aErrorCode);
	DP1("    iWaitingForGet=%d", iWaitingForGet);
	if(iWaitingForGet)
		{
		iWaitingForGet = EFalse;
		if( aErrorCode == KErrNone)
			{
			TRAP_IGNORE(iSession.OpenL());
			DP("    one");
			RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
			DP("    one point five");
			RStringPool pool = iSession.StringPool();
			// Attach to socket server
			DP("    two");
			connInfo.SetPropertyL(pool.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable()), THTTPHdrVal(iPodcastModel.ConnectionEngine().SockServ().Handle()));
			// Attach to connection
			DP("    three");
			TInt connPtr = REINTERPRET_CAST(TInt, &iPodcastModel.ConnectionEngine().Connection());
			connInfo.SetPropertyL(pool.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable()), THTTPHdrVal(connPtr));
			DP("    four");

			iPodcastModel.SetProxyUsageIfNeededL(iSession);
			DoGetAfterConnectL();
			//iWaitingForGet = EFalse; // set to true by DoGetAfterConnectL
			}
		else
			{
			ClientRequestCompleteL(KErrCouldNotConnect);
			iSession.Close();			
			}
		}
	DP("CHttpClient::ConnectCompleteL END");
	}

void CHttpClient::Disconnected()
	{
	iIsActive = EFalse;
	iSession.Close();
	}

void  CHttpClient::DoGetAfterConnectL()
	{	
	DP("CHttpClient::DoGetAfterConnectL BEGIN");
	// since nothing should be downloading now. Delete the handler
	if (iHandler)
		{
		delete iHandler;
		iHandler = NULL;
		}
		
	iHandler = CHttpEventHandler::NewL(this, iObserver, iPodcastModel.FsSession());
	iHandler->SetSilent(iSilentGet);

	TEntry entry;
	TBuf8<KTempBufferSize> rangeText;

	if (iResumeEnabled && iPodcastModel.FsSession().Entry(iCurrentFileName, entry) == KErrNone) {
		DP1("    Found file, with size=%d", entry.iSize);
		// file exists, so we should probably resume
		rangeText.Format(_L8("bytes=%d-"), (entry.iSize-KByteOverlap > 0 ? entry.iSize-KByteOverlap : 0));
		iHandler->SetSaveFileName(iCurrentFileName, ETrue);
	} else {
		// otherwise just make sure the directory exists
		BaflUtils::EnsurePathExistsL(iPodcastModel.FsSession(),iCurrentFileName);
		iHandler->SetSaveFileName(iCurrentFileName);
	}
	
	RStringPool strP = iSession.StringPool();
	RStringF method;
	method = strP.StringF(HTTP::EGET, RHTTPSession::GetTable());
	
	iTrans = iSession.OpenTransactionL(iUriParser, *iHandler, method);
	RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();
	// Add headers appropriate to all methods
	SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
	SetHeaderL(hdr, HTTP::EAccept, KAccept);
	TBuf<KTempBufferSize> range16;
	range16.Copy(rangeText);
	DP1("    range text: %S", &range16);
	if (rangeText.Length() > 0) {
		SetHeaderL(hdr, HTTP::ERange, rangeText);
	}
	iTransactionCount++;
	// submit the transaction
	iTrans.SubmitL();
	iIsActive = ETrue;	
	DP("CHttpClient::DoGetAfterConnectL END");
	}

TBool CHttpClient::GetL(const TDesC& aUrl, const TDesC& aFileName,  TBool aSilent) {
	DP("CHttpClient::Get START");
	DP2("Getting '%S' to '%S'", &aUrl, &aFileName);
	
	if (iIsActive)
		{
		return EFalse;
		}
	iCurrentURL.Copy(aUrl);	
		
	TInt urlError = iUriParser.Parse(iCurrentURL);

	if(urlError != KErrNone ||!iUriParser.IsSchemeValid())
		{		
		iCurrentURL = KNullDesC8;
		iSession.Close();		
		iObserver.CompleteL(this, KErrHttpInvalidUri);
		return EFalse;		
		}	
	
	iSilentGet = aSilent;
	iCurrentFileName.Copy(aFileName);
	
	if (iTransactionCount == 0) 
		{
		DP("CHttpClient::GetL\t*** Opening HTTP session ***");
		iSession.Close();
		iSession.OpenL();
		iWaitingForGet = ETrue;
		ConnectHttpSessionL();			
		}
	else
		{
		iWaitingForGet = EFalse;
		DoGetAfterConnectL();		
		}
	return ETrue;
}

void CHttpClient::Stop()
	{
	iIsActive = EFalse;
	if(iHandler != NULL)
		{
		// cancel the ongoing transaction
		iTrans.Cancel();
		iTransactionCount = 0;
		
		// make sure that we save the file
		iHandler->CloseSaveFile();
		
		// we could now delete the handler since a new will be created
		delete iHandler;
		iHandler = NULL;
		
		// close the session
		DP("CHttpClient::Stop\t*** Closing HTTP session ***");
		iSession.Close();
		}

	TRAP_IGNORE(iObserver.CompleteL(this, KErrDisconnected));

	}

void CHttpClient::ClientRequestCompleteL(TInt aErrorCode) {
	DP1("CHttpClient::ClientRequestCompleteL, aErrorCode=%d", aErrorCode);
	iIsActive = EFalse;
	iObserver.CompleteL(this, aErrorCode);
	DP1("    iTransactionCount=%d", iTransactionCount);
	if(iTransactionCount>0)
		{
		iTransactionCount--;
	
		if(iTransactionCount == 0) 
			{
			DP("CHttpClient::ClientRequestCompleteL\t*** Closing HTTP session ***");
			delete iHandler;
			iHandler = NULL;
			iSession.Close();
			}
		}
}