// 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:
//
#ifndef __CHTTPCONNECTIONMANAGER_H__
#define __CHTTPCONNECTIONMANAGER_H__
#include <e32base.h>
#include <babitflags.h>
#include <stringpool.h>
#include <http/framework/logging.h>
#include "msocketconnectobserver.h"
#include "minputstreamobserver.h"
#include "moutputstreamobserver.h"
#include "mhttprequestobserver.h"
#include "mhttpresponseobserver.h"
#include "mhttpbatchingpropertiescallback.h"
#include "chttpclientoptimiser.h"
class MSocketFactory;
class MSocketConnector;
class MOutputStream;
class MInputStream;
class MHttpRequest;
class MHttpResponse;
class CHttpConnectionInfo;
class CX509Certificate;
class CHttpRequestBatcher;
class MHttpBatchingPropertiesCallback;
class CHttpHostElement : public CBase
{
public:
static CHttpHostElement* New(const TDesC8& aHost);
~CHttpHostElement();
inline const TDesC8& Host() const;
inline void IncFailedCount();
inline TInt FailedCount() const;
inline HBufC8* AcquireHost();
static inline TInt LinkOffset();
private:
TBool Construct(const TDesC8& aHost);
public:
TSglQueLink iLink;
HBufC8* iHost;
};
class CHttpPipelineFallback : public CBase
{
public:
static CHttpPipelineFallback* NewL();
~CHttpPipelineFallback();
TBool NeedPipelineFallback(const TDesC8& aHost);
/**
If the pipeline has failed atleast 2 times due to network problems
the host is inserted into the failed host array. The function checks
for the no. of failures for the given host. Only on time failed hosts
are pushed into the probable pipeline failed host array
*/
void InsertPipelineFailedHost(const TDesC8& aHost);
/**
Add to the pipeline failed host array if not already added.
*/
void AppendPipelineFailedHost(const TDesC8& aHost);
private:
CHttpPipelineFallback();
private:
RPointerArray<HBufC8> iPipelineFailedHosts;
TSglQue<CHttpHostElement> iProbablePipelineFailedHosts;
};
class CHttpConnectionManager : public CBase,
public MHttpRequestObserver,
public MHttpResponseObserver,
public MSocketConnectObserver,
public MInputStreamObserver,
public MOutputStreamObserver
{
public:
enum TConnectionStatus
{
ENotConnected = 0,
EConnectedAndAvailable,
EConnectedNotAvailable,
EConnectedAndBusy,
EConnectingNotAvailable
};
public:
static CHttpConnectionManager* NewL(MSocketFactory& aSocketFactory, MHttpBatchingPropertiesCallback& aCallback,
CHttpPipelineFallback& aPipelineFallback, TInt aMaxTransactionsToPipeline, TBool aEnableOptimalPipeline);
virtual ~CHttpConnectionManager();
void SubmitL(CHttpConnectionInfo& aConnectionInfo, MHttpRequest& aRequest, MHttpResponse& aResponse);
TConnectionStatus Status() const;
const CHttpConnectionInfo& ConnectionInfo() const;
void CancelSubmission(MHttpRequest& aRequest, MHttpResponse& aResponse);
const CX509Certificate* ServerCert();
TInt CipherSuite(TDes8& aCipherSuite);
void TunnelConnection(RStringF aHost);
TBool TunnelMatches(RStringF aHost) const;
void MakeConnectionNonPersistent();
void CheckRequestComplete(MHttpRequest& aRequest);
void DisablePipelining();
void AppendPipelineFailedHost(const TDesC8& aHost);
inline TBool SecureRetry(){ return iSecureRetry;}
private: // methods from MHttpRequestObserver
virtual void SendRequestDataL(const TDesC8& aData);
virtual void RequestComplete();
virtual void SendingBodyData(TBool aValue);
private: // methods from MHttpResponseObserver
virtual void ResponseDataParsed();
virtual void ResponseComplete(const TDesC8& aExcessData);
private: // methods from MSocketConnnectObserver
virtual void ConnectionMadeL(MInputStream& aInputStream, MOutputStream& aOutputStream);
virtual TInt HandleConnectError(TInt aError);
virtual void MSocketConnectObserver_Reserved();
private: // methods from MInputStreamObserver
virtual void ReceivedDataIndL(const TDesC8& aBuffer);
virtual void SecureServerCnf();
virtual void InputStreamCloseInd(TInt aError);
virtual void MInputStreamObserver_Reserved();
virtual MHttpResponse* CurrentResponse();
virtual void OnReceiveTimeOut();
private: // methods from MOutputStreamObserver
virtual void SendDataCnfL();
virtual void SecureClientCnf();
virtual void OutputStreamCloseInd(TInt aError);
virtual void MOutputStreamObserver_Reserved();
virtual void OnSendTimeOut();
virtual TInt SendTimeOutVal();
private:
CHttpConnectionManager(MSocketFactory& aSocketFactory, MHttpBatchingPropertiesCallback& aCallback,
CHttpPipelineFallback& aPipelineFallback, TInt aMaxTransactionsToPipeline, TBool aEnableOptimalPipeline);
void HandleSocketError(TInt aError);
void CloseConnection();
void UpgradeConnectionL();
void SetIdleState();
TInt FindRequest(MHttpRequest& aRequest);
TInt FindResponse(MHttpResponse& aResponse);
void NotifyPendingTransactions(TInt aError);
void ReportSocketError(TInt aError);
void ReconnectSocketL();
void DoResponseCompletion ();
inline TBool CannotPipeline() const;
inline TBool IsFirstTransaction() const;
inline TBool IsPendingWriteInConnectedState() const;
inline TBool DiscardSndDataCnf() const;
void CreateOptimiserL(MHttpDataOptimiser* aDataOptimiser);
void StartRecvTimer();
private:
enum TManagerState
{
EIdle = 0,
EIdleConnected,
EConnecting,
EUpgrading,
EConnected,
EClosing
};
enum TConnectionFlag
{
// Cannot currently pipeline.
// So will not queue transactions on this connection Manager.
//
ECannotPipeline = 0,
// Currently sending/receiving the first transaction on this connection,
// so no other requests are sent out till the response from the server is
// examined to see of it can handle pipelining. However transactions are
// still queued on this connection. These will be cancelled with
// KErrNonPipeliningError should the server be HTTP/1.0.
//
EFirstTransaction = 1,
// Specifies that this transaction is waiting to write its
// request to the supposedly connected connection. Due to timing issues
// the server may have closed the connection, but connection manager has
// not been notified yet.
//
EPendingWriteInConnectedState = 2,
// The Response completed before notification, that a request was sent, was received.
// So now we know when confirmation arrives (SndDataCnf) can disregard it.
//
EDiscardSndDataCnf = 3
};
private:
TBool iSecureRetry;
TBool iEnableOptimalPipeline;
TBool iTunnel;
TInt iMaxTransactionsToPipeline;
TBitFlags8 iFlags;
MSocketFactory& iSocketFactory;
TManagerState iState;
MSocketConnector* iSocketConnector;
MOutputStream* iOutputStream;
MInputStream* iInputStream;
MHttpRequest* iCurrentRequest;
MHttpResponse* iCurrentResponse;
TPtrC8 iExcessData;
RStringF iTunnelHost;
CHttpConnectionInfo* iConnectionInfo;
CHttpRequestBatcher* iRequestBatcher;
MHttpBatchingPropertiesCallback& iCallback;
CHttpClientOptimiser* iOptimiser;
RPointerArray<MHttpRequest> iPendingRequests;
RPointerArray<MHttpResponse> iPendingResponses;
CHttpPipelineFallback& iPipelineFallback;
public:
__FLOG_DECLARATION_MEMBER2
};
inline TBool CHttpConnectionManager::CannotPipeline() const
{
return iFlags.IsSet(ECannotPipeline);
}
inline TBool CHttpConnectionManager::IsFirstTransaction() const
{
return iFlags.IsSet(EFirstTransaction);
}
inline TBool CHttpConnectionManager::IsPendingWriteInConnectedState() const
{
return iFlags.IsSet(EPendingWriteInConnectedState);
}
inline TBool CHttpConnectionManager::DiscardSndDataCnf() const
{
return iFlags.IsSet(EDiscardSndDataCnf);
}
inline const TDesC8& CHttpHostElement::Host() const
{
return *iHost;
}
inline HBufC8* CHttpHostElement::AcquireHost()
{
HBufC8* host = iHost;
iHost = NULL;
return host;
}
inline TInt CHttpHostElement::LinkOffset()
{
return _FOFF(CHttpHostElement, iLink);
}
#endif // __CHTTPCONNECTIONMANAGER_H__