xdmprotocols/XcapProtocol/XcapOperations/src/XcapHttpOperation.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:23:14 +0100
branchRCL_3
changeset 35 fbd2e7cec7ef
parent 0 c8caa15ef882
child 12 e6a66db4e9d0
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201027 Kit: 201035

/*
* Copyright (c) 2005 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:   CXcapHttpOperation
*
*/



#include <XdmErrors.h>
#include <escapeutils.h>
#include "XcapDocument.h"
#include "XcapProtocol.h"
#include "XcapAppUsage.h"
#include "XcapUriParser.h"
#include "XdmXmlParser.h"
#include "XcapHttpRequest.h"
#include "XdmNodeAttribute.h"
#include "XcapEngineDefines.h"
#include "XcapHttpOperation.h"
#include "XcapHttpContSupplier.h"
#include "XcapOperationFactory.h"

// ---------------------------------------------------------
// C++ constructor can NOT contain any code, that
// might leave.
// ---------------------------------------------------------
//
CXcapHttpOperation::CXcapHttpOperation( const CXdmDocument& aTargetDoc,
                                        CXcapDocumentNode* aDocumentSubset,
                                        CXcapOperationFactory& aOperationFactory ) :
                                        CActive( EPriorityStandard ),
                                        iDocumentSubset( aDocumentSubset ),
                                        iTargetDoc( ( CXcapDocument& )aTargetDoc ),
                                        iOperationFactory( aOperationFactory ) 
                                                                                
    {
    }

// ---------------------------------------------------------
// CXcapHttpOperation::BaseConstructL
//
// ---------------------------------------------------------
//
void CXcapHttpOperation::BaseConstructL()
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "-> CXcapHttpOperation::BaseConstructL" ) ); 
    #endif
    iXmlParser = &iTargetDoc.Protocol().Parser();
    iUriParser = CXcapUriParser::NewL( iTargetDoc, iOperationFactory );
    #ifdef _DEBUG
        TPtrC8 contType( iTargetDoc.ApplicationUsage().ContentType() );
        iOperationFactory.WriteToLog( _L8( " Content-Type: %S" ), &contType ); 
    #endif
    CActiveScheduler::Add( this );
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "<- CXcapHttpOperation::BaseConstructL" ) ); 
    #endif
    }

// ---------------------------------------------------------
// Destructor
//
// ---------------------------------------------------------
//
CXcapHttpOperation::~CXcapHttpOperation()
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapHttpOperation::~CXcapHttpOperation()" ) );  
    #endif
    delete iUriParser;
    iRequestQueue.ResetAndDestroy();
    }

// ---------------------------------------------------------
// CXcapOperationBase::IsCompleted
//
// ---------------------------------------------------------
//
TBool CXcapHttpOperation::IsCompleted() const
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapOperationBase::IsCompleted()" ) );  
    #endif
    return iCompleted;
    }
    
// ---------------------------------------------------------
// CXcapOperationBase::CompletionData
//
// ---------------------------------------------------------
//
const TXdmCompletionData& CXcapHttpOperation::CompletionData() const
    {
    return *iRequestData;
    }

// ---------------------------------------------------------
// CXcapOperationBase::CompletionData
//
// ---------------------------------------------------------
//
CXdmDocumentNode* CXcapHttpOperation::TargetNode() const
    {
    return iDocumentSubset;
    }
    
// ---------------------------------------------------------
// CXcapOperationBase::CompletionData
//
// ---------------------------------------------------------
//
void CXcapHttpOperation::Destroy()
    {
    delete this;
    }
    
// ---------------------------------------------------------
// CXcapHttpOperation::Result
//
// ---------------------------------------------------------
//
TInt CXcapHttpOperation::Result() const
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapHttpOperation::Result()" ) );  
    #endif
    return iRequestData != NULL ? iRequestData->iHttpStatus : KErrUnknown;
    }

