diff -r 000000000000 -r b16258d2340f applayerpluginsandutils/httpprotocolplugins/httpheadercodec/chttpgeneralheaderwriter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/applayerpluginsandutils/httpprotocolplugins/httpheadercodec/chttpgeneralheaderwriter.cpp Tue Feb 02 01:09:52 2010 +0200 @@ -0,0 +1,334 @@ +// Copyright (c) 2002-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 "chttpgeneralheaderwriter.h" + +#include +#include +#include + +#include "CHeaderField.h" + +_LIT8(KSemiSpaceSep,"; "); + +CHttpGeneralHeaderWriter* CHttpGeneralHeaderWriter::NewL(RStringPool aStringPool) +/** + Factory constructor. + @internalComponent + @param aStringPool The current string pool. + @return A pointer to a fully initialised object. + @leave KErrNoMemory Not enough memory to create object. +*/ + { + return new(ELeave)CHttpGeneralHeaderWriter(aStringPool); + } + +CHttpGeneralHeaderWriter::~CHttpGeneralHeaderWriter() +/** + Destructor + @internalComponent +*/ + { + } + +CHttpGeneralHeaderWriter::CHttpGeneralHeaderWriter(RStringPool aStringPool) +: CHttpHeaderWriter(aStringPool) +/** + Constructor + @internalComponent + @param aStringPool The current string pool. +*/ + { + } + +void CHttpGeneralHeaderWriter::EncodeCacheControlL(RHeaderField& aHeader) const +/** + Encodes a Cache-Control header. RFC 2616 section 14.9 - + + Cache-Control = "Cache-Control" ":" 1#cache-directive + cache-directive = cache-request-directive + | cache-response-directive + cache-request-directive = "no-cache" + | "no-store" + | "max-age" "=" delta-seconds + | "max-stale" [ "=" delta-seconds ] + | "min-fresh" "=" delta-seconds + | "no-transform" + | "only-if-cached" + | cache-extension + + cache-response-directive= "public" + | "private" [ "=" <"> 1#field-name <"> ] + | "no-cache" [ "=" <"> 1#field-name <"> ] + | "no-store" + | "no-transform" + | "must-revalidate" + | "proxy-revalidate" + | "max-age" "=" delta-seconds + | "s-maxage" "=" delta-seconds + | cache-extension + + cache-extension = token [ "=" ( token | quoted-string ) ] + + The cache-control header value is a comma separated list of values with at + least one value. + @internalComponent + @param aHeader The cache-control header field to encode. + @leave CHttpWriter::DoTokenCsvListHeaderL + @todo Is there any point in this? Why not call DoTokenCsvListHeaderL() + directly +*/ + { + DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeCacheControl); + } + +void CHttpGeneralHeaderWriter::EncodeConnectionL(RHeaderField& aHeader) const +/** + Decodes the Connection header. RFC2616 section 14.10 - + + Connection = "Connection" ":" 1#(connection-token) + connection-token = token + The connection header value is a comma separated list of values with at least + one value. + @internalComponent + @param aHeader The connection header field to encode. + @leave CHttpWriter::DoTokenCsvListHeaderL + @todo Is there any point in this? Why not call DoTokenCsvListHeaderL() + directly +*/ + { + DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeConnection); + } + +void CHttpGeneralHeaderWriter::EncodeDateL(RHeaderField& aHeader) const +/** + Encodes the date header. RFC2616 section 14.18 - + + Date = "Date" ":" HTTP-Date + + The HTTP-Date format has a few formats. E.g. Date: Tue, 15 Nov 1994 08:12:31 GMT + @internalComponent + @param aHeader The date header field to encode. + @leave CHttpWriter::EncodeGenericDateL + @todo Is there any point in this? Why not call EncodeGenericDateL() + directly +*/ + { + EncodeGenericDateL(aHeader, KErrHttpEncodeDate); + } + +void CHttpGeneralHeaderWriter::EncodeTransferEncodingL(RHeaderField& aHeader) const +/** + Encodes the transfer-encoding header. RFC2616 section 14.41 - + + Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding + transfer-coding = "chunked" | transfer-extension + transfer-extension = token *( ";" parameter ) + parameter = attribute "=" value + attribute = token + value = token | quoted-string + + The transfer-encoding header is a comma separated list of values with at + least one value. + @internalComponent + @param aHeader The transfer-encoding header field to encode. + @leave CHttpWriter::DoTokenCsvListHeaderL + @todo Is there any point in this? Why not call DoTokenCsvListHeaderL() + directly +*/ + { + DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeTransferEncoding); + } + +void CHttpGeneralHeaderWriter::EncodeContentTypeL(RHeaderField& aHeader) const +/** + Encodes the content-type header. RFC2616 section 14.17 + + Content-Type = "Content-Type" ":" media-type + media-type = type "/" subtype *( ";" parameter ) + type = token + subtype = token + parameter = attribute '=' value + attribute = token + value = token | quoted-string + + The content-type header has a single media-type value. The atttribute + is normally the 'charset'. E.g. Content-Type: text/html; charset=ISO-8859-4 + @internalComponent + @param aHeader The content-type header field to encode. + @leave RHeaderField::BeginRawDataL + @leave RHeaderField::WriteRawDataL + @leave CHttpWriter::WriteRawStrFPartL + @leave KErrHttpEncodeContentType There are no value tokens, the + parameter was empty or the parameter + was not a string type value. +*/ + { + __START_PERFORMANCE_LOGGER(); + // Check part 1 + THeaderFieldPartIter iter = aHeader.PartsL(); + iter.First(); + if( iter.AtEnd() ) + { + // The header value is empty! + User::Leave(KErrHttpEncodeContentType); + } + aHeader.BeginRawDataL(); + const CHeaderFieldPart* part = WriteRawStrFPartL(aHeader, iter, KErrHttpEncodeContentType); + + // Check for parameters... + THeaderFieldParamIter iter2 = part->Parameters(); + iter2.First(); + while( !iter2.AtEnd() ) + { + // Got a parameter - write a semicolon separator + aHeader.WriteRawDataL(KSemiSpaceSep); + const CHeaderFieldParam* param = iter2(); + if( !param ) + { + // Empty parameter! + User::Leave(KErrHttpEncodeContentType); + } + // Anticipate only string parameter values + THTTPHdrVal paramVal = param->Value(); + if( paramVal.Type() != THTTPHdrVal::KStrFVal ) + { + // Was not a string value... + User::Leave(KErrHttpEncodeContentType); + } + RStringF paramName = iStringPool.StringF(param->Name()); + aHeader.WriteRawDataL(paramName.DesC()); + aHeader.WriteRawDataL('='); + aHeader.WriteRawDataL(paramVal.StrF().DesC()); + + // Move onto the next parameter, writing a separator as necessary + ++iter2; + } + // All done! + aHeader.CommitRawData(); + __END_PERFORMANCE_LOGGER(_L(",CHttpGeneralHeaderWriter::EncodeContentTypeL()")); + } + +void CHttpGeneralHeaderWriter::EncodeContentLengthL(RHeaderField& aHeader) const +/** + Encodes the content-length header. RFC2616 section 14.13 - + + Content-Length = "Content-Length" ":" 1*DIGIT + + The content-length value is a number with at least one digit. + @internalComponent + @param aHeader The content-length header field to encode. + @leave CHttpWriter::EncodeGenericNumberHeaderL + @todo Is there any point in this? Why not call EncodeGenericNumberHeaderL() + directly. +*/ + { + EncodeGenericNumberHeaderL(aHeader, KErrHttpEncodeContentLength); + } + +/* + * Methods from CHeaderWriter + */ + +void CHttpGeneralHeaderWriter::EncodeHeaderL(RHeaderField& aHeader) +/** + Encodes the header field value. + @internalComponent + @param aHeader The header field to be encoded. + @leave CHttpGeneralHeaderWriter::EncodeCacheControlL + @leave CHttpGeneralHeaderWriter::EncodeConnectionL + @leave CHttpGeneralHeaderWriter::EncodeDateL + @leave CHttpGeneralHeaderWriter::EncodeTransferEncodingL + @leave CHttpGeneralHeaderWriter::EncodeContentLengthL + @leave CHttpWriter::DoTokenCsvListHeaderL + @leave KErrNotSupported The writer was asked to encode a header that + is does not support. +*/ + { + RStringF fieldStr = iStringPool.StringF(aHeader.Name()); + switch( fieldStr.Index(iStringTable) ) + { + case HTTP::ECacheControl: + { + EncodeCacheControlL(aHeader); + } break; + case HTTP::EConnection: + { + EncodeConnectionL(aHeader); + } break; + case HTTP::EDate: + { + EncodeDateL(aHeader); + } break; + case HTTP::EPragma: + { + // RFC2616 section 14.32 - + // + // Pragma = "Pragma" ":" 1#pragma-directive + // pragma-directive = "no-cache" | extension-pragma + // extension-pragma = token [ "=" ( token ! quoted-string ) ] + // + // The pragma header value is a comma separated list of values with at + // least one value. + DoTokenCsvListHeaderL(aHeader, KErrHttpEncodePragma); + } break; + case HTTP::ETransferEncoding: + { + EncodeTransferEncodingL(aHeader); + } break; + case HTTP::EContentEncoding: + { + DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeContentEncoding); + } break; + case HTTP::EContentLanguage: + { + // RFC2616 section 14.12 - + // + // Content-Language = "Content-Language" ":" 1#language-tag + // + // The content-language header value is a comma separated list of values + // with at least one value. + DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeContentLanguage); + } break; + case HTTP::EUpgrade: + { + DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeUpgrade); + } break; + case HTTP::EContentLength: + { + EncodeContentLengthL(aHeader); + } break; + case HTTP::EContentLocation: + { + DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeContentLocation); + } break; + case HTTP::EContentMD5: + { + DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeContentMD5); + } break; + case HTTP::EContentType: + { + EncodeContentTypeL(aHeader); + } break; + case HTTP::EExpires: + case HTTP::ELastModified: + { + EncodeDateL(aHeader); + }break; + default: + User::Leave(KErrNotSupported); + break; + } + }