applayerpluginsandutils/httpprotocolplugins/httpclient/chttprequestcomposer.cpp
changeset 0 b16258d2340f
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 "chttprequestcomposer.h"
       
    17 
       
    18 #include <httpstringconstants.h>
       
    19 #include <http/rhttpheaders.h>
       
    20 
       
    21 #include "chttpresponseparser.h"
       
    22 #include "mhttprequestobserver.h"
       
    23 #include "chttpclienttransaction.h"
       
    24 
       
    25 
       
    26 CHttpRequestComposer* CHttpRequestComposer::NewL(CProtTransaction& aProtTrans, MHttpRequestObserver& aObserver)
       
    27 	{
       
    28 	CHttpRequestComposer* self = new (ELeave) CHttpRequestComposer(aProtTrans, aObserver);
       
    29 	CleanupStack::PushL(self);
       
    30 	self->ConstructL();
       
    31 	CleanupStack::Pop(self);
       
    32 	return self;
       
    33 	}
       
    34 
       
    35 CHttpRequestComposer::~CHttpRequestComposer()
       
    36 	{
       
    37     if(iCorkingEnabled)
       
    38         {
       
    39         // Disable corking.
       
    40         iObserver.SendingBodyData(EFalse);
       
    41         }   
       
    42     
       
    43 	iMessageComposer.Close();
       
    44 	iTrailerHeaders.Reset();
       
    45 	
       
    46 //	__FLOG_CLOSE;
       
    47 	}
       
    48 	
       
    49 CHttpRequestComposer::CHttpRequestComposer(CProtTransaction& aProtTrans, MHttpRequestObserver& aObserver)
       
    50 : CTxData(aProtTrans), iStringTable(RHTTPSession::GetTable()), 
       
    51                         iObserver(aObserver),
       
    52 					   iStringPool(aProtTrans.Transaction().Session().StringPool()),
       
    53 					   iRequest(aProtTrans.Transaction().Request()),
       
    54 					   iFields(aProtTrans.Transaction().Request().GetHeaderCollection().Fields()),
       
    55 					   iPropertySet(aProtTrans.Transaction().PropertySet())
       
    56 
       
    57 	{
       
    58 //	__FLOG_OPEN("http", "httpclienthandler.txt");
       
    59 	}
       
    60 	
       
    61 void CHttpRequestComposer::ConstructL()
       
    62 	{
       
    63 	iMessageComposer.OpenL(*this);
       
    64 	}
       
    65 	
       
    66 void CHttpRequestComposer::NotifyMoreRequestBodyData()
       
    67 	{
       
    68 	__FLOG_1(_T8("Trans %d : notify more request body data"), iProtTrans->Transaction().Id());
       
    69 
       
    70 	iMessageComposer.MessageInfoAvailable();
       
    71 	}
       
    72 
       
    73 void CHttpRequestComposer::InitHeadersL()
       
    74 	{
       
    75 	// Extract header fields from the Trailer header, if it exists.
       
    76 	THTTPHdrVal trailerHeaderVal;
       
    77 	RHTTPHeaders headers = iRequest.GetHeaderCollection();
       
    78 	RStringF trailerName = iStringPool.StringF(HTTP::ETrailer, iStringTable);
       
    79 	TInt index =0;
       
    80 	while( headers.GetField(
       
    81 						   trailerName,
       
    82 						   index,
       
    83 						   trailerHeaderVal
       
    84 						   ) != KErrNotFound )
       
    85 		{
       
    86 		__ASSERT_DEBUG( trailerHeaderVal.Type() == THTTPHdrVal::KStrFVal, User::Invariant() );
       
    87 
       
    88 		// @todo should we check to see if header is not Content-Length,
       
    89 		// @todo Transfer-Encoding or Trailer?
       
    90 
       
    91 		// Got a trailer header - append to the list
       
    92 		RStringF header = trailerHeaderVal.StrF();
       
    93 		User::LeaveIfError(iTrailerHeaders.Append(header));
       
    94 
       
    95 		// Next...
       
    96 		++index;
       
    97 		}
       
    98 
       
    99 	if( iTrailerHeaders.Count() > 0 )
       
   100 		{
       
   101 		// There are trailer headers - can only send as trailers if the request
       
   102 		// has a body and it is going to be chunk encoded.
       
   103 		MHTTPDataSupplier* body = iRequest.Body();
       
   104 
       
   105 		if( body == NULL || body->OverallDataSize() != KErrNotFound )
       
   106 			{
       
   107 			// Either there is no body, or the body is not going to be chunk
       
   108 			// encoded - remove the Trailer header field.
       
   109 			headers.RemoveField(trailerName);
       
   110 			iTrailerHeaders.Reset();
       
   111 			}
       
   112 		}
       
   113 
       
   114 	// Reset the fields iterator
       
   115 	iFields.First();	
       
   116 	}
       
   117 
       
   118 TBool CHttpRequestComposer::IsTrailerHeader(RStringF aHeader)
       
   119 	{
       
   120 	TInt count = iTrailerHeaders.Count();
       
   121 	TBool found = EFalse;	
       
   122 	while( count > 0 && !found )
       
   123 		{
       
   124 		if( iTrailerHeaders[--count] == aHeader )
       
   125 			{
       
   126 			// aHeader is a trailer header
       
   127 			found = ETrue;
       
   128 			}
       
   129 		}
       
   130 	return found;
       
   131 	}
       
   132 	
       
   133 /*
       
   134  *	Methods from MHTTPDataSupplier, via CTxData
       
   135  */
       
   136 
       
   137 TBool CHttpRequestComposer::GetNextDataPart(TPtrC8& /*aDataPart*/)
       
   138 	{
       
   139 	// @todo should we deprecate derivation from MHTTPDataSupplier?
       
   140 	User::Invariant();
       
   141 	return EFalse;
       
   142 	}
       
   143 
       
   144 void CHttpRequestComposer::ReleaseData()
       
   145 	{
       
   146 	// @todo should we deprecate derivation from MHTTPDataSupplier?
       
   147 	User::Invariant();
       
   148 	}
       
   149 
       
   150 TInt CHttpRequestComposer::OverallDataSize()
       
   151 	{
       
   152 	// @todo should we deprecate derivation from MHTTPDataSupplier?
       
   153 	User::Invariant();
       
   154 	return KErrNotFound;
       
   155 	}
       
   156 
       
   157 TInt CHttpRequestComposer::Reset()
       
   158 	{
       
   159 	// @todo should we deprecate derivation from MHTTPDataSupplier?
       
   160 	User::Invariant();
       
   161 	return KErrNotFound;
       
   162 	}
       
   163 	
       
   164 /*
       
   165  *	Methods from MHttpRequest
       
   166  */
       
   167 	
       
   168 void CHttpRequestComposer::StartRequest()
       
   169 	{
       
   170 	__FLOG_1(_T8("Trans %d : starting request"), iProtTrans->Transaction().Id());
       
   171 	
       
   172 	RStringF notifyContinue = iStringPool.StringF(HTTP::ENotify100Continue, iStringTable);
       
   173 	RStringF enableNotification = iStringPool.StringF(HTTP::EEnableNotification, iStringTable);
       
   174 	THTTPHdrVal notifyContinueVal;
       
   175 	iPropertySet.Property(notifyContinue, notifyContinueVal);
       
   176 	
       
   177 	((notifyContinueVal.Type()==THTTPHdrVal::KStrFVal) && (notifyContinueVal.StrF() == enableNotification))?(iSuspendRequest = ETrue):(iSuspendRequest = EFalse);
       
   178 
       
   179 	iMessageComposer.MessageInfoAvailable();
       
   180 	}
       
   181 
       
   182 void CHttpRequestComposer::CancelRequest()
       
   183 	{
       
   184 	__FLOG_1(_T8("-> Trans %d : request cancelled"), iProtTrans->Transaction().Id());
       
   185 
       
   186 	iMessageComposer.Reset();
       
   187 	}
       
   188 	
       
   189 void CHttpRequestComposer::RequestDataSent()
       
   190 	{	
       
   191 	if(!IsSuspendedRequest())
       
   192 		{
       
   193 		iMessageComposer.ReleaseMessageData();
       
   194 		}
       
   195 	}
       
   196 
       
   197 void CHttpRequestComposer::OnRequestSendTimeOut()
       
   198 	{
       
   199 	// Notify the client of Request Send TimeOut.
       
   200 	RHTTPTransaction trans = iProtTrans->Transaction();
       
   201 	if(trans.SendEvent(THTTPEvent::ESendTimeOut, THTTPEvent::EIncoming, THTTPFilterHandle(THTTPFilterHandle::EProtocolHandler)) != KErrNone)
       
   202 		{
       
   203 		trans.Fail(THTTPFilterHandle::EProtocolHandler);
       
   204 		}
       
   205 	else
       
   206 		{
       
   207         // Notify the client that Transaction Failed.
       
   208 		if(trans.SendEvent(THTTPEvent::EFailed, THTTPEvent::EIncoming, THTTPFilterHandle(THTTPFilterHandle::EProtocolHandler)) != KErrNone)
       
   209              {
       
   210              trans.Fail(THTTPFilterHandle::EProtocolHandler);             
       
   211              }
       
   212 		}
       
   213 	}
       
   214 
       
   215 TInt CHttpRequestComposer::SendTimeOutValue()
       
   216 	{
       
   217 	RHTTPTransaction trans = iProtTrans->Transaction();
       
   218 	RStringPool stringPool = trans.Session().StringPool();
       
   219 	RStringF sendTimeOut = stringPool.StringF(HTTP::ESendTimeOutValue, iStringTable);
       
   220 	THTTPHdrVal sendTimeOutVal;
       
   221 	
       
   222 	TBool ret = trans.PropertySet().Property(sendTimeOut,sendTimeOutVal); 
       
   223 	if(ret && (sendTimeOutVal.Type() == THTTPHdrVal::KTIntVal))
       
   224 		{
       
   225 		return sendTimeOutVal.Int();
       
   226 		}
       
   227 	return 0;
       
   228 	}
       
   229 
       
   230 /*
       
   231  *	Methods from MHttpMessageComposerObserver
       
   232  */
       
   233 
       
   234 void CHttpRequestComposer::StartLineL(TPtrC8& aMethod, TPtrC8& aRequestUri, TPtrC8& aVersion)
       
   235 	{
       
   236 	// The RFC2616 defines the Request-Line as follows - 
       
   237 	// 
       
   238 	// Request-Line = Method SP Request-URI SP HTTPVersion CRLF
       
   239 	//
       
   240 	// Get Method...
       
   241 	RStringF method = iStringPool.StringF(iRequest.Method());
       
   242 	aMethod.Set(method.DesC());
       
   243 	
       
   244 	RHTTPTransaction trans = iProtTrans->Transaction();
       
   245 	
       
   246 	// Get the Request-URI...
       
   247 	THTTPHdrVal uri;
       
   248 	if( !trans.PropertySet().Property(iStringPool.StringF(HTTP::EUri, iStringTable), uri) )
       
   249 		{
       
   250 		// The EUri property has not been set - leave!
       
   251 		User::Leave(KErrCorrupt);
       
   252 		}
       
   253 	aRequestUri.Set(uri.Str().DesC());
       
   254 	
       
   255 	// Get HTTPVersion - check to see if client has set a version
       
   256 	RHTTPConnectionInfo connectionInfo = trans.Session().ConnectionInfo();
       
   257 	THTTPHdrVal httpVersion;
       
   258 	if( connectionInfo.Property(iStringPool.StringF(HTTP::EHTTPVersion, iStringTable), httpVersion) )
       
   259 		{
       
   260 		// Use the client specified version
       
   261 		aVersion.Set(httpVersion.StrF().DesC());		
       
   262 		}
       
   263 	else
       
   264 		{
       
   265 		// Assume HTTP/1.1
       
   266 		aVersion.Set(iStringPool.StringF(HTTP::EHttp11, iStringTable).DesC());
       
   267 		}
       
   268 	
       
   269 	__FLOG_4(_T8("Trans %d : request-line -> %S %S %S"), iProtTrans->Transaction().Id(), &aMethod, &aRequestUri, &aVersion);
       
   270 	
       
   271 	// Initialise header info
       
   272 	InitHeadersL();
       
   273 	}
       
   274 
       
   275 TInt CHttpRequestComposer::NextHeaderL(TPtrC8& aHeaderName, TPtrC8& aHeaderValue)
       
   276 	{
       
   277 	// Are there any more headers?
       
   278 	TInt err = KErrNotFound;
       
   279 	TBool done = EFalse;
       
   280 	while( !iFields.AtEnd() && !done )
       
   281 		{
       
   282 		// Get field current field.
       
   283 		RStringF name = iStringPool.StringF(iFields());
       
   284 
       
   285 		// Check to see if a trailer header
       
   286 		if( !IsTrailerHeader(name) )
       
   287 			{
       
   288 			// Ok, found a header - done!
       
   289 			err = KErrNone;
       
   290 			done = ETrue;
       
   291 				
       
   292 			// Get the OTA version of the field value
       
   293 			TPtrC8 value;
       
   294 			iRequest.GetHeaderCollection().GetRawFieldL(name, value);
       
   295 			
       
   296 			// Pass back these values
       
   297 			aHeaderName.Set(name.DesC());
       
   298 			aHeaderValue.Set(value);
       
   299 
       
   300 			__FLOG_3(_T8("Trans %d : request header -> %S: %S"), iProtTrans->Transaction().Id(), &aHeaderName, &aHeaderValue);
       
   301 			}
       
   302 		
       
   303 		// Move onto next header field...
       
   304 		++iFields;		
       
   305 		}
       
   306 	return err;
       
   307 	}
       
   308 
       
   309 MHTTPDataSupplier* CHttpRequestComposer::HasBodyL()
       
   310 	{
       
   311 #if defined (_DEBUG) && defined (_LOGGING)
       
   312 	MHTTPDataSupplier* body = iRequest.Body();
       
   313 
       
   314 	if( body == NULL )
       
   315 		{
       
   316 		__FLOG_1(_T8("Trans %d : no request entity body"), iProtTrans->Transaction().Id());
       
   317 		}
       
   318 	else if( body->OverallDataSize() == KErrNotFound )
       
   319 		{
       
   320 		__FLOG_1(_T8("Trans %d : chunked request entity body"), iProtTrans->Transaction().Id());
       
   321 		}
       
   322 	else
       
   323 		{
       
   324 		__FLOG_2(_T8("Trans %d : request entity body length = %d"), iProtTrans->Transaction().Id(), body->OverallDataSize());
       
   325 		}
       
   326 #endif
       
   327 
       
   328 	return iRequest.Body();
       
   329 	}
       
   330 	
       
   331 TInt CHttpRequestComposer::NextTrailerL(TPtrC8& aHeaderName, TPtrC8& aHeaderValue)
       
   332 	{
       
   333 	TInt err = KErrNotFound;
       
   334 
       
   335 	if( iTrailerHeaders.Count() > 0 )
       
   336 		{
       
   337 		// Ok, still got trailers.
       
   338 		err = KErrNone;
       
   339 
       
   340 		// Get trailer field.
       
   341 		RStringF name = iTrailerHeaders[0];
       
   342 
       
   343 		// Get the OTA version of the field value
       
   344 		TPtrC8 value;
       
   345 		iRequest.GetHeaderCollection().GetRawFieldL(name, value);
       
   346 		
       
   347 		// Pass back these values
       
   348 		aHeaderName.Set(name.DesC());
       
   349 		aHeaderValue.Set(value);
       
   350 		
       
   351 		// Remove this trailer from the array.
       
   352 		iTrailerHeaders.Remove(0);
       
   353 
       
   354 		__FLOG_3(_T8("Trans %d : request trailer -> %S: %S"), iProtTrans->Transaction().Id(), &aHeaderName, &aHeaderValue);
       
   355 		}
       
   356 	return err;
       
   357 	}
       
   358 
       
   359 void CHttpRequestComposer::MessageComplete()
       
   360 	{
       
   361 	__FLOG_1(_T8("Trans %d : request complete"), iProtTrans->Transaction().Id());
       
   362 	if(iCorkingEnabled)
       
   363 	    {
       
   364 	    // Disable corking.
       
   365 	    iCorkingEnabled = iRequestHeaderSent = EFalse;
       
   366 	    iObserver.SendingBodyData(EFalse);
       
   367 	    }	
       
   368 		
       
   369 	iObserver.RequestComplete();
       
   370 	iRequestSent = ETrue;
       
   371 	}
       
   372 
       
   373 void CHttpRequestComposer::MessageDataReadyL()
       
   374 	{
       
   375     if(iRequestHeaderSent)
       
   376         {
       
   377         // If we hit this function that means we need to send body data.
       
   378         // So we are sending the body data. Enable corking.
       
   379         if(!iCorkingEnabled)
       
   380             {
       
   381             __FLOG_1(_T8("Trans %d : Corking is enabled"), iProtTrans->Transaction().Id());            
       
   382             iCorkingEnabled = ETrue;
       
   383             iObserver.SendingBodyData(ETrue);
       
   384             }       
       
   385         else
       
   386             {
       
   387             __FLOG_1(_T8("Trans %d : Corking is already enabled"), iProtTrans->Transaction().Id());
       
   388             }
       
   389         }
       
   390     else
       
   391         {
       
   392         __FLOG_1(_T8("Trans %d : request header is set"), iProtTrans->Transaction().Id());        
       
   393         iRequestHeaderSent = ETrue;
       
   394         }		
       
   395     // Notify the observer that there is message data ready to send.
       
   396 	iMessageComposer.GetMessageData(iData);
       
   397 	
       
   398 	iObserver.SendRequestDataL(iData);
       
   399 	}
       
   400 
       
   401 TInt CHttpRequestComposer::HandleComposeError(TInt aError)
       
   402 	{
       
   403 	__FLOG_1(_T8("!! Error : %d"), aError);
       
   404 	__FLOG_1(_T8("-> Trans %d : request composing error - cancelling transaction"), iProtTrans->Transaction().Id());
       
   405 
       
   406 	return static_cast<CHttpResponseParser&>(iProtTrans->RxData()).CancelTransaction(aError);
       
   407 	}
       
   408 	
       
   409 TBool CHttpRequestComposer::CheckRequestPendingComplete()
       
   410 	{
       
   411 	return iMessageComposer.CheckMessagePendingComplete();
       
   412 	}
       
   413 TBool CHttpRequestComposer::RequestSent () const
       
   414 	{
       
   415 	return iRequestSent;		
       
   416 	}
       
   417 
       
   418 TBool CHttpRequestComposer::NeedDisconnectNotification ()
       
   419 	{
       
   420 	CHttpClientTransaction* clientTrans = static_cast < CHttpClientTransaction* > ( iProtTrans );
       
   421     return clientTrans->NeedDisconnectNotification ();
       
   422 	}
       
   423 
       
   424 void CHttpRequestComposer::Reserved_MHttpMessageComposerObserver()
       
   425 	{
       
   426 	User::Invariant();
       
   427 	}
       
   428 
       
   429 void CHttpRequestComposer::ResumeSuspendedRequest()
       
   430 	{
       
   431 	iSuspendRequest = EFalse;
       
   432 	iMessageComposer.ReleaseMessageData();	
       
   433 	}
       
   434 
       
   435 TBool CHttpRequestComposer::IsSuspendedRequest() const
       
   436 	{
       
   437 	return iSuspendRequest;	
       
   438 	}
       
   439 
       
   440 void CHttpRequestComposer::CancelWaitFor100Continue()
       
   441 	{
       
   442 	__FLOG_1(_T8("Trans %d : client declined to wait for the 100-Continue Response"), iProtTrans->Transaction().Id());
       
   443 	if(IsSuspendedRequest())
       
   444 		{
       
   445 		ResumeSuspendedRequest();	
       
   446 		}
       
   447 	}
       
   448 	
       
   449 MHttpDataOptimiser* CHttpRequestComposer::HttpDataOptimiser(TBool& aBatchingEnabled)
       
   450 	{
       
   451 	RHTTPTransaction trans = iProtTrans->Transaction();
       
   452  	MHttpDataOptimiser* httpOptimiser = trans.HttpDataOptimiser();
       
   453  	RHTTPSession sess = trans.Session();
       
   454  	
       
   455  	RStringPool stringPool = sess.StringPool();
       
   456 	THTTPHdrVal value;
       
   457 	RStringF string = stringPool.StringF(HTTP::EHttpBatching, iStringTable);
       
   458 	RStringF str = stringPool.StringF(HTTP::EEnableBatching, iStringTable);
       
   459 	if(sess.ConnectionInfo().Property(string, value))
       
   460 		{
       
   461 		if(value.Type() == THTTPHdrVal::KStrFVal)
       
   462 			{
       
   463 			aBatchingEnabled = value.StrF() == str;
       
   464 			}
       
   465 		}
       
   466 	 	
       
   467  	if( httpOptimiser && !aBatchingEnabled )
       
   468  		{
       
   469 		// the optimiser has not been set for the session.
       
   470  		__FLOG_1(_T8("-> Trans %d : Http optimiser has been set for this transaction"), iProtTrans->Transaction().Id());
       
   471  		return (httpOptimiser);
       
   472  		}
       
   473  	
       
   474  	// the MHttpDataOptimiser hasn't been set for the transaction
       
   475  	// check whether the session encapsulating the transaction is having MHttpDataOptimiser.
       
   476  	httpOptimiser  = sess.HttpDataOptimiser();
       
   477  	if( httpOptimiser )
       
   478  		{
       
   479  		// the optimiser has been set for the session.
       
   480  		__FLOG_1(_T8("-> Trans %d : HTTP optimiser has been set for the session encapsulating this transaction"), iProtTrans->Transaction().Id());
       
   481  		// check if the client has disabled optimiser for a particular transaction.
       
   482  		TBool disableTransOptimiser = EFalse;
       
   483  		string = stringPool.StringF(HTTP::EHTTPTransOptimiser, iStringTable);
       
   484  		str = stringPool.StringF(HTTP::EDisableHTTPTransOptimiser, iStringTable);
       
   485  		if(iProtTrans->Transaction().PropertySet().Property(string, value))
       
   486  			{
       
   487  			if(value.Type() == THTTPHdrVal::KStrFVal)
       
   488  				{
       
   489  				disableTransOptimiser = ( value.StrF() == str );
       
   490  				}
       
   491  			}
       
   492  		
       
   493  		if ( disableTransOptimiser )
       
   494  			{
       
   495  			// the client has disabled the optimiser for a particular transaction.
       
   496  			__FLOG_1(_T8("-> Trans %d : HTTP optimiser has been disabled by the client"), iProtTrans->Transaction().Id());
       
   497  			// do not return the optimiser.
       
   498  			return NULL;
       
   499  			}
       
   500  		
       
   501  		// the client has not diasabled the optimiser for any transaction in particular.
       
   502  		// return the optimiser.
       
   503  		return (httpOptimiser);
       
   504  		}
       
   505  	
       
   506  	// MHttpDataOptimiser has not been set for the session and transaction
       
   507  	__FLOG_1(_T8("-> Trans %d : HTTP optimiser was never set for the transaction and the session enclosing it"), iProtTrans->Transaction().Id());
       
   508  	return NULL;	
       
   509 	}
       
   510