// ---------------------------------------------------------
// CXcapHttpOperation::ExecuteL
//
// ---------------------------------------------------------
//
void CXcapHttpOperation::ExecuteL( TRequestStatus& aStatus, TUint aOptions )
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapHttpOperation::ExecuteL( &status )" ) );  
    #endif
    iOptionFlags = aOptions;
    iClientStatus = &aStatus;
    aStatus = KRequestPending;
    if( !IsActive() )
        {
        iActiveRequest = iRequestQueue[iCurrentIndex];
        TRAPD( error, ExecuteL() );
        if( error == KErrNone )
            {
            if( StartOperationL() )
                SetActive();
            else
                {
                iFailureData.iCompletion = KXcapErrorNetworkNotAvailabe;
                User::RequestComplete( iClientStatus, KXcapErrorNetworkNotAvailabe );
                iRequestData = &iFailureData;
                }      
            }
        else
            {
            #ifdef _DEBUG
                iOperationFactory.WriteToLog( _L8( " Execution failed with %d" ), error );  
            #endif
            iFailureData.iCompletion = error;
            User::RequestComplete( iClientStatus, error );
            iRequestData = &iFailureData;
            }
        }
    else  //This is a re-run of a previously failed request
        {
        if( !StartOperationL() )
            {
            #ifdef _DEBUG
                iOperationFactory.WriteToLog( _L8( " Execution succeeded, network not ready" ) );  
            #endif
            User::RequestComplete( iClientStatus, KXcapErrorNetworkNotAvailabe );
            }
        }  
    }

// ---------------------------------------------------------
// CXcapHttpOperation::ExecuteL
//       
// ---------------------------------------------------------
//
void CXcapHttpOperation::ExecuteL( CXcapHttpRequest* aHttpRequest,
                                   CXdmDocumentNode* aDocumentNode )
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapAddition::ExecuteL()" ) );  
    #endif
    CXdmDocumentNode* node = aDocumentNode == NULL ?
                             iTargetDoc.DocumentRoot() : aDocumentNode;
    __ASSERT_ALWAYS( node != NULL, User::Panic( _L( "CXcapAddition" ), 1 ) );
    User::LeaveIfError( FormatModRequestL( node ) );
    TRAPD( error, iUriParser->ParseL( aHttpRequest->RequestUriL() ) );
    if( error == KErrNone )
        {
        TPtrC8 uri = iUriParser->DesC8();
        HBufC8* escape = CXcapHttpOperation::EscapeLC( uri );
        aHttpRequest->UpdateRequestUriL( escape->Des() );
        CleanupStack::PopAndDestroy();  //escape
        }
    }
    
// ---------------------------------------------------------
// CXcapHttpOperation::StartOperationL
//
// ---------------------------------------------------------
//
TBool CXcapHttpOperation::StartOperationL()
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapHttpOperation::StartOperationL()" ) );  
    #endif
    if( iTargetDoc.Protocol().IsNetworkAvailable() )
        {
        #ifdef _DEBUG
            iOperationFactory.WriteToLog( _L8( " All set, dispatch request to transport" ) );  
        #endif
        if( iOptionFlags & KUseIntendedIdentity )
            {
            TPtrC8 identity( iTargetDoc.Protocol().PublicID() );
            #ifdef _DEBUG
                iOperationFactory.WriteToLog( _L8( " Early-IMS set, add X-3GPP-Intended-Identity header" ) );
                iOperationFactory.WriteToLog( _L8( "  Public ID: %S" ), &identity );  
            #endif
            iActiveRequest->SetHeaderL( KHttpHeaderIntIdentity, identity );
            }
        iActiveRequest->DispatchRequestL( iStatus );
        return ETrue;
        }
    else return EFalse;
    }
    
// ---------------------------------------------------------
// CXcapHttpOperation::RunL
//
// ---------------------------------------------------------
//
void CXcapHttpOperation::RunL()
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( 
        "CXcapHttpOperation::RunL() - Status: %d" ), iStatus.Int() );  
    #endif
    TInt count = iRequestQueue.Count();
    iRequestData = iActiveRequest->ResponseData();
    __ASSERT_DEBUG( iRequestData != NULL, User::Panic( _L( "CXcapHttpOperation" ), 1 ) );
    TRAPD( error, iStatus != KErrNone ? OperationFailedL() : OperationCompleteL() );
    if( error == KErrNone && !iCompleted )
        SetActive();
    else
        {
        #ifdef _DEBUG
            iOperationFactory.WriteToLog( _L8( 
                "  ** Operation completed - Result: %d  Error: %d **" ), iResult, error );  
        #endif
        iCurrentIndex = 0;
        iResult = error < KErrNone ? error : iResult;
        iRequestData->iCompletion = iResult;
        User::RequestComplete( iClientStatus, iResult );
        }
    }

