pkiutilities/ocsp/test/tocsphttpfilter/ocsphttpfilter.cpp
changeset 0 164170e6151a
equal deleted inserted replaced
-1:000000000000 0:164170e6151a
       
     1 // Copyright (c) 2008-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 #include "ocsphttpfilter.h"
       
    17 #include <e32cmn.h>
       
    18 #include <e32std.h>
       
    19 #include <e32property.h>
       
    20 #include <http/rhttptransaction.h>
       
    21 #include <http/rhttpheaders.h>
       
    22 #include <http/thttphdrval.h>
       
    23 #include <httpstringconstants.h>
       
    24 #include "testfilterparameters.h"
       
    25 
       
    26 // Filter name used to register the filter
       
    27 _LIT8(KFilterName,"tocsphttpfilter");
       
    28 
       
    29 // Filter log file read by the test code
       
    30 _LIT(KFilterLogFileName, "\\tocsphttpfilter.log");
       
    31 
       
    32 // HTTPMethod StartTimeInMicroseconds
       
    33 _LIT8(KFilterLogFormat1, "%S %Ld");
       
    34 // StopTimeInMicroseconds
       
    35 _LIT8(KFilterLogFormat2, " %Ld\n"); 
       
    36 
       
    37 // Canned responses
       
    38 _LIT8(KCannedResponseInteralError, "\x30\x03\x0a\x01\x02");
       
    39 _LIT8(KCannedResponseTryLater, "\x30\x03\x0a\x01\x03");
       
    40 _LIT8(KCannedResponseCorruptOCSPData, "\x30\x03\x0a\x01\xf0");
       
    41 
       
    42 // A non-existent ocsp responder. Redirect requests to this
       
    43 // responder to simulate a missing response
       
    44 _LIT8(KNonExistentServer, "http://42.042.042.042:0420/");
       
    45 
       
    46 // HTTP response header for content-type (canned corrupted)
       
    47 _LIT8(KOCSPContentTypeResponseCorrupted, "application/ocsp-reponse");
       
    48 
       
    49 // Byte offset (+1) of Responder ID field of OCSPResponse
       
    50 const TInt KOCSPResponderIDOffset = 42;
       
    51 
       
    52 const TInt KTimeMilliToMicro = 1000;
       
    53 
       
    54 COCSPHTTPFilter::COCSPHTTPFilter()
       
    55 		: iLogLineCompleted(ETrue)
       
    56 	{
       
    57 	}
       
    58 
       
    59 CEComFilter* COCSPHTTPFilter::InstallFilterL(TAny* aSession)
       
    60 	{
       
    61 	RHTTPSession* session = reinterpret_cast<RHTTPSession*>(aSession);
       
    62 	COCSPHTTPFilter* filter = new (ELeave) COCSPHTTPFilter();
       
    63 	CleanupStack::PushL(filter);
       
    64 	filter->ConstructL(*session);
       
    65 	CleanupStack::Pop(filter);
       
    66 	return filter;
       
    67 	}
       
    68 
       
    69 void COCSPHTTPFilter::ConstructL(const RHTTPSession& aSession)
       
    70 	{
       
    71 	iStringPool = aSession.StringPool();
       
    72 	iFilterName = iStringPool.OpenFStringL(KFilterName);
       
    73 	// Register the filter for submit events
       
    74 	aSession.FilterCollection().AddFilterL(*this, THTTPEvent::EAnyTransactionEvent, MHTTPFilter::EClientFilters, iFilterName);
       
    75 	User::LeaveIfError(iFs.Connect());
       
    76 	User::LeaveIfError(iLogFile.Replace(iFs, KFilterLogFileName, EFileShareAny|EFileWrite));
       
    77 	}
       
    78 
       
    79 COCSPHTTPFilter::~COCSPHTTPFilter()
       
    80 	{
       
    81 	iFilterName.Close();
       
    82 	iLogFile.Close();
       
    83 	iFs.Close();
       
    84 	delete iCustomDataSupplier;
       
    85 	}
       
    86 
       
    87 void COCSPHTTPFilter::MHFLoad(RHTTPSession, THTTPFilterHandle)
       
    88 	{
       
    89 	++iLoadCount;
       
    90 	}
       
    91 
       
    92 void COCSPHTTPFilter::MHFUnload(RHTTPSession /*aSession*/, THTTPFilterHandle)
       
    93 	{
       
    94 	if (--iLoadCount)
       
    95 		return;
       
    96 
       
    97 	delete this;
       
    98 	}
       
    99 
       
   100 void COCSPHTTPFilter::MHFRunL(RHTTPTransaction aTransaction,
       
   101 									const THTTPEvent& aEvent)
       
   102 	{
       
   103 	// Read test parameters
       
   104 	TInt countDropResp, numDelayResp;
       
   105 	TInt countCorruptHTTPDataHeader, countCorruptHTTPDataBodySizeLarge, countCorruptHTTPDataBodySizeSmall;
       
   106 	TInt countCorruptOCSPData;
       
   107 	TInt countInternalErrorResp, countTryLaterResp;
       
   108 	TInt countSigValidateFailure;
       
   109 	ReadTestParameters(numDelayResp, countDropResp,
       
   110 			countCorruptHTTPDataHeader, countCorruptHTTPDataBodySizeLarge, countCorruptHTTPDataBodySizeSmall,
       
   111 			countCorruptOCSPData,
       
   112 			countInternalErrorResp, countTryLaterResp, 
       
   113 			countSigValidateFailure);
       
   114 
       
   115 	switch (aEvent.iStatus)
       
   116 		{
       
   117 	case THTTPEvent::ESubmit:
       
   118 		// Start of the HTTP transaction
       
   119 		iDataSupplied = EFalse;
       
   120 		iLogLineCompleted = EFalse;
       
   121 		LogTransactionStartL(aTransaction);
       
   122 		
       
   123 		if (countDropResp > 0)
       
   124 			{
       
   125 			// Drop the request
       
   126 			--countDropResp;
       
   127 			TUriParser8 uri;
       
   128 			uri.Parse(KNonExistentServer);
       
   129 			aTransaction.Request().SetURIL(uri);
       
   130 			}
       
   131 		break;
       
   132 	case THTTPEvent::EGotResponseHeaders:
       
   133 		{
       
   134 		RHTTPResponse response = aTransaction.Response();
       
   135 		RHTTPHeaders headers = response.GetHeaderCollection();
       
   136 		RStringPool stringPool = aTransaction.Session().StringPool();
       
   137 
       
   138 		// Modify http body size if we plan to modify the body (response data) later
       
   139 		if (countInternalErrorResp > 0 || countTryLaterResp > 0 || countCorruptOCSPData > 0) // Common code since size is same for all canned responses
       
   140 			{
       
   141 			// Create the data supplier
       
   142 			delete iCustomDataSupplier;
       
   143 			iCustomDataSupplier = NULL;
       
   144 			TPtrC8 ptr(KCannedResponseInteralError);
       
   145 			RStringF contentLengthString = stringPool.StringF(HTTP::EContentLength, RHTTPSession::GetTable());
       
   146 			if (countTryLaterResp > 0)
       
   147 				{
       
   148 				ptr.Set(KCannedResponseTryLater);
       
   149 				}
       
   150 			else if (countCorruptOCSPData > 0)
       
   151 				{
       
   152 				ptr.Set(KCannedResponseCorruptOCSPData);
       
   153 				}
       
   154 			iCustomDataSupplier = new (ELeave) TCustomDataSupplier(ptr, aTransaction);
       
   155 			THTTPHdrVal contentLengthVal;
       
   156 			TInt size = iCustomDataSupplier->OverallDataSize();
       
   157 			contentLengthVal.SetInt(size);
       
   158 			headers.RemoveFieldPart(contentLengthString, 0);
       
   159 			headers.SetFieldL(contentLengthString, contentLengthVal);
       
   160 			}
       
   161 		// Create and keep a data supplier if we plan to corrupt the data leading to a signature validation failure
       
   162 		if (countSigValidateFailure > 0)
       
   163 			{
       
   164 			// Create the data supplier
       
   165 			delete iCustomDataSupplier;
       
   166 			iCustomDataSupplier = NULL;
       
   167 			TPtrC8 ptr(KNullDesC8);
       
   168 			iCustomDataSupplier = new (ELeave) TCustomDataSupplier(ptr, aTransaction);
       
   169 			}
       
   170 		if (countCorruptHTTPDataHeader > 0)
       
   171 			{
       
   172 			// Corrupt the header
       
   173 			RStringF ocspResponse = stringPool.OpenFStringL(KOCSPContentTypeResponseCorrupted);
       
   174 			CleanupClosePushL(ocspResponse); 
       
   175 			RStringF contentTypeString = stringPool.StringF(HTTP::EContentType, RHTTPSession::GetTable());
       
   176 			THTTPHdrVal contentTypeVal;
       
   177 			contentTypeVal.SetStrF(ocspResponse);
       
   178 			headers.RemoveFieldPart(contentTypeString, 0);
       
   179 			headers.SetFieldL(contentTypeString, contentTypeVal);
       
   180 			CleanupStack::PopAndDestroy(&ocspResponse);
       
   181 			--countCorruptHTTPDataHeader;
       
   182 			}
       
   183 		if (countCorruptHTTPDataBodySizeLarge > 0 || countCorruptHTTPDataBodySizeSmall > 0)
       
   184 			{
       
   185 			// Corrupt the body size recorded in the header
       
   186 			RStringF contentLengthString = stringPool.StringF(HTTP::EContentLength, RHTTPSession::GetTable());
       
   187 			THTTPHdrVal contentLengthVal;
       
   188 			TInt err = headers.GetField(contentLengthString, 0, contentLengthVal);
       
   189 			if ((err == KErrNone) && (contentLengthVal.Type() == THTTPHdrVal::KTIntVal))
       
   190 				{
       
   191 				TInt bodySize = contentLengthVal.Int();
       
   192 				if (countCorruptHTTPDataBodySizeLarge > 0)
       
   193 					{
       
   194 					--bodySize;
       
   195 					--countCorruptHTTPDataBodySizeLarge;
       
   196 					}
       
   197 				else
       
   198 					{
       
   199 					++bodySize;
       
   200 					--countCorruptHTTPDataBodySizeSmall;
       
   201 					}
       
   202 				contentLengthVal.SetInt(bodySize);
       
   203 				headers.RemoveFieldPart(contentLengthString, 0);
       
   204 				headers.SetFieldL(contentLengthString, contentLengthVal);
       
   205 				}
       
   206 			}
       
   207 		}
       
   208 		break;
       
   209 	case THTTPEvent::EGotResponseBodyData:
       
   210 		if (iCustomDataSupplier && (countInternalErrorResp > 0 || countTryLaterResp > 0 || countCorruptOCSPData > 0 || countSigValidateFailure > 0))
       
   211 			{
       
   212 			aTransaction.Response().RemoveBody();
       
   213 			aTransaction.Response().SetBody(*iCustomDataSupplier);
       
   214 			// Make sure state machine goes on
       
   215 			aTransaction.Response().SetStatusCode(THTTPEvent::EResponseComplete);
       
   216 			}
       
   217 		break;
       
   218 	case THTTPEvent::ESucceeded:
       
   219 	case THTTPEvent::EFailed:
       
   220 		// Delay response (numDelayResp is in milliseconds)
       
   221 		if (numDelayResp > 0)
       
   222 			{
       
   223 			User::After(numDelayResp * KTimeMilliToMicro);
       
   224 			}
       
   225 	// Deliberate fall through case
       
   226 	case THTTPEvent::ECancel:
       
   227 		if (!iLogLineCompleted)
       
   228 			{
       
   229 			// End of the HTTP transaction
       
   230 			iLogLineCompleted = ETrue;
       
   231 			LogTransactionEndL(aTransaction);
       
   232 			}
       
   233 		// Since EGotResponseBodyData event can happen more than once per transaction ensure to decrement
       
   234 		// counters only once
       
   235 		if (!iDataSupplied)
       
   236 			{
       
   237 			if (countInternalErrorResp > 0)
       
   238 				{
       
   239 				--countInternalErrorResp;
       
   240 				}
       
   241 			if (countTryLaterResp > 0)
       
   242 				{
       
   243 				--countTryLaterResp;
       
   244 				}
       
   245 			if (countCorruptOCSPData > 0)
       
   246 				{
       
   247 				--countCorruptOCSPData;
       
   248 				}
       
   249 			if (countSigValidateFailure > 0)
       
   250 				{
       
   251 				--countSigValidateFailure;
       
   252 				}
       
   253 			iDataSupplied = ETrue;
       
   254 			}
       
   255 		break;
       
   256 	default:
       
   257 		break;
       
   258 		}
       
   259 
       
   260 	// Write the parameters back to keep them persistent between retries
       
   261 	WriteTestParameters(countDropResp, 
       
   262 			countCorruptHTTPDataHeader, countCorruptHTTPDataBodySizeLarge, countCorruptHTTPDataBodySizeSmall, 
       
   263 			countCorruptOCSPData, 
       
   264 			countInternalErrorResp, countTryLaterResp,
       
   265 			countSigValidateFailure);
       
   266 	}
       
   267 
       
   268 TInt COCSPHTTPFilter::MHFRunError(TInt /*aError*/,
       
   269 										RHTTPTransaction aTransaction,
       
   270 										const THTTPEvent& /*aEvent*/)
       
   271 	{
       
   272 	// If anything left, we've run out of memory or something
       
   273 	// similarly catastrophic has gone wrong.
       
   274 	aTransaction.Fail();
       
   275 	return KErrNone;
       
   276 	}
       
   277 
       
   278 // Logs the transaction method used and the current (start) time
       
   279 void COCSPHTTPFilter::LogTransactionStartL(const RHTTPTransaction& aTransaction)
       
   280 	{
       
   281 	// Get the transaction method being used (GET/POST) and log it
       
   282 	RHTTPRequest request = aTransaction.Request();
       
   283 	RStringF method = request.Method();
       
   284 	TTime time;
       
   285 	time.HomeTime();
       
   286 	TInt64 intTime = time.Int64();
       
   287 	RBuf8 logText;
       
   288 	logText.CreateL(255);
       
   289 	CleanupClosePushL(logText);
       
   290 	logText.Format(KFilterLogFormat1, &method.DesC(), intTime);
       
   291 	User::LeaveIfError(iLogFile.Write(logText));
       
   292 	CleanupStack::PopAndDestroy(&logText);
       
   293 	}
       
   294 
       
   295 // Logs the current (end) time
       
   296 void COCSPHTTPFilter::LogTransactionEndL(const RHTTPTransaction& /*aTransaction*/)
       
   297 	{
       
   298 	TTime time;
       
   299 	time.HomeTime();
       
   300 	TInt64 intTime = time.Int64();
       
   301 	RBuf8 logText;
       
   302 	logText.CreateL(255);
       
   303 	CleanupClosePushL(logText);
       
   304 	logText.Format(KFilterLogFormat2, intTime);
       
   305 	User::LeaveIfError(iLogFile.Write(logText));
       
   306 	CleanupStack::PopAndDestroy(&logText);
       
   307 	}
       
   308 
       
   309 // Read test parameters using Publish & Subscribe method
       
   310 void COCSPHTTPFilter::ReadTestParameters(TInt& aNumDelayResp, TInt& aCountDropResp,
       
   311 		TInt& aCountCorruptHTTPDataHeader, TInt& aCountCorruptHTTPDataBodySizeLarge, TInt& aCountCorruptHTTPDataBodySizeSmall,
       
   312 		TInt& aCountCorruptOCSPData, 
       
   313 		TInt& aCountInternalErrorResp, TInt& aCountTryLaterResp,
       
   314 		TInt& aCountSigValidateFailure)
       
   315 	{
       
   316 	// Set default values which will be used if P&S doesn't exist
       
   317 	aNumDelayResp = aCountDropResp = 
       
   318 	aCountCorruptHTTPDataHeader = aCountCorruptHTTPDataBodySizeLarge = aCountCorruptHTTPDataBodySizeSmall = 
       
   319 		aCountCorruptOCSPData = 
       
   320 		aCountInternalErrorResp = aCountTryLaterResp = 
       
   321 		aCountSigValidateFailure = 0;
       
   322 
       
   323 	TUid categoryUid = TUid::Uid(KFilterParametersCategoryUID);
       
   324 	RProperty::Get(categoryUid, KFilterParameterNumDelayResp, aNumDelayResp);
       
   325 	RProperty::Get(categoryUid, KFilterParameterCountDropResp, aCountDropResp);
       
   326 	RProperty::Get(categoryUid, KFilterParameterCountCorruptHTTPDataHeader, aCountCorruptHTTPDataHeader);
       
   327 	RProperty::Get(categoryUid, KFilterParameterCountCorruptHTTPDataBodySizeLarge, aCountCorruptHTTPDataBodySizeLarge);
       
   328 	RProperty::Get(categoryUid, KFilterParameterCountCorruptHTTPDataBodySizeSmall, aCountCorruptHTTPDataBodySizeSmall);
       
   329 	RProperty::Get(categoryUid, KFilterParameterCountCorruptOCSPData, aCountCorruptOCSPData);
       
   330 	RProperty::Get(categoryUid, KFilterParameterCountInternalErrorResp, aCountInternalErrorResp);
       
   331 	RProperty::Get(categoryUid, KFilterParameterCountTryLaterResp, aCountTryLaterResp);
       
   332 	RProperty::Get(categoryUid, KFilterParameterCountSigValidateFailure, aCountSigValidateFailure);
       
   333 	}
       
   334 
       
   335 // To maintain persistence between retry attempts store the updated counts back
       
   336 void COCSPHTTPFilter::WriteTestParameters(TInt aCountDropResp,
       
   337 		TInt aCountCorruptHTTPDataHeader, TInt aCountCorruptHTTPDataBodySizeLarge, TInt aCountCorruptHTTPDataBodySizeSmall,
       
   338 		TInt aCountCorruptOCSPData, 
       
   339 		TInt aCountInternalErrorResp, TInt aCountTryLaterResp,
       
   340 		TInt aCountSigValidateFailure)
       
   341 	{
       
   342 	TUid categoryUid = TUid::Uid(KFilterParametersCategoryUID);
       
   343 	RProperty::Set(categoryUid, KFilterParameterCountDropResp, aCountDropResp);
       
   344 	RProperty::Set(categoryUid, KFilterParameterCountCorruptHTTPDataHeader, aCountCorruptHTTPDataHeader);
       
   345 	RProperty::Set(categoryUid, KFilterParameterCountCorruptHTTPDataBodySizeLarge, aCountCorruptHTTPDataBodySizeLarge);
       
   346 	RProperty::Set(categoryUid, KFilterParameterCountCorruptHTTPDataBodySizeSmall, aCountCorruptHTTPDataBodySizeSmall);
       
   347 	RProperty::Set(categoryUid, KFilterParameterCountCorruptOCSPData, aCountCorruptOCSPData);
       
   348 	RProperty::Set(categoryUid, KFilterParameterCountInternalErrorResp, aCountInternalErrorResp);
       
   349 	RProperty::Set(categoryUid, KFilterParameterCountTryLaterResp, aCountTryLaterResp);
       
   350 	RProperty::Set(categoryUid, KFilterParameterCountSigValidateFailure, aCountSigValidateFailure);
       
   351 	}
       
   352 
       
   353 TCustomDataSupplier::TCustomDataSupplier(TPtrC8& aData, RHTTPTransaction& aTransaction)
       
   354 	{
       
   355 	iData.Set(aData);
       
   356 	iTransaction = &aTransaction;
       
   357 	iDataSupplied = EFalse;
       
   358 	iOriginalSupplier = aTransaction.Response().Body();
       
   359 	}
       
   360 
       
   361 // Methods from MHTTPDataSupplier
       
   362 TBool TCustomDataSupplier::GetNextDataPart(TPtrC8& aDataPart)
       
   363 	{
       
   364 	// Check if we need to simulate a signature validation failure
       
   365 	if (iData == KNullDesC8)
       
   366 		{
       
   367 		// Get the original data
       
   368 		iOriginalSupplier->GetNextDataPart(aDataPart);
       
   369 		iCorruptData.Create(aDataPart);
       
   370 		// Corrupt it (byte is part of ResponderID field)
       
   371 		--iCorruptData[KOCSPResponderIDOffset];
       
   372 		// Send it along
       
   373 		aDataPart.Set(iCorruptData);
       
   374 		}
       
   375 	else
       
   376 		{
       
   377 		// Consume the original data and pass back canned response
       
   378 		iOriginalSupplier->GetNextDataPart(aDataPart);
       
   379 		if (!iDataSupplied)
       
   380 			{
       
   381 			aDataPart.Set(iData);
       
   382 			iDataSupplied = ETrue;
       
   383 			}
       
   384 		else
       
   385 			{
       
   386 			// no data
       
   387 			aDataPart.Set(KNullDesC8);
       
   388 			}
       
   389 		}
       
   390 	return ETrue;
       
   391 	}
       
   392 
       
   393 void TCustomDataSupplier::ReleaseData()
       
   394 	{
       
   395 	iCorruptData.Close();
       
   396 	// Call original method to ensure it does it's work to let the state machine go on
       
   397 	iOriginalSupplier->ReleaseData();
       
   398 	// We are done supplying canned response so restore original supplier
       
   399 	iTransaction->Response().SetBody(*iOriginalSupplier);
       
   400 	}
       
   401 
       
   402 TInt TCustomDataSupplier::OverallDataSize()
       
   403 	{
       
   404 	return iData.Length();
       
   405 	}
       
   406 
       
   407 TInt TCustomDataSupplier::Reset()
       
   408 	{
       
   409 	return KErrNotSupported;
       
   410 	}