applayerpluginsandutils/httpprotocolplugins/httpclient/chttpclienthandler.cpp
changeset 0 b16258d2340f
child 9 2611c08ee28e
equal deleted inserted replaced
-1:000000000000 0:b16258d2340f
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "chttpclienthandler.h"
       
    17 
       
    18 #include <http.h>
       
    19 #include <http/framework/crxdata.h>
       
    20 #include <http/framework/csecuritypolicy.h>
       
    21 #include <inetprottextutils.h>
       
    22 #include <uriutilscommon.h>
       
    23 #include <uriutils.h>
       
    24 #include <authority8.h>
       
    25 #include <in_sock.h>
       
    26 #include <securesocket.h>
       
    27 #include <x509certext.h>
       
    28 
       
    29 #include "chttptransportlayer.h"
       
    30 #include "chttpclientfilter.h"
       
    31 #include "chttpconnectfilter.h"
       
    32 #include "chttpclientheadercodec.h"
       
    33 #include "chttpclienttransaction.h"
       
    34 #include "chttpconnectioninfo.h"
       
    35 #include "chttpconnectionmanager.h"
       
    36 #include "chttprequestcomposer.h"
       
    37 #include "chttpresponseparser.h"
       
    38 #include "thttpclientpanic.h"
       
    39 
       
    40 const TInt KHttpDefaultPort			= 80;
       
    41 const TInt KHttpDefaultSecurePort	= 443;
       
    42 const TInt KHttpDefaultProxyPort	= 8080;
       
    43 const TInt KMaxConnectionManagers	= 4;
       
    44 const TInt KDefaultBatchingBufSize	= 1400;
       
    45 const TInt KDefaultMaxNumberTransactionsToPipeline = KMaxTInt;
       
    46 const TInt KDefaultBufferSize		= 32*1024;
       
    47 
       
    48 
       
    49 _LIT8(KSecureHttpScheme, "https");
       
    50 _LIT8(KHttpClientCodecName, "HTTP/client");
       
    51 
       
    52 _LIT8(KUAProfile, "x-wap-profile");
       
    53 
       
    54 const TUint KIPv6HostOpenBrace		= '[';
       
    55 const TUint KIPv6HostCloseBrace		= ']';
       
    56 class InetProtTextUtils;
       
    57 
       
    58 CHttpClientHandler* CHttpClientHandler::NewL(TAny* aSession)
       
    59 	{
       
    60 	RHTTPSession* httpSession = REINTERPRET_CAST(RHTTPSession*, aSession);
       
    61 	CHttpClientHandler* self = new (ELeave) CHttpClientHandler(*httpSession);
       
    62 	CleanupStack::PushL(self);
       
    63 	self->ConstructL();
       
    64 	CleanupStack::Pop(self);
       
    65 	return self;
       
    66 	}
       
    67 	
       
    68 CHttpClientHandler::~CHttpClientHandler()
       
    69 	{
       
    70 	iProxyAddress.Close();
       
    71 	iConnectionManagers.ResetAndDestroy();
       
    72 	delete iTransportLayer;
       
    73 	delete iPipelineFallback;
       
    74 	__FLOG_CLOSE;
       
    75 	}
       
    76 	
       
    77 CHttpClientHandler::CHttpClientHandler(RHTTPSession aSession)
       
    78 : CProtocolHandler(aSession),
       
    79 iStringTable(RHTTPSession::GetTable())
       
    80 	{
       
    81 	__FLOG_OPEN("http", "httpclienthandler.txt");
       
    82 	__FLOG(_T8("HTTP Client Protocol Handler Log"));
       
    83 	}
       
    84 	
       
    85 void CHttpClientHandler::ConstructL()
       
    86 	{	
       
    87 	CProtocolHandler::ConstructL(iSession);
       
    88 	
       
    89 	CHttpClientFilter* clientFilter = CHttpClientFilter::NewL(iSession);
       
    90 	CleanupStack::PushL ( clientFilter );
       
    91 	CHttpConnectFilter::NewL(iSession);
       
    92 	CleanupStack::Pop (); // clientFilter
       
    93 
       
    94 	RHTTPConnectionInfo	connInfo = iSession.ConnectionInfo();
       
    95 	RStringPool stringPool = iSession.StringPool();
       
    96 	THTTPHdrVal value;
       
    97 	TBool hasValue = connInfo.Property(stringPool.StringF(HTTP::ESessionClosing, iStringTable), value);
       
    98 	if( hasValue && value.Type() == THTTPHdrVal::KTIntVal )  
       
    99 		{
       
   100 		iSessionClosingPtr = reinterpret_cast<TBool*>(value.Int());
       
   101 		}
       
   102 	else
       
   103 		{
       
   104 		__FLOG_0(_T8("!! Session Closing Flag NOT set"));
       
   105 		User::Leave(KErrNotFound);
       
   106 		}
       
   107 	iPipelineFallback = CHttpPipelineFallback::NewL();	
       
   108 	}
       
   109 
       
   110 CHttpConnectionInfo* CHttpClientHandler::PrepareTransactionL(RHTTPTransaction aTrans, TBool& aNeedTunnel, TBool& aCanPipeline)
       
   111 	{
       
   112     // Check that filters are not added headers that are not needed for CONNECT method.
       
   113     // Remove the unwanted headers. But do only if the property has been set for the 
       
   114     // strict CONNECT method.
       
   115     EnsureStrictConnectMethodHeaders (aTrans);
       
   116 	
       
   117 	// To prepare the transaction need to create the Request-URI, set the Host
       
   118 	// header and establish the connection info.
       
   119 	RStringPool stringPool = iSession.StringPool();
       
   120 	RHTTPRequest request = aTrans.Request();
       
   121 
       
   122 	SetupProxyInformation(aTrans);
       
   123 	
       
   124 	// Store the method index from string table
       
   125 	TInt methodIndex = request.Method().Index(iStringTable); 
       
   126 	// Check for https scheme.
       
   127 	const TUriC8& uri = request.URI();
       
   128 	// secure doesn't count if it's a connect request	
       
   129 	TBool secure = methodIndex != HTTP::ECONNECT &&
       
   130 		(uri.Extract(EUriScheme).CompareF(KSecureHttpScheme) == 0);
       
   131 	// Create the Request-URI for this transaction...
       
   132 	TInt port = (secure) ? KHttpDefaultSecurePort : KHttpDefaultPort;
       
   133 	TPtrC8 host;
       
   134 	CreateRequestUriL(methodIndex, aTrans, host, port);
       
   135 
       
   136 	// If the host name is empty leave as the URI is not complete - a CONNECT
       
   137 	// method request has an empty host as it will go to the proxy.
       
   138 	if( host.Length() == 0 )
       
   139 		{
       
   140 		__FLOG_0(_T8("!! Invalid uri"));
       
   141 		__FLOG_2(_T8("-> Trans %d, Con %d : missing host!"), aTrans.Id(),GetConnectionID(aTrans));
       
   142 
       
   143 		User::Leave(KErrHttpInvalidUri);
       
   144 		}
       
   145 
       
   146 	// Set the Host header...
       
   147 	TBool isHttp10 = SetHostHeaderL(aTrans, host, port);
       
   148 
       
   149 	// Create the connection info. Is a proxy being used?
       
   150 	if( iUseProxy )
       
   151 		{
       
   152 		// Need a tunnel if request is going via a proxy and request is using 
       
   153 		// the https scheme
       
   154 		if( secure )
       
   155 			{
       
   156 			__FLOG_4(_T8("Trans %d, Con %d : tunnel required to host %S, port %d"), aTrans.Id(),GetConnectionID(aTrans), &host, port);
       
   157 
       
   158 			// This request needs a tunnel to be established to the specified 
       
   159 			// host/port - add the ETunnel property to the transaction.
       
   160 			aNeedTunnel = ETrue;
       
   161 			AddTunnelInfoL(aTrans, host, port);
       
   162 			}
       
   163 
       
   164 		// Need to obtain the proxy info.
       
   165 		const TDesC8& proxy = iProxyAddress.DesC();
       
   166 		TAuthorityParser8 auth;
       
   167 		auth.Parse(proxy);
       
   168 
       
   169 		host.Set(auth.Extract(EAuthorityHost));
       
   170 
       
   171 		// Read the proxy port if present
       
   172 		port = KHttpDefaultProxyPort; // Initialise with default proxy port
       
   173 		if( auth.IsPresent(EAuthorityPort) )
       
   174 			{
       
   175 			TPtrC8 portDesc = auth.Extract(EAuthorityPort);
       
   176 			TInt error = InetProtTextUtils::ConvertDescriptorToInt(portDesc, port);
       
   177 			if( error != KUriUtilsErrEmptyData )
       
   178 				{
       
   179 				// An empty port component is allowed - just ignore it.
       
   180 				User::LeaveIfError(error);
       
   181 				}
       
   182 			}
       
   183 		}
       
   184 		
       
   185 	// Is a non-persistent connection required? The connection is non-persistent
       
   186 	// if either it is a HTTP/1.0 request or it is a HTTP/1.1 request and it has
       
   187 	// a Connection: close header.
       
   188 	RHTTPHeaders headers = request.GetHeaderCollection();
       
   189 	CHttpConnectionInfo::THttpPersistent persistentState = isHttp10 ? 
       
   190 														   CHttpConnectionInfo::ENonPersistent : 
       
   191 														   CHttpConnectionInfo::EPersistent;
       
   192 	THTTPHdrVal connVal;
       
   193 	RStringF connStr = stringPool.StringF(HTTP::EConnection, iStringTable);
       
   194 	if( headers.GetField(connStr,0,connVal) == KErrNone )
       
   195 		{
       
   196 		__ASSERT_DEBUG( !isHttp10, THttpClientPanic::Panic(THttpClientPanic::EInvalidHeaderForHTTP10) ); // no connection headers are allowed in HTTP/1.0
       
   197 		
       
   198 		if( (connVal.Type() == THTTPHdrVal::KStrFVal) && 
       
   199 			(connVal.StrF() == stringPool.StringF(HTTP::EClose, iStringTable)) )
       
   200 			{
       
   201 			// Client has specified a Connection: close header - non-persistent
       
   202 			// connection.
       
   203 			persistentState = CHttpConnectionInfo::ENonPersistent;
       
   204 			}
       
   205 		}
       
   206 	
       
   207 	// Create the connection info object
       
   208 	CHttpConnectionInfo* connectionInfo = CHttpConnectionInfo::NewL(stringPool, host, static_cast<TUint16>(port));
       
   209 	connectionInfo->SetSecureState(secure);
       
   210 	connectionInfo->SetPersistentState(persistentState);
       
   211 
       
   212 	// Check to see if this transaction can be pipelined.
       
   213 	switch(methodIndex)
       
   214 		{
       
   215 	case HTTP::EGET:
       
   216 		{
       
   217 		// Can only pipeline non-HTTP/1.0 requests...
       
   218 		if( !isHttp10 )
       
   219 			{
       
   220 			// These methods can be pipelined but only if pipelining has not been 
       
   221 			// specifically disabled for the transaction.
       
   222             aCanPipeline = (CheckPipelineSupport(aTrans) && !iPipelineFallback->NeedPipelineFallback(host));
       
   223             __FLOG_4(_T8("Pipelining --- enabled: %d Support: %d Fallback: %d  Host %S"), aCanPipeline, CheckPipelineSupport(aTrans), !iPipelineFallback->NeedPipelineFallback(host), &host);
       
   224 			break;
       
   225 			}
       
   226 		// Allow the HTTP/1.0 requests to drop through to default case.
       
   227 		}
       
   228 	default:
       
   229 		// All other methods are not to be pipelined.
       
   230 		aCanPipeline = EFalse;
       
   231 		break;
       
   232 		};
       
   233 
       
   234 	return connectionInfo;
       
   235 	} 
       
   236 
       
   237 void CHttpClientHandler::CreateRequestUriL(TInt aMethodIndex, RHTTPTransaction aTrans, TPtrC8& aHost, TInt& aPort)
       
   238 	{
       
   239 	RStringPool stringPool = iSession.StringPool();
       
   240 	RHTTPRequest request = aTrans.Request();
       
   241 	const TUriC8& uri = request.URI();
       
   242 	TBool secure = EFalse;
       
   243 	
       
   244 	RStringF scheme = stringPool.OpenFStringL(uri.Extract(EUriScheme));
       
   245 	CleanupClosePushL(scheme);
       
   246 	if( aMethodIndex == HTTP::ECONNECT )
       
   247 		{
       
   248 		__ASSERT_DEBUG( iUseProxy, User::Invariant() );
       
   249 		aHost.Set(uri.Extract(EUriHost));
       
   250 		}
       
   251 	else if( uri.IsPresent(EUriHost) )
       
   252 		{
       
   253 		// The request URI is absolute - check the scheme is http or https
       
   254 		secure = uri.IsPresent(EUriScheme) && (scheme.Index(iStringTable) == HTTP::EHTTPS);
       
   255 		if( !uri.IsPresent(EUriScheme) || !secure &&
       
   256 			scheme.Index(iStringTable) != HTTP::EHTTP)
       
   257 			{
       
   258 			__FLOG_0(_T8("!! Invalid uri."));
       
   259 			__FLOG_3(_T8("-> Trans %d, Con %d: %S scheme is not supported!"), aTrans.Id(),GetConnectionID(aTrans), &scheme.DesC());
       
   260 
       
   261 			User::Leave(KErrHttpInvalidUri);
       
   262 			}
       
   263 
       
   264 		// Get the host and port info from it.
       
   265 		aHost.Set(uri.Extract(EUriHost));
       
   266 
       
   267 		// Check to see if a port has been specified	
       
   268 		if( uri.IsPresent(EUriPort) )
       
   269 			{
       
   270 			TPtrC8 port = uri.Extract(EUriPort);
       
   271 			TInt error = InetProtTextUtils::ConvertDescriptorToInt(port, aPort);
       
   272 			if( error != KUriUtilsErrEmptyData )
       
   273 				{
       
   274 				// An empty port component is allowed - just ignore it.
       
   275 				User::LeaveIfError(error);
       
   276 				}
       
   277 			}
       
   278 		}
       
   279 	else
       
   280 		{
       
   281 		// The request URI is relative - update the request URI to be absolute.
       
   282 		// The client MUST have supplied a Host header.
       
   283 		RHTTPHeaders headers = request.GetHeaderCollection();
       
   284 		RStringF hostStr = stringPool.StringF(HTTP::EHost, iStringTable);
       
   285 		THTTPHdrVal hostVal;
       
   286 
       
   287 		if( headers.GetField(hostStr, 0, hostVal) == KErrNotFound )
       
   288 			{
       
   289 			// No Host header - do not know which host to connect to.
       
   290 			User::Leave(KErrHttpGeneralHeaderMissingHost);
       
   291 			}
       
   292 
       
   293 		__ASSERT_DEBUG( hostVal.Type() == THTTPHdrVal::KStrFVal, User::Invariant() );
       
   294 
       
   295 		// Set the host output argument
       
   296 		aHost.Set(hostVal.StrF().DesC());
       
   297 
       
   298 		// Create the absolute uri
       
   299 		CUri8* absoluteUri = CUri8::NewLC(uri);
       
   300 
       
   301 		RStringF httpStr = stringPool.StringF(HTTP::EHTTP, iStringTable);
       
   302 		absoluteUri->SetComponentL(httpStr.DesC(), EUriScheme);
       
   303 		absoluteUri->SetComponentL(aHost, EUriHost);
       
   304 
       
   305 		// Check for port info in the Host header
       
   306 		RStringF portStr = stringPool.StringF(HTTP::EPort, iStringTable);
       
   307 		THTTPHdrVal portVal;
       
   308 		TBool hasPort = (headers.GetParam(hostStr, portStr, portVal) == KErrNone);
       
   309 		if( hasPort && portVal.Type() == THTTPHdrVal::KTIntVal )
       
   310 			{
       
   311 			// Set the port output argument
       
   312 			aPort = portVal.Int();
       
   313 
       
   314 			// Convert the int value to its descriptor format
       
   315 			HBufC8* portBuf = NULL;
       
   316 			InetProtTextUtils::ConvertIntToDescriptorL(aPort, portBuf);
       
   317 			CleanupStack::PushL(portBuf);
       
   318 
       
   319 			absoluteUri->SetComponentL(*portBuf, EUriPort);
       
   320 			CleanupStack::PopAndDestroy(portBuf);
       
   321 			}
       
   322 
       
   323 		// Now set the absolute URI back into the transaction
       
   324 		request.SetURIL(absoluteUri->Uri());
       
   325 		CleanupStack::PopAndDestroy(absoluteUri);
       
   326 		}
       
   327 
       
   328 	// Create the Request-URI based on the request URI. 
       
   329 	// NOTE - might have changed from earlier
       
   330 
       
   331 	const TUriC8 reqURI = request.URI();
       
   332 	// CONNECT uses authority while everything else uses absoluteURI or absolutePath
       
   333 	// use absolutePath for direct connections and tunnels, and absoluteURI for proxy
       
   334 	// note: OPTIONS uses "*" as well, but that should still work
       
   335 	CAuthority8* authToUse=NULL;
       
   336 	CUri8* uriToUse = NULL;
       
   337 	if( aMethodIndex == HTTP::ECONNECT)
       
   338 		{
       
   339 		authToUse = CAuthority8::NewLC();
       
   340 		authToUse->SetComponentL(reqURI.Extract(EUriUserinfo),EAuthorityUserinfo);
       
   341 		authToUse->SetComponentL(reqURI.Extract(EUriHost),EAuthorityHost);
       
   342 		authToUse->SetComponentL(reqURI.Extract(EUriPort),EAuthorityPort);	
       
   343 		}
       
   344 	else 
       
   345 		{
       
   346 		uriToUse = CUri8::NewLC(reqURI);
       
   347 		if( !iUseProxy || secure ) // if (useproxy and not secure) or (not useproxy) = not useproxy or secure
       
   348 			{// Not going via a proxy - need to remove the scheme and authority parts
       
   349 			uriToUse->RemoveComponentL(EUriScheme);
       
   350 			uriToUse->RemoveComponentL(EUriHost);	// this also removes the userinfo + port
       
   351 			}
       
   352 		}
       
   353 	// Set the Request-URI for the request
       
   354 	RString uriStr = stringPool.OpenStringL(
       
   355 		authToUse ? authToUse->Authority().AuthorityDes() : uriToUse->Uri().UriDes());
       
   356 	CleanupClosePushL(uriStr);
       
   357 	THTTPHdrVal uriVal(uriStr);
       
   358 	aTrans.PropertySet().SetPropertyL(stringPool.StringF(HTTP::EUri, iStringTable), uriVal);
       
   359 	CleanupStack::PopAndDestroy(3, &scheme); // uriToUse or authToUse, uriStr 
       
   360 	}
       
   361 
       
   362 TBool CHttpClientHandler::SetHostHeaderL(RHTTPTransaction aTrans, const TDesC8& aHost, TInt aPort)
       
   363 	{
       
   364 		__START_PERFORMANCE_LOGGER();
       
   365 	// Set the Host header only if the request is not an HTTP/1.0 request.
       
   366 	RStringPool stringPool = iSession.StringPool();
       
   367 	RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
       
   368 	THTTPHdrVal httpVersion;
       
   369 	TBool isHttp10 = EFalse;
       
   370 	if( connInfo.Property(stringPool.StringF(HTTP::EHTTPVersion,iStringTable), httpVersion) )
       
   371 		{
       
   372 		__ASSERT_DEBUG( httpVersion.Type() == THTTPHdrVal::KStrFVal, THttpClientPanic::Panic(THttpClientPanic::EInvalidHeaderValueType) );
       
   373 		isHttp10 = (httpVersion.StrF() == stringPool.StringF(HTTP::EHttp10, iStringTable));
       
   374 		}
       
   375 
       
   376 	// Regardless of proxy settings a Host header based on the URI authority must be added unless
       
   377 	// this is an HTTP/1.0 request in which case a Host header should not exist.
       
   378 	RHTTPRequest request = aTrans.Request();
       
   379 	RHTTPHeaders headers = request.GetHeaderCollection();
       
   380 	RStringF hostStr = stringPool.StringF(HTTP::EHost, iStringTable);
       
   381 	if( !isHttp10 )
       
   382 		{
       
   383 		// If the Host header does not already exist, add it!
       
   384 		THTTPHdrVal hostValue;
       
   385 		if( headers.GetField(hostStr, 0, hostValue) == KErrNotFound )
       
   386 			{				
       
   387 			// Set the Host header...
       
   388 			RStringF hostValStr;
       
   389 
       
   390 			// Check if its a literal IPV6 address
       
   391 			UriUtils::TUriHostType aHostsType = UriUtils::HostType( aHost );
       
   392 			if ( ( aHostsType != UriUtils::ETextHost ) && ( aHostsType != UriUtils::EIPv4Host ) ) // is an IPv6 or other future protocol address
       
   393 				{
       
   394 
       
   395 				HBufC8* ipv6LiteralHost = HBufC8::NewLC( aHost.Length() + 2 ); // add 2 for the braces
       
   396 			
       
   397 				TPtr8 ipv6LiteralHostPtr = ipv6LiteralHost->Des();	
       
   398 				
       
   399 				ipv6LiteralHostPtr.Append( KIPv6HostOpenBrace );
       
   400 				ipv6LiteralHostPtr.Append( aHost );
       
   401 				ipv6LiteralHostPtr.Append( KIPv6HostCloseBrace );
       
   402 
       
   403 				hostValStr = stringPool.OpenFStringL( ipv6LiteralHostPtr );
       
   404 				CleanupStack::PopAndDestroy( ipv6LiteralHost );
       
   405 				
       
   406 				}
       
   407 			else
       
   408 				{
       
   409 				hostValStr = stringPool.OpenFStringL( aHost );
       
   410 				}
       
   411 			
       
   412 			CleanupClosePushL(hostValStr);
       
   413 
       
   414 	
       
   415 			THTTPHdrVal hostVal(hostValStr);	
       
   416 			headers.SetFieldL(hostStr, hostVal);
       
   417 			CleanupStack::PopAndDestroy(&hostValStr);
       
   418 			
       
   419 			// Also set the port number if Host header is not empty and a port 
       
   420 			// number is not the default.
       
   421 			if( aPort != KHttpDefaultPort && aPort != KHttpDefaultSecurePort )
       
   422 				{
       
   423 				THTTPHdrVal portVal(aPort);
       
   424 				RStringF portStr = stringPool.StringF(HTTP::EPort,iStringTable);
       
   425 				headers.SetParamL(hostStr, portStr, portVal, 0);
       
   426 				}
       
   427 			}
       
   428 		// else the Host header already exists, so do nothing
       
   429 		}
       
   430 	else // This is an HTTP/1.0 request
       
   431 		headers.RemoveField(hostStr);
       
   432 		
       
   433 	__END_PERFORMANCE_LOGGER(_L(",CHttpClientHandler::SetHostHeaderL()"));	
       
   434 	return isHttp10;
       
   435 	}
       
   436 
       
   437 void CHttpClientHandler::AddTunnelInfoL(RHTTPTransaction aTrans, const TDesC8& aHost, TInt aPort)
       
   438 	{
       
   439 	// Convert the port number into a descriptor...
       
   440 	HBufC8* port = NULL;
       
   441 	InetProtTextUtils::ConvertIntToDescriptorL(aPort, port);
       
   442 	CleanupStack::PushL(port);
       
   443 
       
   444 	// Create the Request-URI for the CONNECT request - it is in the 'authority'
       
   445 	// form, as described in RFC2616, section 5.1.2.
       
   446 	CAuthority8* authority = CAuthority8::NewLC();
       
   447 	
       
   448 	authority->SetComponentL(aHost, EAuthorityHost);
       
   449 	authority->SetComponentL(*port, EAuthorityPort);
       
   450 
       
   451 	// Set this as the ETunnel property in the transaction.
       
   452 	RStringPool stringPool = iSession.StringPool();
       
   453 	RStringF tunnelStr = stringPool.OpenFStringL(authority->Authority().AuthorityDes());
       
   454 	CleanupClosePushL(tunnelStr);
       
   455 	THTTPHdrVal tunnelVal(tunnelStr);
       
   456 	aTrans.PropertySet().SetPropertyL(stringPool.StringF(HTTP::ETunnel, iStringTable), tunnelVal);
       
   457 	CleanupStack::PopAndDestroy(3, port); // delete authority and close tunnelStr
       
   458 	}
       
   459 
       
   460 TBool CHttpClientHandler::SelectConnectionManagerL(const CHttpConnectionInfo& aConnectionInfo, RHTTPTransaction aTrans, TBool aCanPipeline, CHttpConnectionManager *&aManager )
       
   461 	{
       
   462 	// Selecting a connection manager depends on whether the transaction can be
       
   463 	// pipelined. If so, then the connection manager of choice would be the one
       
   464 	// that is connected to the correct location and busy with other transactions.
       
   465 	// If there is no connection manager that fits this criteria, then the 
       
   466 	// selection process follows that for a transaction that cannot be pipelined.
       
   467 
       
   468 	// The order of preference for selecting a connection manager - 
       
   469 	// 1) A manager that is connected to the correct location and is available.
       
   470 	//	  This is the backup-choice for a transaction that can be pipelined.
       
   471 	// 2) A manager that is not connected to anywhere.
       
   472 	// 3) Create a new manager if the limit has not been reached.
       
   473 	// 4) Use a manager that is connected to a different host (but not being 
       
   474 	//    used) and will therefore need disconnecting and reconnecting.
       
   475 	
       
   476 	CHttpConnectionManager* backupChoice = NULL;
       
   477 	CHttpConnectionManager* secondChoice = NULL;
       
   478 	CHttpConnectionManager* fourthChoice = NULL;
       
   479     CHttpConnectionManager* managerConnecting = NULL;	
       
   480 	TBool newConnection = ETrue;
       
   481     TInt numConnectionsToSingleServer = 0;
       
   482     
       
   483 	TBool connectMethod = aTrans.Request().Method().Index(iStringTable) == HTTP::ECONNECT;
       
   484 	
       
   485 	const TInt numConnMan = iConnectionManagers.Count();
       
   486 
       
   487 	for( TInt ii=0; (ii < numConnMan && aManager == NULL ); ++ii )
       
   488 		{
       
   489 		CHttpConnectionManager::TConnectionStatus status = iConnectionManagers[ii]->Status();
       
   490 		switch( status )
       
   491 			{
       
   492 		case CHttpConnectionManager::ENotConnected:
       
   493 			{
       
   494 			// This is a pretty good option because it just needs a connection 
       
   495 			// to be established
       
   496 			secondChoice = iConnectionManagers[ii];
       
   497 			} break;
       
   498 		case CHttpConnectionManager::EConnectedAndAvailable:
       
   499 			{
       
   500 			// This is the ideal situation if the location matches, otherwise it
       
   501 			// becomes the fourth choice
       
   502 			const CHttpConnectionInfo& connectionInfo = iConnectionManagers[ii]->ConnectionInfo();
       
   503 			if( connectionInfo.HostAndPortMatches(aConnectionInfo) )
       
   504 				{
       
   505 				if(!connectMethod)
       
   506 				     {
       
   507 	                ++numConnectionsToSingleServer;					
       
   508 				     if( aCanPipeline )
       
   509 					     {
       
   510 						  // This is the backup-choice
       
   511 						  backupChoice = iConnectionManagers[ii];
       
   512 						 }
       
   513 				     else
       
   514 					    {
       
   515 						// This is the one!
       
   516 						aManager = iConnectionManagers[ii];
       
   517 						newConnection = EFalse;
       
   518 					    }
       
   519 				     }
       
   520 				 }
       
   521 			else
       
   522 				{
       
   523 				// Non-matching connection info - fourth choice.
       
   524 				fourthChoice = iConnectionManagers[ii];
       
   525 				}
       
   526 			} break;
       
   527 		case CHttpConnectionManager::EConnectedAndBusy:
       
   528 			{
       
   529 			// This is the ideal choice if the pipelining can done and the 
       
   530 			// location and secure status match.
       
   531 			const CHttpConnectionInfo& connectionInfo = iConnectionManagers[ii]->ConnectionInfo();
       
   532             TBool hostAndPortMatches = connectionInfo.HostAndPortMatches(aConnectionInfo);
       
   533             if(hostAndPortMatches)
       
   534                 {
       
   535                 ++numConnectionsToSingleServer;
       
   536                 }
       
   537 			if( !connectMethod && aCanPipeline && 
       
   538 			    hostAndPortMatches &&
       
   539 				connectionInfo.IsSecure() == aConnectionInfo.IsSecure() )
       
   540 				{
       
   541 				// This is the one!
       
   542 				aManager = iConnectionManagers[ii];
       
   543 				newConnection = EFalse;
       
   544 				}
       
   545 			} break;
       
   546 		case CHttpConnectionManager::EConnectedNotAvailable:
       
   547 			{
       
   548 			// Do nothing - continue the search...
       
   549 			} break;
       
   550 	     case CHttpConnectionManager::EConnectingNotAvailable:
       
   551 	         {
       
   552 	         const CHttpConnectionInfo& connectionInfo = iConnectionManagers[ii]->ConnectionInfo();
       
   553              TBool hostAndPortMatches = connectionInfo.HostAndPortMatches(aConnectionInfo);
       
   554 	         if(hostAndPortMatches)
       
   555 	             {
       
   556 	             ++numConnectionsToSingleServer;
       
   557 	             }
       
   558              if (aCanPipeline &&  hostAndPortMatches && connectionInfo.IsSecure() == aConnectionInfo.IsSecure())
       
   559 	           {
       
   560 	           // We are connecting. So do not initiate another connection.
       
   561 	           // We will be able to send the request via the same connection.
       
   562 	           managerConnecting = iConnectionManagers[ii];
       
   563 	           }
       
   564 	         }
       
   565 	         break;			
       
   566 		default:
       
   567 			// There are no other transport handler states - should not reach here
       
   568 			User::Invariant();
       
   569 			break;
       
   570 			}
       
   571 		}
       
   572 
       
   573 	if( aManager == NULL)
       
   574 		{
       
   575 		if( aCanPipeline && backupChoice != NULL )
       
   576 			{
       
   577 			// Use the connection manager that is connected to the correct 
       
   578 			// location	but not busy.
       
   579 			aManager = backupChoice;
       
   580 			newConnection = EFalse;
       
   581 			}
       
   582 		else if( secondChoice != NULL )	
       
   583 			{
       
   584 			// Use the second choice connection manager - idle one.
       
   585 			aManager = secondChoice;
       
   586 			}
       
   587 		else if( numConnMan < MaxNumConnectionManagers() )
       
   588 			{
       
   589 			// Have not reached the max number of connection managers and so 
       
   590 			// can create a new connection manager - check for a transport layer
       
   591 			if( iTransportLayer == NULL )
       
   592 				{
       
   593 				// Create the transport layer
       
   594 				_LIT8(KTcpProtocol, "TCP");
       
   595 				THttpTransportConstructionParams params = THttpTransportConstructionParams(*this);
       
   596 				
       
   597 				RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
       
   598 				RStringPool stringPool = iSession.StringPool();
       
   599 				THTTPHdrVal valPriority;
       
   600 				RStringF strConnMan = stringPool.StringF(HTTP::ETranspHndlrPriority , iStringTable);
       
   601 				params.iPriority = EFalse;
       
   602 				if( connInfo.Property(strConnMan, valPriority) )
       
   603 					{
       
   604 					if(valPriority== stringPool.StringF(HTTP::EEnableTranspHndlrPriority , iStringTable))
       
   605 						params.iPriority = ETrue;
       
   606 					}				
       
   607 				
       
   608 				iTransportLayer = CHttpTransportLayer::NewL(KTcpProtocol, params);
       
   609 				}
       
   610 			// Check we are doing an optimal pipelining. Read the property value only
       
   611 			// if we haven't created atleast one connection manager yet
       
   612 			if(numConnMan == 0)
       
   613 			    {			  
       
   614                 RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
       
   615                 RStringPool stringPool = iSession.StringPool();
       
   616 			    __ASSERT_DEBUG(!managerConnecting, User::Invariant());
       
   617 			    THTTPHdrVal optimalPipelineValue;
       
   618 			    RStringF strOptimalPipeline = stringPool.StringF(HTTP::EHttpOptimalPipelining, iStringTable);
       
   619 			    if(connInfo.Property(strOptimalPipeline, optimalPipelineValue))
       
   620 			        {
       
   621 			        iEnableOptimalPipeline = (optimalPipelineValue == stringPool.StringF(HTTP::EHttpEnableOptimalPipelining, iStringTable)); 
       
   622 			        }
       
   623 			    }
       
   624 			if(managerConnecting)
       
   625 			    {
       
   626                 newConnection = EFalse;			    
       
   627 			    }
       
   628 			else
       
   629 			    {			    
       
   630 	            // Create the new connection manager
       
   631 	            const TInt maxNumberTransactionsToPipeline = MaxNumTransactionsToPipeline(); 
       
   632 	            aManager = CHttpConnectionManager::NewL(iTransportLayer->SocketFactory(), *this, *iPipelineFallback, maxNumberTransactionsToPipeline, iEnableOptimalPipeline);
       
   633 	            CleanupStack::PushL(aManager);
       
   634 
       
   635 			__RecordConnectionManagerCreationL();
       
   636 
       
   637 
       
   638 #if defined (_DEBUG) && defined (_LOGGING)
       
   639 	            aManager->__logger__ = this->__logger__;
       
   640 #endif
       
   641 
       
   642 	            // Append to the store
       
   643 	            User::LeaveIfError(iConnectionManagers.Append(aManager));
       
   644 	            CleanupStack::Pop(aManager);			    
       
   645 			    }
       
   646 			}
       
   647 		else if( fourthChoice != NULL )	
       
   648 			{
       
   649 			// As a last resort reuse one that is connected to the wrong host but 
       
   650 			// not being used.
       
   651 			aManager = fourthChoice;
       
   652 			}
       
   653 		}
       
   654 	return newConnection;
       
   655 	}
       
   656 
       
   657 CHttpConnectionManager* CHttpClientHandler::SelectTunnelConnectionL(const CHttpConnectionInfo& aConnectionInfo, RHTTPTransaction aTrans, TBool aCanPipeline)
       
   658 	{
       
   659 	// Look for connection manager that is a tunnel connection via appropriate
       
   660 	// proxy to appropriate host. If the transaction can be pipelined, then the
       
   661 	// first choice is a connection manager that is connected and busy. 
       
   662 	RStringPool stringPool = iSession.StringPool();
       
   663 	THTTPHdrVal hostVal;
       
   664 #ifdef _DEBUG
       
   665 	TBool found = 
       
   666 #endif
       
   667 	aTrans.PropertySet().Property(stringPool.StringF(HTTP::ETunnel, iStringTable), hostVal);
       
   668 
       
   669 	__ASSERT_DEBUG( found, User::Invariant() );
       
   670 	__ASSERT_DEBUG( hostVal.Type() == THTTPHdrVal::KStrFVal, User::Invariant() );
       
   671 
       
   672 	RStringF host = hostVal.StrF();
       
   673 	TBool notifyCreateTunnel = ETrue;	
       
   674 	CHttpConnectionManager* manager = NULL;
       
   675 	CHttpConnectionManager* backupChoice = NULL;
       
   676 	
       
   677 	const TInt numConnMan = iConnectionManagers.Count();
       
   678 
       
   679 	for( TInt ii=0; (ii < numConnMan && manager == NULL ); ++ii )
       
   680 		{
       
   681 		CHttpConnectionManager::TConnectionStatus status = iConnectionManagers[ii]->Status();
       
   682 		switch( status )
       
   683 			{
       
   684 		case CHttpConnectionManager::ENotConnected:
       
   685 		case CHttpConnectionManager::EConnectedNotAvailable:
       
   686 		case CHttpConnectionManager::EConnectingNotAvailable:
       
   687 			{
       
   688 			// Do nothing - continue search.
       
   689 			} break;
       
   690 		case CHttpConnectionManager::EConnectedAndAvailable:
       
   691 			{
       
   692 			const CHttpConnectionInfo& connectionInfo = iConnectionManagers[ii]->ConnectionInfo();
       
   693 			if( connectionInfo.HostAndPortMatches(aConnectionInfo) && 
       
   694 				iConnectionManagers[ii]->TunnelMatches(host) )
       
   695 				{
       
   696 				// Location (ie the proxy) and tunnel host match - this is the 
       
   697 				// backup choice if pipelining allowed, otherwise it is the one.
       
   698 				if( aCanPipeline )
       
   699 					{
       
   700 					// This is the backup choice...
       
   701 					backupChoice = iConnectionManagers[ii];
       
   702 					}
       
   703 				else
       
   704 					{
       
   705 					// This is the one! There is no need to create a tunnel.
       
   706 					manager = iConnectionManagers[ii];
       
   707 					notifyCreateTunnel = EFalse;
       
   708 					}
       
   709 				}
       
   710 			} break;
       
   711 		case CHttpConnectionManager::EConnectedAndBusy:
       
   712 			{
       
   713 			const CHttpConnectionInfo& connectionInfo = iConnectionManagers[ii]->ConnectionInfo();
       
   714 			if( aCanPipeline &&
       
   715 				connectionInfo.HostAndPortMatches(aConnectionInfo) && 
       
   716 				iConnectionManagers[ii]->TunnelMatches(host) )
       
   717 				{
       
   718 				// Location (ie the proxy) and tunnel host match and pipelining
       
   719 				// is allowed - this is the one! There is no need to create a 
       
   720 				// tunnel.
       
   721 				manager = iConnectionManagers[ii];
       
   722 				notifyCreateTunnel = EFalse;
       
   723 				}
       
   724 			} break;
       
   725 		default:
       
   726 			// There are no other transport handler states - should not reach here
       
   727 			User::Invariant();
       
   728 			break;
       
   729 			}
       
   730 		}
       
   731 
       
   732 	if( manager == NULL && backupChoice != NULL )
       
   733 		{
       
   734 		// Use the back-up choice - now no need to create a tunnel.
       
   735 		manager = backupChoice;
       
   736 		notifyCreateTunnel = EFalse;
       
   737 		}
       
   738 #if defined (_DEBUG) && defined (_LOGGING)
       
   739 	if( manager != NULL )
       
   740 		{
       
   741 		__FLOG_1(_T8("!! Tunnel to %S available"), &host.DesC());
       
   742 		__FLOG_6(
       
   743 				_T8("-> Trans %d, Con %d : can service via host %S, remote port %d (secure : %d, nonpersistent : %d)"),
       
   744 				aTrans.Id(),
       
   745 				GetConnectionID(aTrans),
       
   746 				&manager->ConnectionInfo().Host(), 
       
   747 				manager->ConnectionInfo().Port(), 
       
   748 				manager->ConnectionInfo().IsSecure(), 
       
   749 				manager->ConnectionInfo().IsNonPersistent()						
       
   750 				);
       
   751 		}
       
   752 #endif
       
   753 	if( notifyCreateTunnel )
       
   754 		{
       
   755 		__FLOG_1(_T8("!! No tunnel to %S"), &host.DesC());
       
   756 		__FLOG_2(_T8("-> Trans %d, Con %d : cannot service until tunnel established"), aTrans.Id(),GetConnectionID(aTrans));
       
   757 
       
   758 		// Notify client (or filter) that a tunnel needs to be established
       
   759 		// before this transaction can be serviced.
       
   760 		aTrans.SendEventL(
       
   761 						 THTTPEvent::ENeedTunnel, 
       
   762 						 THTTPEvent::EIncoming,
       
   763 						 THTTPFilterHandle(THTTPFilterHandle::EProtocolHandler)
       
   764 						 );
       
   765 		}
       
   766 	return manager;
       
   767 	}
       
   768 
       
   769 TInt CHttpClientHandler::MaxNumConnectionManagers() const
       
   770 	{
       
   771 	// Has this value been previously cached?
       
   772 	if( iMaxNumConnectionManagers == 0 )
       
   773 		{
       
   774 		// No. Use this default should the property not be set
       
   775 		iMaxNumConnectionManagers = KMaxConnectionManagers;
       
   776 
       
   777 		// Check session properties
       
   778 		RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
       
   779 		RStringPool stringPool = iSession.StringPool();
       
   780 		THTTPHdrVal maxConnMan;
       
   781 		RStringF strConnMan = stringPool.StringF(HTTP::EMaxNumTransportHandlers, iStringTable);
       
   782 		if( connInfo.Property(strConnMan, maxConnMan) )
       
   783 			{
       
   784 			if( maxConnMan.Type() == THTTPHdrVal::KTIntVal )
       
   785 				iMaxNumConnectionManagers = maxConnMan.Int();
       
   786 			}
       
   787 		}
       
   788 	return iMaxNumConnectionManagers;
       
   789 	}
       
   790 	
       
   791 void CHttpClientHandler::SetupProxyInformation(RHTTPTransaction aTrans)
       
   792 	{
       
   793 	// Assume a direct connection unless the properties specifically indicate 
       
   794 	// that a proxy should be used.
       
   795 	iUseProxy = EFalse;
       
   796 	iProxyAddress.Close();
       
   797 	
       
   798 	RStringPool stringPool(iSession.StringPool());
       
   799 	THTTPHdrVal useProxy;
       
   800 	THTTPHdrVal address;
       
   801 	RStringF proxyUsage = stringPool.StringF(HTTP::EProxyUsage, iStringTable);
       
   802 	RStringF proxyAddress = stringPool.StringF(HTTP::EProxyAddress, iStringTable);
       
   803 
       
   804 	RHTTPPropertySet transactionProperties = aTrans.PropertySet();
       
   805 	RHTTPPropertySet sessionProperties = iSession.ConnectionInfo();
       
   806 
       
   807 	// First check the transaction properties for proxy info. If the transaction
       
   808 	// has its own proxy info set then this should be used, including the fact 
       
   809 	// that a proxy should not be used. Otherwise check the session properties 
       
   810 	// for proxy info.
       
   811 	if( transactionProperties.Property(proxyUsage, useProxy) )
       
   812 		{
       
   813 		__ASSERT_DEBUG( useProxy.Type() == THTTPHdrVal::KStrFVal, THttpClientPanic::Panic(THttpClientPanic::EInvalidProxySetting) );
       
   814 
       
   815 		// The transaction has proxy info set...
       
   816 		iUseProxy = (useProxy.StrF().Index(iStringTable) == HTTP::EUseProxy);
       
   817 	
       
   818 		if( iUseProxy )
       
   819 			{
       
   820 			if( transactionProperties.Property(proxyAddress, address) )
       
   821 				{
       
   822 				__ASSERT_DEBUG( address.Type() == THTTPHdrVal::KStrFVal, THttpClientPanic::Panic(THttpClientPanic::EInvalidProxySetting) );
       
   823 
       
   824 				iProxyAddress = address.StrF().Copy();
       
   825 				}
       
   826 			else
       
   827 				{
       
   828 				// It is invalid to specify using a proxy and not set a proxy
       
   829 				// address!
       
   830 				THttpClientPanic::Panic(THttpClientPanic::EInvalidProxySetting);
       
   831 				}
       
   832 			}	
       
   833 		}
       
   834 	else if( sessionProperties.Property(proxyUsage, useProxy) )
       
   835 		{
       
   836 		__ASSERT_DEBUG( useProxy.Type() == THTTPHdrVal::KStrFVal, THttpClientPanic::Panic(THttpClientPanic::EInvalidProxySetting) );
       
   837 
       
   838 		// The session has proxy info set...
       
   839 		iUseProxy = (useProxy.StrF().Index(iStringTable) == HTTP::EUseProxy);
       
   840 		
       
   841 		if( iUseProxy )
       
   842 			{
       
   843 			if( sessionProperties.Property(proxyAddress, address) )
       
   844 				{
       
   845 				__ASSERT_DEBUG( address.Type() == THTTPHdrVal::KStrFVal, THttpClientPanic::Panic(THttpClientPanic::EInvalidProxySetting) );
       
   846 				
       
   847 				iProxyAddress = address.StrF().Copy();
       
   848 				}
       
   849 			else
       
   850 				{
       
   851 				// It is invalid to specify using a proxy and not set a proxy
       
   852 				// address!
       
   853 				THttpClientPanic::Panic(THttpClientPanic::EInvalidProxySetting);
       
   854 				}
       
   855 			}
       
   856 		}
       
   857 	}
       
   858 
       
   859 TBool CHttpClientHandler::CheckPipelineSupport(RHTTPTransaction aTrans)
       
   860 	{
       
   861 	// Check to see if the pipelining support has been disabled/enabled for this
       
   862 	// transaction.
       
   863 	RStringPool stringPool = iSession.StringPool();
       
   864 	RStringF pipeline = stringPool.StringF(HTTP::EHttpPipelining, iStringTable);
       
   865 	THTTPHdrVal value;
       
   866 	TBool canPipeline = ETrue;
       
   867 
       
   868 	if(	aTrans.PropertySet().Property(pipeline, value) )
       
   869 		{
       
   870 		__ASSERT_DEBUG( value.Type() == THTTPHdrVal::KStrFVal, User::Invariant() );
       
   871 
       
   872 		canPipeline = (value.StrF().Index(iStringTable) != HTTP::EDisablePipelining);
       
   873 		}
       
   874 	return canPipeline;
       
   875 	}
       
   876 
       
   877 /*
       
   878  *	Methods from CProtocolHandler
       
   879  */
       
   880 
       
   881 TInt CHttpClientHandler::SessionServerCert(TCertInfo& /*aServerCert*/)
       
   882 	{
       
   883 	return KErrNotSupported;
       
   884 	}
       
   885 
       
   886 
       
   887 TInt CHttpClientHandler::TransactionServerCert(TCertInfo& aServerCert, RHTTPTransaction aTransaction)
       
   888 	{
       
   889 	TInt error = KErrNotFound;
       
   890 	const CX509Certificate* cert = static_cast<const CX509Certificate*>(TransactionServerCert(aTransaction));
       
   891 	if(cert) 
       
   892 		{
       
   893 		TRAPD( failed, GetCertInfoL(*cert, aServerCert));
       
   894 
       
   895 		// pass back the leaving system error.
       
   896 		error = (failed < 0 ) ? failed : KErrNone;
       
   897 		}
       
   898 	return error;
       
   899 	}
       
   900 
       
   901 void CHttpClientHandler::CreateCodecL()
       
   902 	{
       
   903 	iCodec = CHeaderCodecPlugin::NewL( KHttpClientCodecName, iSession.StringPool());
       
   904 	}
       
   905 
       
   906 CProtTransaction* CHttpClientHandler::CreateProtTransactionL(RHTTPTransaction aTransaction)
       
   907 	{
       
   908 	// Create the appropriate CProtTransaction object
       
   909 	CHttpClientTransaction* transaction = CHttpClientTransaction::NewL(aTransaction);
       
   910 	return transaction;
       
   911 	}
       
   912 	
       
   913 TBool CHttpClientHandler::ServiceL(CProtTransaction& aTrans)
       
   914 	{
       
   915 		__START_PERFORMANCE_LOGGER();
       
   916 	// Prepare the transaction...
       
   917 	TBool needTunnel = EFalse;
       
   918 	TBool canPipeline = EFalse;
       
   919 	CHttpConnectionInfo* info = PrepareTransactionL(aTrans.Transaction(), needTunnel, canPipeline);
       
   920 	CleanupStack::PushL(info);
       
   921 
       
   922 	CHttpConnectionManager* manager = NULL;
       
   923 	TBool isNewConnection = ETrue;
       
   924 	
       
   925 	if( needTunnel )
       
   926 		{
       
   927 		// Find a connection that is tunnelling via appropriate proxy to the
       
   928 		// appropriate host.
       
   929 		manager = SelectTunnelConnectionL(*info, aTrans.Transaction(), canPipeline);
       
   930 		}
       
   931 	else
       
   932 		{
       
   933 		// Look for a normal connection.
       
   934 		isNewConnection = SelectConnectionManagerL(*info, aTrans.Transaction(), canPipeline, manager);
       
   935 		}
       
   936 
       
   937 	if( manager != NULL )
       
   938 		{
       
   939 		// Pass the connection manager to the transaction - need to do this 
       
   940 		// before creating tx- and rx- data objects.
       
   941 		CHttpClientTransaction* trans = static_cast<CHttpClientTransaction*>(&aTrans);
       
   942 		trans->SetConnectionManager(*manager);
       
   943 		
       
   944 		if(isNewConnection)
       
   945 			{
       
   946 			//Increment retry count only if it is a new connection.
       
   947 			trans->IncRetryCount();
       
   948 			}
       
   949 
       
   950 		// Create the tx- and rx- objects in the transaction
       
   951 		aTrans.CreateTxDataL();
       
   952 		aTrans.CreateRxDataL(*this);
       
   953 
       
   954 #if defined (_DEBUG) && defined (_LOGGING)
       
   955 		CHttpRequestComposer* composer = static_cast<CHttpRequestComposer*>(&aTrans.TxData());
       
   956 		CHttpResponseParser* parser = static_cast<CHttpResponseParser*>(&aTrans.RxData());
       
   957 
       
   958 		composer->__logger__ = this->__logger__;
       
   959 		parser->__logger__ = this->__logger__;
       
   960 #endif
       
   961 
       
   962 		// If the transaction cannot be pipelined, then set the connection 
       
   963 		// manager to not allow pipelining. Once this transaction has completed
       
   964 		// the manager will revert to allowing pipelining.
       
   965 		if( !canPipeline )
       
   966 			manager->DisablePipelining();
       
   967 				
       
   968 		// Remove connection info from cleanup stack before submiting to the 
       
   969 		// connection manager - ownership is passed to the connection manager.
       
   970 		CleanupStack::Pop(info);
       
   971 		MHttpRequest& request = static_cast<CHttpRequestComposer&>(aTrans.TxData());
       
   972 		MHttpResponse& response = static_cast<CHttpResponseParser&>(aTrans.RxData());
       
   973 
       
   974 		manager->SubmitL(*info, request, response);
       
   975 		__END_PERFORMANCE_LOGGER(_L(",CHttpClientHandler::ServiceL()"));
       
   976 		return ETrue;
       
   977 		}
       
   978 	CleanupStack::PopAndDestroy(info);
       
   979 		__END_PERFORMANCE_LOGGER(_L(",CHttpClientHandler::ServiceL()"));
       
   980 	return EFalse;
       
   981 	}
       
   982 	
       
   983 void CHttpClientHandler::ClosedTransactionHook(CProtTransaction* aTrans)
       
   984 	{
       
   985 	__FLOG_0(_T8("!! Closing transaction - client request"));
       
   986 	__FLOG_1(_T8("-> Trans %d : closed"), aTrans->Transaction().Id());
       
   987 
       
   988 	delete aTrans;	
       
   989 	}
       
   990 	
       
   991 void CHttpClientHandler::CancelTransactionHook(CProtTransaction& aTransaction)
       
   992 	{
       
   993 	// Is this transaction still alive - check to see if it still has a 
       
   994 	// connection manager.
       
   995 	CHttpClientTransaction& trans = static_cast<CHttpClientTransaction&>(aTransaction);
       
   996 	CHttpConnectionManager* manager = trans.ConnectionManager();
       
   997 
       
   998 	__FLOG_0(_T8("!! Cancelling transaction - client request"));
       
   999 	
       
  1000 	if( manager != NULL )
       
  1001 		{
       
  1002 		__FLOG_2(_T8("-> Trans %d, Con %d : still alive - cancelling its connection manager"), aTransaction.Transaction().Id(),GetConnectionID(manager));
       
  1003 	
       
  1004 		// Transaction is still alive - ask its connection manager to cancel it.
       
  1005 		MHttpRequest& request = static_cast<CHttpRequestComposer&>(aTransaction.TxData());
       
  1006 		MHttpResponse& response = static_cast<CHttpResponseParser&>(aTransaction.RxData());
       
  1007 		manager->CancelSubmission(request, response);
       
  1008 		
       
  1009 		// Connection is now cancelled - remove the connection manager from the
       
  1010 		// transaction.
       
  1011 		trans.RemoveConnectionManager();		
       
  1012 		}
       
  1013 #if defined (_DEBUG) && defined (_LOGGING)
       
  1014 	else
       
  1015 		__FLOG_1(_T8("-> Trans %d : already finished - nothing to do"), aTransaction.Transaction().Id());
       
  1016 #endif
       
  1017 	}
       
  1018 	
       
  1019 void CHttpClientHandler::NotifyNewRequestBodyPart(CProtTransaction& aTransaction)
       
  1020 	{
       
  1021 	// Notify the transaction of more data.
       
  1022 	static_cast<CHttpRequestComposer&>(aTransaction.TxData()).NotifyMoreRequestBodyData();
       
  1023 	}
       
  1024 	
       
  1025 void CHttpClientHandler::GetInterfaceL(TUid aInterfaceId, MProtHandlerInterface*& aInterfacePtr)
       
  1026 	{
       
  1027 	switch(aInterfaceId.iUid)
       
  1028 		{
       
  1029 	case KProtHandlerTransactionServerCertUid:
       
  1030 		{
       
  1031 		aInterfacePtr = this;
       
  1032 		break;
       
  1033 		}
       
  1034 	default:
       
  1035 		{
       
  1036 		CProtocolHandler::GetInterfaceL(aInterfaceId, aInterfacePtr);
       
  1037 		break;
       
  1038 		}
       
  1039 		}
       
  1040 	}
       
  1041 	
       
  1042 /*
       
  1043  *	Methods from MConnectionPrefsProvider
       
  1044  */
       
  1045 
       
  1046 TBool CHttpClientHandler::SupplyCommsConnection( RConnection*& aConnectionPtr )
       
  1047 	{
       
  1048 	aConnectionPtr = NULL;
       
  1049 
       
  1050 	RHTTPConnectionInfo	connInfo = iSession.ConnectionInfo();
       
  1051 	RStringPool stringPool = iSession.StringPool();
       
  1052 	THTTPHdrVal value;
       
  1053 	
       
  1054 	TBool hasValue = connInfo.Property( stringPool.StringF(HTTP::EHttpSocketConnection, iStringTable), value );
       
  1055 	if( hasValue && value.Type() == THTTPHdrVal::KTIntVal )
       
  1056 		{
       
  1057 		aConnectionPtr = reinterpret_cast<RConnection*>(value.Int());
       
  1058 		return ETrue;
       
  1059 		}
       
  1060 	return EFalse;
       
  1061 	}
       
  1062 
       
  1063 TBool CHttpClientHandler::SupplySocketServerHandle ( TInt& aSocketServerHandle ) 
       
  1064 	{
       
  1065 	aSocketServerHandle = 0;
       
  1066 	RHTTPConnectionInfo	connInfo = iSession.ConnectionInfo();
       
  1067 	RStringPool stringPool = iSession.StringPool();
       
  1068 	THTTPHdrVal value;
       
  1069 
       
  1070 	TBool hasValue = connInfo.Property(stringPool.StringF(HTTP::EHttpSocketServ, iStringTable), value);
       
  1071 	if( hasValue && value.Type() == THTTPHdrVal::KTIntVal )  
       
  1072 		{
       
  1073 		aSocketServerHandle = value.Int();
       
  1074 		return ETrue;
       
  1075 		}
       
  1076 	return EFalse;
       
  1077 	}
       
  1078 
       
  1079 void CHttpClientHandler::SetCommsConnectionL( RConnection* aConnectionPtr )
       
  1080 	{
       
  1081 	RHTTPConnectionInfo	connInfo = iSession.ConnectionInfo();
       
  1082 	RStringPool stringPool = iSession.StringPool();
       
  1083 	TInt connectionPtrVal = reinterpret_cast<TInt>(aConnectionPtr);
       
  1084 	connInfo.SetPropertyL ( stringPool.StringF(HTTP::EHttpSocketConnection, iStringTable ), THTTPHdrVal (connectionPtrVal) );
       
  1085 	}
       
  1086 	
       
  1087 void CHttpClientHandler::SetSocketServerHandleL ( TInt aSocketServerHandle )
       
  1088 	{
       
  1089 	RHTTPConnectionInfo	connInfo = iSession.ConnectionInfo();
       
  1090 	RStringPool stringPool = iSession.StringPool();
       
  1091 	connInfo.SetPropertyL ( stringPool.StringF(HTTP::EHttpSocketServ, iStringTable ), THTTPHdrVal (aSocketServerHandle) );		
       
  1092 	}
       
  1093 
       
  1094 void CHttpClientHandler::GetSecurityPrefs(TBool& aDialogPrompt, MSecurityPolicy*& aSecurityPolicy)
       
  1095 	{
       
  1096 	// Set the security policy
       
  1097 	aSecurityPolicy = iSecurityPolicy;
       
  1098 
       
  1099 	// Set the dialog info - check the session properties
       
  1100 	THTTPHdrVal value;
       
  1101 	RStringF secureDialog = iSession.StringPool().StringF(HTTP::ESecureDialog, iStringTable);
       
  1102 	TBool hasValue = iSession.ConnectionInfo().Property(secureDialog, value);
       
  1103 	if( hasValue && value.Type() == THTTPHdrVal::KStrFVal && 
       
  1104 		value.StrF().Index(iStringTable) == HTTP::EDialogNoPrompt )
       
  1105 		{
       
  1106 		// Client has requested to not be prompted
       
  1107 		aDialogPrompt = EFalse;
       
  1108 		}
       
  1109 	else
       
  1110 		{
       
  1111 		// The default value - the client will be prompted
       
  1112 		aDialogPrompt = ETrue;
       
  1113 		}
       
  1114 	}
       
  1115 
       
  1116 TBool CHttpClientHandler::ImmediateSocketShutdown()
       
  1117 	{
       
  1118 	TBool immediateSocketShutdown = EFalse;
       
  1119 	if( *iSessionClosingPtr ) // iSessionClosingPtr cannot be NULL as its is set in ConstructL
       
  1120 		{
       
  1121 		// Session is closing down, check the session properties to check if the client has requested
       
  1122 		// an immediate socket shutdown
       
  1123 		THTTPHdrVal value;
       
  1124 		RStringF socketShutdownMode = iSession.StringPool().StringF(HTTP::ESocketShutdownMode, iStringTable);
       
  1125 		TBool hasValue = iSession.ConnectionInfo().Property(socketShutdownMode, value);
       
  1126 		if( hasValue && value.Type() == THTTPHdrVal::KStrFVal && 
       
  1127 			value.StrF().Index(iStringTable) == HTTP::ESocketShutdownImmediate )
       
  1128 			{
       
  1129 			__FLOG_0(_T8("!! Immediate socket shutdown requested by client"));
       
  1130 			immediateSocketShutdown = ETrue;
       
  1131 			}
       
  1132 		}
       
  1133 
       
  1134 	return immediateSocketShutdown;
       
  1135 	}
       
  1136 	
       
  1137 TInt CHttpClientHandler::SessionId()
       
  1138 	{
       
  1139 	THTTPHdrVal value;
       
  1140 	TInt result = KErrNotFound;
       
  1141 	const TBool hasValue = iSession.ConnectionInfo().Property(iSession.StringPool().StringF(HTTP::ESessionId, iStringTable), value);
       
  1142 	if( hasValue && value.Type()==THTTPHdrVal::KTIntVal) // silently ignore inappropriate types
       
  1143 		{
       
  1144 		result = value.Int();
       
  1145 		if(result<0)
       
  1146 			{
       
  1147 			result = KErrNotFound;
       
  1148 			}
       
  1149 		}
       
  1150 	return result;
       
  1151 	}
       
  1152 
       
  1153 
       
  1154 /*
       
  1155  *	Methods from MRxDataObserver
       
  1156  */
       
  1157  
       
  1158 TInt CHttpClientHandler::SetStatus(CRxData& aRxData, TInt aStatus)
       
  1159 	{
       
  1160 	// Have received a status message from an Rx data object - check the status.
       
  1161 	CHttpClientTransaction& protTrans = static_cast<CHttpClientTransaction&>(aRxData.ProtTrans());
       
  1162 	RHTTPTransaction trans = protTrans.Transaction();
       
  1163 	TInt err = KErrNone;
       
  1164 	switch( aStatus )
       
  1165 		{
       
  1166 	case THTTPEvent::EResponseComplete:
       
  1167 		{
       
  1168 		__FLOG_2(_T8("Trans %d, Con %d : transaction completed"), trans.Id(), GetConnectionID(trans));
       
  1169 
       
  1170 		// The response is complete - the client has been passed all the data
       
  1171 		// and released it. Check to see if this was a CONNECT request.
       
  1172 		RStringPool stringPool = iSession.StringPool();
       
  1173 
       
  1174 		TInt status = aStatus;
       
  1175 		if( trans.Request().Method().Index(iStringTable) == HTTP::ECONNECT )
       
  1176 			{
       
  1177 			if( HTTPStatus::IsSuccessful(trans.Response().StatusCode()) )
       
  1178 				{
       
  1179 				// A 2xx status code - tunnel has been successfully established. 
       
  1180 				// Mark the connection manager as tunnelled connection, providing 
       
  1181 				// the host to which the tunnel leads.
       
  1182 				THTTPHdrVal hostVal;
       
  1183 #ifdef _DEBUG
       
  1184 				TBool found = 
       
  1185 #endif
       
  1186 				trans.PropertySet().Property(stringPool.StringF(HTTP::ETunnel, iStringTable), hostVal);
       
  1187 
       
  1188 				__ASSERT_DEBUG( found, User::Invariant() );
       
  1189 				__ASSERT_DEBUG( hostVal.Type() == THTTPHdrVal::KStrFVal, User::Invariant() );
       
  1190 
       
  1191 				protTrans.ConnectionManager()->TunnelConnection(hostVal.StrF());
       
  1192 				}
       
  1193 			else
       
  1194 				{
       
  1195 				status = THTTPEvent::EFailed;
       
  1196 				
       
  1197 #if defined (_DEBUG) && defined (_LOGGING)
       
  1198 				THTTPHdrVal hostVal;
       
  1199 				TBool found = trans.PropertySet().Property(stringPool.StringF(HTTP::ETunnel, iStringTable), hostVal);
       
  1200 
       
  1201 				__ASSERT_DEBUG( found, User::Invariant() );
       
  1202 				__ASSERT_DEBUG( hostVal.Type() == THTTPHdrVal::KStrFVal, User::Invariant() );
       
  1203 
       
  1204 				const CHttpConnectionInfo& connectionInfo = protTrans.ConnectionManager()->ConnectionInfo();
       
  1205 
       
  1206 				__FLOG_2(
       
  1207 						_T8("!! Tunnel failed : %d %S"),
       
  1208 						trans.Response().StatusCode(), 
       
  1209 						&trans.Response().StatusText().DesC()
       
  1210 						);
       
  1211 				__FLOG_5(
       
  1212 						_T8("-> Tunnel to %S on connection to host %S, remote port %d (secure : %d, nonpersistent : %d)"),
       
  1213 						&hostVal.StrF().DesC(), 
       
  1214 						&connectionInfo.Host(), 
       
  1215 						connectionInfo.Port(), 
       
  1216 						connectionInfo.IsSecure(), 
       
  1217 						connectionInfo.IsNonPersistent()
       
  1218 						);
       
  1219 #endif
       
  1220 				}
       
  1221 			}
       
  1222 
       
  1223 		// Ensure that the connection manager is still not dealing with this 
       
  1224 		// request.
       
  1225 		MHttpRequest& request = static_cast<CHttpRequestComposer&>(protTrans.TxData());
       
  1226 		protTrans.ConnectionManager()->CheckRequestComplete(request);
       
  1227 
       
  1228 		// The transaction has no further use for the connection manager - it 
       
  1229 		// can now be removed.
       
  1230 		protTrans.RemoveConnectionManager();
       
  1231 			
       
  1232 		// The transaction is now complete - inform the base class.
       
  1233 		err = TransactionCompleted(trans, status);
       
  1234 		} break;
       
  1235 	default:
       
  1236 		// Unknown status - do nothing, unless an error
       
  1237 		if( aStatus < 0 )
       
  1238 			{
       
  1239 			__FLOG_1(_T8("!! Error : %d"), aStatus);
       
  1240 
       
  1241 			if( aStatus == KErrHttpPipeliningError )
       
  1242 				{
       
  1243 				__FLOG_2(_T8("-> Trans %d, Con %d : transaction was being pipelined"), trans.Id(), GetConnectionID(trans));
       
  1244 				__FLOG_2(_T8("-> Trans %d, Con %d : re-try without pipelining"), trans.Id(), GetConnectionID(trans));
       
  1245 
       
  1246 				// Specify that this transaction should not be pipelined when 
       
  1247 				// it is re-submitted.
       
  1248 				RStringPool stringPool = iSession.StringPool();
       
  1249 				RStringF pipeline = stringPool.StringF(HTTP::EHttpPipelining, iStringTable);
       
  1250 				RStringF disable = stringPool.StringF(HTTP::EDisablePipelining, iStringTable);
       
  1251 
       
  1252 				err = trans.PropertySet().SetProperty(pipeline, disable);
       
  1253 				if(err != KErrNone)
       
  1254 				    {
       
  1255 				    break;
       
  1256 				    }
       
  1257 				}
       
  1258 #if defined (_DEBUG) && defined (_LOGGING)
       
  1259 			else if( aStatus == KErrHttpNonPipeliningError )
       
  1260 				{
       
  1261 				__FLOG_2(_T8("-> Trans %d, Con %d : transaction was being pipelined"), trans.Id(), GetConnectionID(trans));
       
  1262 				__FLOG_2(_T8("-> Trans %d, Con %d : re-try with pipelining again"), trans.Id(), GetConnectionID(trans));
       
  1263 				}
       
  1264 			else
       
  1265 				{
       
  1266 				__FLOG_2(_T8("-> Trans %d, Con %d : transaction failed"), trans.Id(), GetConnectionID(trans));
       
  1267 				}
       
  1268 #endif
       
  1269 			// An error code has occured. As no further data will be exchanged
       
  1270 			// with the origin server. The connection manager can now be removed.
       
  1271 			protTrans.RemoveConnectionManager();
       
  1272 
       
  1273 			if( aStatus == KErrEof )
       
  1274 				{
       
  1275 				__FLOG_4(_T8("-> Trans %d, Con %d : reporting %d (KErrDisconnected) instead of %d"), trans.Id(), GetConnectionID(trans), KErrDisconnected, aStatus);				
       
  1276 
       
  1277 				// Convert these errors to KErrDisconnected
       
  1278 				aStatus = KErrDisconnected;
       
  1279 				}
       
  1280 
       
  1281 			// Propagate the error back to the client and mark this transaction
       
  1282 			// as completed.
       
  1283 			err = TransactionCompleted(trans, aStatus);
       
  1284 			}
       
  1285 		break;
       
  1286 		}
       
  1287 	return err;
       
  1288 	}
       
  1289 
       
  1290 void CHttpClientHandler::SetStatusL(CRxData& aRxData, TInt aStatus)
       
  1291     {
       
  1292     User::LeaveIfError(SetStatus(aRxData, aStatus));
       
  1293     }
       
  1294 
       
  1295 /*
       
  1296  *	Methods from MHttpBatchingPropertiesCallback
       
  1297  */
       
  1298 
       
  1299 TInt CHttpClientHandler::GetMaxBatchingBufferSize()
       
  1300 	{
       
  1301 	TInt batchingBuffer = 0;
       
  1302 	RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
       
  1303 	RStringPool stringPool = iSession.StringPool();
       
  1304 
       
  1305 	THTTPHdrVal doBatching;
       
  1306 	RStringF batchingSetting = stringPool.StringF(HTTP::EHttpBatching, iStringTable);
       
  1307 
       
  1308 	if (connInfo.Property(batchingSetting, doBatching))
       
  1309 		{
       
  1310 		TBool batchingSupported = EFalse;	// default behaviour is batching disabled
       
  1311 
       
  1312 		// First of all check if batching has been enabled
       
  1313 		batchingSupported = (doBatching.StrF().Index(iStringTable) == HTTP::EEnableBatching);
       
  1314 		if (batchingSupported)
       
  1315 			{
       
  1316 			THTTPHdrVal bufferSize;
       
  1317 			RStringF buffer = stringPool.StringF(HTTP::EBatchingBufferSize, iStringTable);
       
  1318 
       
  1319 			// If batching has been enabled, check for a client-specified buffer size to use
       
  1320 			if (connInfo.Property(buffer, bufferSize))
       
  1321 				{
       
  1322 				__ASSERT_DEBUG(bufferSize.Type() == THTTPHdrVal::KTIntVal, THttpClientPanic::Panic(THttpClientPanic::EInvalidBatchingSetting));
       
  1323 				batchingBuffer = bufferSize.Int();
       
  1324 				}
       
  1325 			// No client-specified buffer size therefore use the default value
       
  1326 			else
       
  1327 				batchingBuffer = KDefaultBatchingBufSize;
       
  1328 			}
       
  1329 		}
       
  1330 	return batchingBuffer;
       
  1331 	}
       
  1332 
       
  1333 
       
  1334 /*
       
  1335  *	Methods from MProtHandlerInterface
       
  1336  */
       
  1337 
       
  1338 const CCertificate*  CHttpClientHandler::SessionServerCert()
       
  1339 	{
       
  1340 	return NULL;
       
  1341 	}
       
  1342 	
       
  1343 const CCertificate* CHttpClientHandler::TransactionServerCert(RHTTPTransaction aTransaction)
       
  1344 	{
       
  1345 	const CProtTransaction* trans = FindProtocolTransaction(aTransaction);
       
  1346 	if(trans != NULL)
       
  1347 		{
       
  1348 		CHttpConnectionManager* manager = static_cast<const CHttpClientTransaction*>(trans)->ConnectionManager();
       
  1349 		if( manager )
       
  1350 			{
       
  1351 			return manager->ServerCert();
       
  1352 			}
       
  1353 		}
       
  1354 	return NULL;
       
  1355 	}
       
  1356 
       
  1357 
       
  1358 void CHttpClientHandler::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
       
  1359 	{
       
  1360 	// Handle the event
       
  1361 	switch (aEvent.iStatus)
       
  1362 		    {
       
  1363 	case THTTPEvent::EGetCipherSuite:
       
  1364 		    {
       
  1365 		    GetCipherSuiteL(aTransaction);
       
  1366 		    }
       
  1367 		    break;
       
  1368 	case THTTPEvent::ECancelWaitFor100Continue:
       
  1369 		{
       
  1370 		const CProtTransaction* pT = FindProtocolTransaction(aTransaction);
       
  1371 		if(pT != NULL)
       
  1372 			{
       
  1373 			static_cast<CHttpRequestComposer&>(pT->TxData()).CancelWaitFor100Continue();
       
  1374 			}
       
  1375 		}
       
  1376 		break;
       
  1377 	default:
       
  1378 		   CProtocolHandler::MHFRunL(aTransaction,aEvent);
       
  1379 		   }
       
  1380 	}
       
  1381 
       
  1382 void CHttpClientHandler::GetCipherSuiteL(RHTTPTransaction aTransaction)
       
  1383 	{
       
  1384 	RStringPool stringPool = iSession.StringPool();
       
  1385 	RHTTPTransactionPropertySet properties(aTransaction.PropertySet());
       
  1386 	const CProtTransaction* transaction = FindProtocolTransaction(aTransaction);
       
  1387 	
       
  1388 	if (transaction != NULL)
       
  1389 		{
       
  1390 		CHttpConnectionManager* connectionManager = static_cast<const CHttpClientTransaction*>(transaction)->ConnectionManager();
       
  1391 		if(connectionManager)
       
  1392 			{
       
  1393 			TBuf8<8> cipherSuite;
       
  1394 			TInt error = connectionManager->CipherSuite(cipherSuite);
       
  1395 			
       
  1396 			if (error == KErrNone)
       
  1397 				{
       
  1398 				RString cipherSuiteString = stringPool.OpenStringL(cipherSuite);
       
  1399 				THTTPHdrVal hdrValue(cipherSuiteString);
       
  1400 				CleanupClosePushL(cipherSuiteString);
       
  1401 				properties.SetPropertyL(stringPool.StringF(HTTP::ECipherSuiteValue, iStringTable), hdrValue);
       
  1402 				CleanupStack::PopAndDestroy(&cipherSuiteString);	
       
  1403 				return;
       
  1404 				}		
       
  1405 			}
       
  1406 		}
       
  1407 	// No cipher suite could be obtained so set the ECipherSuiteValue property to an empty string.
       
  1408 	properties.SetPropertyL(stringPool.StringF(HTTP::ECipherSuiteValue, iStringTable), THTTPHdrVal(RString()));
       
  1409 	}
       
  1410 
       
  1411 TInt CHttpClientHandler::MaxNumTransactionsToPipeline() const
       
  1412 	{
       
  1413 	/* This is called when the first transaction is submitted. This is so filters can set the
       
  1414 	   session setting HTTP::EMaxNumTransactionsToPipeline
       
  1415 	   However it is only required to be set when the first transaction is submitted. Therefore
       
  1416 	   check to see if the value is already cached.
       
  1417 	*/
       
  1418  	if (iMaxNumTransactionsToPipeline == 0)
       
  1419  		{
       
  1420  		iMaxNumTransactionsToPipeline = KDefaultMaxNumberTransactionsToPipeline;
       
  1421  		
       
  1422  		// Check session properties
       
  1423 		RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
       
  1424 		RStringPool stringPool = iSession.StringPool();
       
  1425 		THTTPHdrVal maxToPipeline;
       
  1426 		RStringF maxToPipelineString = stringPool.StringF(HTTP::EMaxNumTransactionsToPipeline, iStringTable);
       
  1427 		if(connInfo.Property(maxToPipelineString, maxToPipeline))
       
  1428 			{
       
  1429 			if(maxToPipeline.Type() == THTTPHdrVal::KTIntVal)
       
  1430 				{
       
  1431 				iMaxNumTransactionsToPipeline = maxToPipeline.Int();
       
  1432 				}
       
  1433 			}
       
  1434 		}
       
  1435  	
       
  1436  	return iMaxNumTransactionsToPipeline;
       
  1437 	}
       
  1438 
       
  1439 
       
  1440 void CHttpClientHandler::__RecordConnectionManagerCreationL()
       
  1441 	// In debug mode update a session property to record when each connection manager is created
       
  1442 	// This is used to validate the runtime behavior of pipelining use cases
       
  1443 	{
       
  1444 	#if defined (_DEBUG)
       
  1445 	_LIT8(KNumberConnectionManagers, "__NumConnectionManagers");
       
  1446 	
       
  1447 	RStringPool stringPool = iSession.StringPool();
       
  1448 	RStringF numberConnectionsString = stringPool.OpenFStringL(KNumberConnectionManagers);
       
  1449 	CleanupClosePushL(numberConnectionsString);
       
  1450 	RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
       
  1451 	TInt numberConnections =0;
       
  1452 	
       
  1453 	THTTPHdrVal numberConnectionsVal;
       
  1454 	if (connInfo.Property(numberConnectionsString, numberConnectionsVal))
       
  1455 		{
       
  1456 		numberConnections = numberConnectionsVal.Int();
       
  1457 		connInfo.RemoveProperty(numberConnectionsString);
       
  1458 		}
       
  1459 	
       
  1460 	numberConnections++;
       
  1461 	numberConnectionsVal.SetInt(numberConnections);
       
  1462 	connInfo.SetPropertyL(numberConnectionsString, numberConnectionsVal);
       
  1463 	
       
  1464 	CleanupStack::PopAndDestroy(&numberConnectionsString);
       
  1465 	#endif	
       
  1466 	}
       
  1467 	
       
  1468 #if defined (_DEBUG)
       
  1469 	TInt CHttpClientHandler::GetConnectionID( const CHttpConnectionManager* aConnectionManager )
       
  1470 	//in debug mode it returns the connection ID, if not in the list returns 0
       
  1471 	{
       
  1472 	TInt i = iConnectionManagers.Count();
       
  1473 	for( ;i > 0; --i )
       
  1474 		{
       
  1475 		if( iConnectionManagers[i-1] == aConnectionManager )
       
  1476 			{
       
  1477 			break;
       
  1478 			}
       
  1479 		}
       
  1480 	return 	i;	
       
  1481 	}
       
  1482 	
       
  1483 	TInt CHttpClientHandler::GetConnectionID( const RHTTPTransaction &aTrans )
       
  1484 	{
       
  1485 	CHttpConnectionManager* manager = NULL;
       
  1486 	const CProtTransaction* trans = FindProtocolTransaction(aTrans);
       
  1487 	if(trans != NULL)
       
  1488 		{
       
  1489 		manager = static_cast< const CHttpClientTransaction* >( trans )->ConnectionManager();
       
  1490 		}
       
  1491 		
       
  1492 	return GetConnectionID( manager );
       
  1493 	}
       
  1494 
       
  1495 
       
  1496 
       
  1497 
       
  1498 #endif
       
  1499 
       
  1500 void CHttpClientHandler::GetCertInfoL(const CX509Certificate& aSource, TCertInfo& aDest)
       
  1501 	{
       
  1502 	TInt len;
       
  1503 
       
  1504 	//Fetch Fingerprint
       
  1505 	len = Min(aSource.Fingerprint().Length(),aDest.iFingerprint.MaxLength());
       
  1506 	aDest.iFingerprint.Copy(aSource.Fingerprint().Ptr(),len);
       
  1507 
       
  1508 	//Fetch SerialNumber
       
  1509 	len = Min(aSource.SerialNumber().Length(),aDest.iSerialNo.MaxLength());
       
  1510 	aDest.iSerialNo.Copy(aSource.SerialNumber().Ptr(),len);
       
  1511 
       
  1512 	//Fetch PublicKey
       
  1513 	const CSubjectPublicKeyInfo& publicKeyInfo = aSource.PublicKey();
       
  1514 	len = Min(publicKeyInfo.KeyData().Length(),aDest.iPublicKey.MaxLength());
       
  1515 	aDest.iPublicKey.Copy(publicKeyInfo.KeyData().Ptr(),len);
       
  1516 
       
  1517 	//Fetch PublicKeyAlg
       
  1518 	aDest.iPkAlg= publicKeyInfo.AlgorithmId();
       
  1519 
       
  1520 	//Fetch VersionNo
       
  1521 	aDest.iVersionNo = aSource.Version();
       
  1522 
       
  1523 	//Fetch StartValDate
       
  1524 	const CValidityPeriod& validityPeriod = aSource.ValidityPeriod();
       
  1525 	aDest.iStartValDate = validityPeriod.Start();
       
  1526 
       
  1527 	//Fetch EndValDate
       
  1528 	aDest.iEndValDate = validityPeriod.Finish();
       
  1529 
       
  1530 	//Fetch SubjectDNInfo
       
  1531 	const CX500DistinguishedName& subjectName = aSource.SubjectName();
       
  1532 	GetDNInfo(subjectName,aDest.iSubjectDNInfo);
       
  1533 
       
  1534 	//Fetch IssuerDNInfo;
       
  1535 	const CX500DistinguishedName& issuerName = aSource.IssuerName();
       
  1536 	GetDNInfo(issuerName,aDest.iIssuerDNInfo);
       
  1537 
       
  1538 	// Fetch Alt Name
       
  1539 	aDest.iDNSName.Copy(KNullDesC);
       
  1540 
       
  1541 	//fetch digest alg
       
  1542 	aDest.iDigAlg = aSource.SigningAlgorithm().DigestAlgorithm().Algorithm();
       
  1543 	const CX509CertExtension* ext = aSource.Extension(KSubjectAltName); 
       
  1544 
       
  1545 	if( ext )
       
  1546 		{
       
  1547 		CX509AltNameExt* subjectAltName = CX509AltNameExt::NewLC(ext->Data());
       
  1548 		const CArrayPtrFlat<CX509GeneralName>& gNs = subjectAltName->AltName();
       
  1549 		const TInt count = gNs.Count(); 
       
  1550 
       
  1551 		for( TInt i = 0; i < count; ++i )
       
  1552 			{ 
       
  1553 			const CX509GeneralName* gN = gNs.At(i);
       
  1554 			
       
  1555 			if( gN->Tag() == EX509DNSName )
       
  1556 				{ 
       
  1557 				CX509DNSName* dNS = CX509DNSName::NewLC(gN->Data());
       
  1558 				const TPtrC dNSValue = dNS->Name();
       
  1559 				aDest.iDNSName.Copy(dNSValue);
       
  1560 				CleanupStack::PopAndDestroy(dNS);
       
  1561 				break;
       
  1562 				} 
       
  1563 			}
       
  1564 		CleanupStack::PopAndDestroy(subjectAltName);
       
  1565 		} 
       
  1566 
       
  1567 	}
       
  1568 
       
  1569 void CHttpClientHandler::GetDNInfo(const CX500DistinguishedName& aSource, TDNInfo& aDest)
       
  1570 	{
       
  1571 	const TInt count = aSource.Count();
       
  1572 	for( TInt i=0; i<count; ++i )
       
  1573 		{
       
  1574 		const CX520AttributeTypeAndValue& attribute = aSource.Element(i);
       
  1575 
       
  1576 		HBufC* valuePtr = NULL;
       
  1577 		TDes8* destination = NULL;
       
  1578 		TInt maxLength = 0 ;
       
  1579 		TBool found = ETrue;
       
  1580 
       
  1581 		const TDesC& type = attribute.Type();
       
  1582 		if( type.Compare(KX520CountryName) == 0 )
       
  1583 			{
       
  1584 			maxLength = aDest.iCountry.MaxLength();
       
  1585 			destination = &aDest.iCountry;
       
  1586 			}
       
  1587 		else if( type.Compare(KX520OrganizationalUnitName) == 0 )
       
  1588 			{
       
  1589 			maxLength = aDest.iOrganizationUnit.MaxLength();
       
  1590 			destination = &aDest.iOrganizationUnit;
       
  1591 			}
       
  1592 		else if( type.Compare(KX520OrganizationName) == 0 )
       
  1593 			{
       
  1594 			maxLength = aDest.iOrganization.MaxLength();
       
  1595 			destination = &aDest.iOrganization;
       
  1596 			}
       
  1597 		else if( type.Compare(KX520CommonName) == 0 )
       
  1598 			{
       
  1599 			maxLength = aDest.iCommonName.MaxLength();
       
  1600 			destination = &aDest.iCommonName;
       
  1601 			}
       
  1602 		else if( type.Compare(KX520LocalityName) == 0 )
       
  1603 			{
       
  1604 			maxLength = aDest.iLocality.MaxLength();
       
  1605 			destination = &aDest.iLocality;
       
  1606 			}
       
  1607 		else
       
  1608 			{
       
  1609 			found = EFalse;
       
  1610 			}
       
  1611 
       
  1612 		if( found )
       
  1613 			{
       
  1614 			TRAPD(ret, (valuePtr = attribute.ValueL()));
       
  1615 
       
  1616 			if( ret != KErrNone )
       
  1617 				{
       
  1618 				// Non fatal error - just zero the descriptor
       
  1619 				destination->Zero();
       
  1620 				}
       
  1621 			else
       
  1622 				{
       
  1623 				TInt len = Min(valuePtr->Length(), maxLength);
       
  1624 				TPtrC value = TPtrC(valuePtr->Des().Ptr(), len);
       
  1625 				destination->Copy(value);
       
  1626 				delete valuePtr;
       
  1627 				}
       
  1628 			}
       
  1629 		}
       
  1630 	}
       
  1631 
       
  1632 TInt CHttpClientHandler::GetRecvBufferSize()
       
  1633 	{
       
  1634 	
       
  1635 		iRecvBufferSize = KDefaultBufferSize;
       
  1636  		// Check session properties
       
  1637 		RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
       
  1638 		RStringPool stringPool = iSession.StringPool();
       
  1639 		THTTPHdrVal value;
       
  1640 		RStringF recvBufferSize = stringPool.StringF(HTTP::ERecvBufferSize, iStringTable);
       
  1641 		if(connInfo.Property(recvBufferSize, value))
       
  1642 			{
       
  1643 			if(value.Type() == THTTPHdrVal::KTIntVal && value.Int() > 0)
       
  1644 				{
       
  1645 				iRecvBufferSize = value.Int();
       
  1646 				}
       
  1647 			}
       
  1648 	
       
  1649  	return iRecvBufferSize;
       
  1650 	}
       
  1651 
       
  1652 void CHttpClientHandler::EnsureStrictConnectMethodHeaders(RHTTPTransaction aTransaction)
       
  1653     {
       
  1654     // Check only for CONNECT method request
       
  1655     // Strict & mandatory headers as needed by CONNECT request are
       
  1656     // User-Agent, x-wap-profile, EProxyAuthorization
       
  1657     
       
  1658     RHTTPRequest request = aTransaction.Request();
       
  1659     RHTTPSession session = aTransaction.Session();
       
  1660     RStringPool sp = session.StringPool();
       
  1661     if(aTransaction.Request().Method().Index(iStringTable) == HTTP::ECONNECT)
       
  1662         {
       
  1663         RStringF strictConnectHeaders = sp.StringF(HTTP::EStrictConnectHeaders, iStringTable);
       
  1664         RHTTPPropertySet sessionProperties = session.ConnectionInfo();
       
  1665         THTTPHdrVal hdrVal;
       
  1666         if(sessionProperties.Property(strictConnectHeaders, hdrVal) && 
       
  1667                 (hdrVal.Type() == THTTPHdrVal::KStrFVal) && 
       
  1668                 (hdrVal.StrF().Index(iStringTable) == HTTP::EEnableStrictConnectHeaders))
       
  1669             {
       
  1670             RStringF profileHeader = sp.OpenFStringL(KUAProfile);
       
  1671             CleanupClosePushL(profileHeader);
       
  1672 
       
  1673             
       
  1674             RHTTPHeaders hdr = request.GetHeaderCollection();
       
  1675             THTTPHdrFieldIter it = hdr.Fields();
       
  1676             while(!it.AtEnd())
       
  1677                 {
       
  1678                 RStringTokenF hdrStr = it();
       
  1679                 RStringF hdrNameStr = sp.StringF(hdrStr);
       
  1680                 TInt hdrIndex = hdrNameStr.Index(iStringTable);
       
  1681                 // Check if it is a UA/User-Agent/Proxy-Auhorization Profile header
       
  1682                 if((hdrNameStr == profileHeader) || (hdrIndex == HTTP::EUserAgent) || (hdrIndex == HTTP::EProxyAuthorization))
       
  1683                     {
       
  1684                     ++it; // Keep going
       
  1685                     }
       
  1686                 else
       
  1687                     {
       
  1688                     // Anything else remove the header and reset the iterator
       
  1689                     hdr.RemoveField(hdrNameStr);
       
  1690                     it.First(); // Not so efficient. 
       
  1691                     }
       
  1692                 }
       
  1693             CleanupStack::PopAndDestroy(&profileHeader);            
       
  1694             }        
       
  1695         }
       
  1696     }
       
  1697