servicediscoveryandcontrol/pnp/test/upnp/upnpmessage/src/cupnprequestparser.cpp
changeset 0 f5a58ecadc66
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servicediscoveryandcontrol/pnp/test/upnp/upnpmessage/src/cupnprequestparser.cpp	Tue Feb 02 01:12:20 2010 +0200
@@ -0,0 +1,393 @@
+// Copyright (c) 2008-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 <inetprottextutils.h>
+#include <httperr.h>
+#include <httpstringconstants.h>
+
+#include "cupnprequestparser.h"
+#include "tupnpmessagepanic.h"
+
+_LIT8(KHeaderSeparator,	"\n");
+
+__FLOG_STMT(_LIT8(KSubsys,"UPnPReqParser");)
+__FLOG_STMT(_LIT8(KComponent,"UPnPMessage");)
+
+
+EXPORT_C CUpnpRequestParser* CUpnpRequestParser::NewL(MParserObserver& aObserver)
+	{
+	CUpnpRequestParser* self = new(ELeave) CUpnpRequestParser(aObserver);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CUpnpRequestParser::CUpnpRequestParser(MParserObserver& aObserver)
+	:iObserver(aObserver)
+	{
+	}
+
+EXPORT_C CUpnpRequestParser::~CUpnpRequestParser()
+	{
+	iMessageParser.Close();
+	iBodyParts.Close();
+	if(!iMsgBuf.IsEmpty())
+		{
+		iMsgBuf.Free();	
+		}
+	iRawDataArray.Close();
+	__FLOG(_L8("-> Request parser destroyed"));
+	__FLOG_CLOSE;
+	}
+
+void CUpnpRequestParser::ConstructL()
+	{
+	iMessageParser.OpenL(*this);
+	__FLOG_OPEN(KSubsys, KComponent);
+	__FLOG(_L8("-> Request parser created"));
+	}
+
+TBool CUpnpRequestParser::GetNextDataPart(TPtrC8& aDataPart)
+	{
+	__FLOG(_L8("-> Supplying request body part"));
+	
+	TInt bodyPartsCount = iBodyParts.Count();
+	__ASSERT_ALWAYS((bodyPartsCount > 0), TUPnPMessagePanic::Panic(TUPnPMessagePanic::ENoBodyPartInDataSupplier));
+		
+	// Provide the first chunk.
+	aDataPart.Set(iBodyParts[0]);
+	__FLOG_1(_L8("%S"), &aDataPart);
+	
+	return (BodyComplete() && bodyPartsCount == 1);
+	}
+
+void CUpnpRequestParser::ReleaseData()
+	{
+	__FLOG(_L8("-> Releasing request body part"));
+	
+	// Remove the oldest chunk.
+	if( iBodyParts.Count () > 0 )
+		{
+		iBodyParts.Remove ( 0 ); 
+		}
+	
+	// Are there any more chunks?
+	if( iBodyParts.Count () > 0 )
+		{
+		// Notify the sender about the presence of the body. He can then call
+		// MHTTPDataSupplier::GetNextDataPart() to get the body data.
+		iObserver.GotBodyData();
+		}
+
+	else
+		{
+		// Does this data packet need to be released?
+		if( NotifyReleaseData() )
+			{
+			// Notify sender that the current data is no longer needed.
+			// Can release as there are no body chunks waiting to be passed to the
+			// client.
+			iObserver.DataParsed();
+			iFlags &= ~ENotifyReleaseData;
+			}
+		}
+	}
+	
+TInt CUpnpRequestParser::OverallDataSize()
+	{
+	return (iOverallDataSize < 0) ? KErrNotFound : iOverallDataSize;
+	}
+
+TInt CUpnpRequestParser::Reset()
+	{
+	return KErrNotSupported;
+	}
+
+void CUpnpRequestParser::GetDataPacket(TPtrC8& aData)
+	{
+	__FLOG(_L8("-> Supplying request data to the HTTP message parser"));
+	aData.Set(iRawDataArray[0]);
+	iRawDataArray.Remove(0);
+	}
+
+void CUpnpRequestParser::ReleaseDataPacket()
+	{
+	__FLOG(_L8("-> Releasing request data"));
+	if ( iBodyParts.Count () == 0 )
+		{
+		if(iRawDataArray.Count() > 0 && !IsExcessData())
+			{
+			iMessageParser.ReceivedMessageData();
+			}
+		else
+			{
+			// Notify sender that the current data is no longer needed.
+			// Can release as there are no body chunks waiting to be passed to the
+			// client.
+			iObserver.DataParsed();
+			}
+		}
+	else
+		{
+		// Flag that the data needs to be released
+		iFlags |= ENotifyReleaseData;
+		}
+	}
+
+void CUpnpRequestParser::StartLineL(const TDesC8& aStartLine)
+	{	
+	// From RFC 2616 Sec 5.1 Request-Line   = Method SP Request-URI SP HTTP-Version CRLF
+	// Request-Line == Start-Line
+	__FLOG(_L8("-> Got the request start line"));
+	__FLOG_1(_L8("%S"), &aStartLine);
+	
+	TPtrC8 startLinePtr ( aStartLine );
+	// Find the first space.
+	TInt pos = startLinePtr.Locate ( ' ' );
+	User::LeaveIfError ( pos );
+	
+	// Extract the method
+	TPtrC8 method ( startLinePtr.Left ( pos ) );
+	InetProtTextUtils::RemoveWhiteSpace ( method, InetProtTextUtils::ERemoveBoth );
+		
+	// Now move past the space that we located
+	startLinePtr.Set ( startLinePtr.Mid ( pos + 1 ) );
+		
+	// Locate the next space.
+	pos = startLinePtr.Locate ( ' ' );
+	User::LeaveIfError ( pos );
+	
+	// Extract the request URI
+	TPtrC8 requestUri ( startLinePtr.Left ( pos ) );
+	InetProtTextUtils::RemoveWhiteSpace ( requestUri, InetProtTextUtils::ERemoveBoth );
+	
+	TUriParser8 uriParser;
+	User::LeaveIfError ( uriParser.Parse ( requestUri ) );
+	
+	// Now move past the space that we located
+	startLinePtr.Set ( startLinePtr.Mid ( pos + 1 ) );
+	
+	// Extract the version
+	TPtrC8 versionPtr ( startLinePtr );
+	if ( versionPtr.Length () == 0 )
+		User::Leave ( KErrCorrupt );
+	
+	InetProtTextUtils::RemoveWhiteSpace ( requestUri, InetProtTextUtils::ERemoveBoth );
+
+
+	RStringPool sp = iRequest->StringPool();
+
+	pos = versionPtr.Locate('/');
+	if( pos == KErrNotFound )
+		User::Leave(KErrCorrupt);
+	
+	versionPtr.Set(versionPtr.Mid(pos + 1));
+
+	// Extract the major version number
+	TInt major;
+	pos = InetProtTextUtils::ConvertDescriptorToInt(versionPtr, major);
+	User::LeaveIfError(pos);
+	
+	// Skip past major version number and the "."
+	versionPtr.Set(versionPtr.Mid(pos + 1));
+
+	// Extract the minor version number
+	TInt minor;
+	pos = InetProtTextUtils::ConvertDescriptorToInt(versionPtr, minor);
+	User::LeaveIfError(pos);
+
+	RStringF methodStr = sp.OpenFStringL ( method );
+	CleanupClosePushL(methodStr);
+	
+	RRequest request = iRequest->Handle ();
+	request.SetMethod ( methodStr );
+	request.SetURIL ( uriParser );
+	
+	TVersion version ( major, minor, 0);	
+	request.SetVersion ( version );
+	
+	CleanupStack::PopAndDestroy(&methodStr);
+	}
+
+void CUpnpRequestParser::HeaderL(const TDesC8& aFieldName, TDesC8& aFieldValue)
+	{
+	__FLOG(_L8("-> Got header value pair"));
+	__FLOG_2(_L8("%S: %S"), &aFieldName, &aFieldValue);
+	
+	RStringF name = iRequest->StringPool().OpenFStringL(aFieldName);
+	CleanupClosePushL(name);
+	
+	iRequest->Handle().GetHeaderCollection().SetRawFieldL(name, aFieldValue, KHeaderSeparator);
+	
+	CleanupStack::PopAndDestroy(&name);
+	}
+
+TInt CUpnpRequestParser::BodySizeL()
+	{
+	// Notify the sender that all the request headers have been parsed.
+	iObserver.GotHeaders();
+	
+	//First check for a Transfer-Encoding header field.
+	iRequest->Handle().SetBody(*this);
+	THTTPHdrVal value;
+	RStringF name = iRequest->StringPool().StringF(HTTP::ETransferEncoding, THTTPTable::Table());
+
+	if( iRequest->Handle().GetHeaderCollection().GetField(name, 0, value) == KErrNone )
+		{
+		// It exists - what's the value?
+		if( value.Type() == THTTPHdrVal::KStrFVal &&
+			value.StrF().Index(THTTPTable::Table()) == HTTP::EChunked )
+			{
+			// The Transfer-Encoding header is Chunked and as the chunked
+			// encoding is removed, we remove the header.
+			iRequest->Handle().GetHeaderCollection().RemoveField(name);
+			
+			__FLOG(_L8("-> Request has chunked body"));
+			// As the entity body is chunked the overall data size is unknown.
+			iOverallDataSize = MHttpMessageParserObserver::EChunked;
+			}
+		}
+
+	else
+		{
+		// Transfer-Encoding header was not present - now check for a 
+		// Content-Length header.
+		name = iRequest->StringPool().StringF(HTTP::EContentLength, THTTPTable::Table());
+		TInt err = iRequest->Handle().GetHeaderCollection().GetField(name, 0, value);
+		
+		if( err != KErrNone && err != KErrNotFound )
+			User::Leave(err);
+			
+		if( err == KErrNone && value.Type() == THTTPHdrVal::KTIntVal )
+			{
+			// Content-Length header value specified the length of entity in bytes.
+			iOverallDataSize = value.Int();
+			__FLOG_1(_L8("-> Request body length = %d"), iOverallDataSize);
+			}
+		}
+		
+	return iOverallDataSize;	
+	}
+
+void CUpnpRequestParser::BodyChunkL(const TDesC8& aData)
+	{
+	__FLOG(_L8("-> Got request body chunk"));
+	__FLOG_1(_L8("%S"), &aData);
+	iFlags |= EBodyPresent;
+	
+	if (aData.Length() > 0)
+		{
+		iBodyParts.Append(aData);
+		}
+
+	// Only notify the client that there is a body part if there is one.
+	if (iBodyParts.Count() > 0)
+		{
+		// Notify the sender about the presence of the body. He can then call
+		// MHTTPDataSupplier::GetNextDataPart() to get the body data.
+		iObserver.GotBodyData();
+		}
+	}
+
+void CUpnpRequestParser::BodyCompleteL()
+	{
+	__FLOG(_L8("-> Request body complete"));
+	iFlags |= EBodyComplete;
+	}
+
+void CUpnpRequestParser::MessageCompleteL(const TPtrC8& aExcessData)
+	{
+	__FLOG(_L8("-> Message complete"));
+	
+	if ( aExcessData.Length() > 0 || iRawDataArray.Count() > 0 )
+		{
+		__FLOG(_L8("->Excess Data:"));
+		__FLOG_1(_L8("%S"), &aExcessData);
+
+		iFlags |= EExcessData;
+		}
+	else
+		{
+		__FLOG(_L8("-> No excess data"));		
+		}
+	
+	// Post a message to the sender with aExcessData as the payload
+	TInt excessDataLen = aExcessData.Length();
+	TInt count = iRawDataArray.Count();
+	while(count > 0)
+		{
+		excessDataLen += iRawDataArray[count-1].Length();
+		count--;
+		}	
+	
+	TInt lenToTrim = iMsgBuf.Length() - excessDataLen;
+	iMsgBuf.TrimStart(lenToTrim);	
+	iObserver.ParsingComplete(iMsgBuf);
+	}
+
+TInt CUpnpRequestParser::HandleParserError(TInt aError)
+	{
+	__FLOG_1(_L8("-> HTTP message parser received error: %d"), aError);
+	iRawDataArray.Reset();
+	iBodyParts.Reset();
+	iObserver.ParserError(aError);
+	return KErrNone;
+	}
+
+EXPORT_C void CUpnpRequestParser::ParseRequest(RMemChunk& aMessage, CRequest* aRequest)
+	{
+	__FLOG(_L8("-> Parsing request"));
+	__ASSERT_DEBUG(aRequest, TUPnPMessagePanic::Panic(TUPnPMessagePanic::EMissingRequest));
+	__ASSERT_DEBUG(!aMessage.IsEmpty(), TUPnPMessagePanic::Panic(TUPnPMessagePanic::ENoMessage));
+
+	iRequest = aRequest;
+	if(!iMsgBuf.IsEmpty())
+		{
+		iMsgBuf.Init();	
+		}
+	iMsgBuf.Assign(aMessage);
+	TPtrC8 rMBufPtr;
+	RMemCell* rMBuf;
+	TMemCellIterator mBufIter(iMsgBuf);
+	TInt err = KErrNone;
+	while((rMBuf = mBufIter++) != NULL)
+		{
+		rMBufPtr.Set(rMBuf->Ptr(), rMBuf->Length());
+		err = iRawDataArray.Append(rMBufPtr);
+		if(err != KErrNone)
+			{
+			HandleParserError(err);
+			break;
+			}
+		}
+	
+	if(err == KErrNone)
+		{
+		// Initiate the message parser.
+		iMessageParser.ReceivedMessageData();
+		}
+	}
+
+EXPORT_C void CUpnpRequestParser::ResetParser()
+	{
+	__FLOG(_L8("-> Request parser reset"));
+	iMsgBuf.Init();
+	iMessageParser.Reset();
+	iRawDataArray.Reset();
+	iBodyParts.Reset();
+	iOverallDataSize = 0;
+	iFlags &= ~EExcessData;
+	}