--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/engine/transport/src/catalogshttpstack.cpp Tue Jan 26 12:06:03 2010 +0200
@@ -0,0 +1,1029 @@
+/*
+* 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: Implementation of CCatalogsHttpStack
+*
+*/
+
+
+#include "catalogshttpstack.h"
+
+#include <uri8.h>
+#include <http.h>
+#include <chttpformencoder.h>
+#include <httpstringconstants.h>
+#include <http/rhttptransaction.h>
+#include <http/rhttpsession.h>
+#include <http/rhttpheaders.h>
+#include <es_enum.h>
+#include <in_sock.h>
+
+
+// HTTP headers
+
+#include <httpfilteracceptheaderinterface.h>
+#include <uaproffilter_interface.h>
+#include <deflatefilterinterface.h>
+#include <httpfiltercommonstringsext.h>
+#include <httpfilterproxyinterface.h>
+#include <CookieFilterInterface.h>
+
+#include "catalogs_device_config.h"
+#include "catalogshttptypes.h"
+#include "catalogshttpconnectioncreator.h"
+#include "catalogshttpsessionmanagerimpl.h"
+#include "catalogsnetworkmanager.h"
+#include "catalogserrors.h"
+#include "catalogsconnectionmethod.h"
+#include "catalogshttputils.h"
+#include "catalogsconnection.h"
+#include "catalogsconstants.h"
+
+#include "catalogsdebug.h"
+
+// Uncomment this to enable CHttpDeflateFilter in ARM-builds (accepts zipped input)
+#define ENABLE_DEFLATE_FILTER
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::NewL()
+//
+// Creates instance of CCatalogsHttpStack.
+// ----------------------------------------------------------------------------
+CCatalogsHttpStack* CCatalogsHttpStack::NewL(
+ MCatalogsHttpStackObserver* aObserver,
+ CCatalogsConnection& aConnection,
+ CCatalogsHttpConnectionCreator& aConnectionCreator )
+ {
+ CCatalogsHttpStack* self = CCatalogsHttpStack::NewLC(
+ aObserver,
+ aConnection,
+ aConnectionCreator );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::NewLC()
+//
+// Creates instance of CCatalogsHttpStack.
+// ----------------------------------------------------------------------------
+CCatalogsHttpStack* CCatalogsHttpStack::NewLC(
+ MCatalogsHttpStackObserver* aObserver,
+ CCatalogsConnection& aConnection,
+ CCatalogsHttpConnectionCreator& aConnectionCreator )
+ {
+ CCatalogsHttpStack* self = new (ELeave) CCatalogsHttpStack(
+ aObserver,
+ aConnection,
+ aConnectionCreator );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::CCatalogsHttpStack()
+//
+// First phase constructor.
+// ----------------------------------------------------------------------------
+CCatalogsHttpStack::CCatalogsHttpStack(
+ MCatalogsHttpStackObserver* aObserver,
+ CCatalogsConnection& aConnection,
+ CCatalogsHttpConnectionCreator& aConnectionCreator ) :
+ CActive( EPriorityNormal ),
+ iTable( RHTTPSession::GetTable() ),
+ iObserver( aObserver ),
+ iConnection( aConnection ),
+ iConnectionCreator( aConnectionCreator )
+ {
+ CActiveScheduler::Add( this );
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::~CCatalogsHttpStack()
+//
+// Destructor.
+// ----------------------------------------------------------------------------
+CCatalogsHttpStack::~CCatalogsHttpStack()
+ {
+ DLTRACEIN( ( "" ) );
+ CancelTransaction();
+
+ iTimer.Close();
+ iSession.Close(); // closes also iTransaction if necessary
+ delete iPostData;
+ iRunning = EFalse;
+ // The headers are deleted when the transaction configuration is deleted
+ iUserHeaders.Reset();
+ DLTRACEOUT( ( "" ) );
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::ConstructL()
+//
+// Second phase construction.
+// ----------------------------------------------------------------------------
+void CCatalogsHttpStack::ConstructL()
+ {
+ DLTRACE( ( "CCatalogsHttpStack::ConstructL(): %X", this ) );
+
+ iConnectionOpened = ETrue;
+
+ // Open RHTTPSession with default protocol ( "HTTP/TCP" )
+ // Most common error for leaves: no access point configured,
+ // and session creation
+ // leaves with KErrNotFound.
+
+ iSession.OpenL();
+ iPool = iSession.StringPool();
+
+ // Initialize the HTTP to use the created socket server. Without these
+ // settings, the HTTP protocol would open a connection of its own; this is not
+ // desired, because the GPRS connection would then be broken after every query.
+
+ RHTTPConnectionInfo info = iSession.ConnectionInfo();
+
+ info.SetPropertyL( iPool.StringF( HTTP::EHttpSocketServ, iTable ),
+ iConnection.SocketServer().Handle() );
+
+ info.SetPropertyL( iPool.StringF( HTTP::EHttpSocketConnection, iTable ),
+ ( TInt )&iConnection.Connection() );
+
+ // Open tables to enable HTTP filters
+ iPool.OpenL( HttpFilterCommonStringsExt::GetTable() );
+ iPool.OpenL( HttpFilterCommonStringsExt::GetLanguageTable() );
+
+
+ // Install this class as the callback for authentication requests. When
+ // page requires authentication the framework calls GetCredentialsL to get
+ // user name and password.
+ InstallAuthenticationL( iSession );
+
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// Note: these filters do not seem to work on the E60 phone
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ // Install accept filters
+ // This crashes on 3.0 week 42 and earlier
+ DLTRACE(( "->installing AcceptHeader filter" ));
+ TRAPD( err, CHttpFilterAcceptHeaderInterface::InstallFilterL( iSession ) );
+ if ( err != KErrNone )
+ {
+ DLTRACE(("->CHttpFilterAcceptHeaderInterface::InstallFilterL() ERROR: %d",
+ err ) );
+ }
+
+
+// Don't install UAprof filter if user agent is overridden
+#ifndef CATALOGS_OVERRIDE_USERAGENT
+
+ // This does not crash on 3.0. Wonders!
+ // Install UAprof filters, ignore errors
+ DLTRACE(( "->installing UAProf filter" ));
+ TRAP( err, CHttpUAProfFilterInterface::InstallFilterL( iSession ) );
+ if ( err != KErrNone )
+ {
+
+ DLTRACE( ("->CHttpUAProfFilterInterface::InstallFilterL() ERROR: %d",
+ err ) );
+ }
+#endif
+// This is available on 3.0 but crashes on E60 wk40 and earlier.
+
+
+#ifdef ENABLE_DEFLATE_FILTER
+ // Accept zipped input
+ DLTRACE( (_L( "->installing deflate filter" ) ) );
+ TRAP( err, CHttpDeflateFilter::InstallFilterL( iSession ) );
+ if ( err != KErrNone )
+ {
+ DLTRACE(("->CHttpDeflateFilter::InstallFilterL() ERROR: %d", err ));
+ }
+#endif // ENABLE_DEFLATE_FILTER
+
+
+ // Install proxy filter, ignore errors
+ DLTRACE( ( "->installing proxy filter" ) );
+ TRAP( err, CHttpFilterProxyInterface::InstallFilterL( iSession ) );
+ if ( err != KErrNone )
+ {
+ DLTRACE( ("CHttpFilterProxyInterface::InstallFilterL() ERROR: %d", err ) );
+ }
+
+ // Install cookie filter, ignore errors
+ DLTRACE( ( "->installing cookie filter" ) );
+ TRAP( err, CHttpCookieFilter::InstallFilterL( iSession ) );
+ if ( err != KErrNone )
+ {
+ DLTRACE( ("CHttpCookieFilter::InstallFilterL() ERROR: %d", err ) );
+ }
+
+ User::LeaveIfError( iTimer.CreateLocal() );
+
+ DLTRACE( ("->CCatalogsHttpStack::ConstructL() ok") );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpStack::SetConnectionMethodL(
+ const TCatalogsConnectionMethod& aMethod )
+ {
+ DLTRACEIN((("ap type: %d id: %u"), aMethod.iType, aMethod.iId ));
+
+ iConnectionMethod = aMethod;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TUint32 CCatalogsHttpStack::AccessPointID() const
+ {
+ return iConnectionMethod.iApnId;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpStack::SetObserver( MCatalogsHttpStackObserver* aObserver )
+ {
+ iObserver = aObserver;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpStack::SetConnectionManager(
+ CCatalogsHttpConnectionManager* aManager )
+ {
+ iConnectionManager = aManager;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpStack::ClearHeaders()
+ {
+ DLTRACEIN((""));
+ // iUserHeaders doesn't own the headers
+ iUserHeaders.Reset();
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpStack::AddHeaderL( const CCatalogsKeyValuePair* aPair )
+ {
+ DLTRACEIN((""));
+ User::LeaveIfError( iUserHeaders.Append( aPair ) );
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::SetHeaderL()
+//
+// Used to set header value to HTTP request
+// ----------------------------------------------------------------------------
+void CCatalogsHttpStack::SetHeaderL( RHTTPHeaders aHeaders,
+ TInt aHdrField,
+ const TDesC8& aHdrValue )
+ {
+ DLTRACEIN((""));
+ RStringF valStr = iSession.StringPool().OpenFStringL( aHdrValue );
+ CleanupClosePushL( valStr );
+
+ THTTPHdrVal val( valStr );
+
+ aHeaders.SetFieldL(
+ iSession.StringPool().StringF( aHdrField, iTable ), val );
+
+ CleanupStack::PopAndDestroy( &valStr );
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::IssueHTTPRequestL()
+//
+// Start a new HTTP transaction.
+// ----------------------------------------------------------------------------
+void CCatalogsHttpStack::IssueHttpRequestL( const TDesC8& aMethod,
+ const TDesC8& aURI,
+ const TDesC8& aContentType,
+ const TDesC8& aBody )
+ {
+ DLTRACEIN( ( "body size: %d, this: %X",
+ aBody.Size(), this ) );
+
+ DLINFO( ( "-> URI: %S", &aURI ) );
+
+ // Parse string to URI
+ TUriParser8 uri;
+ uri.Parse( aURI );
+
+ // Using post as default HTTP method
+ RStringF method;
+ if ( aMethod.Length() == 0 )
+ {
+ // Get request method string for HTTP POST
+ method = iSession.StringPool().StringF( HTTP::EPOST, iTable );
+ }
+ else
+ {
+ method = iSession.StringPool().OpenFStringL( aMethod );
+ }
+
+ CleanupClosePushL( method );
+ iTransaction = iSession.OpenTransactionL( uri, *this, method );
+ CleanupStack::PopAndDestroy( &method );
+
+ RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection();
+
+ TInt count = iUserHeaders.Count();
+ for ( TInt i = 0; i < count; i++ )
+ {
+ CCatalogsKeyValuePair* pair = iUserHeaders[i];
+
+ RStringF headerStr = iSession.StringPool().OpenFStringL( pair->Key() );
+ CleanupClosePushL( headerStr );
+
+ RStringF valueStr = iSession.StringPool().OpenFStringL( pair->Value() );
+ CleanupClosePushL( valueStr );
+
+ DLTRACE(("Header: %S, data: %S", &headerStr.DesC(), &valueStr.DesC() ));
+ hdr.SetFieldL( headerStr, valueStr );
+
+ CleanupStack::PopAndDestroy( 2, &headerStr ); // headerStr, valueStr
+
+ }
+
+ // Copy data to be posted into member variable; iPostData is used later in
+ // methods inherited from MHTTPDataSupplier.
+ delete iPostData;
+ iPostData = 0;
+ iPostData = aBody.AllocL();
+
+
+#ifdef CATALOGS_OVERRIDE_USERAGENT
+
+ // Override user agent string
+ DLINFO(("Overriding user agent string with: %S", &KCatalogsOverrideUserAgent ));
+ SetHeaderL( hdr, HTTP::EUserAgent, KCatalogsOverrideUserAgent );
+
+#endif
+
+ if ( aBody.Length() > 0 )
+ {
+ if ( aContentType.Length() )
+ {
+ SetHeaderL( hdr, HTTP::EContentType, aContentType );
+ }
+ else
+ // default to "text/xml"
+ // Content-type must be sent in POST requests because some
+ // proxies will reject the request if it's not present and doesn't
+ // contain something
+ {
+ SetHeaderL( hdr, HTTP::EContentType, KMimeTypeXml );
+ }
+
+ // Set this class as an data supplier. Inherited MHTTPDataSupplier methods
+ // are called when framework needs to send body data.
+ MHTTPDataSupplier* dataSupplier = this;
+ iTransaction.Request().SetBody( *dataSupplier );
+ }
+
+ iRunning = ETrue;
+
+ iTransaction.SubmitL();
+ if ( iObserver )
+ {
+ iObserver->RequestSubmitted();
+ }
+
+ SetTimeoutTimer();
+
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::CancelTransaction()
+//
+// Cancels currently running transaction and frees resources related to it.
+// ----------------------------------------------------------------------------
+void CCatalogsHttpStack::CancelTransaction()
+ {
+ DLTRACEIN( ("iActive: %d, iState: %d, this: %X",
+ IsActive(),
+ TInt( iState ),
+ this ) ); // cast required for armcc
+
+ // Close() also cancels transaction ( Cancel() can also be used but
+ // resources allocated by transaction must be still freed with Close())
+ if ( iRunning )
+ {
+ iTransaction.Close();
+
+ // Not running anymore
+ iRunning = EFalse;
+ }
+
+ Cancel();
+
+ iState = ENone;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::MHFRunL()
+//
+// Inherited from MHTTPTransactionCallback
+// Called by framework to pass transaction events.
+// ----------------------------------------------------------------------------
+void CCatalogsHttpStack::MHFRunL( RHTTPTransaction aTransaction,
+ const THTTPEvent& aEvent )
+ {
+ DLTRACEIN( ( "CCatalogsHttpStack::MHFRunL(), event: %d, this: %X",
+ aEvent.iStatus, this ) );
+
+ // Cancel timeout
+ CancelTimeoutTimer();
+
+ switch ( aEvent.iStatus )
+ {
+ case THTTPEvent::EGotResponseHeaders:
+ {
+ // HTTP response headers have been received. Use
+ // aTransaction.Response() to get the response. However, it's not
+ // necessary to do anything with the response when this event occurs.
+
+ // Get HTTP status code from header
+ RHTTPResponse resp = aTransaction.Response();
+ iLastError = resp.StatusCode();
+
+ if ( !iObserver )
+ {
+ DLTRACEOUT(("No observer"));
+ return;
+ }
+
+ // Report response status code
+ if ( iObserver->ResponseReceived( iLastError, resp.StatusText().DesC() ) )
+ {
+ return;
+ }
+
+ // what to do in case of redirect etc.?
+ switch ( iLastError )
+ {
+ case 100: // Continue
+ case 101: // Switching Protocols
+ {
+ // Informational
+ break;
+ }
+
+ case 200: // OK
+ case 201: // Created
+ case 202: // Accepted
+ case 203: // Non-Authoritative Information
+ case 204: // No Content
+ case 205: // Reset Content
+ case 206: // Partial Content
+ {
+ // Success
+ break;
+ }
+
+ case 300: // Multiple Choices
+ case 301: // Moved Permanently
+ case 302: // Found
+ case 303: // See Other
+ case 304: // Not Modified
+ case 305: // Use Proxy
+ case 306: // ( Unused )
+ case 307: // Temporary Redirect
+ {
+ break;
+ }
+
+ case 400: // Bad Request
+ case 401: // Unauthorized
+ case 402: // Payment Required
+ case 403: // Forbidden
+ case 404: // Not Found
+ case 405: // Method Not Allowed
+ case 406: // Not Acceptable
+ case 407: // Proxy Authentication Required
+ case 408: // Request Timeout
+ case 409: // Conflict
+ case 410: // Gone
+ case 411: // Length Required
+ case 412: // Precondition Failed
+ case 413: // Request Entity Too Large
+ case 414: // Request-URI Too Long
+ case 415: // Unsupported Media Type
+ case 416: // Requested Range Not Satisfiable
+ case 417: // Expectation Failed
+ {
+ // Client error
+ break;
+ }
+ case 500: // Internal Server Error
+ case 501: // Not Implemented
+ case 502: // Bad Gateway
+ case 503: // Service Unavailable
+ case 504: // Gateway Timeout
+ case 505: // HTTP Version Not Supported
+ {
+ // Server error
+ break;
+ }
+ }
+
+ // Parse response headers
+ RHTTPHeaders headers = resp.GetHeaderCollection();
+ THTTPHdrFieldIter iter = headers.Fields();
+
+ RStringTokenF name = iter();
+ while ( !name.IsNull() )
+ {
+ DLTRACE(( "Start adding next header" ));
+ // Header
+ RStringF stringF;
+ stringF = iSession.StringPool().StringF( name );
+ const TDesC8& header = stringF.DesC();
+
+ DLTRACE( ( "Header: %S" , &header ) );
+
+ TPtrC8 rawField( KNullDesC8 );
+ TInt err2 = headers.GetRawField( stringF, rawField );
+
+ if ( err2 == KErrNone )
+ {
+ DLTRACE( ( "Raw value: %S", &rawField ) );
+ iObserver->ResponseHeaderReceived( header, rawField );
+ }
+
+ if ( header.CompareF( KCatalogsHeaderErrorNumber ) == 0 )
+ {
+ iLastError = KCatalogsErrorHeaderPresent;
+ }
+ ++iter;
+ name = iter();
+ DLTRACE(( "Added header" ));
+ }
+ DLTRACE(( "EGotResponseHeaders done" ));
+ }
+ break;
+
+
+ case THTTPEvent::EGotResponseBodyData:
+ {
+ // Part ( or all ) of response's body data received. Use
+ // aTransaction.Response().Body()->GetNextDataPart() to get the actual
+ // body data.
+
+ DLTRACE(("Got response body"));
+ // Get the body data supplier
+ iBody = aTransaction.Response().Body();
+
+ if ( !iObserver )
+ {
+ DLTRACEOUT(("No observer. Releasing data"));
+ iBody->ReleaseData();
+ iBody = NULL;
+ return;
+ }
+
+ switch ( iLastError )
+ {
+ /// Add further study what codes are acceptable
+ case 200: // OK
+ case 201: // Created
+ case 202: // Accepted
+ case 203: // Non-Authoritative Information
+ case 204: // No Content
+ case 205: // Reset Content
+ case 206: // Partial Content
+ {
+
+ // GetNextDataPart() returns ETrue, if the received part is the last
+ // one.
+ TPtrC8 dataChunk;
+ iBody->GetNextDataPart( dataChunk );
+ TBool releaseData = iObserver->ResponseBodyReceived( dataChunk );
+
+
+ // Check if still processing the request
+ // Not running if the client cancelled the transaction
+ if ( iRunning )
+ {
+ iBody->ReleaseData();
+ iBody = 0;
+ }
+
+ // Issue timer for timeout handling
+ SetTimeoutTimer();
+
+ break;
+ }
+ default:
+ {
+ // Just release the data, not interested in the error messages
+ // Should there be a separate callback for these?
+ iBody->ReleaseData();
+ iBody = 0;
+ break;
+ }
+ }
+ }
+ break;
+
+ case THTTPEvent::EResponseComplete:
+ {
+ // Indicates that header & body of response is completely received.
+ // No further action here needed.
+ DLTRACE(("Response complete"));
+ }
+ break;
+
+ case THTTPEvent::ESucceeded:
+ {
+ DLTRACE( ( "ESucceeded" ) );
+ // Transaction can be closed now. It's not needed anymore.
+ aTransaction.Close();
+ iRunning = EFalse;
+ if ( iObserver )
+ {
+
+ if ( iLastError == KCatalogsErrorHeaderPresent )
+ {
+ iObserver->RequestCompleted( KErrUnknown );
+ }
+ else
+ {
+ iObserver->RequestCompleted( KErrNone );
+ }
+ }
+ }
+ break;
+
+ case THTTPEvent::EFailed:
+ {
+ DLTRACE( ( "EFailed" ) );
+ // Transaction completed with failure.
+
+ aTransaction.Close();
+ iRunning = EFalse;
+
+ if ( iObserver )
+ {
+ iObserver->RequestCompleted( iLastError );
+ }
+ }
+
+ break;
+
+ case THTTPEvent::EGotResponseTrailerHeaders:
+ case THTTPEvent::EMoreDataReceivedThanExpected:
+
+ case THTTPEvent::ERedirectedTemporarily:
+ case THTTPEvent::ERedirectedPermanently:
+ // Should the client change it's URI?
+
+ case THTTPEvent::ERedirectRequiresConfirmation:
+ // ?
+
+ case THTTPEvent::ETooMuchRequestData:
+ case THTTPEvent::EUnrecoverableError:
+ // ?
+
+ default:
+ // There are more events in THTTPEvent, but they are not usually
+ // needed. However, event status smaller than zero should be handled
+ // correctly since it's an error.
+ {
+ if ( aEvent.iStatus < 0 )
+ {
+ DLTRACE(( "-> ERROR: %d", aEvent.iStatus ) );
+
+ // Just close the transaction on errors
+ aTransaction.Close();
+ iRunning = EFalse;
+
+ if ( iObserver )
+ {
+ iObserver->RequestCompleted( aEvent.iStatus );
+ }
+ }
+ else if ( aEvent == THTTPEvent::ERedirectRequiresConfirmation )
+ {
+ DLTRACE( ("-> Redirection confirmation requested, confirming..." ) );
+
+ TRAPD( err, iTransaction.SubmitL() );
+
+ if ( err == KErrNone && iObserver )
+ {
+ iObserver->RequestSubmitted();
+ }
+ else if ( err != KErrNone )
+ {
+ DLTRACE( ( "-> Error resubmitting the request: %d", err ) );
+
+ // Just close the transaction on errors
+ aTransaction.Close();
+ iRunning = EFalse;
+ if ( iObserver )
+ {
+ iObserver->RequestCompleted( aEvent.iStatus );
+ }
+ }
+ }
+ else
+ {
+ DLTRACE(( "-> UNHANDLED EVENT: %d", aEvent.iStatus ));
+
+ // Other events are not errors (e.g. permanent and temporary
+ // redirections )
+ }
+ }
+ break;
+ }
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::MHFRunError()
+//
+// Inherited from MHTTPTransactionCallback
+// Called by framework when *leave* occurs in handling of transaction event.
+// These errors must be handled, or otherwise HTTP-CORE 6 panic is thrown.
+// ----------------------------------------------------------------------------
+TInt CCatalogsHttpStack::MHFRunError( TInt aError,
+ RHTTPTransaction /*aTransaction*/,
+ const THTTPEvent& /*aEvent*/ )
+ {
+ DLTRACEIN( ( "CCatalogsHttpStack::MHFRunError( %d )", aError ) );
+
+ // Just notify about the error and return KErrNone.
+ if ( iObserver )
+ {
+ iObserver->RequestCompleted( aError );
+ }
+
+ return KErrNone;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::GetNextDataPart()
+//
+// Inherited from MHTTPDataSupplier
+// Called by framework when next part of the body is needed. In this example
+// this provides data for HTTP post.
+// ----------------------------------------------------------------------------
+TBool CCatalogsHttpStack::GetNextDataPart( TPtrC8& aDataPart )
+ {
+ DLTRACEIN( ("CCatalogsHttpStack::GetNextDataPart()") );
+
+ if ( iPostData )
+ {
+ // Provide pointer to next chunk of data ( return ETrue, if last chunk )
+ // Usually only one chunk is needed, but sending big file could require
+ // loading the file in small parts.
+
+ // body in multiple parts?
+ aDataPart.Set( iPostData->Des() );
+ }
+ return ETrue;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::ReleaseData()
+//
+// Inherited from MHTTPDataSupplier
+// Called by framework. Allows us to release resources needed for previous
+// chunk. (e.g. free buffers )
+// ----------------------------------------------------------------------------
+void CCatalogsHttpStack::ReleaseData()
+ {
+ DLTRACE(( "CCatalogsHttpStack::ReleaseData()" ));
+
+ // When sending data in multiple parts we must notify the framework here:
+ // ( the framework can call GetNextDataPart() when we notify it by calling
+ // NotifyNewRequestBodyPartL())
+
+ // Doesn't anything since we send only one part and that is released in
+ // the destructor and also before we send a new request
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::Reset()
+//
+// Inherited from MHTTPDataSupplier
+// Called by framework to reset the data supplier. Indicates to the data
+// supplier that it should return to the first part of the data.
+// In practise an error has occured while sending data, and framework needs to
+// resend data.
+// ----------------------------------------------------------------------------
+TInt CCatalogsHttpStack::Reset()
+ {
+ DLTRACE(( "CCatalogsHttpStack::Reset()" ));
+
+ // Nothing needed since iPostData still exists and contains all the data.
+ // ( If a file is used and read in small parts we should seek to beginning
+ // of file and provide the first chunk again in GetNextDataPart() )
+ return KErrNone;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::OverallDataSize()
+//
+// Inherited from MHTTPDataSupplier
+// Called by framework. We should return the expected size of data to be sent.
+// If it's not know we can return KErrNotFound ( it's allowed and does not cause
+// problems, since HTTP protocol allows multipart bodys without exact content
+// length in header ).
+// ----------------------------------------------------------------------------
+TInt CCatalogsHttpStack::OverallDataSize()
+ {
+ DLTRACEIN(("this-ptr: %X", this));
+ if ( iPostData )
+ {
+ DLTRACE( ( "CCatalogsHttpStack::OverallDataSize(), data size: %d",
+ iPostData->Length() ) );
+
+ return iPostData->Length();
+ }
+ else
+ {
+ DLTRACE( ( "CCatalogsHttpStack::OverallDataSize(), ERROR, no body" ) );
+
+ return KErrNotFound;
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CCatalogsHttpStack::GetCredentialsL()
+//
+// Inherited from MHTTPAuthenticationCallback
+// Called by framework when we requested authenticated page and framework
+// needs to know username and password.
+// ----------------------------------------------------------------------------
+TBool CCatalogsHttpStack::GetCredentialsL( const TUriC8& /*aURI*/,
+ RString /*aRealm*/,
+ RStringF /*aAuthenticationType*/,
+ RString& /*aUsername*/,
+ RString& /*aPassword*/ )
+ {
+ DLTRACE( ( "CCatalogsHttpStack::GetCredentialsL()" ) );
+
+ // aURI, aRealm and aAuthenticationType are informational only. We only need
+ // to set aUsername and aPassword and return ETrue, if aUsername and
+ // aPassword are provided by user.
+ return EFalse;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpStack::ReleaseBody()
+ {
+ // If a received body part exists, release it
+ if ( iBody )
+ {
+ iBody->ReleaseData();
+ iBody = 0;
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpStack::RunL()
+ {
+ DLTRACEIN( ( "iState: %d, iStatus: %d, this: %X",
+ TInt( iState ), // cast required for armcc
+ iStatus.Int(),
+ this ) );
+
+ switch ( iState )
+ {
+ case ENone:
+ {
+ break;
+ }
+
+ case ETimeout:
+ {
+ DLTRACE(("Timeout"));
+ if ( iStatus != KErrCancel )
+ {
+ DLTRACE(( "Request timed out, cancelling" ));
+ // Request has timed out, close transaction
+ CancelTransaction();
+
+ DLERROR(("Couldn't reach the host. Reset AP"));
+ iConnectionMethod.iApnId = 0;
+
+ if ( iObserver )
+ {
+ iObserver->UpdateAccessPoint( iConnectionMethod );
+ iObserver->RequestCompleted( KErrTimedOut );
+ }
+ }
+ break;
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpStack::DoCancel()
+ {
+ DLTRACEIN(( "iStatus != KRequestPending: %d",
+ iStatus != KRequestPending ));
+
+ switch ( iState )
+ {
+ case ETimeout:
+ {
+ DLTRACE( ( "ETimeout" ) );
+ iTimer.Cancel();
+ break;
+ }
+
+
+ default:
+ {
+ // Crash fix: instead of Stop(), call Close() and then Open().
+ // When calling Stop() in early phases of connection building
+ // the phone will crash to white screen. ESock IP will crash first.
+ // Close()+Open() circumvents and seems to work.
+ break;
+ }
+ }
+ DASSERT( iStatus != KRequestPending );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpStack::SetTimeoutTimer()
+ {
+ Cancel();
+ iTimer.After( iStatus, KRequestTimeoutMicroseconds );
+
+ iState = ETimeout;
+
+ SetActive();
+ DASSERT( iStatus.Int() == KRequestPending );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpStack::CancelTimeoutTimer()
+ {
+ Cancel();
+ }