applayerprotocols/httptransportfw/httpmessage/chttpmessageparser.cpp
changeset 0 b16258d2340f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerprotocols/httptransportfw/httpmessage/chttpmessageparser.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,860 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "chttpmessageparser.h"
+
+#include <inetprottextutils.h>
+#include <uriutilscommon.h>
+
+#include "mhttpmessageparserobserver.h"
+#include "thttpmessagepanic.h"
+
+const TInt KDefaultBufferSize	= 128;
+const TUint KColon				= ':';
+_LIT8 ( KLineFeed, "\n" );
+
+// 'this' used in base member initializer list, The 'this' pointer being used is a base class pointer.
+#pragma warning( disable : 4355 )
+
+CHttpMessageParser* CHttpMessageParser::NewL(MHttpMessageParserObserver& aObserver)
+/**
+	Factory constructor. 
+	@param		aObserver	The observer for the parser.
+	@return		A pointer to a fully constructed and initialised object.
+*/
+	{
+	return new (ELeave) CHttpMessageParser(aObserver);
+	}
+
+CHttpMessageParser::~CHttpMessageParser()
+/**
+	Destructor
+*/
+	{
+	Cancel();
+
+	// Cleanup
+	delete iLineBuffer;
+	}
+
+CHttpMessageParser::CHttpMessageParser(MHttpMessageParserObserver& aObserver)
+: CActive(CActive::EPriorityStandard + 1), iObserver(aObserver), iDataParser(*this)
+/**
+	Constructor.
+	See note in CHttpMessageComposer
+*/
+	{
+	CActiveScheduler::Add(this);
+	}
+
+void CHttpMessageParser::ReceivedMessageData()
+/**
+	Notifies the parser of more message data. The parser gets the data packet
+	from the observer and continues processing its state machine.
+	@panic	EHttpMessagePanicBadDataState	The current data packet has not been
+											completely parsed.
+*/
+	{
+	__ASSERT_DEBUG( iDataState == EWaitingForData, THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataState) );
+
+	// Have now got some data - update the data state
+	iDataState = EGotData;
+
+	// Get the received data packet
+	TPtrC8 data;
+	iObserver.GetDataPacket(data);
+
+	// Pass it to the data parser
+	iDataParser.SetData(data);
+
+	// Continue parsing...
+	CompleteSelf();
+	}
+
+void CHttpMessageParser::CompletedBodyDataL()
+/**
+	Tells the parser that there is no more body data. When using HTTP 1.0 style
+	responses the body data maybe of unknown length so this method allows clients
+	to inform the parser that the body data is completed.
+*/
+	{
+	iDataSizeLeft = 0;
+	
+	// Notify the observer that the body has been received
+	iObserver.BodyCompleteL();
+
+	// Notify the observer that the message is complete.
+	iObserver.MessageCompleteL(KNullDesC8());
+
+	// Move to the Idle state.
+	iParserState = EIdle;
+	iDataState = EWaitingForData;
+	}
+
+void CHttpMessageParser::Reset()
+/**
+	Parser reset request. As the observer can reset the parser during one the 
+	callback functions, the parser must check for re-entrancy to avoid releasing
+	resources that are still required. If the parser is either waiting for more
+	message data or is waiting to process its state machine, the parser can 
+	safely reset immediately. Otherwise the parser is being reset from within 
+	its RunL() and so it must defer resetting itself to a safer point. This is
+	the point in the RunL() where the next step is decided.
+	@panic EHttpMessagePanicDoubleReset	The parser has been reset twice in one 
+										of the observer callback functions.
+*/
+	{
+	// Check the data state of the parser - the parser cannot be reset if the 
+	// Reset() was called in one of the observer callbacks. It is safe to reset
+	// now if - 
+	// 1) the data state is WaitingForData
+	// 2) the parser is active - waiting to for its RunL() to be called.
+	if( iDataState == EWaitingForData || IsActive() )
+		{
+		// Cancel and do the reset.
+		Cancel();
+		DoReset();
+		}
+	else
+		{
+		// Debug check for a double Reset() call...
+		__ASSERT_DEBUG( iDataState != EReset, THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicDoubleReset) );
+
+		// The Reset() was called inside a callback - defer resetting the parser
+		// until call stack back in the parser RunL().
+		iDataState = EReset;
+		}
+	}
+
+void CHttpMessageParser::CompleteSelf()
+/**
+	Self-complete function. Ensures that the state machine is processed.
+*/
+	{
+	TRequestStatus* pStat = &iStatus;
+	User::RequestComplete(pStat, KErrNone);
+	SetActive();
+	}
+
+void CHttpMessageParser::DoReset()
+/**
+	Resets the parser. The parser moves into the Idle state. Allocated resources 
+	are also reset. 
+*/
+	{
+	// Reset the parser - parser state should be Idle and the data state should
+	// be WaitingForData.
+	iParserState = EIdle;
+	iDataState = EWaitingForData;
+
+	// Reset the data parser
+	iDataParser.Reset();
+	}
+
+CHttpMessageParser::TParsingStatus CHttpMessageParser::ParseStartLineL()
+/**
+	Parses for the start-line. The start-line is delimited by the first eol 
+	marker. No further parsing of the start-line is done by the parser - it is
+	left to the observer to parse for either a request-line or a status-line.
+	The observer is informed of the start-line.
+	@return		The parsing status for the start-line. The value ESectionDone 
+				indicates the start-line has been parsed. The value EBufferEmpty
+				indicates that more message data is required to parse the 
+				start-line.
+	@panic		EHttpMessagePanicBadDataParserResult	An unexpected status was 
+														returned by the data 
+														parser.
+*/
+	{
+	// Get line from the parser
+	TPtrC8 startLine;
+	THttpDataParser::TParseResult parseResult = iDataParser.GetLineL(startLine);
+
+	// Check the parse status...
+	TParsingStatus  startlineStatus = ESectionNotDone;
+	switch( parseResult )
+		{
+	case THttpDataParser::ELineParsed:
+		{
+		// The start-line has been parsed - inform the observer.
+		iObserver.StartLineL(startLine);
+		startlineStatus = ESectionDone;
+		} break;
+	case THttpDataParser::EPartialData:
+		{
+		// Not all of start-line received - need more data.
+		startlineStatus = EBufferEmpty;
+		} break;
+	case THttpDataParser::EEmptyLine:
+		{
+		// Although blank-lines are not allowed, be tolerent. Need to parse for 
+		// the start-line again. The start-line is not complete - use default 
+		// return value.
+		} break;
+	default:
+		// This covers EGotData case.
+		THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataParserResult);
+		break;
+		}
+	return startlineStatus;
+	}
+
+CHttpMessageParser::TParsingStatus CHttpMessageParser::ParseSingleHeaderL()
+/**
+	Parses for a header field line. A header field line is delimited by an eol 
+	marker. If an empty line is parser then this indicates the end of the header
+	fields section. If a header field is found then the field name and field
+	value are extracted. The observer is passed the field name and value.
+	
+	If a malformed header field is found (ie the colon ':' is missing) then that
+	line is ignored. The function will leave if an error occurs in removing the 
+	leading and trailing whitespace from the parsed header field name. 
+	
+	Note that the header field value may be empty.
+	@return		The parsing status for the header fields section. The value 
+				ESectionDone indicates that an empty line has been parsed which
+				means that all the header fields have been parsed. The value 
+				ESectionNotDone indicates that a header field has been found. 
+				The	value EBufferEmpty indicates that more message data is 
+				required to parse the header fields section.
+	@panic		EHttpMessagePanicBadDataParserResult	An unexpected status was 
+														returned by the data 
+														parser.
+*/
+	{
+	// Get line from the parser
+	TPtrC8 line;
+	THttpDataParser::TParseResult parseResult = iDataParser.GetHeaderLineL(line);
+
+	// Check the parse status...
+	TParsingStatus  headerStatus = ESectionNotDone;
+	switch( parseResult )
+		{
+	case THttpDataParser::ELineParsed:
+		{
+		// Got a header field - find the field name and value.
+		TInt colonPos = line.Locate(KColon);
+
+		if( colonPos == KErrNotFound )
+			{
+			// No colon - syntax error. Be robust and ignore the this line. 
+			// There are still more headers to find - use default return value.
+			break;
+			}
+
+		// Found the field name and value
+		TPtrC8 name = line.Left(colonPos);
+		TPtrC8 value = line.Mid(colonPos + 1);	// move past the colon
+
+		// Remove any leading/trailing whitespace but if it is empty, try to be robust and continue with the next one.
+		TInt rwsErr = InetProtTextUtils::RemoveWhiteSpace(name, InetProtTextUtils::ERemoveBoth);
+
+		// Field value may be empty - e.g. "host:". Ignore any returned error.
+		InetProtTextUtils::RemoveWhiteSpace(value, InetProtTextUtils::ERemoveBoth);
+
+		// Pass the header field name and value to the observer if it seemed valid.
+		if( rwsErr == KErrNone )
+			{
+			iObserver.HeaderL(name, value);
+			}
+ 
+		// There are still more headers to find - use default return value.
+		} break;
+	case THttpDataParser::EPartialData:
+		{
+		// Not all of header field received - need more data.
+		headerStatus = EBufferEmpty;
+		} break;
+	case THttpDataParser::EEmptyLine:
+		{
+		// Reached the end of the headers section - move on.
+		headerStatus = ESectionDone;
+		} break;
+	default:
+		// This covers EGotData case.
+		THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataParserResult);
+		break;
+		}
+	return headerStatus;
+	}
+
+CHttpMessageParser::TParsingStatus CHttpMessageParser::ParseHeadersL()
+    {
+    // Do parsing of 5 headers without AO scheduling
+    TParsingStatus  headerStatus = ParseSingleHeaderL();
+    if(headerStatus == ESectionNotDone)
+        {
+        headerStatus = ParseSingleHeaderL();
+        if(headerStatus == ESectionNotDone)
+            {
+            headerStatus = ParseSingleHeaderL();
+            if(headerStatus == ESectionNotDone)
+                {
+               headerStatus = ParseSingleHeaderL();
+                if(headerStatus == ESectionNotDone)
+                    {
+                    headerStatus = ParseSingleHeaderL();
+                    }
+                }
+            }
+        }
+    return headerStatus;
+    }
+
+CHttpMessageParser::TParsingStatus CHttpMessageParser::ReadBodyData(TPtrC8& aData)
+/**
+	Reads the entity body data from the current data packet. As the entity body
+	data can be segmented by the tranport layer this function may need to be 
+	called more than once. The remaining amount of entity body data is updated.
+	@param		aData	An output argument set the entity body data extracted 
+						from the current data packet.
+	@return		The parsing status for the entity body. The value ESectionDone 
+				indicates the entity body has been extracted. The value 
+				EBufferEmpty indicates that more message data is required to 
+				extract the entity body.
+	@panic		EHttpMessagePanicBadDataParserResult	An unexpected status was 
+														returned by the data 
+														parser.
+	@panic		EInvariantFalse	The data parser returned a status that conflicts
+								with the amount of entity body data to extract.
+*/
+	{
+	// If the body length is unknown then set the data size to a maximum value
+	if(iDataSizeLeft==-1)
+		iDataSizeLeft = KMaxTInt;
+
+	// Get the remaining body data from the data parser
+	THttpDataParser::TParseResult parseResult = iDataParser.GetData(aData, iDataSizeLeft);
+
+	// Update the size of the data left to get
+	iDataSizeLeft -= aData.Length();
+
+	// Check the parse status...
+	TParsingStatus  dataStatus = EBufferEmpty;
+	switch( parseResult )
+		{
+	case THttpDataParser::EGotData:
+		{
+		__ASSERT_DEBUG( iDataSizeLeft == 0, User::Invariant() );
+
+		// Got all the data - section is done.
+		dataStatus = ESectionDone;
+		} break;
+	case THttpDataParser::EPartialData:
+		{
+		__ASSERT_DEBUG( iDataSizeLeft > 0, User::Invariant() );
+
+		// Use the default value...
+		} break;
+	default:
+		// This covers ELineParsed and EEmptyLine cases.
+		THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataParserResult);
+		break;
+		}
+	return dataStatus;
+	}
+
+CHttpMessageParser::TParsingStatus CHttpMessageParser::ParseChunkSizeL()
+/**
+	Parses for a chunk-size component. The chunk-size component specifies the 
+	size of following chunk-data component. As the chunk-size can be segmented 
+	at the transport layer this function may need to called several times for 
+	the same chunk-size component.
+
+	Section 3.6.1 in RFC2616 defines the following - 
+		chunk			=	chunk-size [ chunk-extension ] CRLF
+							chunk-data CRLF
+		chunk-size		=	1*HEX
+		chunk-extension	=	*( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+
+	The chunk-size component is delimited by the eol marker. There can be an 
+	optional chunk-extension component between the chunk-size and the eol marker.
+	This is parsed but ignored - a leading ';' is not checked for. Also, if an
+	empty line is parsed this is also ignored. The function will also leave if
+	there is an error in converting the hex number to its numeric value.
+	@return		The parsing status for this chunk-size component. The value 
+				ESectionDone indicates that all the chunk-data has been parsed
+				and the value EBufferEmpty indicates that more message data is
+				required to parse this chunk-size component.
+	@leave		THttpDataParser::GetLineL
+	@panic		EHttpMessagePanicBadDataParserResult	An unexpected status was 
+														returned by the data 
+														parser.
+*/
+	{
+	// Get line from the parser
+	TPtrC8 line;
+	THttpDataParser::TParseResult parseResult = iDataParser.GetLineL(line);
+
+	// Check the parse status...
+	TParsingStatus  sizeStatus = ESectionDone;
+	switch( parseResult )
+		{
+	case THttpDataParser::ELineParsed:
+		{
+		// Ok got the line - find the hex number defining the chunk-size.
+		TInt val = InetProtTextUtils::ConvertDescriptorToHex(line, iDataSizeLeft);
+		if( val < 0 )
+			{
+			// Error: invalid data.. ignore it.
+			sizeStatus = ESectionDone;
+			}
+		// Do not care about the chunk-extension - do not bother to check that 
+		// it is well formed.
+
+		// The chunk-size has been parsed - use default return value.
+		} break;
+	case THttpDataParser::EPartialData:
+		{
+		// Not all of start-line received - need more data.
+		sizeStatus = EBufferEmpty;
+		} break;
+	case THttpDataParser::EEmptyLine:
+		{
+		// The chunk-size was expected - got an empty line. Ignore.
+		sizeStatus = ESectionNotDone;
+		} break;
+	default:
+		// This covers EGotData case.
+		THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataParserResult);
+		break;
+		}
+	return sizeStatus;
+	}
+
+CHttpMessageParser::TParsingStatus CHttpMessageParser::ParseChunkDataL(TPtrC8& aData)
+/**
+	Parses for a chunk-data component. The preceeding chunk-size component 
+	specified the length of this chunk-data component. As the chunk-data can be
+	segmented at the transport layer this function may need to called several
+	times for the same chunk-data component.
+
+	Section 3.6.1 in RFC2616 defines the following - 
+		chunk			=	chunk-size [ chunk-extension ] CRLF
+   							chunk-data CRLF
+   
+	The chunk-data component is delimited by the eol marker. If the amount of
+	chunk-data does not match the amount defined by the chunk-size then the
+	function will leave with KErrCorrupt.
+	@param		aData	An output argument set to the chunk-data parsed.
+	@return		The parsing status for this chunk-data component. The value 
+				ESectionDone indicates that all the chunk-data has been parsed
+				and the value EBufferEmpty indicates that more message data is
+				required to parse this chunk-data component.
+	@leave		KErrCorrupt	An incorrect amount of chunk-data was parsed.
+	@panic		EInvariantFalse	The body data extraction indicated that it had
+								extracted all the body data but the parser still
+								expected more.
+	@panic		EHttpMessagePanicBadDataParserResult	An unexpected status was 
+														returned by the data 
+														parser.
+*/
+   	{
+   	// Has the data-chunk been read? Check iDataSizeLeft.
+   	TParsingStatus dataStatus = ESectionDone;
+   	if( iDataSizeLeft > 0 )
+   		{
+   		// There is chunk-data to extract
+   		dataStatus = ReadBodyData(aData);
+   		}
+
+	// Does the end CRLF need to be parsed? The chunk-data may have been found.
+	if( dataStatus == ESectionDone )
+		{
+		__ASSERT_DEBUG( iDataSizeLeft == 0, User::Invariant() );
+
+		// Need to extract an empty-line
+		TPtrC8 line;
+		THttpDataParser::TParseResult parseResult = iDataParser.GetLineL(line);
+
+		// Check the parse status...
+		switch( parseResult )
+			{
+		case THttpDataParser::EEmptyLine:
+			{
+			// Got the CRLF - section is done. Use default value.
+			} break;
+		case THttpDataParser::EPartialData:
+			{
+			dataStatus = EBufferEmpty;
+			} break;
+		case THttpDataParser::ELineParsed:
+			{
+			// There was more data than the chunk-size specified.
+			
+			// Error ignored to add robustness against problematic real-world servers.
+			//User::Leave(KErrCorrupt);
+			} break;
+		default:
+			// This covers EGotData case.
+			THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataParserResult);
+			break;
+			}
+		}
+	return dataStatus;
+	}
+
+/*
+ *	Methods from MHttpDataParserObserver
+ */
+
+void CHttpMessageParser::ReAllocBufferL(TInt aRequiredSize, TPtr8& aBuffer)
+/**	
+	Reallocates the line buffer. The parser supplies the line buffer to the data
+	parser. The data parser needs more space to store the current line. If the 
+	line buffer has not been created then it is created, otherwise it is 
+	reallocated to at least the required size.
+	@param		aRequiredSize	The minimum size of buffer required.
+	@param		aBuffer			An output argument set to the reallocated buffer.
+	@panic		EInvariantFalse	The required size was less then the current max
+								size of the buffer.
+*/
+	{
+	if( iLineBuffer == NULL )
+		{
+		// Create the buffer..
+		iLineBuffer = HBufC8::NewL(aRequiredSize + KDefaultBufferSize);
+		}
+	else
+		{
+		__ASSERT_DEBUG( aRequiredSize > iLineBuffer->Des().MaxLength(), User::Invariant() );
+
+		iLineBuffer = iLineBuffer->ReAllocL(aRequiredSize + KDefaultBufferSize);
+		}
+	aBuffer.Set(iLineBuffer->Des());
+	}
+
+void CHttpMessageParser::DeleteBuffer()
+/**
+	Deletes the line buffer.
+	@internalComponent
+*/
+	{
+	delete iLineBuffer;
+	iLineBuffer = NULL;
+	}
+
+/*
+ *	Methods from CActive
+ */
+void CHttpMessageParser::RunL()
+/**
+	Asynchronous request service handler. The parser state machine is processed
+	in this function. Behaviour depends on the state. The parser will self-
+	complete if the current data packet has unparsed data. If all the data in 
+	the current data packet has been parsed then the parser suspends its state
+	machine and waits for the observer to notify it when there is more data
+	available. If the observer has reset the parser in one of the callback then
+	the parser will defer resetting itself until it is back in the RunL().
+	@panic		EHttpMessagePanicBadParserState	The parser state machine was in 
+												a illegal state.
+	@panic		EHttpMessagePanicBadDataState	The parser was in the incorrect
+												data state.
+	@panic		EHttpMessagePanicBadBodySize	The observer specified an unknown
+												non-positive body size.
+*/
+	{
+	__ASSERT_DEBUG( iDataState == EGotData, THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadDataState) ); 
+	TParsingStatus status = ESectionNotDone;
+	switch( iParserState )
+		{
+	case EIdle:
+		{
+		// Move to the ParsingStartLine and set the parsing status to move on.
+		iParserState = EParsingStartLine;
+		status = ESectionDone;
+		} 
+		//coverity [MISSING_BREAK]
+		// Fallthrough is required here as we no longer parse line by line. We parse startline & headers (5) at one go.
+	case EParsingStartLine:
+		{
+		status = ParseStartLineL();
+
+		// Has the start-line been parsed?
+		if( status == ESectionDone )
+			{
+			// Start-line has been parsed - parse for headers next.
+			iParserState = EParsingHeaders;
+			}
+		else
+			{
+			break; //Start line is not parsed yet as we haven't received the complete data. Break and wait for more data.
+			}
+		}
+	case EParsingHeaders:
+		{
+		status = ParseHeadersL();
+
+		if( status == ESectionDone )
+			{
+			// No more headers - obtain entity body size from the observer.
+			iDataSizeLeft = iObserver.BodySizeL();
+			switch( iDataSizeLeft )
+				{
+			case MHttpMessageParserObserver::EChunked:
+				{
+				// Chunk-encoded body.
+				iParserState = EParsingChunkSize;
+				} break;
+			case MHttpMessageParserObserver::EUnknown:
+				{
+				// for HTTP/1.0-style responses
+				iParserState = EReadingBodyData;
+				} break;
+			case MHttpMessageParserObserver::ENoBody:
+				{
+				// No body expected - message is complete.
+				iParserState = EMessageComplete;
+				} break;
+			default:
+				__ASSERT_DEBUG( iDataSizeLeft > 0, THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadBodySize) );
+
+				// Non-encoded body.
+				iParserState = EReadingBodyData;
+				break;
+				}
+			}
+		} break;
+	case EParsingChunkSize:
+		{
+		status = ParseChunkSizeL();
+
+		if( status == ESectionDone )
+			{
+			// Need to check the chunk size for last-chunk
+			if( iDataSizeLeft == 0 )
+				{
+				// Recieved a chunk of size 0, inform the observer.
+				TPtrC8 data;
+				iObserver.BodyChunkL(data);
+
+				// Notify the observer that the body has been received
+				iObserver.BodyCompleteL();
+
+				// Received the last-chunk token - now parse for trailers.
+				iParserState = EParsingTrailerHeaders;
+				}
+			else
+				{
+				// Still expecting chunk-data...
+				iParserState = EReadingChunkData;
+				}
+			}
+		} break;
+	case EParsingTrailerHeaders:
+		{
+		status = ParseHeadersL();
+
+		if( status == ESectionDone )
+			{
+			// All the trailers have been found.
+			iParserState = EMessageComplete;
+			}
+		} break;
+	case EReadingBodyData:
+		{
+		// Read the body data...
+		TPtrC8 data;
+		status = ReadBodyData(data);
+
+		// Only inform the observer if there is any data.
+		if( data.Length() > 0 )
+			{
+			iObserver.BodyChunkL(data);
+			}
+		// Has all the body data been received - need to check that the parser
+		// has not been reset.
+		if( status == ESectionDone && iDataState != EReset )
+			{
+			// Notify the observer that the body has been received
+			iObserver.BodyCompleteL();
+
+			// Have received all the body data - message is complete.
+			iParserState = EMessageComplete;
+			}
+		} break;
+	case EReadingChunkData:
+		{
+		// Read the chunk-data...
+		TPtrC8 data;
+		status = ParseChunkDataL(data);
+
+		// Only inform the observer if there is any data.
+		if( data.Length() )
+			{
+			iObserver.BodyChunkL(data);
+			}
+
+		if( status == ESectionDone )
+			{
+			// Have received all the body data - get the size of the next chunk.
+			iParserState = EParsingChunkSize;
+			}
+		} break;
+	case EMessageComplete:
+		{
+		// Message complete - is there any excess data?
+		TPtrC8 data;
+		iDataParser.UnparsedData(data);
+
+		// Notify the observer that the message is complete.
+		iObserver.MessageCompleteL(data);
+
+		// Move to the Idle state and set the parsing status to Stop.
+		iParserState = EIdle;
+		status = EStop;
+		} break;
+	default:
+		THttpMessagePanic::Panic(THttpMessagePanic::EHttpMessagePanicBadParserState);
+		break;
+		}
+	// Determine the next action...
+	if( iDataState == EReset )
+		{
+		// The observer has reset the parser during one of the callbacks - it is
+		// now safe to do the reset.
+		DoReset();
+		}
+	else if( status == EBufferEmpty || status == EStop )
+		{
+		// Expect more data before being able to continue parsing.
+		iDataState = EWaitingForData;
+
+		// The current message component cannot be parsed due to lack of data,
+		// or the parsing has stopped. Need to release the current data packet
+		// (and wait for the next one in the case of EBufferEmpty).
+		iObserver.ReleaseDataPacket();
+		}
+	else 
+		{
+		// Here status is ESectionNotDone or ESectionDone - either the current
+		// message component has been completed and the parser needs to move 
+		// onto the next component, or the current component still needs to 
+		// complete. In both cases, self-complete to continue parsing.
+		CompleteSelf();
+		}
+	}
+
+void CHttpMessageParser::DoCancel()
+/**
+	Asynchronous request cancel. This function does nothing as the only asynch
+	request that is made is a self-complete request.
+*/
+	{
+	// Do nothing...
+	}
+
+TInt CHttpMessageParser::RunError(TInt aError)
+/**	
+	Asynchronous request service error handler. An error has occured whilst
+	processing the state machine. Reset the parser and notify the observer of 
+	the error.
+	@param		aError	The error code.
+	@return		An interger value of KErrNone indicates that the error has been
+				handled.
+	@post		The parser has been reset.
+*/
+	{
+	// Stop parsing and reset.
+	DoReset();
+
+	// Notify the observer of the error
+	return iObserver.HandleParserError(aError);
+	}
+
+void CHttpMessageParser::Flush ()
+	{
+	// Say a response like this.
+	// HTTP/1.0 302 Moves\nStatus: 302 Moved\nPragma: no-cache\nLocation: http://127.0.0.1\n
+	// In this response, there is no empty line after the header. Parser cannot parse the last header if 
+	// it didn't find an empty line after the header. Force the parser to parse the last header line.
+	if ( iDataState == EWaitingForData && iParserState == EParsingHeaders )
+		{
+		iDataParser.SetData ( KLineFeed() );		
+		TRAP_IGNORE( ParseHeadersL () );
+		}
+	// Message is completed but observer notification hasn't happened
+	// Notify now with uparsed data.
+	if ( iParserState == EMessageComplete )
+		{
+		TPtrC8 unparsedData;
+		iDataParser.UnparsedData(unparsedData);
+		iObserver.MessageCompleteL(unparsedData);
+		iParserState = EIdle;			
+		}		
+	}
+
+	// Completes parsing of the message. Header parts has been parsed.
+	// Complete the body part of the message. This happens in case of 3xx response
+	// where HTTP FW parses the headers and notify the client/filters. The client/filter
+	// will cancel the transaction and resubmit on the new URL.
+TBool CHttpMessageParser::CompleteMessage ( const TDesC8& aData )
+	{		
+	// Set the parser data	
+	if ( aData.Length () > 0 )
+		iDataParser.SetData ( aData );
+	
+	// We are reading body data. A content length value is known.
+	if ( iParserState == EReadingBodyData )		
+ 		{
+		TPtrC8 data;
+		if ( ReadBodyData(data) == ESectionDone )
+			{
+			iObserver.BodyCompleteL();
+			iParserState = EMessageComplete;
+ 			}				
+ 		}
+	// Read the chunked response.
+	if ( iParserState == EReadingChunkData || iParserState == EParsingChunkSize 
+		||  iParserState == EParsingTrailerHeaders )
+		{
+		TParsingStatus status = ESectionNotDone;
+		// This tiny look executes till the buffer is empty or the parser state is EMessageComplete
+		while ( status != EBufferEmpty && iParserState != EMessageComplete )
+			{
+			switch ( iParserState )
+				{
+				case EReadingChunkData:
+					{
+					TPtrC8 data;
+					status = ParseChunkDataL(data);				
+					if( status == ESectionDone )
+						{				
+						iParserState = EParsingChunkSize;
+						}													
+					}
+				break;				
+				case EParsingChunkSize:
+				status = ParseChunkSizeL();
+				if ( status == ESectionDone )
+					iParserState = (iDataSizeLeft == 0) ? EParsingTrailerHeaders : EReadingChunkData;
+				break;
+					
+				case EParsingTrailerHeaders:
+				status = ParseHeadersL();
+				if ( status == ESectionDone )
+					iParserState = EMessageComplete;
+				break;
+				default:
+				// Do nothing.
+				break;
+				}
+			}				
+ 		}
+	return iParserState == EMessageComplete;
+ 	}
+
+
+