--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/engine/transport/src/catalogshttptransaction.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1151 @@
+/*
+* Copyright (c) 2006-2008 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 "catalogshttptransaction.h"
+
+#include "catalogshttptransactionmanager.h"
+#include "catalogshttpobserver.h"
+#include "catalogshttpconfigimpl.h"
+#include "catalogskeyvaluepair.h"
+#include "catalogshttpheadersimpl.h"
+#include "catalogshttpstack.h"
+#include "catalogsutils.h"
+#include "catalogserrors.h"
+#include "catalogshttpconnectionmanager.h"
+#include "catalogsconnection.h"
+#include "catalogshttputils.h"
+
+#include "catalogsdebug.h"
+
+// HTTP header strings
+_LIT8( KHttpContentRangeHeader, "Content-Range" );
+_LIT8( KHttpContentLengthHeader, "Content-Length" );
+_LIT8( KHttpContentTypeHeader, "Content-Type" );
+
+
+const TInt KTransactionRetries = 3;
+
+// ======== MEMBER FUNCTIONS ========
+
+TInt CCatalogsHttpTransaction::StartCallBack( TAny* aPtr )
+ {
+ DLTRACEIN((""));
+ CCatalogsHttpTransaction* transaction =
+ static_cast<CCatalogsHttpTransaction*>( aPtr );
+
+ TInt err = transaction->Start();
+ if ( err != KErrNone )
+ {
+ transaction->iObserver->HandleHttpError(
+ *transaction,
+ TCatalogsHttpError(
+ ECatalogsHttpErrorGeneral,
+ err ) );
+ }
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Creator
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpTransaction* CCatalogsHttpTransaction::NewL(
+ MCatalogsHttpTransactionManager& aOwner,
+ const CCatalogsHttpConfig& aConfig,
+ const TCatalogsTransportOperationId& aId,
+ TCatalogsHttpTransactionType aType )
+ {
+ CCatalogsHttpTransaction* self = NewLC( aOwner, aConfig, aId, aType );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Creator
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpTransaction* CCatalogsHttpTransaction::NewLC(
+ MCatalogsHttpTransactionManager& aOwner,
+ const CCatalogsHttpConfig& aConfig,
+ const TCatalogsTransportOperationId& aId,
+ TCatalogsHttpTransactionType aType )
+ {
+ CCatalogsHttpTransaction* self = new( ELeave ) CCatalogsHttpTransaction(
+ aOwner, aId, aType );
+
+ CleanupStack::PushL( self );
+ self->ConstructL( &aConfig );
+ return self;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpTransaction::~CCatalogsHttpTransaction()
+ {
+ DLTRACEIN(( "Deleting Operation: %i, id: %i",
+ reinterpret_cast<TInt>( this ), OperationId().Id() ));
+
+ SetTransferring( EFalse );
+
+ ReleasePtr( iConnection );
+
+ DLTRACE(( "Removing from owner" ));
+ delete iHttp;
+
+ iOwner.RemoveOperation( this );
+
+ iOwner.CompleteOperation( this );
+
+
+ DLTRACE(( "Deleting config" ));
+ delete iConfig;
+
+ DLTRACE(( "Deleting response headers" ));
+ delete iResponseHeaders;
+
+ DLTRACE(( "Deleting request body" ));
+ delete iRequestBody;
+
+ DLTRACE(( "Deleting content type" ));
+ delete iContentType;
+
+ delete iUri;
+
+ delete iEncodedUri;
+
+ delete iResponseStatusText;
+
+ delete iCallBack;
+ DLTRACEOUT(( "" ));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Add a reference
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpTransaction::AddRef()
+ {
+ iRefCount++;
+ return iRefCount;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Release a reference
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpTransaction::Release()
+ {
+ DLTRACEIN(( "" ));
+ iRefCount--;
+ if ( !iRefCount )
+ {
+ delete this;
+ return 0;
+ }
+ return iRefCount;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Reference count
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpTransaction::RefCount() const
+ {
+ return iRefCount;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Cancel transaction
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpTransaction::Cancel()
+ {
+ DLTRACEIN(( "" ));
+ iState.iOperationState = ECatalogsHttpOpDeleting;
+ SetTransferring( EFalse );
+ if ( iHttp )
+ {
+ iHttp->CancelTransaction();
+
+ DeletePtr( iHttp );
+ }
+
+ if ( iState.iProgressState != ECatalogsHttpNone &&
+ iState.iProgressState != ECatalogsHttpDone )
+ {
+ iOwner.CompleteOperation( this );
+ }
+ DLTRACE(("Calling release"));
+ return Release();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Transaction progress
+// ---------------------------------------------------------------------------
+//
+TCatalogsTransportProgress CCatalogsHttpTransaction::Progress() const
+ {
+ return TCatalogsTransportProgress( iState.iOperationState, iTransferredLength,
+ iContentLength );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Start download
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpTransaction::Start( TResumeStartInformation /*aResumeOrigin*/ )
+ {
+ DLTRACEIN(( "" ));
+
+ if ( !iEncodedUri || !iEncodedUri->Length() )
+ {
+ DLTRACEOUT(( "No URI, return KErrNotReady" ));
+ return KErrNotReady;
+ }
+
+ DASSERT( iConfig );
+
+ // Update the member variable
+ iObserver = iConfig->Observer();
+
+ if ( !iObserver )
+ {
+ DLTRACEOUT(( "iObserver = NULL, return KErrNotReady" ));
+ return KErrNotReady;
+ }
+
+ TInt err = KErrNone;
+ if ( iState.iOperationState == ECatalogsHttpOpCreated
+ || iState.iOperationState == ECatalogsHttpOpQueued )
+ {
+ UpdateConfiguration();
+
+ TInt err = iOwner.StartOperation( this );
+
+ if ( err == KErrNone )
+ {
+ TRAP( err, DoStartL() );
+ }
+ else if ( err == KCatalogsHttpOperationQueued )
+ {
+ DLTRACE(( "Transaction queued" ));
+ err = KErrNone;
+
+ // Set as queued and notify observer if any
+ iState.iOperationState = ECatalogsHttpOpQueued;
+ if ( iObserver )
+ {
+ // Start errors are returned so no NotifyObserver
+ TRAP( err, iObserver->HandleHttpEventL( *this, iState ) );
+ }
+ }
+ }
+ DLTRACEOUT(("err: %d", err));
+ return err;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Pause download
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpTransaction::Pause()
+ {
+ DLTRACEIN(( "" ));
+ return KErrNotSupported;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::NotifyCancel()
+ {
+ DLTRACEIN((""));
+ if ( iObserver )
+ {
+ iObserver->HandleHttpError( *this, TCatalogsHttpError(
+ ECatalogsHttpErrorGeneral, KErrCancel ) );
+ }
+ else
+ {
+ Cancel();
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Set body
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::SetBodyL( const TDesC8& aBody )
+ {
+ DLTRACEIN(( "" ));
+ delete iRequestBody;
+ iRequestBody = NULL;
+ iRequestBody = aBody.AllocL();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Set body
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::SetBodyL( const TDesC16& aBody )
+ {
+ DLTRACEIN(( "" ));
+ delete iRequestBody;
+ iRequestBody = NULL;
+ iRequestBody = ConvertUnicodeToUtf8L( aBody );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Body getter
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CCatalogsHttpTransaction::Body() const
+ {
+ return iResponseBody;
+ }
+
+
+// ---------------------------------------------------------------------------
+// URI setter
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::SetUriL( const TDesC8& aUri )
+ {
+ delete iUri;
+ iUri = NULL;
+ iUri = aUri.AllocL();
+ EncodeUriL();
+ }
+
+
+// ---------------------------------------------------------------------------
+// URI setter
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::SetUriL( const TDesC16& aUri )
+ {
+ delete iUri;
+ iUri = NULL;
+ iUri = ConvertUnicodeToUtf8L( aUri );
+ EncodeUriL();
+ }
+
+
+// ---------------------------------------------------------------------------
+// URI getter
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CCatalogsHttpTransaction::Uri() const
+ {
+ if( iUri )
+ {
+ return *iUri;
+ }
+ return KNullDesC8();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Configuration
+// ---------------------------------------------------------------------------
+//
+MCatalogsHttpConfig& CCatalogsHttpTransaction::Config() const
+ {
+ return *iConfig;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Request headers
+// ---------------------------------------------------------------------------
+//
+MCatalogsHttpHeaders& CCatalogsHttpTransaction::RequestHeadersL() const
+ {
+ return iConfig->RequestHeaders();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Response headers
+// ---------------------------------------------------------------------------
+//
+const MCatalogsHttpHeaders& CCatalogsHttpTransaction::ResponseHeadersL() const
+ {
+ return *iResponseHeaders;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Operation type
+// ---------------------------------------------------------------------------
+//
+TCatalogsHttpOperationType CCatalogsHttpTransaction::OperationType() const
+ {
+ return ECatalogsHttpTransaction;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Operation ID
+// ---------------------------------------------------------------------------
+//
+const TCatalogsTransportOperationId&
+ CCatalogsHttpTransaction::OperationId() const
+ {
+ return iId;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Content type setter
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::SetContentTypeL( const TDesC8& aContentType )
+ {
+ delete iContentType;
+ iContentType = NULL;
+ iContentType = aContentType.AllocL();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Content type setter
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::SetContentTypeL( const TDesC16& aContentType )
+ {
+ delete iContentType;
+ iContentType = NULL;
+ iContentType = ConvertUnicodeToUtf8L( aContentType );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Content type getter
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CCatalogsHttpTransaction::ContentType() const
+ {
+ if ( iContentType )
+ {
+ return *iContentType;
+ }
+ return KNullDesC8();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Content size getter
+// ---------------------------------------------------------------------------
+//
+TInt32 CCatalogsHttpTransaction::ContentSize() const
+ {
+ return iContentLength;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Downloaded size getter
+// ---------------------------------------------------------------------------
+//
+TInt32 CCatalogsHttpTransaction::TransferredSize() const
+ {
+ return iTransferredLength;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Is download pausable
+// ---------------------------------------------------------------------------
+//
+TBool CCatalogsHttpTransaction::IsPausable() const
+ {
+ return EFalse;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Sets header mode
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::SetHeaderMode( TCatalogsHttpHeaderMode
+ /*aMode*/ )
+ {
+ // not supported
+ }
+
+
+// ---------------------------------------------------------------------------
+// Transaction status code
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpTransaction::StatusCode() const
+ {
+ return iResponseStatusCode;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Transaction status text
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CCatalogsHttpTransaction::StatusText() const
+ {
+ if ( iResponseStatusText )
+ {
+ return *iResponseStatusText;
+ }
+ return KNullDesC8();
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::SetConnection( CCatalogsConnection& aConnection )
+ {
+ DLTRACEIN((""));
+ ReleasePtr( iConnection );
+
+ iConnection = &aConnection;
+ iConnection->AddRef();
+ Config().SetConnectionMethod( aConnection.ConnectionMethod() );
+
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::ReportConnectionError( TInt aError )
+ {
+ DLTRACEIN(("aError: %d", aError ));
+ iObserver->HandleHttpError( *this,
+ TCatalogsHttpError( ECatalogsHttpErrorGeneral, aError ) );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpConnectionManager& CCatalogsHttpTransaction::ConnectionManager()
+ {
+ return iOwner.ConnectionManager();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Not supported
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::ExternalizeL( RWriteStream& /* aStream */ ) const
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Not supported
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::InternalizeL( RReadStream& /* aStream */ )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+// ---------------------------------------------------------------------------
+// Operation state
+// ---------------------------------------------------------------------------
+//
+TCatalogsHttpOperationState CCatalogsHttpTransaction::State() const
+ {
+ return iState.iOperationState;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Handles events from the configuration
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpTransaction::HandleHttpConfigEvent(
+ MCatalogsHttpConfig* /* aConfig */,
+ const TCatalogsHttpConfigEvent& aEvent )
+ {
+ if ( aEvent == ECatalogsHttpCfgPriorityChanged )
+ {
+ return iOwner.OperationPriorityChanged( this );
+ }
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Response received
+// ---------------------------------------------------------------------------
+//
+TBool CCatalogsHttpTransaction::ResponseReceived( TInt aResponseStatusCode,
+ const TDesC8& aResponseStatusText )
+ {
+ DLTRACEIN(( "%d, text: %S", aResponseStatusCode,
+ &aResponseStatusText ));
+
+ iResponseStatusCode = aResponseStatusCode;
+
+ iResponseStatusText = aResponseStatusText.Alloc();
+
+ if ( !iResponseStatusText )
+ {
+ return HandleHttpError( ECatalogsHttpErrorGeneral, KErrNoMemory );
+ }
+
+
+ if ( aResponseStatusCode >= 400 )
+ {
+ iState.iOperationState = ECatalogsHttpOpFailed;
+
+ return iObserver->HandleHttpError( *this, TCatalogsHttpError(
+ ECatalogsHttpErrorHttp,
+ KCatalogsErrorHttpBase - aResponseStatusCode ) );
+ }
+ else
+ {
+ iState.iOperationState = ECatalogsHttpOpInProgress;
+ iState.iProgressState = ECatalogsHttpConnected;
+ NotifyObserver();
+ }
+ DLTRACEOUT((""));
+ return EFalse;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Received a response header
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::ResponseHeaderReceived( const TDesC8& aHeader,
+ const TDesC8& aValue )
+ {
+ DLTRACEIN( ("") );
+ DASSERT( iObserver );
+
+ TRAPD( err, iResponseHeaders->AddHeaderL( aHeader, aValue ) );
+ if ( err != KErrNone )
+ {
+ HandleHttpError( ECatalogsHttpErrorGeneral, err );
+ return;
+ }
+
+ iState.iOperationState = ECatalogsHttpOpInProgress;
+ iState.iProgressState = ECatalogsHttpResponseHeaderReceived;
+
+
+ if ( aHeader.CompareF( KHttpContentRangeHeader ) == 0 )
+ {
+ //
+ // Content-Range, bytes x-y/z
+ // Extract 'z' and use it as the total content length
+ //
+ TPtrC8 ptr( aValue );
+ TInt offset = ptr.Locate( '/' );
+ if ( offset != KErrNotFound )
+ {
+ TLex8 val;
+ val.Assign( ptr.Mid( offset + 1 ) );
+
+ TInt value;
+ TInt err = val.Val( value );
+ if ( err == KErrNone )
+ {
+ iContentLength = value;
+ DLTRACE(( "Content length: %i", iContentLength ));
+ }
+ }
+ }
+ else if ( aHeader.CompareF( KHttpContentLengthHeader ) == 0 )
+ {
+ //
+ // If content length for this request has not been already set
+ // e.g. from a Content-Range header, extract from Content-Length header
+ //
+ if ( iContentLength == 0 )
+ {
+ TLex8 val;
+ val.Assign( aValue );
+
+ TInt value;
+ TInt err = val.Val( value );
+ if ( err == KErrNone )
+ {
+ iContentLength = value;
+ DLTRACE(( "Content length: %i", iContentLength ));
+ }
+ }
+ else
+ {
+ DLTRACE(( "-> ContentLength set, ignoring" ));
+ }
+ }
+ else if ( aHeader.CompareF( KHttpContentTypeHeader ) == 0 )
+ {
+ // Content type from the header
+ DLTRACE( ( "Content type received" ) );
+
+ TRAPD( err, SetContentTypeL( aValue ) );
+ if ( err != KErrNone )
+ {
+ DLTRACE( ( "Content type setting failed with err: %i",
+ err ) );
+ HandleHttpError( ECatalogsHttpErrorGeneral, err );
+ return;
+ }
+ else
+ {
+ iState.iProgressState = ECatalogsHttpContentTypeReceived;
+ }
+ }
+
+ // Report the observer that a header has been received
+ NotifyObserver();
+ }
+
+
+
+// ---------------------------------------------------------------------------
+// Received a part of the response
+// ---------------------------------------------------------------------------
+//
+TBool CCatalogsHttpTransaction::ResponseBodyReceived( const TDesC8& aData )
+ {
+ DLTRACEIN( ( "" ) );
+ DASSERT( iObserver );
+
+ iState.iOperationState = ECatalogsHttpOpInProgress;
+ iState.iProgressState = ECatalogsHttpResponseBodyReceived;
+
+ // Set body to point to response body
+ iResponseBody.Set( aData );
+
+ iTransferredLength += iResponseBody.Length();
+
+ DLTRACE( ( "Calling observer" ) );
+ NotifyObserver();
+
+ DLTRACE( ( "Observer finished" ) );
+
+ // Response body back to empty
+ iResponseBody.Set( KNullDesC8 );
+ return ETrue;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Request submitted
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::RequestSubmitted()
+ {
+ DLTRACEIN((""));
+ SetTransferring( ETrue );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Request completed
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::RequestCompleted( TInt aError )
+ {
+ DLTRACEIN( ("Error: %d", aError ) );
+ DASSERT( iObserver );
+ AddRef();
+
+ SetTransferring( EFalse );
+ if ( aError != KErrNone )
+ {
+ iOwner.ConnectionManager().ReportConnectionError(
+ iConfig->ConnectionMethod(),
+ aError );
+ }
+
+ // If reference count is 1, then the operation has already been
+ // cancelled/released
+ if ( iRefCount > 1 )
+ {
+ TRAPD( err, DoRequestCompletedL( aError ) );
+ if ( err != KErrNone )
+ {
+ DLERROR(("DoRequestCompletedL leaved with: %d", err));
+ // Symbian error codes
+ iObserver->HandleHttpError( *this, TCatalogsHttpError(
+ ECatalogsHttpErrorGeneral, err) );
+ }
+ }
+
+ Release();
+ DLTRACEOUT((""));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Request completed
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::DoRequestCompletedL( TInt aError )
+ {
+ DLTRACEIN( ("Error: %d", aError ) );
+
+ iOwner.CompleteOperation( this );
+
+ if ( ( aError == KErrDisconnected ) &&
+ iRetryCount &&
+ iState.iProgressState < ECatalogsHttpResponseHeaderReceived )
+ {
+ DLTRACE(("Retrying"));
+ iRetryCount--;
+
+ // This ensures that connection is reset for this op
+ ReleasePtr( iConnection );
+
+ iState.iOperationState = ECatalogsHttpOpCreated;
+ iState.iProgressState = ECatalogsHttpNone;
+
+ // Start asynchronously so that CCatalogsHttpStack is not deleted
+ // inside an MHFRunL-callback
+ AsyncStartL();
+ return;
+ }
+
+
+ if ( aError == KErrNone )
+ {
+ iState.iOperationState = ECatalogsHttpOpCompleted;
+ iState.iProgressState = ECatalogsHttpDone;
+ // Report to the observer
+ NotifyObserver();
+
+ }
+ else
+ {
+ DLTRACE(("Handling error"));
+ iState.iOperationState = ECatalogsHttpOpFailed;
+
+ // HandleHttpError would also Cancel the operation but it's
+ // already been complete by CompleteOperation
+ if ( aError < KErrNone )
+ {
+ UpdateAccessPoint( TCatalogsConnectionMethod() );
+
+ // Symbian error codes
+ iObserver->HandleHttpError( *this, TCatalogsHttpError(
+ ECatalogsHttpErrorGeneral, aError ) );
+
+ }
+ else
+ {
+
+ // HTTP errors
+ iObserver->HandleHttpError( *this, TCatalogsHttpError(
+ ECatalogsHttpErrorHttp,
+ KCatalogsErrorHttpBase - aError ) );
+ }
+ }
+
+ DLTRACEOUT((""));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Update accesspoint
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::UpdateAccessPoint(
+ const TCatalogsConnectionMethod& aMethod )
+ {
+ DLTRACEIN(("AP, type: %d, id: %u, apn: %u",
+ aMethod.iType, aMethod.iId, aMethod.iApnId ));
+
+ iConfig->SetConnectionMethod( aMethod );
+
+ DLTRACE(("Setting new default AP"));
+
+ // Update default ap to connection manager if it's not set
+
+ iOwner.ConnectionManager().SetAccessPointForDefaultConnectionMethod(
+ aMethod );
+
+ }
+
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpTransaction::CCatalogsHttpTransaction(
+ MCatalogsHttpTransactionManager& aOwner,
+ const TCatalogsTransportOperationId& aId,
+ TCatalogsHttpTransactionType aType ) :
+ iOwner( aOwner ), iId( aId ), iState( ECatalogsHttpOpCreated,
+ ECatalogsHttpNone ),
+ iRefCount( 1 ),
+ iType( aType ),
+ iRetryCount( KTransactionRetries ),
+ iStartCallBack( &StartCallBack, this )
+ {
+ }
+
+
+// ---------------------------------------------------------------------------
+// 2nd phase constructor
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::ConstructL( const CCatalogsHttpConfig* aConfig )
+ {
+ iResponseBody.Set( KNullDesC8 );
+ iResponseHeaders = CCatalogsHttpHeaders::NewL();
+
+
+ // Create a copy of the configuration
+ if ( aConfig )
+ {
+ iConfig = aConfig->CloneL();
+ }
+ else
+ {
+ // Or create a new configuration
+ iConfig = CCatalogsHttpConfig::NewL();
+ iConfig->SetHttpMethod( ECatalogsHttpPost );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates the http stack to match the configuration
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::UpdateConfiguration()
+ {
+ DLTRACEIN( ("" ) );
+ DASSERT( iConfig );
+
+ const TCatalogsConnectionMethod& method( iConfig->ConnectionMethod() );
+
+ // If no APN id or method id is set, we need to use the default
+ if ( !method.iApnId &&
+ !method.iId )
+ {
+ iConfig->SetConnectionMethod(
+ iOwner.ConnectionManager().DefaultConnectionMethod() );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates the request headers to the HTTP stack
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::UpdateRequestHeadersL()
+ {
+ DLTRACEIN( ("") );
+ RPointerArray<CCatalogsKeyValuePair>& headers(
+ iConfig->RequestHeaders().Headers() );
+
+ // Clear previously declared headers
+ iHttp->ClearHeaders();
+
+ // Iterate through headers and add them to the request headers
+ // in HTTP stack
+ for ( TInt i = 0; i < headers.Count(); ++i )
+ {
+ iHttp->AddHeaderL( headers[i] );
+ }
+
+ DLTRACEOUT( ("" ) );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Handle HTTP error
+// ---------------------------------------------------------------------------
+//
+TBool CCatalogsHttpTransaction::HandleHttpError( TCatalogsHttpErrorType aType,
+ TInt aErr )
+ {
+ DLTRACE( ( "Error: %d ", aErr ) );
+ iState.iOperationState = ECatalogsHttpOpFailed;
+
+ // Start processing next transactions
+ iOwner.CompleteOperation( this );
+
+ return iObserver->HandleHttpError(
+ *this, TCatalogsHttpError( aType, aErr ) );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Actually starts the transaction
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::DoStartL()
+ {
+ DLTRACEIN((""));
+
+ DASSERT( iConnection );
+
+ if ( !iOwner.ConnectionManager().AskConnectionConfirmation(
+ Config().ConnectionMethod() ) )
+ {
+ DLINFO(("Connection denied!"));
+ User::Leave( KCatalogsErrorHttpConnectionDenied );
+ }
+
+ // If the operation disconnected prematurely it will be restarted
+ // so we need to delete the old iHttp
+ DeletePtr( iHttp );
+ iHttp = CCatalogsHttpStack::NewL(
+ this,
+ *iConnection,
+ iOwner.ConnectionCreatorL() );
+
+ iHttp->SetConnectionManager( &iOwner.ConnectionManager() );
+
+ UpdateRequestHeadersL();
+ const TDesC8* method = &KCatalogsHttpPost;
+ // Choose the correct method string
+ switch( Config().HttpMethod() )
+ {
+ case ECatalogsHttpGet:
+ {
+ method = &KCatalogsHttpGet;
+ break;
+ }
+
+ case ECatalogsHttpHead:
+ {
+ method = &KCatalogsHttpHead;
+ }
+
+ default:
+ {
+ }
+ }
+
+ iState.iOperationState = ECatalogsHttpOpInProgress;
+ iState.iProgressState = ECatalogsHttpStarted;
+
+ if ( iRequestBody )
+ {
+ // Send the request
+ iHttp->IssueHttpRequestL( *method, EncodedUri(), ContentType(),
+ *iRequestBody );
+ }
+ else
+ {
+ // Send the request with empty body
+ iHttp->IssueHttpRequestL( *method, EncodedUri(), ContentType(),
+ KNullDesC8 );
+ }
+
+ // Notify observer about operation start
+ // This method can leave so not using NotifyObserver
+ iObserver->HandleHttpEventL( *this, iState );
+
+ DLTRACEOUT(("successful"));
+ }
+
+
+void CCatalogsHttpTransaction::NotifyObserver()
+ {
+ DLTRACEIN((""));
+ if ( iObserver )
+ {
+ TRAPD( err, iObserver->HandleHttpEventL( *this, iState ) );
+ if ( err != KErrNone )
+ {
+ DLERROR(("Observer's HandleHttpEventL leaved with: %d", err));
+ // Symbian error codes
+ iObserver->HandleHttpError( *this, TCatalogsHttpError(
+ ECatalogsHttpErrorGeneral, err) );
+ }
+ }
+ }
+
+
+void CCatalogsHttpTransaction::SetTransferring( TBool aTransferring )
+ {
+ if ( iTransferring != aTransferring )
+ {
+ iTransferring = aTransferring;
+ iOwner.ReportConnectionStatus( iTransferring );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Starts the operation asynchronously
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::AsyncStartL()
+ {
+ DLTRACEIN((""));
+ DeletePtr( iCallBack );
+ iCallBack = new ( ELeave ) CAsyncCallBack(
+ iStartCallBack, CActive::EPriorityStandard );
+ iCallBack->CallBack();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Encodes the URI
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpTransaction::EncodeUriL()
+ {
+ DeletePtr( iEncodedUri );
+ iEncodedUri = CatalogsHttpUtils::EncodeUriL( Uri() );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Returns the encoded URI
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CCatalogsHttpTransaction::EncodedUri() const
+ {
+ DASSERT( iEncodedUri );
+ return *iEncodedUri;
+ }
+