diff -r 000000000000 -r 307788aac0a8 realtimenetprots/sipfw/SIP/Codec/src/CSIPPreParser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/realtimenetprots/sipfw/SIP/Codec/src/CSIPPreParser.cpp Tue Feb 02 01:03:15 2010 +0200 @@ -0,0 +1,438 @@ +// Copyright (c) 2004-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: +// Name : CSIPPreParser.cpp +// Part of : SIP Codec +// Version : SIP/4.0 +// + + + + +#include "CSIPPreParser.h" +#include "CSIPHeaderNameValue.h" +#include "sipcodecerr.h" + +_LIT8 (KCRLFCRLF, "\r\n\r\n"); +_LIT8 (KCRCRLF, "\r\r\n"); +_LIT8 (KLFCRLF, "\n\r\n"); + +// ----------------------------------------------------------------------------- +// CSIPPreParser::NewL +// ----------------------------------------------------------------------------- +// +CSIPPreParser* CSIPPreParser::NewL (HBufC8* aSipMessageBuf) + { + CSIPPreParser* self= CSIPPreParser::NewLC (aSipMessageBuf); + CleanupStack::Pop(self); + return self; + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::NewLC +// ----------------------------------------------------------------------------- +// +CSIPPreParser* CSIPPreParser::NewLC (HBufC8* aSipMessageBuf) + { + __ASSERT_ALWAYS (aSipMessageBuf!=0, User::Leave(KErrSipCodecPreParser)); + __ASSERT_ALWAYS (aSipMessageBuf->Length()>0, User::Leave(KErrSipCodecPreParser)); + + CSIPPreParser* self= new(ELeave)CSIPPreParser (*aSipMessageBuf); + CleanupStack::PushL(self); + self->ConstructL(aSipMessageBuf); + return self; + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::CSIPPreParser +// ----------------------------------------------------------------------------- +// +CSIPPreParser::CSIPPreParser (const TDesC8& aSipMessageDes) + : iLexBuf(aSipMessageDes) + { + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::ConstructL +// ----------------------------------------------------------------------------- +// +void CSIPPreParser::ConstructL (HBufC8* aSipMessageBuf) + { + CreateHeaderBufL (*aSipMessageBuf); + ParseL (); + // aSipMessageBuf ownership taken only after the pre-parsing has succeeded. + iSipMessageBuf = aSipMessageBuf; + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::~CSIPPreParser +// ----------------------------------------------------------------------------- +// +CSIPPreParser::~CSIPPreParser () + { + iHeaderStartArray.Close(); + delete iHeaderBuf; + delete iSipMessageBuf; + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::ParseL +// ----------------------------------------------------------------------------- +// +void CSIPPreParser::ParseL () + { + TChar chr = GetCharL(); + while (chr == ' ' || chr == '\t' || chr == '\r' || chr == '\n') + { + chr = GetCharL(); + } + + TBool headerPartEnds = EFalse; + while (!headerPartEnds) + { + switch (chr) + { + case '\n': headerPartEnds = HandleLfL(); break; + case '\r': headerPartEnds = HandleCrL(); break; + default: iHeaderBuf->Des().Append(chr); break; + } + if (!headerPartEnds) + { + chr = GetChar(); + } + } + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::FirstLineL +// ----------------------------------------------------------------------------- +// +TPtrC8 CSIPPreParser::FirstLineL () + { + // The first line of any SIP message is a request line or a status line. + TPtrC8 firstLine(GetLineL(0)); + return firstLine; + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::ContentL +// ----------------------------------------------------------------------------- +// +HBufC8* CSIPPreParser::ContentL () + { + // The ownership of the content is given to the caller. + // The function is not re-entrant. Content can be only asked once. + // The purpose of this is to avoid unnecessary copying. + __ASSERT_ALWAYS (iSipMessageBuf != 0, User::Leave (KErrSipCodecPreParser)); + + // Delete the header part from the original SIP message. "Delete" does not + // free any memory. It just changes the starting position of the descriptor + // in the original buffer. + TInt originalLength = iSipMessageBuf->Length(); + iSipMessageBuf->Des().Delete (0, iOriginalHeaderPartLength); + TInt contentLength = originalLength - iOriginalHeaderPartLength; + + // With relatively big content parts try to avoid unnecessary copying. + HBufC8* content = NULL; + if (contentLength < iOriginalHeaderPartLength) + { + // Relatively small content part. Make a copy. See HBufC8::ReAllocL. + content = iSipMessageBuf->ReAllocL (contentLength); + } + else + { + // Relatively big content part. Do not copy into smaller buffer. + content = iSipMessageBuf; + } + iSipMessageBuf = 0; + return content; + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::HeaderCount +// ----------------------------------------------------------------------------- +// +TUint CSIPPreParser::HeaderCount () + { + return iHeaderStartArray.Count(); + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::ParseNameValueL +// ----------------------------------------------------------------------------- +// +CSIPHeaderNameValue* CSIPPreParser::ParseNameValueL (TInt aIndex) + { + __ASSERT_ALWAYS (aIndex < iHeaderStartArray.Count(), + User::Leave(KErrSipCodecPreParser)); + + TUint lineStartPos = iHeaderStartArray[aIndex]; + TPtrC8 line (GetLineL(lineStartPos)); + TInt colonPos = line.Locate (':'); // find the first colon + + __ASSERT_ALWAYS (colonPos > 0, User::Leave(KErrSipCodecPreParser)); + + TPtrC8 name(line.Left(colonPos)); + TPtrC8 value(line.Mid(colonPos+1)); + + return CSIPHeaderNameValue::NewL(name, value); + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::GetLineL +// ----------------------------------------------------------------------------- +// +TPtrC8 CSIPPreParser::GetLineL (TInt aLineStartPosition) + { + __ASSERT_ALWAYS (aLineStartPosition < iHeaderBuf->Length(), + User::Leave(KErrSipCodecPreParser)); + + TPtrC8 lineStartBuf (iHeaderBuf->Des().Mid (aLineStartPosition)); + + // All the line ends (CR,LF or CRLF) have been replaced by LF. + TInt lineEndPosition = lineStartBuf.Locate('\n'); + + __ASSERT_ALWAYS (lineEndPosition > 0, User::Leave (KErrSipCodecPreParser)); + + return lineStartBuf.Left(lineEndPosition); + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::CreateHeaderBufL +// ----------------------------------------------------------------------------- +// +void CSIPPreParser::CreateHeaderBufL (const TDesC8& aSipMessageDes) + { + TLex8 lex(aSipMessageDes); + lex.SkipSpace(); + TInt headerPartEndPosition = 0; + FindHeaderPartEndPositionL (lex.Remainder(),headerPartEndPosition); + if (headerPartEndPosition <= 0) + { + User::Leave (KErrSipCodecPreParser); + } + iHeaderBuf = HBufC8::NewL(headerPartEndPosition+1); + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::FindHeaderPartEndPositionL +// ----------------------------------------------------------------------------- +// +void CSIPPreParser::FindHeaderPartEndPositionL ( + const TDesC8& aSipMessageDes, + TInt& aPosition) + { + // The header part may end only with CRLFCRLF, CRCRLF or LFCRLF + RArray positions; + CleanupClosePushL(positions); + + // CRLFCRLF + TInt CrLfCrLfPos = aSipMessageDes.Find(KCRLFCRLF); + if (CrLfCrLfPos >= 0) + { + User::LeaveIfError(positions.Append(CrLfCrLfPos)); + } + + // CRCRLF + TInt CrCrLfPos = aSipMessageDes.Find(KCRCRLF); + if (CrCrLfPos >= 0) + { + User::LeaveIfError(positions.InsertInOrder(CrCrLfPos)); + } + + // LFCRLF + TInt LfCrLfPos = aSipMessageDes.Find(KLFCRLF); + if (LfCrLfPos >= 0) + { + User::LeaveIfError(positions.InsertInOrder(LfCrLfPos)); + } + + if (positions.Count() == 0) + { + User::Leave(KErrNotFound); + } + + aPosition = positions[0]; + CleanupStack::PopAndDestroy(); // positions + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::HandleLfL +// ----------------------------------------------------------------------------- +// +TBool CSIPPreParser::HandleLfL () + { + TChar chr = GetCharL (); + switch (chr) + { + case ' ' : // LFSP + case '\t': // LFHTAB + // The header continues on the next line. + SkipSpacesAndTabsL (); + iHeaderBuf->Des().Append(' '); // replace by one space + break; + + case '\r': // LFCR + chr = GetCharL (); + if (chr == '\n') // LFCRLF + { + // Header part ends according to the old SIP specs. + // Replace LFCRLF with LF to simplify name-value parsing. + iHeaderBuf->Des().Append('\n'); + return ETrue; + } + else // LFCR"AnyText" not allowed. + { + User::Leave (KErrSipCodecPreParser); + } + + case '\n': // LFLF not allowed. + User::Leave (KErrSipCodecPreParser); + + default: // LF"AnyText" + MoveToNextLineL (); + break; + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::HandleCrL +// ----------------------------------------------------------------------------- +// +TBool CSIPPreParser::HandleCrL () + { + TChar chr = GetCharL (); + switch (chr) + { + case ' ' : // CRSP + case '\t': // CRHTAB + // The header continues on the next line. + SkipSpacesAndTabsL (); + iHeaderBuf->Des().Append(' '); // replace by one space + break; + + case '\r': // CRCR + chr = GetCharL (); + if (chr == '\n') // CRCRLF + { + // Header part ends according to the old SIP specs. + // Replace CRCRLF with LF to simplify name-value parsing. + iHeaderBuf->Des().Append('\n'); + return ETrue; + } + else // CRCR"AnyText" not allowed. + { + User::Leave (KErrSipCodecPreParser); + } + + case '\n': // CRLF + chr = GetCharL (); + switch (chr) + { + case '\n': // CRLFLF not allowed. + User::Leave (KErrSipCodecPreParser); + + case ' ' : case '\t': // CRLFSP or CRLFHTAB + // The header continues on the next line. + SkipSpacesAndTabsL (); + iHeaderBuf->Des().Append(' '); // replace by one space + break; + + case '\r': // CRLFCR + chr = GetCharL (); + if (chr == '\n') // CRLFCRLF. Header part ends. + { + // Replace with LF to simplify name-value parsing. + iHeaderBuf->Des().Append('\n'); + return ETrue; + } + else // CRLFCR"AnyText" not allowed. + { + User::Leave (KErrSipCodecPreParser); + } + + default: // CRLF"AnyText" + MoveToNextLineL (); + break; + } + break; + + default: // CR"AnyText" + MoveToNextLineL (); + break; + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::SkipSpacesAndTabsL +// ----------------------------------------------------------------------------- +// +void CSIPPreParser::SkipSpacesAndTabsL () + { + TChar chr = GetCharL (); + while (chr == ' ' || chr == '\t') + { + chr = GetCharL(); + } + UnGetChar(); // Put back the last one that was not a space or a tab + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::MoveToNextLineL +// ----------------------------------------------------------------------------- +// +void CSIPPreParser::MoveToNextLineL () + { + UnGetChar(); + // Replace the line end (CR, LF or CRLF) with LF + iHeaderBuf->Des().Append('\n'); + TUint nextLineStartPosition = iHeaderBuf->Length(); + User::LeaveIfError (iHeaderStartArray.Append(nextLineStartPosition)); + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::GetCharL +// ----------------------------------------------------------------------------- +// +inline TChar CSIPPreParser::GetCharL() + { + TChar chr = GetChar(); + if (chr == 0) + { + User::Leave (KErrSipCodecPreParser); + } + return chr; + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::GetChar +// ----------------------------------------------------------------------------- +// +inline TChar CSIPPreParser::GetChar() + { + TChar chr = iLexBuf.Get(); + if (chr != 0) iOriginalHeaderPartLength++; + return chr; + } + +// ----------------------------------------------------------------------------- +// CSIPPreParser::UnGetChar +// ----------------------------------------------------------------------------- +// +inline void CSIPPreParser::UnGetChar() + { + iLexBuf.UnGet(); + iOriginalHeaderPartLength--; + }