applayerpluginsandutils/httpprotocolplugins/httpheadercodec/chttpserverheaderreader.cpp
changeset 0 b16258d2340f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerpluginsandutils/httpprotocolplugins/httpheadercodec/chttpserverheaderreader.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,356 @@
+// 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 "chttpserverheaderreader.h"
+
+#include <http/rhttpsession.h>
+#include <httpstringconstants.h>
+#include <httperr.h>
+#include <inetprottextutils.h>
+
+_LIT8(KCommaSpaceSep,", ");
+_LIT8(KFieldSeparator, "\n");
+_LIT8(KCodecSpace, " ");
+_LIT8(KSemiSpaceSep," ;");
+
+const TUint KCommaChar		= ',';
+const TUint KSemiColonChar	= ';';
+const TUint KEqualsChar		= '=';
+
+
+CHttpServerHeaderReader* CHttpServerHeaderReader::NewL(RStringPool aStringPool)
+	{
+	return new (ELeave) CHttpServerHeaderReader(aStringPool);
+	}
+
+CHttpServerHeaderReader::~CHttpServerHeaderReader()
+	{
+	}
+
+CHttpServerHeaderReader::CHttpServerHeaderReader(RStringPool aStringPool)
+: CHttpHeaderReader(aStringPool)
+	{
+	}
+
+// Helper to DoAcceptL(), DoAcceptCharsetL(), DoAcceptLanguageL() and DoAcceptEncodingL() 
+// for comma-separated lists incorporating q-values..
+// name : value, value; q= 2.2, value,...
+void CHttpServerHeaderReader::DecodeGenericAcceptL(RHeaderField& aHeader, TInt aErrorCode) const
+	{
+	
+	TPtrC8 rawData;
+	aHeader.RawDataL(rawData);
+	TInt remaining = rawData.Length();
+	TPtrC8 token;
+	TInt tokensFound = 0;
+	while (remaining > 0)
+		{
+		remaining -= InetProtTextUtils::ExtractNextTokenFromList(rawData, token, KCommaChar);
+
+		TInt pos = token.Locate(KSemiColonChar);
+		if (pos < 0)
+			{
+			// No parameters. Just store the field value
+			InetProtTextUtils::RemoveWhiteSpace(token, InetProtTextUtils::ERemoveBoth);
+			SetNewFStringPartL(aHeader, tokensFound, token);
+			}
+		else if (pos==0)
+			{
+			// No valid q-value. Just store the parameter.
+			User::Leave(aErrorCode);
+			}
+		else
+			{
+			// parameter value(s) exist.
+
+			if (pos==token.Length())
+				// if no field value exists. i.e. an invalid header
+				User::Leave(aErrorCode);
+
+			// store the field
+			TPtrC8 fieldValue(token.Left(pos));
+			TPtrC8 parameters(token.Mid(pos+1));
+			InetProtTextUtils::RemoveWhiteSpace(fieldValue, InetProtTextUtils::ERemoveBoth);
+
+			CHeaderFieldPart* part = SetNewFStringPartL(aHeader, tokensFound, fieldValue);
+
+			TPtrC8 thisParam;
+			do {
+				// check if there is another parameter
+				pos = parameters.Locate(KSemiColonChar);
+				if (pos > 0)
+					{
+					if (pos==token.Length())
+						// if no field value exists. i.e. an invalid header
+						User::Leave(aErrorCode);
+
+					thisParam.Set(parameters.Left(pos));
+					parameters.Set(parameters.Mid(pos+1));
+					}
+				else
+					thisParam.Set(parameters);
+
+				
+				TInt pPos = thisParam.Locate(KEqualsChar);
+				if (pPos <= 0 || pPos==thisParam.Length())
+					// Invalid parameter, missing '=' char, or missing field value.
+					User::Leave(aErrorCode);
+
+				TPtrC8 paramField(thisParam.Left(pPos));
+ 				TPtrC8 paramData(thisParam.Mid(pPos + 1));
+
+				SetNewFStringParamL(*part, paramField, paramData);
+
+				} while (pos > 0);
+			}
+		++tokensFound;
+		}
+		
+		
+	}
+
+void CHttpServerHeaderReader::DecodeAuthorizationL(RHeaderField& aHeader) const
+	{
+	// RFC2616, section 14.8;  RFC2617, section 
+	// Authorization  = "Authorization" ":" credentials
+	// credentials = auth-scheme #auth-param
+	// credentials = "Basic" basic-credentials
+	// basic-credentials = base64-user-pass
+    // base64-user-pass  = <base64 [4] encoding of user-pass, except not limited to 76 char/line>
+    // user-pass   = userid ":" password
+    // userid      = *<TEXT excluding ":">
+    // password    = *TEXT
+	
+	// Parts are encoded with no punctuation after them and parameters are comma
+	// separated with the value in quotes. This means that for basic
+	// authentication, part 1 must be 'Basic' and part 2 is the
+	// credentials. For digest, part1 is 'Digest', and the digest
+	// response is stored in parameters.
+
+	TPtrC8 buffer;
+	aHeader.RawDataL(buffer);
+
+	TInt totalBytesConsumed = 0;
+	TInt numParam = 0;
+	CHeaderFieldPart* part = NULL;
+	TBool done = EFalse;
+
+	TPtrC8 token;
+	TInt bytesConsumed = InetProtTextUtils::ExtractNextTokenFromList(buffer, token, KCommaSpaceSep);
+	part = SetNewFStringPartL(aHeader, numParam, token);		//first assignment
+	++numParam;
+	
+	TBool equalsPresent = (token.Locate('=') != KErrNotFound);
+	if ((totalBytesConsumed == bytesConsumed) && equalsPresent)
+		{
+		// The first token has an equals sign in it. That
+		// can't be as it has to be in an Authorization scheme
+		User::Leave(KErrHttpDecodeAuthorization);
+		}
+
+	RStringF basic = iStrPool.StringF(HTTP::EBasic , RHTTPSession::GetTable());
+
+	if (token==basic.DesC())
+		{
+		// Get next part and store away
+		bytesConsumed = InetProtTextUtils::ExtractNextTokenFromList(buffer, token, KCommaSpaceSep);
+		++numParam;
+		if (bytesConsumed==0)
+			{
+			// Need a second value if "Basic"
+			User::Leave(KErrHttpDecodeAuthorization);
+			}
+
+		// Remove surrounding quotes
+		TPtrC8 val;
+		if (token[0] == '"')
+			{
+			bytesConsumed += 
+				InetProtTextUtils::ExtractQuotedStringL(token,val);
+			}
+		else
+			{
+			val.Set(token);
+			}
+		SetNewFStringPartL(aHeader, numParam - 1, val);	
+		}
+	else // Get Digest parameters. Should check if it is digest
+		{
+		while (!done)
+			{
+			TPtrC8 token;
+			TInt bytesConsumed = InetProtTextUtils::ExtractNextTokenFromList(buffer, token, KCommaSpaceSep);
+
+			done = (bytesConsumed == 0);
+			if (done) 
+				{
+				if (numParam == 0)// if we didn't find _anything_ at all...
+					User::Leave(KErrHttpDecodeAuthorization);
+				}
+			else if (token.Length() > 0)
+				{
+				totalBytesConsumed += bytesConsumed;
+
+				if (token.Locate('=') == KErrNotFound)
+					{
+					// Got a new part. Add it.
+					++numParam;
+					part = SetNewFStringPartL(aHeader, numParam - 1, token);
+					}
+				else
+					{
+					TPtrC8 paramName;
+					TPtrC8 paramVal;
+					bytesConsumed += GetParamNameAndValueL(token, paramName, paramVal, KErrHttpDecodeBasicAuth);
+					SetNewStringParamL(*part, paramName, paramVal);
+					}
+				}
+			}
+		}
+	}
+
+void CHttpServerHeaderReader::DecodeHostL(RHeaderField& aHeader) const
+	{
+	// RFC2616, section 14.23
+    // Host = "Host" ":" host [ ":" port ] ; Section 3.2.2
+	
+	// Our convention will be that a string called HTTP::EPort will be used to
+	// set a parameter holding the integer port number
+
+	// We are looking for a hostname and optional port number, 0 or more values
+
+	TPtrC8 rawData;
+	aHeader.RawDataL(rawData);
+	TInt remaining = rawData.Length();
+	TPtrC8 token;
+	TInt tokensFound =0;
+	
+	remaining -= InetProtTextUtils::ExtractNextTokenFromList(rawData, token, KFieldSeparator);
+
+	if (remaining)
+		{
+		// Should not be more data
+		}
+
+	// Check for colon in our token
+	TInt colonPos = token.Locate(':');
+	InetProtTextUtils::RemoveWhiteSpace(token, InetProtTextUtils::ERemoveBoth);
+	if (colonPos == KErrNotFound)
+		{
+		// Just a host name
+		SetNewFStringPartL(aHeader, tokensFound, token);
+		}
+	else
+		{
+		//.. also has a port number. 
+
+		TPtrC8 host(token.Left(colonPos));
+		CHeaderFieldPart* part = SetNewFStringPartL(aHeader, tokensFound, host);
+
+		if (colonPos==token.Length())
+			// No port number supplied
+			User::Leave(KErrHttpGeneralHeaderMissingHost);
+
+		TPtrC8 port(token.Mid(colonPos + 1));
+		TPtrC8 name(iStrPool.StringF(HTTP::EPort,RHTTPSession::GetTable()).DesC());
+		SetNewFStringParamL(*part, name ,port);
+		}
+	}
+
+void CHttpServerHeaderReader::DecodeExpectL(RHeaderField& aHeader) const
+	{
+	//	Expect       =  "Expect" ":" 1#expectation
+	//
+	//	expectation  =  "100-continue" | expectation-extension
+	//	expectation-extension =  token [ "=" ( token | quoted-string )
+	//	                         *expect-params ]
+	//	expect-params =  ";" token [ "=" ( token | quoted-string ) ]
+
+	TPtrC8 buffer;
+	aHeader.RawDataL(buffer);
+
+	TInt numParam = 0;
+
+	TPtrC8 token;
+	InetProtTextUtils::ExtractNextTokenFromList(buffer, token, KSemiSpaceSep);
+	++numParam;
+	
+	SetNewFStringPartL(aHeader, 0, buffer);
+	}
+
+void CHttpServerHeaderReader::DecodeTEL(RHeaderField& aHeader) const
+	{
+	//	TE        = "TE" ":" #( t-codings )
+	//	t-codings = "trailers" | ( transfer-extension [ accept-params ] )
+	//	Examples of its use are:
+	//	TE: deflate
+	//	TE:
+	//	TE: trailers, deflate;q=0.5
+       
+	DecodeGenericAcceptL(aHeader, KErrHttpDecodeTE);
+	}
+	
+/*
+ *	Methods from CHeaderReader
+ */
+
+void CHttpServerHeaderReader::DecodeHeaderL(RHeaderField& aHeader)
+	{
+	RStringF fieldStr = iStrPool.StringF(aHeader.Name());
+	switch( fieldStr.Index(RHTTPSession::GetTable()) )
+		{
+	case HTTP::EAccept:
+		DecodeGenericAcceptL(aHeader, KErrHttpDecodeAccept);
+		break;
+	case HTTP::EAcceptCharset:
+		DecodeGenericAcceptL(aHeader, KErrHttpDecodeAcceptCharset);
+		break;
+	case HTTP::EAuthorization:
+		DecodeAuthorizationL(aHeader);
+		break;
+	case HTTP::EAcceptLanguage:
+		DecodeGenericAcceptL(aHeader, KErrHttpDecodeAcceptLanguage);
+		break;
+	case HTTP::EAcceptEncoding:
+		DecodeGenericAcceptL(aHeader, KErrHttpDecodeAcceptEncoding);
+		break;
+	case HTTP::EHost:
+		DecodeHostL(aHeader);
+		break;
+	case HTTP::EUserAgent:
+		DecodeTokenListHeaderL(aHeader, KCodecSpace());
+		break;
+	case HTTP::EIfMatch:
+		DecodeTokenListHeaderL(aHeader, KCommaSpaceSep());
+		break;
+	case HTTP::EIfNoneMatch:
+		DecodeTokenListHeaderL(aHeader, KCommaSpaceSep());
+		break;
+	case HTTP::EIfModifiedSince:
+		DecodeDateL(aHeader);
+		break;
+	case HTTP::EIfUnmodifiedSince:
+		DecodeDateL(aHeader);
+		break;
+	case HTTP::EExpect:
+		DecodeExpectL(aHeader);
+		break;
+	case HTTP::ETE:
+		DecodeTEL(aHeader); 
+		break;
+	default:
+		User::Leave(KErrNotSupported);
+		}
+	}