applayerprotocols/httptransportfw/core/CTransaction.cpp
changeset 0 b16258d2340f
child 22 26ce6fb6aee2
child 23 ea9c9681bbaf
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 // System includes
       
    17 #include <e32std.h>
       
    18 
       
    19 
       
    20 #include <http/mhttptransactioncallback.h>
       
    21 #include <http/thttpfilterregistration.h>
       
    22 #include <httpstringconstants.h>
       
    23 #include <httperr.h>
       
    24 
       
    25 // Local includes
       
    26 #include "CHTTPSession.h"
       
    27 #include "CRequest.h"
       
    28 #include "CResponse.h"
       
    29 #include "CHTTPManager.h"
       
    30 #include "CHeaderField.h"
       
    31 
       
    32 // Class signature
       
    33 #include "CTransaction.h"
       
    34 
       
    35 #define LOGFILE "events.csv"
       
    36 
       
    37 void CTransaction::CancelTransaction(THTTPFilterHandle aStart)
       
    38 	{
       
    39 	// Delete all current events.
       
    40 	iEventQueue.Reset();
       
    41 	// Cancel the active object
       
    42 	Cancel();
       
    43 	// And send the cancel event
       
    44 	SynchronousSendEvent(THTTPEvent::ECancel, THTTPEvent::EOutgoing, aStart);
       
    45 	if (iStatus != EInFilter && iStatus != ECancelled)
       
    46 		iStatus = EPassive;
       
    47 	else
       
    48 		iStatus = ECancelled;
       
    49 	}
       
    50 
       
    51 void CTransaction::Close()
       
    52 	{
       
    53 	// If the request and the response don't exist yet, the object
       
    54 	// isn't fully constructed and so shouldn't send any cancel or
       
    55 	// close messages as its part-constructed state could confuse
       
    56 	// filters.
       
    57 	if (!iResponse)
       
    58 		{
       
    59 		CHeaderFieldPart::ClosePropertySet(iPropertySet);
       
    60 		delete iRequest;
       
    61 		delete this;
       
    62 		return;
       
    63 		}
       
    64 
       
    65 	// If we're currently processing a close event we should stop
       
    66 	// right now, to prevent infinite loops.
       
    67 	if (iProcessingSyncEvent && 
       
    68 		iCurrentSyncEvent.iEvent.iStatus == THTTPEvent::EClosed)
       
    69 		return;
       
    70 
       
    71 	// Cancel the transaction
       
    72 	CancelTransaction(THTTPFilterHandle::EClient);
       
    73 	// Remember the status
       
    74 	TInt status = iStatus.Int();
       
    75 	// And send out the 'close' message.
       
    76 	SynchronousSendEvent(THTTPEvent(THTTPEvent::EClosed), 
       
    77 						 THTTPEvent::EOutgoing, THTTPFilterHandle::EClient);
       
    78 	iStatus = status;
       
    79 	// The state will now be cancelled if and only if we were in a filter
       
    80 
       
    81 	iSession.RemoveTransaction(this);
       
    82 	CHeaderFieldPart::ClosePropertySet(iPropertySet);
       
    83 	delete iRequest;
       
    84 	delete iResponse;
       
    85 
       
    86 	// Cancel the active object
       
    87 	Cancel();
       
    88 
       
    89 	if (status == CTransaction::ECancelled)
       
    90 		{
       
    91 		// If we're our transaction's RunL (which we probably are),
       
    92 		// wait until we're back in the CTransaction before we delete it.
       
    93 		iStatus = CTransaction::EExiting;
       
    94 		}
       
    95 	else
       
    96 		{
       
    97 		// We can safeley close straight away
       
    98 		delete this;
       
    99 		}
       
   100 
       
   101 	}
       
   102 
       
   103 void CTransaction::ConstructL(const TUriC8& aURI, RStringF aMethod)
       
   104 	{
       
   105 	RStringPool strP = iSession.Manager().StringPool();
       
   106 	// If the string is the empty string, this means the default value
       
   107 	// (of GET) should be used.
       
   108 	if (aMethod == RStringF())
       
   109 		aMethod = strP.StringF(HTTP::EGET,RHTTPSession::GetTable());
       
   110 	aMethod.Copy();
       
   111 	// The 0 header val in the property set has no meaning; the value
       
   112 	// of the part is not used by property sets.
       
   113 	CHeaderFieldPart* fieldPart = CHeaderFieldPart::NewL(THTTPHdrVal(0));
       
   114 	fieldPart->SetPropertySet(iPropertySet);
       
   115 	iRequest = CRequest::NewL(aMethod, aURI, this);
       
   116 	iResponse = CResponse::NewL(this);
       
   117 	iId = iSession.NextTransactionID();
       
   118 	CActiveScheduler::Add(this);
       
   119 	iSession.AddTransactionL(this);
       
   120 	__OPEN_LOG(LOGFILE);
       
   121 	__LOG(_L(",Transaction ID, Event, Direction, Filter"));
       
   122 	}
       
   123 
       
   124 void CTransaction::RunL()
       
   125 	{
       
   126 	// If we're in another transaction's RunL (which has called a
       
   127 	// filter that has in turn run a nested active scheduler) we
       
   128 	// should block now and try again when that transaction has
       
   129 	// finished. This is to prevent obscure re-entrancy problems in
       
   130 	// client code. See the comments on the blocking functions in the
       
   131 	// session's header file for more details.
       
   132 	THTTPEvent currentEvent = CurrentEvent().iEvent;	
       
   133 	if(currentEvent == THTTPEvent::ESuspend)
       
   134 		{	
       
   135 		__ASSERT_DEBUG(iStatus != ESuspended, HTTPPanic::Panic(HTTPPanic::EInvalidEvent));				
       
   136 		iStatus = ESuspended;		
       
   137 		iSession.TransactionHasBlocked();
       
   138 		RemoveEvent();
       
   139 		return;
       
   140 		}
       
   141 	if(currentEvent == THTTPEvent::EResume)
       
   142 		{		
       
   143 		if(iStatus != ESuspended)
       
   144 		HTTPPanic::Panic(HTTPPanic::EInvalidEvent);
       
   145 		RemoveEvent();	
       
   146 		iSession.Unblock();
       
   147 		return;
       
   148 		}	
       
   149 	if (iSession.IsBlocking())
       
   150 		{
       
   151 		if(iStatus.Int() != ESuspended)
       
   152 			{
       
   153 			iStatus = EBlocked;
       
   154 			iSession.TransactionHasBlocked();
       
   155 			}				
       
   156 		return;
       
   157 		}	
       
   158 	iSession.Block();
       
   159 	TBool runNext = RunOneFilterL();	
       
   160 	iSession.Unblock();	
       
   161 	if (iStatus.Int() == EExiting)
       
   162 		{
       
   163 		iStatus = EPassive;
       
   164 		delete this;
       
   165 		}
       
   166 	else if (runNext)
       
   167 		{
       
   168 		// Move on to the next filter and find out what to do next.
       
   169 		Activate(FindNextFilter());
       
   170 		}
       
   171 	}
       
   172 
       
   173 
       
   174 
       
   175 TInt CTransaction::RunError(TInt aError)
       
   176 	{
       
   177 	TInt error = KErrNone;
       
   178 	RHTTPTransaction t;
       
   179 	t.iImplementation = this;
       
   180 	switch (iStatus.Int())
       
   181 		{
       
   182 	case EInFilter:
       
   183 	case ECancelled:
       
   184 		{
       
   185 		// Get the right event, according to whether it's being sent synchronously or not
       
   186 		THTTPEvent currentEvent;
       
   187 		if (iProcessingSyncEvent==1)
       
   188 			currentEvent = CurrentEvent().iEvent;
       
   189 		else
       
   190 			currentEvent = iASyncEvent;
       
   191 
       
   192 		// Is it a session event
       
   193 		TBool isSessionEvent = currentEvent.IsSessionEvent();
       
   194 
       
   195 		// Now, offer to the appropriate handler - MHFRunError for transaction events
       
   196 		// or MHFSessionRunError for session events
       
   197 		if (iProcessingSyncEvent==1)
       
   198 			{
       
   199 			MHTTPFilter* filter = iSession.FilterQueue()[iNextFilter].iFilter;
       
   200 			if (isSessionEvent)
       
   201 				error = filter->MHFSessionRunError(aError, STATIC_CAST(THTTPSessionEvent&, currentEvent));
       
   202 			else
       
   203 				error = filter->MHFRunError(aError, t, currentEvent);
       
   204 			}
       
   205 		else
       
   206 			{
       
   207 			MHTTPFilter* filter = iSession.FilterQueue()[iCurrentASyncFilter].iFilter;
       
   208 			if (isSessionEvent)
       
   209 				error = filter->MHFSessionRunError(aError, STATIC_CAST(THTTPSessionEvent&, currentEvent));
       
   210 			else
       
   211 				error = filter->MHFRunError(aError, t, currentEvent);
       
   212 			}
       
   213 
       
   214 		// Unless we've been deleted, move on to the next filter and
       
   215 		// find out what to do next.
       
   216 		if (iStatus.Int() != EExiting)
       
   217 			Activate(FindNextFilter());
       
   218 		} break;
       
   219 	case EExiting:
       
   220 		break;
       
   221 	default:
       
   222 		__ASSERT_DEBUG(EFalse, HTTPPanic::Panic(HTTPPanic::ETransactionUnhandledError));
       
   223 		}
       
   224 
       
   225 	if (!iProcessingSyncEvent)
       
   226 		iSession.Unblock();
       
   227 
       
   228 	// Panic if MHFRunError hasn't handled the error
       
   229 	if (error)
       
   230 		HTTPPanic::Panic(HTTPPanic::ETransactionUnhandledError);
       
   231 
       
   232 	if (iStatus.Int() == EExiting)
       
   233 		{
       
   234 		delete this;
       
   235 		}
       
   236 
       
   237 	return KErrNone;
       
   238 	}
       
   239 
       
   240 void CTransaction::DoCancel()
       
   241 	{
       
   242 	// Nothing to do here. This only happens when the transaction is
       
   243 	// cancelled or deleted.
       
   244 	}
       
   245 
       
   246 
       
   247 
       
   248 
       
   249 	
       
   250 #if defined (_DEBUG)
       
   251 
       
   252 void CTransaction::LogEvent(TInt aTransactionId, const THTTPEvent& aEvent, 
       
   253 						   TInt aDirection, const TDesC8& aFilterName)
       
   254 	/* 	creates a single line comma separated list comment of
       
   255 		Transaction Number, Event, Direction, Filter Name
       
   256 	*/
       
   257 	{
       
   258 	_LIT(KSubmit,"Submit");
       
   259 	_LIT(KCancel,"Cancel");
       
   260 	_LIT(KNotifyNewRequestBodyPart,"NotifyNewRequestBodyPart");
       
   261 	_LIT(KClosed,"Closed");
       
   262 	_LIT(KGotResponseHeaders,"GotResponseHeaders");
       
   263 	_LIT(KGotResponseBodyData,"GotResponseBodyData");
       
   264 	_LIT(KResponseComplete, "ResponseComplete");
       
   265 	_LIT(KGotResponseTrailerHeaders,"GotResponseTrailerHeaders");
       
   266 	_LIT(KSucceeded,"Succeeded");
       
   267 	_LIT(KFailed, "Failed");
       
   268 	_LIT(KUnrecoverableError, "Unrecoverable Error");
       
   269 	_LIT(KTooMuchRequestData, "TooMuchRequestData");
       
   270 	_LIT(KRedirectRequiresConfirmation, "RedirectRequiresConfirmation");
       
   271 	_LIT(KNeedTunnel, "NeedTunnel");
       
   272 	_LIT(KGetCipherSuite, "GetCipherSuite");
       
   273 	
       
   274 	_LIT(KUnknownEvent, "UnknownEvent");
       
   275 
       
   276 	TPtrC event(KNullDesC);
       
   277 	
       
   278 	switch (aEvent.iStatus)
       
   279 		{
       
   280 	case THTTPEvent::ESubmit:
       
   281 		event.Set(KSubmit);
       
   282 		break;
       
   283 	case THTTPEvent::ECancel:
       
   284 		event.Set(KCancel);
       
   285 		break;
       
   286 	case THTTPEvent::ENotifyNewRequestBodyPart:
       
   287 		event.Set(KNotifyNewRequestBodyPart);
       
   288 		break;
       
   289 	case THTTPEvent::EClosed:
       
   290 		event.Set(KClosed);
       
   291 		break;
       
   292 	case THTTPEvent::EGotResponseHeaders:
       
   293 		event.Set(KGotResponseHeaders);
       
   294 		break;
       
   295 	case THTTPEvent::EGotResponseBodyData:
       
   296 		event.Set(KGotResponseBodyData);
       
   297 		break;
       
   298 	case THTTPEvent::EResponseComplete:
       
   299 		event.Set(KResponseComplete);
       
   300 		break;
       
   301 	case THTTPEvent::EGotResponseTrailerHeaders:
       
   302 		event.Set(KGotResponseTrailerHeaders);
       
   303 		break;
       
   304 	case THTTPEvent::ESucceeded:
       
   305 		event.Set(KSucceeded);
       
   306 		break;
       
   307 	case THTTPEvent::EFailed:
       
   308 		event.Set(KFailed);
       
   309 		break;
       
   310 	case THTTPEvent::EUnrecoverableError:
       
   311 		event.Set(KUnrecoverableError);
       
   312 		break;
       
   313 	case THTTPEvent::ETooMuchRequestData:
       
   314 		event.Set(KTooMuchRequestData);
       
   315 		break;
       
   316 	case THTTPEvent::ERedirectRequiresConfirmation:
       
   317 		event.Set(KRedirectRequiresConfirmation);
       
   318 		break;
       
   319 	case THTTPEvent::ENeedTunnel:
       
   320 		event.Set(KNeedTunnel);
       
   321 		break;
       
   322 	case THTTPEvent::EGetCipherSuite:
       
   323 		event.Set(KGetCipherSuite);
       
   324 		break;
       
   325 	default:
       
   326 		event.Set(KUnknownEvent);
       
   327 	};
       
   328 	
       
   329 	_LIT(KHandled, "Handled");	
       
   330 	_LIT(KOutgoing,"Outgoing");
       
   331 	_LIT(KIncoming,"Incoming");
       
   332 	TPtrC direction(KHandled);
       
   333 
       
   334 	switch (aDirection)
       
   335 		{
       
   336 	case THTTPEvent::EIncoming:
       
   337 		direction.Set(KIncoming);
       
   338 		break;
       
   339 	case THTTPEvent::EOutgoing:
       
   340 		direction.Set(KOutgoing);
       
   341 		break;	
       
   342 		};
       
   343 	TBuf<64> filterName;
       
   344 	filterName.Copy(aFilterName);	
       
   345 	TBuf<256> logBuffer; // if its longer than 256 then http logging code will fall over anyway
       
   346 	_LIT(KLogFormat, ", Transaction %d, %S, %S, %S");
       
   347 	logBuffer.AppendFormat(KLogFormat, aTransactionId, &event, &direction, &filterName);
       
   348 	__LOG(logBuffer);
       
   349 	}
       
   350 
       
   351 #endif
       
   352 
       
   353 
       
   354 
       
   355 TBool CTransaction::RunOneFilterL()
       
   356 	{
       
   357 	// The active scheduler is only really used to split up filtering
       
   358 	// in order to make things more interactive. By now, the next
       
   359 	// filter to run should have been worked out, so run it and work
       
   360 	// out what to do next time.
       
   361 	RHTTPTransaction t;
       
   362 	t.iImplementation = this;
       
   363 	TBool processNext = EFalse;
       
   364 	iCurrentFilter = iNextFilter;
       
   365 	iStatus = EInFilter;
       
   366 	__LOGEVENT(iId, CurrentEvent().iEvent,CurrentEvent().iDirection,
       
   367 		iSession.Manager().StringPool().StringF(
       
   368 		iSession.FilterQueue()[iNextFilter].iName).DesC());
       
   369 	
       
   370 	// Run it.
       
   371 
       
   372 	MHTTPFilter* filter = iSession.FilterQueue()[iNextFilter].iFilter;
       
   373 	THTTPEvent currentEvent = CurrentEvent().iEvent;
       
   374 	//I need to keep a copy of the event and if the  event is asyncronous I need to keep the event 
       
   375 
       
   376 	if(iProcessingSyncEvent==0 ) 
       
   377 		{
       
   378 		iASyncEvent= iEventQueue[0].iEvent;
       
   379 		iCurrentASyncFilter=iNextFilter;
       
   380 		}
       
   381 	if (currentEvent.IsSessionEvent())
       
   382 		{
       
   383 		filter->MHFSessionRunL(STATIC_CAST(THTTPSessionEvent&, currentEvent));
       
   384 		}
       
   385 	else
       
   386 		filter->MHFRunL(t, currentEvent);
       
   387 	
       
   388 	switch (iStatus.Int())
       
   389 		{
       
   390 	case EInFilter:
       
   391 		processNext = ETrue;
       
   392 		iStatus = EFilter;
       
   393 		break;
       
   394 	case ECancelled:
       
   395 		iStatus = EPassive;
       
   396 		processNext = ETrue;
       
   397 		break;
       
   398 	default:
       
   399 		break;
       
   400 		}
       
   401 	return processNext;
       
   402 	}
       
   403 	
       
   404 		
       
   405 	
       
   406 
       
   407 TInt CTransaction::AddEvent(THTTPEvent& aEvent, TInt aDirection,
       
   408 							  THTTPFilterHandle aStart)
       
   409 	{
       
   410 	// API for adding new events to the queue.
       
   411 	TInt startFilter = 0;
       
   412 	// Look at the start filter handle to decide where to start the filter.
       
   413 	switch (aStart.iValue)
       
   414 		{
       
   415 	case THTTPFilterHandle::EUndefined:
       
   416 		HTTPPanic::Panic(HTTPPanic::EInvalidFilterHandle);
       
   417 		break;
       
   418 	case THTTPFilterHandle::EClient:
       
   419 		startFilter = iSession.FilterQueue().Count() - 1;
       
   420 		__LOGEVENT(iId,aEvent,aDirection,_L8("Client"));
       
   421 		break;
       
   422 	case THTTPFilterHandle::EProtocolHandler:
       
   423 		startFilter = 0;
       
   424 		__LOGEVENT(iId,aEvent,aDirection,_L8("Protocol Handler"));
       
   425 		break;
       
   426 	case THTTPFilterHandle::ECurrentFilter:
       
   427 		if (iStatus.Int() != EInFilter && iStatus.Int() != ECancelled && iStatus.Int() != ESuspended)
       
   428 			HTTPPanic::Panic(HTTPPanic::EInvalidFilterHandle);
       
   429 		startFilter = iCurrentFilter;
       
   430 		
       
   431 		__LOGEVENT(iId,aEvent,aDirection,iSession.Manager().StringPool().StringF(
       
   432 			iSession.FilterQueue()[iCurrentFilter].iName).DesC());
       
   433 		break;
       
   434 	default:
       
   435 		// Assume any other value is a filter handle.
       
   436 		{
       
   437 		TInt i;
       
   438 		TInt count = iSession.FilterQueue().Count();
       
   439 		// If there aren't any filters, you shouldn't be specifying a
       
   440 		// filter handle. Return an error.
       
   441 		if (count == 0)
       
   442 			HTTPPanic::Panic(HTTPPanic::EInvalidFilterHandle);
       
   443 		for (i = 0; i < count; ++i)
       
   444 			{
       
   445 			if (iSession.FilterQueue()[i].iHandle == aStart.iValue)
       
   446 				break;
       
   447 			}
       
   448 		if (i == count)
       
   449 			{
       
   450 			// We haven't found that filter. We may as well leave
       
   451 			HTTPPanic::Panic(HTTPPanic::EInvalidFilterHandle);
       
   452 			}
       
   453 		startFilter = i;
       
   454 		__LOGEVENT(iId,aEvent,aDirection,iSession.Manager().StringPool().
       
   455 			  StringF(iSession.FilterQueue()[i].iName).DesC());
       
   456 		break;
       
   457 		}
       
   458 		}
       
   459 
       
   460 	TEventRegistration r(aEvent, aDirection, startFilter);
       
   461 	return AppendEvent(r);
       
   462 	}
       
   463 
       
   464 TInt CTransaction::SendEvent(THTTPEvent& aEvent, TInt aDirection, THTTPFilterHandle aStart)
       
   465     {
       
   466     TInt err = AddEvent(aEvent, aDirection, aStart);
       
   467     if(err != KErrNone)
       
   468         {
       
   469         return err;
       
   470         }
       
   471         
       
   472     // If necessary, process the event having added it to the
       
   473     // queue. It's not necessary if we're inside a MHFRunL (in which
       
   474     // case the event will be processed when we return to
       
   475     // CTransaction::RunL) or if we've already added an event that
       
   476     // hasn't been run yet (in which case we'll be active)
       
   477     if (iStatus.Int() == EPassive)
       
   478         {
       
   479         Activate(FindNextFilter());
       
   480         }    
       
   481     return err;
       
   482     }
       
   483 
       
   484 void CTransaction::SendEventL(THTTPEvent& aEvent, TInt aDirection,
       
   485 							  THTTPFilterHandle aStart)
       
   486 	{
       
   487 	User::LeaveIfError(SendEvent(aEvent, aDirection, aStart));
       
   488 	}
       
   489 
       
   490 
       
   491 void CTransaction::SynchronousSendEvent(THTTPEvent aEvent, TInt aDirection, 
       
   492 										 THTTPFilterHandle aStart)
       
   493 	{
       
   494 	// Remember the current async event, in case this is a nested async event.
       
   495 	TEventRegistration storedSyncEvent = iCurrentSyncEvent;
       
   496 	iProcessingSyncEvent = ETrue;
       
   497 
       
   498 	// As we're in sync mode, this call must succeed.
       
   499 	AddEvent(aEvent, aDirection, aStart);
       
   500 
       
   501 	TInt s = iStatus.Int();
       
   502 	// Remember the current filter so that events fired after a cancel
       
   503 	// start from the right place.
       
   504 	TInt rememberedCurrentFilter = iCurrentFilter;
       
   505 	iStatus = EPassive;
       
   506 	do 
       
   507 		{
       
   508 		iStatus = FindNextFilter();
       
   509 		if (iStatus.Int() != EPassive)
       
   510 			{
       
   511 			TRAPD(error, RunOneFilterL());
       
   512 			if (error)
       
   513 				RunError(error);
       
   514 			}
       
   515 		}
       
   516 	while (iStatus.Int() != EPassive && iStatus.Int() != EExiting);
       
   517 
       
   518 	iCurrentFilter = rememberedCurrentFilter;
       
   519 	if ( iStatus.Int() != EExiting )
       
   520 		{
       
   521 			iStatus = s;
       
   522 		}
       
   523 	iProcessingSyncEvent = EFalse;
       
   524 	iCurrentSyncEvent = storedSyncEvent;
       
   525 	}
       
   526 
       
   527 CTransaction::TTransactionStates CTransaction::FindNextFilter()
       
   528 	{
       
   529 	if (!EventAvailable())
       
   530 		return EPassive;
       
   531 	NextFilter();
       
   532 	if (iStatus.Int() == EPassive)
       
   533 		{
       
   534 		// Starts processing of the event on the front of the queue.
       
   535 		// The event starts at the filter after the one that generated it,
       
   536 		// in the direction it's going.
       
   537 		iNextFilter = CurrentEvent().iStartFilter;
       
   538 		NextFilter();
       
   539 		}
       
   540 	do
       
   541 		{
       
   542 		// See if there's another filter to process this event.
       
   543 		iStatus = FindFilterForThisEvent();
       
   544 		// If not, move on to the next event
       
   545 		if (iStatus.Int() == EPassive && EventAvailable())
       
   546 			{
       
   547 			// Starts processing of the event on the front of the queue.
       
   548 			// The event starts at the filter after the one that generated it,
       
   549 			// in the direction it's going.
       
   550 			iNextFilter = CurrentEvent().iStartFilter;
       
   551 			NextFilter();
       
   552 			// Having identified the first filter to be considered for this
       
   553 			// event, identify the first filter that actualy matches the
       
   554 			// event.
       
   555 			}
       
   556 		}
       
   557 	while (iStatus.Int() == EPassive && EventAvailable());
       
   558 	return static_cast<TTransactionStates>(iStatus.Int());
       
   559 	}
       
   560 
       
   561 CTransaction::TTransactionStates CTransaction::FindFilterForThisEvent()
       
   562 	{
       
   563 	// Identify the next filter to run.
       
   564 	TBool found = EFalse;
       
   565 
       
   566 	do
       
   567 		{
       
   568 		// If we've run out of filters, this event is finished.
       
   569 		if (iNextFilter < 0 || 
       
   570 			iNextFilter >= iSession.FilterQueue().Count())
       
   571 			break;
       
   572 		if (iNextFilter < iSession.FilterQueue().Count())
       
   573 			{
       
   574 			THTTPFilterRegistration& filter = 
       
   575 				iSession.FilterQueue()[iNextFilter];
       
   576 			// Is this filter interested in this event?
       
   577 			RStringF hdr = 
       
   578 				iSession.Manager().StringPool().StringF(filter.iHeader);
       
   579 
       
   580 			// If a header has been specified in the filter, check if
       
   581 			// it's present by searching for part 0 of that header.
       
   582 			THTTPHdrVal headerValue;
       
   583 			TBool hasHeader = hdr == RStringF() ||
       
   584 				!iResponse->Headers().GetField(hdr,0,headerValue);
       
   585 
       
   586 			// Does this filter match the event? That is to say:
       
   587 			//  The event matches, or the filter matches any event and
       
   588 			//  The filter matches any status code or the status matches and
       
   589 			//  The filter matches any header or the header matches.
       
   590 
       
   591 			// first check UID's
       
   592 			if (CurrentEvent().iEvent.iUID == KHTTPMatchAnyEventUid || 
       
   593 				filter.iEvent.iUID == KHTTPMatchAnyEventUid ||
       
   594 				filter.iEvent.iUID == CurrentEvent().iEvent.iUID)
       
   595 				{
       
   596 				if (CurrentEvent().iEvent.IsSessionEvent())
       
   597 					{
       
   598 					if (filter.iEvent.iStatus == THTTPEvent::EAnySessionEvent ||
       
   599 						filter.iEvent.iStatus == THTTPEvent::EAll ||
       
   600 						filter.iEvent.iStatus == CurrentEvent().iEvent.iStatus)
       
   601 						found = ETrue;
       
   602 					}
       
   603 				else if (
       
   604 					(filter.iEvent.iStatus == CurrentEvent().iEvent.iStatus || 
       
   605 						filter.iEvent.iStatus == THTTPEvent::EAnyTransactionEvent ||
       
   606 						filter.iEvent.iStatus == THTTPEvent::EAll) &&
       
   607 					(filter.iStatus == KAnyStatusCode || filter.iStatus == iResponse->Status()) &&
       
   608 					(filter.iHeader == RStringF() || hasHeader))
       
   609 						found = ETrue;
       
   610 				}
       
   611 			}
       
   612 
       
   613 		if (!found)
       
   614 			{
       
   615 			// If not, move on to the next filter.
       
   616 			NextFilter();
       
   617 			}
       
   618 		}while (!found);
       
   619 
       
   620 	if (!found)
       
   621 		{
       
   622 		// We haven't found a filter interested in this message, so we
       
   623 		// must have finised processing it. Move on to the next event
       
   624 		// if there is one.
       
   625 		RemoveEvent();
       
   626 		if (EventAvailable())
       
   627 			{
       
   628 			iNextFilter = CurrentEvent().iStartFilter;
       
   629 			NextFilter();
       
   630 			}
       
   631 		return EPassive;
       
   632 		}
       
   633 	else
       
   634 		{
       
   635 		// We have found a filter. 
       
   636 		return EFilter;
       
   637 		}
       
   638 	}
       
   639 
       
   640 // Activate and complete ourself.
       
   641 void CTransaction::Activate(TTransactionStates aStatus)
       
   642 	{
       
   643 	if (aStatus == EPassive)
       
   644 		{
       
   645 		iStatus = aStatus;
       
   646 		return;
       
   647 		}
       
   648 	SetActive();
       
   649 	TRequestStatus* r = &iStatus;
       
   650 	User::RequestComplete(r, aStatus);	
       
   651 	}
       
   652 
       
   653 
       
   654 // This function is not allowed to fail in async mode.
       
   655 TInt CTransaction::AppendEvent(TEventRegistration& aEvent)
       
   656 	{	
       
   657 	if (iProcessingSyncEvent)
       
   658 		{
       
   659 		iCurrentSyncEvent = aEvent;
       
   660 		return KErrNone;
       
   661 		}
       
   662 	else
       
   663 		{
       
   664 		if(aEvent.iEvent == THTTPEvent::EResume)
       
   665 			{			
       
   666 			TInt pos(0);
       
   667 			return iEventQueue.Insert(aEvent,pos);
       
   668 			}
       
   669 		return iEventQueue.Append(aEvent);
       
   670 		}
       
   671 	}
       
   672 	
       
   673 RString CTransaction::CipherSuite()
       
   674 	{
       
   675 	RHTTPTransactionPropertySet properties(PropertySet());
       
   676 	RStringPool strPool(Session().StringPool());
       
   677 	THTTPHdrVal cipherSuiteValue;
       
   678 	TBool foundCipherSuiteProperty = properties.Property(strPool.StringF(HTTP::ECipherSuiteValue,
       
   679 														RHTTPSession::GetTable()), cipherSuiteValue);
       
   680 						
       
   681 	if(!foundCipherSuiteProperty)
       
   682 		{
       
   683 		// Send synchronous event down to Protocol Handler to ask it to query the connection for
       
   684 		// the cipher suite used and store it as a property of the transaction.
       
   685 		SynchronousSendEvent(THTTPEvent::EGetCipherSuite, THTTPEvent::EOutgoing, THTTPFilterHandle::EClient);
       
   686 		foundCipherSuiteProperty = properties.Property(strPool.StringF(HTTP::ECipherSuiteValue,
       
   687 														RHTTPSession::GetTable()), cipherSuiteValue);
       
   688 		}																	
       
   689 	
       
   690 	// Make sure property is set to correct type.
       
   691 	__ASSERT_DEBUG(foundCipherSuiteProperty && cipherSuiteValue.Type() == THTTPHdrVal::KStrVal, 
       
   692 					HTTPPanic::Panic(HTTPPanic::EHeaderInvalidType));				
       
   693 	return cipherSuiteValue.Str();
       
   694 	}
       
   695 
       
   696 void CTransaction::SetupHttpDataOptimiser (MHttpDataOptimiser& aHttpOptimiser)
       
   697  	{
       
   698  	iHttpDataOptimiser = &aHttpOptimiser;
       
   699  	} 
       
   700 
       
   701 MHttpDataOptimiser* CTransaction::HttpDataOptimiser ()
       
   702  	{
       
   703  	return iHttpDataOptimiser;
       
   704  	}
       
   705 
       
   706 
       
   707