applayerpluginsandutils/httpprotocolplugins/filters/ValidationFilter.cpp
changeset 0 b16258d2340f
equal deleted inserted replaced
-1:000000000000 0:b16258d2340f
       
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #ifdef MARM_ARMV5
       
    17 #pragma push
       
    18 #pragma O3
       
    19 #pragma Otime
       
    20 #endif
       
    21 
       
    22 #include "ValidationFilter.h"
       
    23 #include <http/rhttptransaction.h>
       
    24 #include <http/rhttpheaders.h>
       
    25 #include <http/mhttpdatasupplier.h>
       
    26 #include <httpstringconstants.h>
       
    27 #include <httperr.h>
       
    28 #include "corefilterspanic.h"
       
    29 
       
    30 CValidationFilter::CValidationFilter()
       
    31 : iStringTable(RHTTPSession::GetTable())
       
    32 	{ 
       
    33 	__LOG(_L("**********VF LOADED**********"));
       
    34 	}
       
    35 
       
    36 CEComFilter* CValidationFilter::InstallFilterL(TAny* aSession)
       
    37 	{
       
    38 	RHTTPSession* session = REINTERPRET_CAST(RHTTPSession*, aSession);
       
    39 	CValidationFilter* filter = new (ELeave) CValidationFilter();
       
    40 	CleanupStack::PushL(filter);
       
    41 	filter->ConstructL(*session);
       
    42 	CleanupStack::Pop(filter); 
       
    43 	return filter;
       
    44 	}
       
    45 
       
    46 void CValidationFilter::ConstructL(RHTTPSession aSession)
       
    47 	{
       
    48 	iStringPool = aSession.StringPool();
       
    49 	aSession.FilterCollection().AddFilterL(*this, THTTPEvent::EAnyTransactionEvent,		// Any transaction event
       
    50 											RStringF(),									// Any header
       
    51 											KAnyStatusCode,								// Any status code
       
    52 											MHTTPFilter::ETidyUp,						// Priority of filter
       
    53 											iStringPool.StringF(HTTP::EValidation,iStringTable));	// Name of filter
       
    54 	}
       
    55 
       
    56 CValidationFilter::~CValidationFilter()
       
    57 	{
       
    58 	__LOG(_L("**********VF UNLOADED**********"));
       
    59 	}
       
    60 
       
    61 
       
    62 void CValidationFilter::MHFUnload(RHTTPSession,THTTPFilterHandle)
       
    63 	{
       
    64 	// We must be only registered on one session, as we register in our
       
    65 	// ConstructL and no-one else has a pointer to us. Therefore, we
       
    66 	// know we can be deleted at this point.
       
    67 	delete this;
       
    68 	}
       
    69 
       
    70 void CValidationFilter::MHFLoad(RHTTPSession /*aSession*/, THTTPFilterHandle /*aHandle*/)
       
    71 	{
       
    72 	}
       
    73 
       
    74 void CValidationFilter::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
       
    75 	{
       
    76 	if (aEvent.iUID != KHTTPUid)
       
    77 		return;
       
    78 	
       
    79 
       
    80 	switch(aEvent.iStatus)
       
    81 		{
       
    82 	case THTTPEvent::ESubmit:
       
    83 		{
       
    84 		__LOG(_L("VF has detected ESubmit event "));
       
    85 		iTransactionFailed=0; // reset it for a new transaction
       
    86 		ValidateRequestMethodL(aTransaction);
       
    87 		}
       
    88 		break;
       
    89 	case THTTPEvent::EResponseComplete:
       
    90 		{
       
    91 		__LOG(_L("VF has detected EResponseComplete event "));
       
    92 		//Assumption: no need to validate servers response headers or methods
       
    93 		iTransactionFailed = ValidateResponseStatusCode(aTransaction);
       
    94 	
       
    95 		THTTPEvent event = THTTPEvent::EFailed;
       
    96 
       
    97 		if(!iTransactionFailed )// no failures(4xx or 5xx messages) or errors(request errors)
       
    98 			{
       
    99 			event = THTTPEvent::ESucceeded;
       
   100 			__LOG(_L("VF sends an incoming ESucceeded"));
       
   101 			}
       
   102 		else
       
   103 			__LOG(_L("VF sends an incoming EFailed"));
       
   104 		aTransaction.SendEventL(event,THTTPEvent::EIncoming,THTTPFilterHandle::ECurrentFilter ) ;
       
   105 
       
   106 		}
       
   107 		break;
       
   108 	default:
       
   109 		if (aEvent.iStatus< 0)  //this error can only happen from incoming event
       
   110 			{
       
   111 			__LOG(_L("VF has detected a 'negative' event "));
       
   112 			aTransaction.SendEventL(THTTPEvent::EFailed,THTTPEvent::EIncoming,THTTPFilterHandle::ECurrentFilter ) ;
       
   113 			__LOG(_L("VF sends an incoming EFailed"));
       
   114 			}
       
   115 		break;
       
   116 		}
       
   117 	}
       
   118 
       
   119 
       
   120 TInt CValidationFilter::MHFRunError(TInt /*aError*/, RHTTPTransaction aTransaction, const THTTPEvent& /*aEvent*/)
       
   121 	{
       
   122 	// If anything left, we've run out of memory or something
       
   123 	// similarly catastrophic has gone wrong.
       
   124 	aTransaction.Fail();
       
   125 	return KErrNone;
       
   126 	}
       
   127 
       
   128 void CValidationFilter::MHFSessionRunL(const THTTPSessionEvent& /*aEvent*/)
       
   129 	{
       
   130 	}
       
   131 
       
   132 TInt CValidationFilter::MHFSessionRunError(TInt aError, const THTTPSessionEvent& /*aEvent*/)
       
   133 	{
       
   134 	return aError;
       
   135 	}
       
   136 
       
   137 void CValidationFilter::ValidateRequestMethodL(RHTTPTransaction aTransaction)
       
   138 	{
       
   139 	TInt method = aTransaction.Request().Method().Index(iStringTable);
       
   140 	switch (method)
       
   141 		{
       
   142 	case HTTP::EGET:
       
   143 		ValidateRequestGetL(aTransaction);
       
   144 		break;
       
   145 	case HTTP::EPOST:
       
   146 		ValidateRequestPostL(aTransaction);
       
   147 		break;
       
   148 	case HTTP::EPUT:
       
   149 		ValidateRequestPutL(aTransaction);
       
   150 		break;
       
   151 	case HTTP::EHEAD:
       
   152 		ValidateRequestHeadL(aTransaction);
       
   153 		break;
       
   154 	case HTTP::ETRACE:
       
   155 		ValidateRequestTraceL(aTransaction);
       
   156 		break;
       
   157 	case HTTP::EOPTIONS:
       
   158 		ValidateRequestOptionsL(aTransaction);
       
   159 		break;
       
   160 	default:
       
   161 		//  if  method is not a standard http 1.1 event we must not validate it
       
   162 		;
       
   163 		}
       
   164 		
       
   165 	if(!iTransactionFailed)
       
   166 		iTransactionFailed = ValidateRequestHeadersL(aTransaction);
       
   167 
       
   168 	}
       
   169 
       
   170 TBool CValidationFilter::ValidateResponseStatusCode(RHTTPTransaction aTransaction)
       
   171 	{
       
   172 	TInt statusCode = aTransaction.Response().StatusCode();
       
   173 	// 400 to 599 is the error and warning range of http status codes
       
   174 	if (statusCode >= 300 && statusCode <1000)
       
   175 		return ETrue;
       
   176 	return EFalse;
       
   177 	}
       
   178 	
       
   179 TBool CValidationFilter::RequestFailIfContainsBodyL(RHTTPTransaction aTransaction)
       
   180 	{
       
   181 	if (aTransaction.Request().HasBody())
       
   182 		{
       
   183 		FailAndCancelL(aTransaction, KErrHttpRequestHasBody);
       
   184 		return ETrue; 
       
   185 		}
       
   186 	return EFalse;
       
   187 	}
       
   188 
       
   189 
       
   190 void CValidationFilter::ValidateRequestGetL(RHTTPTransaction aTransaction)
       
   191 	{
       
   192 	iTransactionFailed = RequestFailIfContainsBodyL(aTransaction);
       
   193 	}
       
   194 
       
   195 
       
   196 void CValidationFilter::ValidateRequestHeadL(RHTTPTransaction aTransaction)
       
   197 	{
       
   198 	iTransactionFailed = RequestFailIfContainsBodyL(aTransaction);
       
   199 	}
       
   200 
       
   201 
       
   202 void CValidationFilter::ValidateRequestTraceL(RHTTPTransaction aTransaction)
       
   203 	{
       
   204 	iTransactionFailed = RequestFailIfContainsBodyL(aTransaction);
       
   205 	}
       
   206 
       
   207 
       
   208 void CValidationFilter::ValidateRequestOptionsL(RHTTPTransaction aTransaction)
       
   209 	{
       
   210 	iTransactionFailed = RequestFailIfContainsBodyL(aTransaction);
       
   211 	}
       
   212 
       
   213 
       
   214 void CValidationFilter::ValidateRequestPostL(RHTTPTransaction aTransaction)
       
   215 	{
       
   216 
       
   217    	// 1.0 Origin Server can't handle body  data where size is unknonwn [rfc2616 section 4.4.5]
       
   218   	if (aTransaction.Request().HasBody() && aTransaction.Request().Body()->OverallDataSize() == KErrNotFound)
       
   219 		{
       
   220 		// Get version
       
   221 		RHTTPConnectionInfo connInfo = aTransaction.Session().ConnectionInfo();
       
   222 		THTTPHdrVal httpVersion;
       
   223 		if (connInfo.Property(iStringPool.StringF(HTTP::EHTTPVersion,iStringTable), httpVersion))
       
   224 			{
       
   225 			if ( httpVersion.StrF() == iStringPool.StringF(HTTP::EHttp10,iStringTable) )
       
   226 				{
       
   227 				FailAndCancelL(aTransaction,KErrHttpPostReqBodyWithoutSizeOnHTTP10);
       
   228 				iTransactionFailed=ETrue;
       
   229 				}
       
   230 			}
       
   231 		}
       
   232 	}
       
   233 
       
   234 void CValidationFilter::ValidateRequestPutL(RHTTPTransaction aTransaction)
       
   235 	{
       
   236 	if(!aTransaction.Request().HasBody()) 
       
   237 		{
       
   238 		FailAndCancelL(aTransaction, KErrHttpRequestBodyMissing);
       
   239 		iTransactionFailed=ETrue;
       
   240 		}
       
   241 	}
       
   242 
       
   243 
       
   244 TBool CValidationFilter::ValidateRequestHeadersL(RHTTPTransaction aTransaction)
       
   245 	{
       
   246    	// This method returns ETrue if the transaction must fail due to invalid headers in the request
       
   247    
       
   248    	RHTTPHeaders  requestHeaderSet =aTransaction.Request().GetHeaderCollection();
       
   249  	//request with body must have at least a content-type header for the body
       
   250  
       
   251    	TBool hasBody = aTransaction.Request().HasBody();
       
   252   	if (hasBody)
       
   253   		{
       
   254   		TInt bodySize = aTransaction.Request().Body()->OverallDataSize();
       
   255   		if (bodySize != 0)
       
   256   			{
       
   257   			THTTPHdrVal hVal;
       
   258   			TBool hasContentType = (requestHeaderSet.GetField(iStringPool.StringF(HTTP::EContentType,iStringTable),0,hVal) != KErrNotFound);
       
   259   			if (!(hasContentType )) 
       
   260   				{
       
   261   				FailAndCancelL(aTransaction, KErrHttpEntityHeaderMissingContentType);
       
   262   				return ETrue;
       
   263   				}	
       
   264   			}
       
   265   		}
       
   266   	
       
   267 	THTTPHdrFieldIter fields = requestHeaderSet.Fields();
       
   268 	fields.First();
       
   269 	while (fields.AtEnd() == EFalse)
       
   270 		{
       
   271 		TInt field = iStringPool.StringF(fields()).Index(iStringTable);
       
   272 		switch (field)
       
   273 			{	
       
   274 		// Entity Headers
       
   275 		case HTTP::EAllow:
       
   276 		case HTTP::EContentEncoding:
       
   277 		case HTTP::EContentLanguage:
       
   278 		case HTTP::EContentLength:
       
   279 		case HTTP::EContentLocation:
       
   280 		case HTTP::EContentMD5:
       
   281 		case HTTP::EContentRange:
       
   282 		case HTTP::EContentType:
       
   283 		case HTTP::ELastModified:
       
   284 		case HTTP::EExpires:	
       
   285 			if (hasBody) // if no body in the request, remove all entity headers 
       
   286 				break;
       
   287 			// else fall through and remove the field
       
   288 		// Response Headers (not allowed in requests)
       
   289 		case HTTP::EAcceptRanges:
       
   290 		case HTTP::EAge:
       
   291 		case HTTP::EETag:
       
   292 		case HTTP::ELocation:
       
   293 		case HTTP::EProxyAuthenticate:
       
   294 		case HTTP::ERetryAfter:
       
   295 		case HTTP::EServer:
       
   296 		case HTTP::ESetCookie:
       
   297 		case HTTP::EVary:
       
   298 		case HTTP::EWWWAuthenticate:
       
   299 			requestHeaderSet.RemoveField(iStringPool.StringF(field,iStringTable));
       
   300 			break;
       
   301 		default:
       
   302 			break;
       
   303 			};
       
   304 		++fields;
       
   305 		}
       
   306 	return EFalse;
       
   307 	}
       
   308 
       
   309 
       
   310 void CValidationFilter::FailAndCancelL(RHTTPTransaction aTransaction, THTTPEvent aStatus)
       
   311 	{
       
   312 	aTransaction.Cancel(THTTPFilterHandle::ECurrentFilter);
       
   313 	__LOG(_L("VF cancels the transaction"));
       
   314 
       
   315 	aTransaction.SendEvent(aStatus,THTTPEvent::EIncoming,THTTPFilterHandle::ECurrentFilter );
       
   316 	__LOG1(_L("VF sends an incoming error: %d"), aStatus.iStatus);
       
   317 
       
   318 	aTransaction.SendEventL(THTTPEvent::EFailed,THTTPEvent::EIncoming,THTTPFilterHandle::ECurrentFilter );
       
   319 	__LOG(_L("VF sends an incoming EFailed"));
       
   320 	}
       
   321 
       
   322 #ifdef MARM_ARMV5
       
   323 #pragma pop
       
   324 #endif
       
   325