diff -r 000000000000 -r b16258d2340f applayerprotocols/httptransportfw/httpmessage/chttpmessageparser.cpp --- /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 +#include + +#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; + } + + +