// ---------------------------------------------------------
// CXcapRetrieval::CancelOperation
//
// ---------------------------------------------------------
//
void CXcapHttpOperation::CancelOperation()
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapHttpOperation::CancelOperation()" ) );  
    #endif
    if( IsActive() )
        {
        #ifdef _DEBUG
            iOperationFactory.WriteToLog( _L8( "Active, cancel HTTP request" ) );  
        #endif
        Cancel();
        iRequestData = &iFailureData;
        iFailureData.iCompletion = KErrCancel;
        User::RequestComplete( iClientStatus, KErrCancel );
        }
    }
    
// ---------------------------------------------------------
// CXcapHttpOperation::CancelOperation
//
// ---------------------------------------------------------
//
void CXcapHttpOperation::DoCancel()
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapHttpOperation::DoCancel()" ) );  
    #endif
    iRequestQueue[iCurrentIndex]->CancelRequest();   
    }

// ---------------------------------------------------------
// CXcapHttpOperation::Descriptor
//
// ---------------------------------------------------------
//
TPtrC8 CXcapHttpOperation::Descriptor( HBufC8* aBuffer )
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapHttpOperation::Descriptor()" ) );  
    #endif
    if( aBuffer != NULL )
        {
        TPtrC8 descriptor( aBuffer->Des() );
        return descriptor.Length() > 0 ? descriptor : TPtrC8();
        }
    else
        {
        #ifdef _DEBUG
            iOperationFactory.WriteToLog( _L8( " Buffer is NULL, return empty descriptor" ) );  
        #endif
        return TPtrC8();
        }
    }

// ---------------------------------------------------------
// CXcapHttpOperation::Transport
//
// ---------------------------------------------------------
//
CXcapHttpTransport& CXcapHttpOperation::Transport() const
    {
    return iTargetDoc.Protocol().Transport();
    }
    
// ---------------------------------------------------------
// CXcapHttpOperation::FormatModRequestL
//
// ---------------------------------------------------------
//
TInt CXcapHttpOperation::FormatModRequestL( const CXdmDocumentNode* aDocumentNode )
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapHttpOperation::FormatModRequestL()" ) );  
    #endif
    HBufC8* body = NULL;
    TInt error = KErrNone;
    CXcapAppUsage& usage = iTargetDoc.ApplicationUsage();
    CXcapHttpContSupplier* request = ( CXcapHttpContSupplier* )iActiveRequest;
    switch( iUriParser->NodeType() )
        {
        case EXdmElementAttribute:
            {
            CXdmNodeAttribute* attribute = ( CXdmNodeAttribute* )aDocumentNode;
            body = attribute->EightBitValueLC();
            request->SetRequestBodyL( body->Des() );
            CleanupStack::PopAndDestroy();  //body
            request->SetHeaderL( KHttpHeaderAccept, _L8( "application/xcap-diff+xml" ) );
            request->SetHeaderL( KHttpHeaderContentType, _L8( "application/xcap-att+xml" ) );
            }
            break;
        case EXdmElementNode:
            {
            #ifndef __OVERRIDE_VALIDATION__
                error = usage.Validate( CONST_CAST( CXdmDocumentNode&, *aDocumentNode ), iUriParser, EFalse );
            #endif
            if( error == KErrNone )
                {
                #ifdef _DEBUG
                    iOperationFactory.WriteToLog( _L8( " Validation of a partial document OK" ) );  
                #endif
                body = iXmlParser->FormatToXmlLC( EFalse, &iTargetDoc, aDocumentNode );
                request->SetRequestBodyL( body->Des() );
                CleanupStack::PopAndDestroy();  //body
                request->SetHeaderL( KHttpHeaderAccept, _L8( "application/xcap-diff+xml" ) );
                request->SetHeaderL( KHttpHeaderContentType, _L8( "application/xcap-el+xml" ) );
                }
            else
                {
                #ifdef _DEBUG
                    iOperationFactory.WriteToLog( _L8( " Validation failed: %d" ), error );  
                #endif
                }
            }
            break;
        default:
        #ifndef __OVERRIDE_VALIDATION__
            error = usage.Validate( iTargetDoc, ETrue );
        #endif
            if( error == KErrNone )
                {
                #ifdef _DEBUG
                    iOperationFactory.WriteToLog( _L8( " Validation OK" ) );  
                #endif
                body = iXmlParser->FormatToXmlLC( ETrue, &iTargetDoc, aDocumentNode );
                request->SetRequestBodyL( body->Des() );
                CleanupStack::PopAndDestroy();  //body
                }
            else
                {
                #ifdef _DEBUG
                    iOperationFactory.WriteToLog( _L8( " Validation failed: %d" ), error );  
                #endif
                }
            break;
        }
    return error;
    }

