--- /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;
+ }
+
+
+