diff -r 000000000000 -r f5a58ecadc66 servicediscoveryandcontrol/pnp/test/upnp/upnpmessage/src/cupnprequestparser.cpp --- /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 +#include +#include + +#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; + }