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 <http/rhttpsession.h>
+#include <httpstringconstants.h>
+#include <httperr.h>
+
+#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;
+ }
+ }