applayerprotocols/httptransportfw/httpmessage/chttpmessagecomposer.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 "chttpmessagecomposer.h"
       
    17 
       
    18 #include <http/mhttpdatasupplier.h>
       
    19 #include <inetprottextutils.h>
       
    20 
       
    21 #include "mhttpmessagecomposerobserver.h"
       
    22 #include "thttpmessagepanic.h"
       
    23 
       
    24 const TInt KDefaultBufferSize	= 128;
       
    25 
       
    26 // 'this' used in base member initializer list, The 'this' pointer being used is a base class pointer.
       
    27 #pragma warning( disable : 4355 )
       
    28 
       
    29 CHttpMessageComposer* CHttpMessageComposer::NewL(MHttpMessageComposerObserver& aObserver)
       
    30 /**
       
    31 	Factory constructor. 
       
    32 	@param		aObserver	The observer for the composer.
       
    33 	@return		A pointer to a fully constructed and initialised object.
       
    34 */
       
    35 	{
       
    36 	return new (ELeave) CHttpMessageComposer(aObserver);
       
    37 	}
       
    38 
       
    39 CHttpMessageComposer::~CHttpMessageComposer()
       
    40 /**
       
    41 	Destructor
       
    42 */
       
    43 	{
       
    44 	Cancel();
       
    45 
       
    46 	delete iDataBuffer;
       
    47 	}
       
    48 
       
    49 CHttpMessageComposer::CHttpMessageComposer(MHttpMessageComposerObserver& aObserver)
       
    50 : CActive(CActive::EPriorityStandard + 1), iObserver(aObserver), iDataComposer(*this)
       
    51 /**
       
    52 	Constructor.
       
    53 	We want the request/response to be sent/received and processed as early as possible to avoid the latency by keeping 
       
    54 	it in the framework. We reduced the scheduling of AOs by 1/6th + 2 when composing and 1/5th + 2 for parsing the header. The value 2 
       
    55 	indicates the EIdle state and the startline composing/parsing.
       
    56 */
       
    57 	{
       
    58 	CActiveScheduler::Add(this);
       
    59 	}
       
    60 
       
    61 void CHttpMessageComposer::MessageInfoAvailable()
       
    62 /**
       
    63 	Notifies the composer that more message info is available. The composer can
       
    64 	continue composing the message.
       
    65 	@pre		The composer is waiting for more message info.
       
    66 	@post		The composer continues composing the message.
       
    67 	@panic		EHttpMessagePanicBadDataState	The composer was not waiting for
       
    68 												more info.
       
    69 */
       
    70 	{
       
    71 	__ASSERT_DEBUG( iDataState == EWaitingForInfo, THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataState) ); 
       
    72 
       
    73 	// Message info available - update data state and continue/start composing.
       
    74 	iDataState = EGotInfo;
       
    75 	CompleteSelf();
       
    76 	}
       
    77 
       
    78 void CHttpMessageComposer::GetMessageData(TPtrC8& aData)
       
    79 /**
       
    80 	Get the current message data.
       
    81 	@panic		EHttpMessagePanicBadDataState	There is no current data buffer 
       
    82 												ready.
       
    83 	@pre		The observer has been notified of available message data.
       
    84 */
       
    85 	{
       
    86 	__ASSERT_DEBUG( iDataState == EWaitingForRelease, THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataState) ); 
       
    87 
       
    88 	aData.Set(iSendBuffer);
       
    89 	}
       
    90 
       
    91 void CHttpMessageComposer::ReleaseMessageData()
       
    92 /**
       
    93 	Release the message data. The observer has finished with the current message 
       
    94 	data buffer. The composer can continue composing the message.
       
    95 	@panic		EHttpMessagePanicBadDataState	There is no current data buffer 
       
    96 												ready.
       
    97 	@pre		The observer has been notified of available message data.
       
    98 	@post		The composer continues composing the message.
       
    99 */
       
   100 	{
       
   101 	__ASSERT_DEBUG( iDataState == EWaitingForRelease, THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataState) );
       
   102 
       
   103 	// Is there an entity body?
       
   104 	if (CheckMessagePendingComplete())
       
   105 		{
       
   106 		iObserver.MessageComplete();
       
   107 
       
   108 		//The composer is done.
       
   109 		iState = EIdle;
       
   110 		}
       
   111 	else
       
   112 		{
       
   113 		// Update data state and continue composing.
       
   114 		iDataState = EGotInfo;
       
   115 		CompleteSelf();
       
   116 		}
       
   117 	}
       
   118 
       
   119 void CHttpMessageComposer::Reset()
       
   120 /**
       
   121 	Composer reset request. As the observer can reset the composer during one of
       
   122 	the callback functions, the composer must check for re-entrancy to avoid 
       
   123 	releasing resources that are still required. If the composer is either 
       
   124 	waiting for more message info, waiting for its data part to be released or 
       
   125 	is waiting to process its state machine, the composer can safely reset 
       
   126 	immediately. Otherwise the composer is being reset from within its RunL() 
       
   127 	and so it must defer resetting itself until a safer point - this is the 
       
   128 	point in the RunL() where the next step is decided.
       
   129 	@panic		EHttpMessagePanicDoubleReset	The composer has been reset twice
       
   130 												in one of the callback functions.
       
   131 */
       
   132 	{
       
   133 	// Check the data state of the composer - the composer cannot be reset if 
       
   134 	// the Reset() was called in one of the observer callbacks. It is safe to 
       
   135 	// reset now if - 
       
   136 	// 1) the data state is WaitingForInfo
       
   137 	// 2) the data state is WaitingForRelease
       
   138 	// 3) the composer is active - waiting to for its RunL() to be called.
       
   139 	if( iDataState == EWaitingForInfo || iDataState == EWaitingForRelease || IsActive() )
       
   140 		{
       
   141 		// Cancel and do the reset.
       
   142 		Cancel();
       
   143 		DoReset();
       
   144 		}
       
   145 	else
       
   146 		{
       
   147 		// Debug check for a double Reset() call...
       
   148 		__ASSERT_DEBUG( iDataState != EReset, THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicDoubleReset) );
       
   149 
       
   150 		// The Reset() was called inside a callback - defer reseting the composer
       
   151 		// until call stack is back in the composer RunL().
       
   152 		iDataState = EReset;
       
   153 		}
       
   154 	}
       
   155 
       
   156 void CHttpMessageComposer::CompleteSelf()
       
   157 /**
       
   158 	Self-complete function. Ensures that the state machine is processed.
       
   159 */
       
   160 	{
       
   161 	TRequestStatus* pStat = &iStatus;
       
   162 	User::RequestComplete(pStat, KErrNone);
       
   163 	SetActive();
       
   164 	}
       
   165 
       
   166 void CHttpMessageComposer::DoReset()
       
   167 /**
       
   168 	Resets the composer. The composer moves into the Idle state. Allocated 
       
   169 	resources are also reset. 
       
   170 */
       
   171 	{
       
   172 	// Reset the composer - composer state should be Idle and the data state 
       
   173 	// should be WaitingForInfo.
       
   174 	iState = EIdle;
       
   175 	iDataState = EWaitingForInfo;
       
   176 	iLastChunk = EFalse;
       
   177 
       
   178 	// Reset the data composer
       
   179 	iDataComposer.Reset();
       
   180 	}
       
   181 
       
   182 CHttpMessageComposer::TComposingStatus CHttpMessageComposer::ComposeStartLineL()
       
   183 /**
       
   184 	Composes the message start-line. The start-line can be either a Request-Line
       
   185 	or a Status-Line. Both have three tokens.
       
   186 
       
   187 		generic-message	=	start-line
       
   188 							*(message-header CRLF)
       
   189 							CRLF
       
   190 							[ message-body ]
       
   191 		
       
   192 		start-line		=	Request-Line | Status-Line
       
   193 
       
   194 		Request-Line	=	Method SP Request-URI SP HTTP-Version CRLF
       
   195 
       
   196 		Status-Line		=	HTTP-Version SP Status-Code SP Reason-Phrase CRLF
       
   197 
       
   198 	The observer supplies these tokens.
       
   199 	@return		A value of ESectionDone indicating that the start-line has been 
       
   200 				done.
       
   201 */
       
   202 	{
       
   203 	__START_PERFORMANCE_LOGGER();
       
   204 	// Get the start-line tokens from the observer.
       
   205 	TPtrC8 token1, token2, token3;
       
   206 	iObserver.StartLineL(token1, token2, token3);
       
   207 
       
   208 	// Add the tokens to the data buffer.
       
   209 	iDataComposer.AddTokenL(token1, THttpDataComposer::ESpace);
       
   210 	iDataComposer.AddTokenL(token2, THttpDataComposer::ESpace);
       
   211 	iDataComposer.AddTokenL(token3, THttpDataComposer::ECRLF);
       
   212 	__END_PERFORMANCE_LOGGER(_L(",CHttpMessageComposer::ComposeStartLineL()"));
       
   213 
       
   214 	return ESectionDone;
       
   215 	}
       
   216 
       
   217 CHttpMessageComposer::TComposingStatus CHttpMessageComposer::ComposeHeadersL()
       
   218     {
       
   219     // Compose maximum of 6 headers at one go without AO scheduling
       
   220     TComposingStatus status = ComposeSingleHeaderL();
       
   221     if(status == ESectionNotDone)
       
   222         {
       
   223         status = ComposeSingleHeaderL();
       
   224         if(status == ESectionNotDone)
       
   225             {
       
   226             status = ComposeSingleHeaderL();
       
   227             if(status == ESectionNotDone)
       
   228                 {
       
   229                 status = ComposeSingleHeaderL();                
       
   230                 if(status == ESectionNotDone)
       
   231                     {
       
   232                     status = ComposeSingleHeaderL();                
       
   233                 		if(status == ESectionNotDone)
       
   234                     	{
       
   235                     	status = ComposeSingleHeaderL();                
       
   236                     	}                    
       
   237                     }
       
   238                 }
       
   239             }
       
   240         }
       
   241     return status;
       
   242     }
       
   243 
       
   244 CHttpMessageComposer::TComposingStatus CHttpMessageComposer::ComposeSingleHeaderL()
       
   245 /**
       
   246 	Composes a header field or the end of headers marker. Each header field is
       
   247 	delimited by a CRLF end of line marker.
       
   248 
       
   249 		generic-message	=	start-line
       
   250 							*(message-header CRLF)
       
   251 							CRLF
       
   252 							[ message-body ]
       
   253 		
       
   254 		message-header	=	field-name ":" [ field-value ]
       
   255 
       
   256 	The observer supplies the field name and value tokens. If there is no more
       
   257 	header field info then the end of headers marker is added - the composer is
       
   258 	now ready to send the start-line and headers section of the message. The 
       
   259 	optional message-body will follow if there is one. The current data buffer
       
   260 	is set to contain the start-line and message-headers.
       
   261 	@return		A value of ESectionNotDone indicating that there are more headers
       
   262 				to add. A value of ESendData indicating that the current message 
       
   263 				buffer should be sent.
       
   264 */
       
   265 	{
       
   266 	__START_PERFORMANCE_LOGGER();
       
   267 	// Get header field info for the next header from the observer - the return
       
   268 	// value should indicate if there is any more header info.
       
   269 	TPtrC8 name, value;
       
   270 	TInt error = iObserver.NextHeaderL(name, value);
       
   271 
       
   272 	// Was there any header info?
       
   273 	TComposingStatus status = ESectionNotDone;
       
   274 	if( error == KErrNone )
       
   275 		{
       
   276 		// Add header info to the data buffer - return default status.
       
   277 		iDataComposer.AddTokenL(name, THttpDataComposer::EColonSpace);
       
   278 		iDataComposer.AddTokenL(value, THttpDataComposer::ECRLF);
       
   279 		}
       
   280 	else
       
   281 		{
       
   282 		// No more headers - add an empty line to mark the end of the headers.
       
   283 		iDataComposer.AddTokenL(KNullDesC8(), THttpDataComposer::ECRLF);
       
   284 
       
   285 		// Set the send buffer - need to send it so return ESendData status.
       
   286 		iSendBuffer.Set(*iDataBuffer);
       
   287 		status = ESendData;
       
   288 		}
       
   289 		__END_PERFORMANCE_LOGGER(_L(",CHttpMessageComposer::ComposeSingleHeaderL()"));
       
   290 	return status;
       
   291 	}
       
   292 
       
   293 CHttpMessageComposer::TComposingStatus CHttpMessageComposer::ComposeChunkSizeL()
       
   294 /**
       
   295 	Compose the chunk-size component. The chunk-size component indicates the 
       
   296 	size of the subsequent chunk-data component.
       
   297 
       
   298 		chunk			=	chunk-size [ chunk-extension ] CRLF
       
   299 							chunk-data CRLF
       
   300 		chunk-size		=	1*HEX
       
   301 
       
   302 	The composer is ready to send the chunk-size component before sending the
       
   303 	chunk-data. Also, an empty line marker from a previous chunk-data component
       
   304 	is included in the send buffer if this is not the first chunk-size component.
       
   305 	Note that if the chunk-data component is zero-length it should be ignored
       
   306 	since a zero value chunk-size indicates the last-chunk component.
       
   307 	@return		A value of ESendData indicating that the current message buffer
       
   308 				should be sent. A value	of ESectionDone if the chunk is of zero-
       
   309 				length.
       
   310 */
       
   311 	{
       
   312 	__START_PERFORMANCE_LOGGER();
       
   313 	// Get the current data chunk from the data supplier
       
   314 	TPtrC8 chunk;
       
   315 	iBodyData->GetNextDataPart(chunk);
       
   316 
       
   317 	TComposingStatus status = ESendData;
       
   318 	TInt chunkSize = chunk.Length();
       
   319 	if( chunkSize > 0 )
       
   320 		{
       
   321 		// Convert the size to its HEX representation.
       
   322 		HBufC8* hex = NULL;
       
   323 		InetProtTextUtils::ConvertHexToDescriptorL(chunkSize, hex);
       
   324 		CleanupStack::PushL(hex);
       
   325 
       
   326 		// Add the chunk-size componennt.
       
   327 		iDataComposer.AddTokenL(*hex, THttpDataComposer::ECRLF);
       
   328 		CleanupStack::PopAndDestroy(hex);
       
   329 
       
   330 		// Set the send buffer - need to send it so return ESendData status.
       
   331 		iSendBuffer.Set(*iDataBuffer);
       
   332 		}
       
   333 	else
       
   334 		{
       
   335 		// The chunk is zero-length - this section is done.
       
   336 		status = ESectionDone;
       
   337 		}
       
   338 	__END_PERFORMANCE_LOGGER(_L(",CHttpMessageComposer::ComposeChunkSizeL()"));
       
   339 	return status;
       
   340 	}
       
   341 
       
   342 CHttpMessageComposer::TComposingStatus CHttpMessageComposer::ComposeLastChunkL()
       
   343 /**
       
   344 	Composes the last-chunk component. The last-chunk component marks the end
       
   345 	of the chunked data. 
       
   346 
       
   347 		last-chunk		=	1*("0") [ chunk-extension ] CRLF
       
   348 
       
   349 	Optional trailers may follow.
       
   350 	@return		A value of ESectionDone indicating that the last-chunk component
       
   351 				has	been added to the message.
       
   352 */
       
   353 	{
       
   354 	// Add zero to mark the last-chunk.
       
   355 	_LIT8(KZero, "0");
       
   356 	iDataComposer.AddTokenL(KZero(), THttpDataComposer::ECRLF);
       
   357 
       
   358 	// The trailers now follow so this section is done.
       
   359 	return ESectionDone;
       
   360 	}
       
   361 
       
   362 CHttpMessageComposer::TComposingStatus CHttpMessageComposer::ComposeTrailerL()
       
   363 /**
       
   364 	Composes a trailer header field. Each trailer header field is delimited by 
       
   365 	a CRLF end of line marker.
       
   366 
       
   367 		Chunked-Body	=	*chunk
       
   368 							last-chunk
       
   369 							trailer
       
   370 							CRLF
       
   371 
       
   372 		trailer			=	*(entity-header CRLF)
       
   373 
       
   374 		entity-header	=	message-header
       
   375 		
       
   376 		message-header	=	field-name ":" [ field-value ]
       
   377 
       
   378 	The observer supplies the field name and value tokens. If there is no more
       
   379 	trailer header field info then the end of headers marker is added - the 
       
   380 	composer is now ready to send the trailer headers section of the message. 
       
   381 	The last-chunk section is also included in the send buffer.
       
   382 	@return		A value of ESectionNotDone indicating that there are more headers
       
   383 				to add. A value of ESendData indicating that the current message 
       
   384 				buffer should be sent.
       
   385 */
       
   386 	{
       
   387 	__START_PERFORMANCE_LOGGER();
       
   388 	// Get trailer header field info for the next trailer from the observer - the
       
   389 	// return value should indicate if there is any more trailer info.
       
   390 	TPtrC8 name, value;
       
   391 	TInt error = iObserver.NextTrailerL(name, value);
       
   392 
       
   393 	// Was there any trailer info?
       
   394 	TComposingStatus status = ESectionNotDone;
       
   395 	if( error == KErrNone )
       
   396 		{
       
   397 		// Add trailer info to the data buffer - return default status.
       
   398 		iDataComposer.AddTokenL(name, THttpDataComposer::EColonSpace);
       
   399 		iDataComposer.AddTokenL(value, THttpDataComposer::ECRLF);
       
   400 		}
       
   401 	else
       
   402 		{
       
   403 		// No more trailers - add an empty line to mark the end of the trailers.
       
   404 		iDataComposer.AddTokenL(KNullDesC8(), THttpDataComposer::ECRLF);
       
   405 
       
   406 		// Set the send buffer - need to send it so return ESendData status.
       
   407 		iSendBuffer.Set(*iDataBuffer);
       
   408 		status = ESendData;
       
   409 		}
       
   410 	__END_PERFORMANCE_LOGGER(_L(",CHttpMessageComposer::ComposeTrailerL()"));
       
   411 	return status;
       
   412 	}
       
   413 
       
   414 /*
       
   415  *	Methods from MHttpBufferSupplier
       
   416  */
       
   417 
       
   418 void CHttpMessageComposer::ReAllocBufferL(TInt aRequiredSize, TPtr8& aBuffer)
       
   419 /**	
       
   420 	Reallocates the data buffer. The composer supplies the data buffer to the
       
   421 	data composer. The data composer needs more space to store the current token.
       
   422 	If the data buffer has not been created then it is created, otherwise it is 
       
   423 	reallocated to at least the required size.
       
   424 	@param		aRequiredSize	The minimum size of buffer required.
       
   425 	@param		aBuffer			An output argument set to the reallocated buffer.
       
   426 	@panic		EInvariantFalse	The required size was less then the current max
       
   427 								size of the buffer.
       
   428 */
       
   429 	{
       
   430 	if( iDataBuffer == NULL )
       
   431 		{
       
   432 		// Create the buffer..
       
   433 		iDataBuffer = HBufC8::NewL(aRequiredSize + KDefaultBufferSize);
       
   434 		}
       
   435 	else
       
   436 		{
       
   437 		__ASSERT_DEBUG( aRequiredSize > iDataBuffer->Des().MaxLength(), User::Invariant() );
       
   438 
       
   439 		iDataBuffer = iDataBuffer->ReAllocL(aRequiredSize + KDefaultBufferSize);
       
   440 		}
       
   441 	aBuffer.Set(iDataBuffer->Des());
       
   442 	}
       
   443 
       
   444 void CHttpMessageComposer::DeleteBuffer()
       
   445 /**
       
   446 	Deletes the data buffer.
       
   447 */
       
   448 	{
       
   449 	delete iDataBuffer;
       
   450 	iDataBuffer = NULL;
       
   451 	}
       
   452 
       
   453 /*
       
   454  *	Methods from CActive
       
   455  */
       
   456 void CHttpMessageComposer::RunL()
       
   457 /**
       
   458 	Asynchronous request service handler. The composer state machine is processed
       
   459 	in this function. Behaviour depends on the state. The composer will self-
       
   460 	complete if it can continue composing the message. The composer informs its
       
   461 	observer when it has message data ready to send. It will then suspend 
       
   462 	processing until the observer notifies it that it has finished with the 
       
   463 	current data. If the composer requires more message info it will stop 
       
   464 	processing until it is notified that more message info is available.
       
   465 	
       
   466 	If the observer has reset the composer in one of the callback functions then
       
   467 	the composer will defer resetting itself until it is back in the RunL().
       
   468 	@leave		KErrCorrupt	The body data supplier indicated that the last data
       
   469 							part even though it had not supplied all the data it
       
   470 							specified. Or the body data supplier has supplied 
       
   471 							all the data it specified but has not indicated a 
       
   472 							last data part.
       
   473 	@panic		EHttpMessagePanicBadDataState	The composer has no info to compose
       
   474 												the message with.
       
   475 	@panic		EInvarinatFalse	The composer is trying to send entity body data 
       
   476 								when there is none to send.
       
   477 	@panic		EHttpMessagePanicBadComposerStata	The composer is in an illegal
       
   478 													state.
       
   479 */
       
   480 	{
       
   481 	__ASSERT_DEBUG( iDataState == EGotInfo, THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataState) ); 
       
   482 
       
   483 	TComposingStatus status = ESectionNotDone;
       
   484 	switch( iState )
       
   485 		{
       
   486 	case EIdle:
       
   487 		{
       
   488 		status = ESectionDone;
       
   489 		iState = ECreatingStartLine;
       
   490 		} 
       
   491 		//coverity [MISSING_BREAK]
       
   492 		// Fallthrough is required here as we no longer compose line by line. We compose startline & headers (6) at one go.
       
   493 	case ECreatingStartLine:
       
   494 		{
       
   495 		status = ComposeStartLineL();
       
   496 		iState = ECreatingHeaders;
       
   497         } 
       
   498 		//coverity [MISSING_BREAK]
       
   499 		// Fallthrough is required here as we no longer compose line by line. We compose startline & headers (6) at one go.
       
   500 	case ECreatingHeaders:
       
   501 		{
       
   502 		status = ComposeHeadersL();
       
   503 		// Is the headers section complete?
       
   504 		if( status != ESectionNotDone )
       
   505 			{
       
   506 			iState = EPendingEntityBody;
       
   507 
       
   508 			// Is there an entity body?
       
   509 			iBodyData = iObserver.HasBodyL();
       
   510 			}
       
   511 		// Stay in this state if there are more headers to compose.
       
   512 		} break;
       
   513 	case EPendingEntityBody:
       
   514 		{
       
   515 		// Release the current data buffer
       
   516 		iDataComposer.Release();
       
   517 
       
   518 		// Set the amount of the entity body data
       
   519 		if( iBodyData != NULL )
       
   520 			iDataSizeLeft = iBodyData->OverallDataSize();
       
   521 		else
       
   522 			iDataSizeLeft = 0;
       
   523 
       
   524 		// Determine next action depending on amount of entity data to send.
       
   525 		if( iDataSizeLeft > 0 )
       
   526 			{
       
   527 			// A known amount of data greater than zero. Send entity body with
       
   528 			// no transfer encoding. 
       
   529 			iState = ESendEntityData;
       
   530 			}
       
   531 		else if( iDataSizeLeft == 0 )
       
   532 			{
       
   533 			// No entity body or zero length entity body. The message is 
       
   534 			// complete. 
       
   535 			iState = EPendingIdle;
       
   536 			}
       
   537 		else
       
   538 			{
       
   539 			// An unknown amount of data. Send entity body with chunked transfer
       
   540 			// encoding. 
       
   541 			iState = ECreatingChunkSize;
       
   542 			}
       
   543 		status = ESectionDone;
       
   544 		} break;
       
   545 	case ESendEntityData:
       
   546 		{
       
   547 		__ASSERT_DEBUG( !iLastChunk, User::Invariant() );
       
   548 
       
   549 		// Get the next entity body part
       
   550 		iLastChunk = iBodyData->GetNextDataPart(iSendBuffer);
       
   551 
       
   552 		// Only send data if there is any to send.
       
   553 		TInt dataLength = iSendBuffer.Length();
       
   554 		if( dataLength > 0 )
       
   555 			status = ESendData;
       
   556 		else
       
   557 			status = ESectionDone;
       
   558 
       
   559 		// Update how much data is left to send.
       
   560 		iDataSizeLeft -= dataLength;
       
   561 
       
   562 		// Check whether the client is sending more/less data than it should.
       
   563 		if( (iDataSizeLeft < 0) || (iDataSizeLeft > 0 && iLastChunk) )
       
   564 			User::Leave(KErrCorrupt);
       
   565 
       
   566 		iState = EPendingReleaseData;
       
   567 		} break;
       
   568 	case EPendingReleaseData:
       
   569 		{
       
   570 		// Release the current data part.
       
   571 		iBodyData->ReleaseData();
       
   572 
       
   573 		// Has the last entity body part been released?
       
   574 		if( iLastChunk )
       
   575 			{
       
   576 			// Yep, message is complete.
       
   577 			status = ESectionDone;
       
   578 			iState = EPendingIdle;
       
   579 			}
       
   580 		else
       
   581 			{
       
   582 			// Stop composing until more data received.
       
   583 			status = EStop;
       
   584 			iState = ESendEntityData;
       
   585 			}
       
   586 		} break;
       
   587 	case ECreatingChunkSize:
       
   588 		{
       
   589 		status = ComposeChunkSizeL();
       
   590 		iState = ESendChunkData;
       
   591 		} break;
       
   592 	case ESendChunkData:
       
   593 		{
       
   594 		// Release the current data buffer
       
   595 		iDataComposer.Release();
       
   596 
       
   597 		// Get the chunk-data from the body data supplier.
       
   598 		iLastChunk = iBodyData->GetNextDataPart(iSendBuffer);
       
   599 
       
   600 		// Only send data if there is any to send.
       
   601 		if( iSendBuffer.Length() > 0 )
       
   602 			status = ESendData;
       
   603 		else
       
   604 			status = ESectionDone;
       
   605 		
       
   606 		// Move to the PendingReleaseChunk state.
       
   607 		iState = EPendingReleaseChunk;
       
   608 		} break;
       
   609 	case EPendingReleaseChunk:
       
   610 		{
       
   611 		// Release the current data part.
       
   612 		iBodyData->ReleaseData();
       
   613 
       
   614 		// RFC2616 states - 
       
   615 		//
       
   616 		// chunk			=	chunk-size [ chunk-extension ] CRLF
       
   617 		//						chunk-data CRLF
       
   618 		// 
       
   619 		// Therefore need to add CRLF marker.
       
   620 		iDataComposer.AddTokenL(KNullDesC8(), THttpDataComposer::ECRLF);
       
   621 
       
   622 		// Has the last entity body part been released?
       
   623 		  if ( iLastChunk )
       
   624 			{
       
   625 			// Yep - mark with last-chunk component
       
   626 			status = ComposeLastChunkL();
       
   627 			iState = ECreatingTrailers;
       
   628 			}
       
   629 		else
       
   630 			{
       
   631 			// Stop composing until more data received.
       
   632 			status = EStop;
       
   633 			iState = ECreatingChunkSize;
       
   634 			}
       
   635 		} break;
       
   636 	case ECreatingTrailers:
       
   637 		{
       
   638 		status = ComposeTrailerL();
       
   639 
       
   640 		// Have all the trailers been added?
       
   641 		if( status != ESectionNotDone )
       
   642 			{
       
   643 			iState = EPendingEndOfChunkedBody;
       
   644 			}
       
   645 		// Stay in this state if there are more trailers to compose.
       
   646 		} break;
       
   647 	case EPendingEndOfChunkedBody:
       
   648 		{
       
   649 		// Release the current data buffer.
       
   650 		iDataComposer.Release();
       
   651 
       
   652 		// The message is complete.
       
   653 		status = ESectionDone;
       
   654 		iState = EPendingIdle;
       
   655 		} break;
       
   656 	case EPendingIdle:
       
   657 		{
       
   658 		// The message is complete - inform the observer.
       
   659 		iObserver.MessageComplete();
       
   660 
       
   661 		// The composer is done.
       
   662 		iState = EIdle;
       
   663 		status = EStop;
       
   664 		} break;
       
   665 	default:
       
   666 		THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadComposerState);
       
   667 		break;
       
   668 		}
       
   669 	// Determine what to do next...
       
   670 	if( iDataState == EReset )
       
   671 		{
       
   672 		// The observer has reset the composer during one of the callbacks - it 
       
   673 		// is now safe to do the reset.
       
   674 		DoReset();
       
   675 		}
       
   676 	else if( status == ESectionDone || status == ESectionNotDone )
       
   677 		{
       
   678 		// Need to keep composing - complete-self.
       
   679 		CompleteSelf();
       
   680 		}
       
   681 	else if( status == ESendData )
       
   682 		{
       
   683 		// Update data state...
       
   684 		iDataState = EWaitingForRelease;
       
   685 
       
   686 		// Inform the observer that there is message data to send.
       
   687 		iObserver.MessageDataReadyL();
       
   688 		}
       
   689 	else
       
   690 		{
       
   691 		// Data state is EStop - stop composing and wait for more message data.
       
   692 		iDataState = EWaitingForInfo;
       
   693 		}
       
   694 	}
       
   695 
       
   696 void CHttpMessageComposer::DoCancel()
       
   697 /**
       
   698 	Asynchronous request cancel. This function does nothing as the only asynch
       
   699 	request that is made is a self-complete request.
       
   700 */
       
   701 	{
       
   702 	// Do nothing...
       
   703 	}
       
   704 
       
   705 TInt CHttpMessageComposer::RunError(TInt aError)
       
   706 /**
       
   707 	Asynchronous request service error handler. An error has occured whilst
       
   708 	processing the state machine. Reset the composer and notify the observer of 
       
   709 	the error.
       
   710 	@param		aError	The error code.
       
   711 	@return		An interger value of KErrNone indicates that the error has been
       
   712 				handled.
       
   713 	@post		The composer has been reset.
       
   714 */
       
   715 	{
       
   716 	// Stop composing and reset.
       
   717 	DoReset();
       
   718 
       
   719 	// Notify the observer of the error
       
   720 	return iObserver.HandleComposeError(aError);
       
   721 	}
       
   722 
       
   723 TBool CHttpMessageComposer::CheckMessagePendingComplete()
       
   724 /**
       
   725 	Check if the message has been completely sent. 
       
   726 	i.e. the headers have been composed and sent and there is no body to send.
       
   727 	Only waiting for a confirmation socket that it has in fact been sent. 
       
   728 
       
   729 	@return		TBool ETrue if the message is complete.
       
   730 	@post		The composer has been reset.
       
   731 */
       
   732 	{
       
   733 	return (iState == EPendingEntityBody && iBodyData==NULL) ? ETrue:EFalse;
       
   734 	}
       
   735