--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerpluginsandutils/httpprotocolplugins/WspProtocolHandler/CWspHeaderUtils.cpp Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,391 @@
+// Copyright (c) 2001-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:
+//
+
+// System includes
+#include <wspstringconstants.h>
+#include <wspdecoder.h>
+#include <wsperror.h>
+
+// User includes
+#include "wsppanic.h"
+
+// Class signature
+#include "cwspheaderutils.h"
+
+// Constants used in this file
+const TInt KDefaultSessionHeadersBufferSize = 512;
+const TInt KByteLength = 1;
+
+const TUint8 KNullTerminator = 0x00;
+const TUint8 KConvertToShortInt = 0x80;
+
+LOCAL_C void StringArrayCleanup(TAny* aStringArray);
+
+CWspHeaderUtils* CWspHeaderUtils::NewL(CWspHeaderCodec& aCodec)
+ {
+ return new(ELeave) CWspHeaderUtils(aCodec);
+ }
+
+CWspHeaderUtils::CWspHeaderUtils(CWspHeaderCodec& aCodec)
+ :iCodec(aCodec)
+ {
+ }
+
+CWspHeaderUtils::~CWspHeaderUtils()
+ {
+ }
+
+HBufC8* CWspHeaderUtils::EncodeHeadersL(RStringPool aStringPool, RHTTPHeaders aHeaders)
+ {
+ // Create a buffer for the encoded headers
+ HBufC8* buf = HBufC8::NewL(KDefaultSessionHeadersBufferSize);
+ CleanupStack::PushL(buf);
+
+ // Encode the content-type header if it exists
+ TBool hasContentType = EncodeContentTypeL(aStringPool, aHeaders, buf);
+
+ // Go through the headers
+ THTTPHdrFieldIter fields = aHeaders.Fields();
+ fields.First();
+ while( fields.AtEnd() == EFalse )
+ {
+ // Get the field value
+ RStringF headerField = aStringPool.StringF(fields());
+
+ // Was there a content-type header present? Make sure that it is not
+ // appended a second time.
+ TInt headerFieldValue = iCodec.EncodeFieldName(headerField);
+ if( !hasContentType || headerFieldValue != WSP::EContentType )
+ {
+ // Encode the header field
+ EncodeHeaderFieldL(aHeaders, headerField, buf);
+ }
+ // Next header field
+ ++fields;
+ }
+ // Cleanup...
+ CleanupStack::Pop(buf);
+ return buf;
+ }
+
+HBufC8* CWspHeaderUtils::EncodeNoTrailerHeadersL(RStringPool aStringPool, RHTTPHeaders aHeaders, HBufC8*& aTrailerData)
+ {
+ // Need an array of RStringFs for the headers in the trailers - need to put
+ // on the cleanup stack
+ RArray<RStringF> trailerHeaders;
+ TCleanupItem arrayCleaner = TCleanupItem(&StringArrayCleanup, (TAny*) &trailerHeaders);
+ CleanupStack::PushL(arrayCleaner);
+
+ // Need to find out what headers are in the trailers
+ THTTPHdrVal trailerHeaderVal;
+ TInt index =0;
+ while( aHeaders.GetField(
+ aStringPool.StringF(WSP::ETrailer, WSP::Table),
+ index, // Zero index -> first part
+ trailerHeaderVal
+ ) != KErrNotFound )
+ {
+ __ASSERT_DEBUG( trailerHeaderVal.Type() == THTTPHdrVal::KStrFVal, Panic(KWspPanicBadTrailerHeader) );
+
+ // Got a trailer header - append to the list
+ RStringF header = trailerHeaderVal.StrF();
+ User::LeaveIfError(trailerHeaders.Append(header));
+
+ // Need to increment the reference count of this string
+ header.Copy();
+
+ // Next...
+ ++index;
+ }
+ __ASSERT_DEBUG( trailerHeaders.Count() > 0, Panic(KWspPanicNoTrailerHeaders) );
+
+ // Create a buffer for the encoded headers
+ HBufC8* bufHdrs = HBufC8::NewL(KDefaultSessionHeadersBufferSize);
+ CleanupStack::PushL(bufHdrs);
+
+ // Encode the content-type header if it exists
+ TBool hasContentType = EncodeContentTypeL(aStringPool, aHeaders, bufHdrs);
+
+ // Ok, now encode all the headers bar the ones in trailerHeaders
+ // Go through the headers
+ THTTPHdrFieldIter fields = aHeaders.Fields();
+ fields.First();
+ while( fields.AtEnd() == EFalse )
+ {
+ // Get the header field
+ RStringF headerField = aStringPool.StringF(fields());
+
+ // Was there a content-type header present? Make sure that it is not
+ // appended a second time, and only append if this is a trailer header.
+ TInt headerFieldValue = iCodec.EncodeFieldName(headerField);
+ if( !IsTrailerHeader(trailerHeaders, headerField) &&
+ (!hasContentType || headerFieldValue != WSP::EContentType) )
+ {
+ // Encode the field
+ EncodeHeaderFieldL(aHeaders, headerField, bufHdrs);
+ }
+ // Next header field
+ ++fields;
+ }
+ // Now, need to encode the trailer headers. Create a buffer for the trailer
+ // headers
+ HBufC8* bufTrls = HBufC8::NewL(KDefaultSessionHeadersBufferSize);
+ CleanupStack::PushL(bufTrls);
+
+ TInt count = trailerHeaders.Count();
+ for( TInt i=0; i < count; ++i)
+ {
+ // Encode the header field
+ EncodeHeaderFieldL(aHeaders, trailerHeaders[i], bufTrls);
+ }
+ // Pass back the encoded trailer headers and other headers
+ aTrailerData = bufTrls->ReAllocL(bufTrls->Des().Length());
+
+ // Cleanup...
+ CleanupStack::Pop(2, bufHdrs);
+ CleanupStack::PopAndDestroy(&trailerHeaders);
+
+ return bufHdrs;
+ }
+
+void CWspHeaderUtils::DecodeReplyHeadersL(RStringPool aStringPool, const TDesC8& aEncodedData, RHTTPHeaders& aHeaders)
+ {
+ // Ok, the data should have a content-type header at the start, but without
+ // the header field name - straight onto the field value. The type of the
+ // first byte will give the length of the field value.
+ TWspPrimitiveDecoder decoder = TWspPrimitiveDecoder(aEncodedData);
+
+ TInt dataLength = 0;
+ switch( decoder.VarType() )
+ {
+ case TWspPrimitiveDecoder::ELengthVal:
+ {
+ // The content-type header follows the BNF -
+ //
+ // content-type-value = content-general-form = value-length media-type
+
+ // The length of the data has been specified - extra it and include the
+ // length of value-length
+ TInt consumed = decoder.LengthVal(dataLength);
+ dataLength += consumed;
+ } break;
+ case TWspPrimitiveDecoder::EString:
+ {
+ // The content-type header follows the BNF -
+ //
+ // content-type-value = constrained-media = extension-media = *TEXT end-of-string
+
+ // The end of the string is give by a NULL terminator
+ TInt endPos = aEncodedData.Locate(KNullTerminator);
+ if( endPos == KErrNotFound )
+ {
+ // The header data is corrupt
+ User::Leave(KErrCorrupt);
+ }
+ dataLength = endPos + 1;
+ } break;
+ case TWspPrimitiveDecoder::E7BitVal:
+ {
+ // The content-type header follows the BNF -
+ //
+ // content-type-value = constrained-media = short-integer = OCTET
+
+ // The header data is a single byte long
+ dataLength = KByteLength;
+ } break;
+ default:
+ // The header data is corrupt
+ User::Leave(KErrCorrupt);
+ break;
+ }
+ // Set the content type field value
+ TPtrC8 contentTypeValue = aEncodedData.Left(dataLength);
+
+ // Set the raw data in the header object
+ TBuf8<KByteLength> contentTypeToken;
+ contentTypeToken.Append((TUint8)WSP::EContentType);
+ aHeaders.SetRawFieldL(aStringPool.StringF(WSP::EContentType, WSP::Table), contentTypeValue, contentTypeToken);
+
+ // Skip past the content-type field value
+ TPtrC8 encodedData = aEncodedData.Mid(dataLength);
+
+ // Segment the remaining data
+ DecodeHeadersL(aStringPool, encodedData, aHeaders);
+ }
+
+void CWspHeaderUtils::DecodeHeadersL(RStringPool aStringPool, const TDesC8& aEncodedData, RHTTPHeaders& aHeaders)
+ {
+ // Use a segmentor to slice-up the data buffer
+ TWspHeaderSegmenter segmentor = TWspHeaderSegmenter(aStringPool, WSP::Table, aEncodedData);
+
+ // Slice..
+ TBool done = EFalse;
+ while( !done )
+ {
+ // Get the next field
+ TWspField field;
+ TInt error = segmentor.NextL(field);
+
+ // Add the field name to the cleanup stack
+ CleanupClosePushL(field.iHdrName);
+
+ // Check for corrupt data
+ if( error == KErrCorrupt )
+ {
+ // Data is corrupt
+ User::Leave(KErrCorrupt);
+ }
+
+ // Was there a field found?
+ if( error == KErrNotFound )
+ {
+ // No more data - stop
+ done = ETrue;
+ }
+ else
+ {
+ // Set-up the field in the headers object
+ TInt headerToken = field.iHdrName.Index(WSP::Table);
+ if( headerToken == KErrNotFound )
+ {
+ // No token value so add as straight text with a NULL terminator
+ HBufC8* tokenText = HBufC8::NewLC(field.iHdrName.DesC().Length() + 1);
+ TPtr8 tokenTextBuffer(tokenText->Des());
+ tokenTextBuffer.Append(KNullTerminator);
+ aHeaders.SetRawFieldL(field.iHdrName, field.iValBuffer, *tokenText);
+ CleanupStack::PopAndDestroy(tokenText);
+ }
+ else
+ {
+ // Encoded token available so use binary token as separator
+ headerToken += KConvertToShortInt;
+ TBuf8<KByteLength> headerTokenDes;
+ headerTokenDes.Append((TUint8)headerToken);
+ aHeaders.SetRawFieldL(field.iHdrName, field.iValBuffer, headerTokenDes);
+ }
+ }
+
+ // Cleanup the field variable
+ CleanupStack::PopAndDestroy(&field.iHdrName);
+
+ }
+ }
+
+TBool CWspHeaderUtils::EncodeContentTypeL(RStringPool aStringPool, RHTTPHeaders aHeaders, HBufC8*& aBuf)
+ {
+ // Get the TPtr8 from the buffer
+ TPtr8 encodedHdrs = aBuf->Des();
+
+ // Get the content-type header, if it exists
+ RStringF headerField = aStringPool.StringF(WSP::EContentType, WSP::Table);
+ TPtrC8 encodedData;
+ TInt foundContentType = aHeaders.GetRawField(headerField, encodedData);
+ TBool hasContentType = foundContentType != KErrNotFound;
+
+ // If the content-type header exists, append to the start of the buffer
+ // without the field name.
+ if( hasContentType )
+ {
+ // Append the encoded field value - check for space first
+ while( encodedHdrs.Length() + encodedData.Length() > encodedHdrs.MaxLength() )
+ {
+ aBuf = aBuf->ReAllocL(encodedHdrs.MaxLength() + KDefaultSessionHeadersBufferSize);
+ encodedHdrs = aBuf->Des();
+ }
+ // Append the field value
+ encodedHdrs.Append(encodedData);
+ }
+ return hasContentType;
+ }
+
+void CWspHeaderUtils::EncodeHeaderFieldL(RHTTPHeaders aHeaders, RStringF aHeaderField, HBufC8*& aBuf)
+ {
+ // Check to see if the header field is well-known
+ TInt headerFieldValue = iCodec.EncodeFieldName(aHeaderField);
+
+ TBool wellKnownHeader = headerFieldValue != KErrNotFound;
+
+ // Calculate the header field length
+ TInt fieldNameLength = KByteLength;
+ if( !wellKnownHeader )
+ {
+ // The header is not well-known - need to encode the header field
+ // name as token text, which is NULL-terminated.
+ fieldNameLength = aHeaderField.DesC().Length() + 1;
+ }
+ // Need to add the header field name and then the encoded header value.
+ // First get the OTA format of the field value
+ TPtrC8 encodedData;
+ TInt err = aHeaders.GetRawField(aHeaderField, encodedData);
+
+ // Was there any error encoding the header?
+ if( err != KErrNone )
+ {
+ // Header isn't here - something has gone wrong
+ User::Leave(KWspErrMissingHeader);
+ }
+
+ // Ensure there is enough space in the buffer.
+ TPtr8 encodedHdrs = aBuf->Des();
+ while( encodedHdrs.Length() + encodedData.Length() + fieldNameLength > encodedHdrs.MaxLength() )
+ {
+ aBuf = aBuf->ReAllocL(encodedHdrs.MaxLength() + KDefaultSessionHeadersBufferSize);
+ encodedHdrs = aBuf->Des();
+ }
+ // Append the field name - check to see if well-known
+ if( wellKnownHeader )
+ {
+ // Append as an encoded byte-value - the top bit must be set, since well-known
+ // header field names are encoded as short-int ([WSP] Sect. 8.4.2.6 "Header")
+ encodedHdrs.Append(headerFieldValue | KConvertToShortInt);
+ }
+ else
+ {
+ // Append as token text
+ encodedHdrs.Append(aHeaderField.DesC());
+ encodedHdrs.Append(KNullTerminator);
+ }
+ // Append the encoded field value
+ encodedHdrs.Append(encodedData);
+ }
+
+TBool CWspHeaderUtils::IsTrailerHeader(RArray<RStringF> aTrailerHeaders, RStringF aHeaderField)
+ {
+ // Search the list of trailer headers to see if aHeaderField is in it.
+ TInt index = 0;
+ TInt count = aTrailerHeaders.Count();
+ TBool found = EFalse;
+ while( !found && index < count )
+ {
+ // Make the comparison
+ RStringF header = aTrailerHeaders[index];
+ found = header == aHeaderField;
+ ++index;
+ }
+ return found;
+ }
+
+LOCAL_C void StringArrayCleanup(TAny* aStringArray)
+ {
+ RArray<RStringF> array = *REINTERPRET_CAST(RArray<RStringF>*, aStringArray);
+
+ TInt count = array.Count();
+ for( TInt i = 0; i < count; ++i)
+ {
+ // Close the string
+ array[i].Close();
+ }
+ array.Close();
+ }