// ----------------------------------------------------------
// CXcapHttpOperation::ReinterpretStatus
// 
// ----------------------------------------------------------
//
TInt CXcapHttpOperation::ReinterpretStatus( const TInt aHttpStatus ) const
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapHttpOperation::ReinterpretStatus()" ) );  
    #endif
    switch( aHttpStatus )
        {
        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
        case 405:  //Method Not Allowed
		case 408:  //Request Timeout
		case 410:  //Gone
		case 411:  //Length Required
		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
            return KXcapErrorHttpServer;
        case 400:
            return KXcapErrorHttpBadRequest;
        case 401:
            return KXcapErrorHttpUnauthorised;
        case 403:
            return KXcapErrorHttpForbidden;
        case 404:
            return KXcapErrorHttpNotFound;
        case 409:
            return KXcapErrorHttpConflict;
        case 412:
            return KXcapErrorHttpPrecondFailed;
        default:
            return KErrNone;
        }
    }

// ---------------------------------------------------------
// CXcapHttpOperation::Escape2LC
// 
// ---------------------------------------------------------
//
HBufC8* CXcapHttpOperation::Escape2LC( const TDesC& aDescriptor )
    {
    HBufC8* eight = EscapeUtils::ConvertFromUnicodeToUtf8L( aDescriptor );
    CleanupStack::PushL( eight );
    HBufC8* buf = EscapeUtils::EscapeEncodeL( eight->Des(), EscapeUtils::EEscapeNormal );
    CleanupStack::PopAndDestroy();  //eight
    CleanupStack::PushL( buf );
    return buf;
    }
    
// ---------------------------------------------------------
// CXcapHttpOperation::EscapeLC
// 
// ---------------------------------------------------------
//
HBufC8* CXcapHttpOperation::EscapeLC( const TDesC8& aDescriptor )
    {
    CBufFlat* buffer = CBufFlat::NewL( 50 );
    CleanupStack::PushL( buffer );
    TInt bufPos = 0;
    TBuf8<10> format;
    for( TInt i = 0;i < aDescriptor.Length();i++ )
        {
        TUint8 byte = aDescriptor[i];
        if( byte < 0x7F )                 //US-ASCII
            {
            switch( byte )
                {
                case 0x20:                // ' '
                case 0x22:                // '"'
                case 0x3B:                // ';'                 
                case 0x26:                // '&'                  
                case 0x3C:                // '<'                  
                case 0x3E:                // '>'
                case 0x5B:                // '['
                case 0x5D:                // ']'                              
                    format.Append( _L8( "%" ) );
                    format.AppendFormat( _L8( "%x" ), byte );
                    break;               
                default:
                    format.Append( byte );
                    break;
                }
            }
        else
            {
            format.Append( _L8( "%" ) );  //UNICODE
            format.AppendFormat( _L8( "%x" ), byte );
            }
        buffer->InsertL( bufPos, format );
        bufPos = bufPos + format.Length();
        format.Zero();
        }
    HBufC8* ret = HBufC8::NewL( buffer->Size() );
    TPtr8 pointer( ret->Des() );
    buffer->Read( 0, pointer, buffer->Size() );
    CleanupStack::PopAndDestroy();  //buffer
    CleanupStack::PushL( ret );
    return ret;
    }
               
// ---------------------------------------------------------
// CXcapHttpOperation::HttpRequest
//
// ---------------------------------------------------------
//
CXcapHttpRequest* CXcapHttpOperation::HttpRequest() const
    {
    #ifdef _DEBUG
        iOperationFactory.WriteToLog( _L8( "CXcapHttpOperation::HttpRequest()" ) );  
    #endif
    return iActiveRequest;
    }



//  End of File