applayerprotocols/httptransportfw/Test/T_HttpPipeliningTest/CTestServerStreamManager.cpp
// Copyright (c) 2003-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 <minputstream.h>
#include <moutputstream.h>
#include "CTestServerStreamManager.h"
#include "httptestutils.h"
#include "MPipeliningTestCase.h"
#include "ctestcasepipelinefallback.h"
const TInt KTimeOut = 50000000;
const TInt KResponseBatchSize = 5;
_LIT8(KTxtConnectionClose, "Connection: Close");
CTestServerStreamManager* CTestServerStreamManager::NewL(CHTTPTestUtils& aTestUtils, TInt aConnectionIndex, MPipeliningTestCase* aTestCase, MInputStream* aInputStream, MOutputStream* aOutputStream)
{
CTestServerStreamManager* self = new (ELeave) CTestServerStreamManager(aTestUtils, aConnectionIndex, aTestCase, aInputStream, aOutputStream);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CTestServerStreamManager::CTestServerStreamManager(CHTTPTestUtils& aTestUtils, TInt aConnectionIndex, MPipeliningTestCase* aTestCase, MInputStream* aInputStream, MOutputStream* aOutputStream)
: CTimer(EPriorityNormal), iTestUtils(aTestUtils), iInputStream(aInputStream), iOutputStream(aOutputStream), iTestCase(aTestCase), iConnectionIndex(aConnectionIndex)
{
CActiveScheduler::Add(this);
iTransCount = iTestCase->TransactionCount(iConnectionIndex);
iInputStream->Bind(*this);
iOutputStream->Bind(*this);
}
CTestServerStreamManager::~CTestServerStreamManager()
{
Cancel();
if(iInputStream!=NULL)
iInputStream->Close();
if(iOutputStream!=NULL)
iOutputStream->Close();
delete iDataStore;
delete iDataToSend;
delete iHttpTimer;
delete iASW;
}
void CTestServerStreamManager::ConstructL()
{
CTimer::ConstructL();
iHttpTimer = new(ELeave) CHttpTimer(*this);
iASW = new(ELeave) CActiveSchedulerWait();
}
// From MInputStreamObserver
void CTestServerStreamManager::ReceivedDataIndL(const TDesC8& aBuffer)
{
// Got data
_LIT(KTxtGotData, "Server - received request data.");
iTestUtils.LogIt(KTxtGotData());
iTestUtils.DumpData(aBuffer, ETrue);
if(iDataStore==NULL)
iDataStore = aBuffer.AllocL(); // First data chunk received
else
{
// Already got data before so append the data to the existing data
TInt newLength = (iDataStore->Length()) + aBuffer.Length();
iDataStore = iDataStore->ReAllocL( newLength );
TPtr8 buf = iDataStore->Des();
buf.Append(aBuffer);
}
iInputStream->ReceivedDataRes();
_LIT(KTxtTitle, "Defect Fix INC036954");
if (iTestCase->TestCaseName().Match(KTxtTitle) == 0)
{
iInputStream->ShutdownReq();
}
else
{
// Try processing the requests
SendDataL();
}
}
void CTestServerStreamManager::SecureServerCnf()
{
}
void CTestServerStreamManager::InputStreamCloseInd(TInt aError)
{
_LIT(KTxtInputClosed, "Server - Input stream %d closed. Error: %d.");
iTestUtils.LogIt(KTxtInputClosed(), iConnectionIndex+1, aError);
iInputStream = NULL;
}
void CTestServerStreamManager::MInputStreamObserver_Reserved()
{
User::Invariant();
}
// From MOutputStreamObserver
void CTestServerStreamManager::SendDataCnfL()
{
_LIT(KTxtDataSent, "Server - Data Sent.");
iTestUtils.LogIt(KTxtDataSent());
if( iMoreResponseBatches )
{
// If there is more batches to process try and process them
iMoreResponseBatches = EFalse;
TRAPD(err, SendDataL());
if(err!=KErrNone)
{
_LIT(KTxtSendError, "Server - Error %d sending data. Closing stream.");
iTestUtils.LogIt(KTxtSendError(), err);
iInputStream->ShutdownReq();
}
}
else
{
delete iDataToSend;
iDataToSend = NULL;
// Do we need to close the connection
if(iCloseConnection)
{
_LIT(KTxtCloseConn, "Server - Closing connection.");
iTestUtils.LogIt(KTxtCloseConn());
if( (iTestCase->TestCaseName().Match(_L("Test Case 3")) == 0) || (iTestCase->TestCaseName().Match(_L("CINC073400")) == 0) || (iTestCase->TestCaseName().Match(_L("Test Case 19")) == 0) )
{
TTimeIntervalMicroSeconds32 time(5000000);
iHttpTimer->After(time);
iASW->Start();
}
if(iInputStream)
iInputStream->ShutdownReq();
}
_LIT(KTxtTitle, "Defect Fix CINC077703");
if (iTestCase->TestCaseName().Match(KTxtTitle) == 0)
{
iInputStream->ShutdownReq();
}
}
}
void CTestServerStreamManager::SecureClientCnf()
{
}
void CTestServerStreamManager::OutputStreamCloseInd(TInt aError)
{
_LIT(KTxtOutputClosed, "Server - Output stream %d closed. Error: %d.");
iTestUtils.LogIt(KTxtOutputClosed(), iConnectionIndex+1, aError);
iOutputStream = NULL;
}
void CTestServerStreamManager::MOutputStreamObserver_Reserved()
{
}
TBool CTestServerStreamManager::ProcessRequestL()
{
TBool processingRequest = ETrue;
TInt currentBatch = 0;
_LIT(KDefectTitle, "Defect Fix CDEF143497");
while((iTestCase->TestCaseName().Match(KDefectTitle) == 0) && (processingRequest && (iCurrentTrans <= iTransCount)) && (currentBatch<KResponseBatchSize))
{
// Do we have enough data to respond to the current transaction?
TPtrC8 rawRequest = iTestCase->GetRawRequest(iConnectionIndex, iCurrentTrans);
TInt requestLength = rawRequest.Length();
TPtrC8 dataWindow = iDataStore->Mid(iDataPos);
// Prepare the response data to send
iDataPos += requestLength;
processingRequest = ETrue;
TPtrC8 rawResponse = iTestCase->GetRawResponse(iConnectionIndex, iCurrentTrans);
if(iDataToSend==NULL)
iDataToSend = rawResponse.AllocL();
else
{
TInt responseLength = rawResponse.Length();
iDataToSend = iDataToSend->ReAllocL( (iDataToSend->Length()) + responseLength );
TPtr8 buffer = iDataToSend->Des();
buffer.Append(rawResponse);
}
// Check for a Connection: Close in the request
iCloseConnection = IsConnectionCloseInData(rawRequest, rawResponse);
if(iCloseConnection)
processingRequest = EFalse;
++iCurrentTrans;
++currentBatch;
if( processingRequest && currentBatch==KResponseBatchSize)
iMoreResponseBatches = ETrue;
else
iMoreResponseBatches = EFalse;
if(iDataToSend!=NULL)
return ETrue;
return EFalse;
}
while( (processingRequest && (iCurrentTrans < iTransCount)) && (currentBatch<KResponseBatchSize) )
{
// Do we have enough data to respond to the current transaction?
TPtrC8 rawRequest = iTestCase->GetRawRequest(iConnectionIndex, iCurrentTrans);
TInt requestLength = rawRequest.Length();
TPtrC8 dataWindow = iDataStore->Mid(iDataPos);
// Test pipeline fallback scenario
_LIT(KTxtTitle, "Test Case Pipeline Fallback");
if (iTestCase->TestCaseName().Match(KTxtTitle) == 0)
{
CTestCasePipelineFallback* pipelineFallback = (CTestCasePipelineFallback*)(iTestCase);
if(pipelineFallback->FallingBack())
{
_LIT(KTxtSendError, "Fallingback .");
iTestUtils.LogIt(KTxtSendError());
// we are fallingback. We should receive the exact request size as we
// will be processing the request one by one
if(dataWindow.Length() > requestLength)
{
User::Leave(KErrCancel);
}
}
else
{
_LIT(KTxtSendError, "Not Fallingback.");
iTestUtils.LogIt(KTxtSendError());
// If we are not fallingback then we need to close the connection twice
// We are pipelining as well as batching. Shutdown the connection
// First time we get only one request. Just process.
if(dataWindow.Length() > requestLength)
{
_LIT(KTxtSendError, "Incremented and shutdown.");
iTestUtils.LogIt(KTxtSendError());
// We have to shut down 2 times
iInputStream->ShutdownReq();
pipelineFallback->IncFallingBack();
break;
}
}
}
if( requestLength <= dataWindow.Length() )
{
// Check that the raw request and the actual request match
if( dataWindow.FindF(rawRequest) != 0 )
{
_LIT(KTxtRequestDataMismatch, "Server - Fail. Request data for transaction %d does not match expected data.");
iTestUtils.LogIt(KTxtRequestDataMismatch(), iCurrentTrans+1);
_LIT(KTxtExpectedData, "Server - Expected data: %S");
iTestUtils.LogIt(KTxtExpectedData(), &rawRequest);
iTestUtils.LogIt(KTxtExpectedData(), &dataWindow);
User::Leave(KErrNotFound);
}
// Prepare the response data to send
iDataPos += requestLength;
processingRequest = ETrue;
TPtrC8 rawResponse = iTestCase->GetRawResponse(iConnectionIndex, iCurrentTrans);
if(iDataToSend==NULL)
iDataToSend = rawResponse.AllocL();
else
{
TInt responseLength = rawResponse.Length();
iDataToSend = iDataToSend->ReAllocL( (iDataToSend->Length()) + responseLength );
TPtr8 buffer = iDataToSend->Des();
buffer.Append(rawResponse);
}
// Check for a Connection: Close in the request
iCloseConnection = IsConnectionCloseInData(rawRequest, rawResponse);
if(iCloseConnection)
processingRequest = EFalse;
++iCurrentTrans;
++currentBatch;
}
else
{
// No more requests can be processed
processingRequest = EFalse;
}
// Flag that we have more processing to do with we are still processing the data
// but we have reached the maximum batch size.
if( processingRequest && currentBatch==KResponseBatchSize)
iMoreResponseBatches = ETrue;
else
iMoreResponseBatches = EFalse;
}
if(iDataToSend!=NULL)
return ETrue;
return EFalse;
}
TBool CTestServerStreamManager::IsConnectionCloseInData(const TDesC8& aRequest, const TDesC8& aResponse) const
{
if( (aRequest.FindF(KTxtConnectionClose()) != KErrNotFound) || (aResponse.FindF(KTxtConnectionClose()) != KErrNotFound) )
{
// Either the request or response has Connection: Close header
_LIT(KTxtConnectionCloseDetected, "Server - Connection: Close detected in request or response, transaction: %d");
iTestUtils.LogIt(KTxtConnectionCloseDetected(), iCurrentTrans+1);
return ETrue;
}
return EFalse;
}
void CTestServerStreamManager::SendDataL()
{
Cancel();
_LIT(KTcTitle, "CRecvTimeOut");
if (iTestCase->TestCaseName().Match(KTcTitle) == 0)
{
_LIT(KTxtTimeout, "Server - Data Send Timeout.");
iTestUtils.LogIt(KTxtTimeout());
After(61000000);
return;
}
if( !iMoreResponseBatches )
{
// Try processing the requests
if( ProcessRequestL() )
{
// We have enough, send the response.
iOutputStream->SendDataReqL(*iDataToSend);
_LIT(KTxtSendData, "Server - Sending response data.");
iTestUtils.LogIt(KTxtSendData());
iTestUtils.DumpData(*iDataToSend, ETrue);
}
else
{
After(KTimeOut); // Start the inactivity timer
}
}
}
void CTestServerStreamManager::RunL()
{
_LIT(KTcTitle, "CRecvTimeOut");
if (iTestCase->TestCaseName().Match(KTcTitle) == 0)
{
_LIT(KTxtTimeout, "TC-Receive Timeout Timer RunL.");
iTestUtils.LogIt(KTxtTimeout());
return;
}
if( iStatus.Int() == KErrNone )
{
// The connection has timed out.
_LIT(KTxtTimedOut, "Server - Fail, Connection %d timed out. Current transaction: %d");
iTestUtils.LogIt(KTxtTimedOut(), iConnectionIndex+1, iCurrentTrans+1);
iInputStream->ShutdownReq();
}
}
MHttpResponse* CTestServerStreamManager::CurrentResponse()
{
return NULL;
}
void CTestServerStreamManager::OnReceiveTimeOut()
{
}
void CTestServerStreamManager::OnSendTimeOut()
{
}
TInt CTestServerStreamManager::SendTimeOutVal()
{
return 0;
}
void CTestServerStreamManager::TimeOut()
{
iASW->AsyncStop();
}
CHttpTimer::CHttpTimer(MTimerClient& aClient)
:CActive(EPriorityStandard), iClient(aClient)
{
CActiveScheduler::Add(this);
iTimer.CreateLocal();
}
CHttpTimer::~CHttpTimer()
{
Cancel();
iTimer.Close();
}
void CHttpTimer::After(TTimeIntervalMicroSeconds32 anInterval)
{
iTimer.After(iStatus, anInterval);
SetActive();
}
void CHttpTimer::DoCancel()
{
}
void CHttpTimer::RunL()
{
iClient.TimeOut();
}