webengine/wmlengine/src/FileLoader/src/fileloader_cfilehandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 09 Jun 2010 10:52:50 +0300
branchRCL_3
changeset 42 a1a5d4e727e8
parent 26 cb62a4f66ebe
permissions -rw-r--r--
Revision: 201021 Kit: 2010123

/*
* Copyright (c) 2003 - 2004 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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:  Handler for loading file scheme.
*
*/

// INCLUDE FILES
#include <e32std.h>
#include <e32base.h>
#include <uri16.h>
#include <apmrec.h>
#include <apgcli.h>
#include <EscapeUtils.h>

#include "fileloader_cfilehandler.h"
#include "fileloader_cfileloader.h"
//#include "urlloader_loaderutils.h"
#include "nwx_http_defs.h"
#include "fileloader_csaveddeckhandler.h"
#include "TEncodingMapping.h"

//#include "PluginHandler.h"

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES

// CONSTANTS

// MACROS

// LOCAL CONSTANTS AND MACROS

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

// ============================= LOCAL FUNCTIONS ===============================


// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CFileHandler::CFileHandler
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CFileHandler::CFileHandler(const TUint16 *aUrl,
                           TUint8 aMethod,
                           TUint16 aTransId,
                           TUint8 aLoadType,
                           void *aLoadContext,
                           NW_Url_RespCallback_t *aLoadCallback,
                           CKFileLoader* aFileLoader) :
        CActive(CActive::EPriorityUserInput), iData(NULL, 0), iFileName(NULL, 0),
        iSize(0)
{
    iUrl = aUrl;
    iRedirectedUrl = NULL;
    iTransId = aTransId;
    iLoadContext = aLoadContext;
    iLoadCallback = aLoadCallback;
    iFileLoader = aFileLoader;
    iRfsOpen = EFalse;
    iFileOpen = EFalse;
    iMethod = aMethod;
    iLoadType = aLoadType;
}


// -----------------------------------------------------------------------------
// CFileHandler::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CFileHandler::ConstructL()
{
    TInt ret = KErrNone;

    if (!GetFileNameL())
    {
        User::Leave(KErrBadName);
    }

    // connect to file server
    User::LeaveIfError(iRfs.Connect(1));
    iRfsOpen = ETrue;
    // Open the file
    ret = iFile.Open(iRfs, iFileName, EFileRead | EFileShareAny);
    if (ret == KErrNotFound)
    {
        // Try again with the Uri-decoded name.
		HBufC16* decodedFileName = EscapeUtils::EscapeDecodeL(iFileName);
		TPtrC decodedFileNamePtr(*decodedFileName);

		ret = iFile.Open(iRfs, decodedFileNamePtr, EFileRead | EFileShareAny);
        if (ret == KErrNotFound)
		{
            // Convert the error KErrNotFound to a file specific error
            ret = KErrPathNotFound;
		}
		else 
		{
			// Use the decoded filename
			iFileName.Copy(decodedFileNamePtr);
			iFileName.ZeroTerminate();
		}
		delete decodedFileName;
    }

    User::LeaveIfError(ret);
    iFileOpen = ETrue;

    // Get file size
    User::LeaveIfError(iFile.Size(iSize));

    CActiveScheduler::Add(this);
}


// -----------------------------------------------------------------------------
// CFileHandler::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CFileHandler* CFileHandler::NewL(const TUint16 *aUrl,
                                 TUint8	aMethod,
                                 TUint16 aTransId,
                                 TUint8 aLoadType,
                                 void *aLoadContext,
                                 NW_Url_RespCallback_t *aLoadCallback,
                                 CKFileLoader* aFileLoader)
{
    CFileHandler* self = new( ELeave ) CFileHandler(aUrl, aMethod, aTransId,
                                                    aLoadType,
                                                    aLoadContext, aLoadCallback,
                                                    aFileLoader);

    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();

    return self;
}


// -----------------------------------------------------------------------------
// CFileHandler::~CFileHandler
// Destructor.
// -----------------------------------------------------------------------------
//
CFileHandler::~CFileHandler()
{
    if ((iFileName.Length() > 0) && (iFileName.Ptr() != NULL))
    {
        delete (TUint16*) iFileName.Ptr();
    }
    if (iFileOpen)
    {
        iFile.Close();
    }
    if (iRfsOpen)
    {
        iRfs.Close();
    }
    if(iContentType)
		{
		delete iContentType;
		}
    delete (TUint8*)iData.Ptr();
    delete iRedirectedUrl;
}


// -----------------------------------------------------------------------------
// CFileHandler::RunL
// Return the response after file loading from the File system is complete.
// -----------------------------------------------------------------------------
//
void CFileHandler::RunL()
{
    switch (iStatus.Int())
    {
        case KErrNone:
        {            
			const TText8* wmltStr = (TText8*)"0";
			TPtrC8 wmltPtr(wmltStr);
			const TText8* wmltcStr = (TText8*)"1";
			TPtrC8 wmltcPtr(wmltcStr);
			const TText8* wmlaStr = (TText8*)"2";
			TPtrC8 wmlaPtr(wmlaStr);
			const TText8* wmlacStr = (TText8*)"3";
			TPtrC8 wmlacPtr(wmlacStr);

			_LIT(KContentTypeT,"text/vnd.wap.wml");
			_LIT(KContentTypeTC,"text/vnd.wap.wmlc");
			_LIT(KContentWMLSType,"application/vnd.wap.wmlscriptc");
			_LIT(KContentWMLACType,"application/vnd.wap.wmlc");

			TInt len = KContentWMLSType().Length();
			TUint8* contentTypeString = new(ELeave) TUint8 [len + 1];
			TPtrC8 script = iData.Right(1);
			if( script.operator==(wmltPtr) )
				{
				TPtr8 contentTypeStringPtr(contentTypeString, KContentTypeT().Length() + 1); 
				contentTypeStringPtr.Copy(KContentTypeT);
				contentTypeStringPtr.ZeroTerminate();
				}
			else if(script.operator==(wmltcPtr))
				{
				TPtr8 contentTypeStringPtr(contentTypeString, KContentTypeTC().Length() + 1); 
				contentTypeStringPtr.Copy(KContentTypeTC);
				contentTypeStringPtr.ZeroTerminate();
				}
			else if(script.operator==(wmlaPtr))
				{
				TPtr8 contentTypeStringPtr(contentTypeString, KContentWMLSType().Length() + 1); 
				contentTypeStringPtr.Copy(KContentWMLSType);
				contentTypeStringPtr.ZeroTerminate();
				}
			else if(script.operator==(wmlacPtr))
				{
				TPtr8 contentTypeStringPtr(contentTypeString, KContentWMLACType().Length() + 1); 
				contentTypeStringPtr.Copy(KContentWMLACType);
				contentTypeStringPtr.ZeroTerminate();
				}

			// Get the file's content encoding.
			//If there is charset in the file, use it. Otherwise, get it basing on the content type string
			TUint16 charset = HTTP_iso_8859_1; //default to latin-1
			TBool bHasCharset = ETrue;
			TInt position = iData.LocateReverse('*');
			TInt posDollar = iData.LocateReverse('$');

			if((posDollar == KErrNotFound) || (posDollar < position)) //no charset was set
			{
				bHasCharset = EFalse;
				charset = ContentEncoding(contentTypeString);
			}
			else
			{
				TPtrC8 charsetfromfile = iData.Mid( posDollar + 1, (iData.Length() - (posDollar + 2)));
				for (int i = 0; supportedCharset[i].uid != 0; i++)
				{
					TPtrC8 charsetTemp(supportedCharset[i].charset);
					if (charsetTemp == charsetfromfile)
					{
					  charset = supportedCharset[i].ianaEncoding;
					  break;
					}
				}
			}
               
            // Check if it is a saved deck.
			// Put the "application saved page" string const and the
			// "ContentType" string in TPtrC8 to find if this is a saved page
			TPtrC8 httpSavedString(HTTP_application_saved_string);
			TPtrC8 contentString(contentTypeString);

            TUint index = contentString.FindF(httpSavedString);
			
			if ( !((0 == index) && ParseSavedDeck()) )
            {
				// Not a saved deck, send a response
                //TPtr8 data( iData ); declared up
                //
                TUint contentLength = 0;

                const TUint16* responseUrl = (iRedirectedUrl == NULL) ? iUrl : iRedirectedUrl;
                HBufC* newUrl = NULL;

                if (iMethod == NW_URL_METHOD_GET)
					{
					TInt urlLen = 0;
					if(bHasCharset)
					{
						urlLen = posDollar - position;
					}
					else
					{
						urlLen = iData.Length() - position -1;
					}

					//R->fake the url
					newUrl = HBufC::NewL( urlLen );
					newUrl->Des().Copy(iData.Mid( position + 1, urlLen-1 ));
					newUrl->Des().ZeroTerminate();				

					// Transfer ownership before calling Response
					TUint8* data = new TUint8[position];
					TPtr8 dataDes(data, position);
					dataDes.Copy(iData.Ptr(), position);
					iData.Set(NULL,0, 0);
					delete (TUint8*)iData.Ptr();		
					
					responseUrl = (TUint16*)newUrl->Ptr();

					// Send the response
					iFileLoader->PartialResponse( (TUint16*)newUrl->Ptr(), dataDes, NULL, contentTypeString, NULL, NW_FALSE, // multipart information is missing.
						NULL, NULL, charset, NULL, Success, NW_URL_METHOD_GET, iTransId, 0 /*first chunk*/, NULL, dataDes.Length(),
						KErrNone, iLoadContext, iLoadCallback);
					}
                
                // Send the close response
                iContentType = NULL;
				TPtr8 emptyData(NULL,0,0);     
                contentTypeString = iContentType;
                
				iFileLoader->PartialResponse( responseUrl, emptyData, NULL, contentTypeString, NULL, NW_FALSE, // multipart information is missing
                  NULL, NULL, charset, NULL, Success, iMethod, iTransId, -1 /*last chunk*/, NULL, contentLength,
                  KErrNone, iLoadContext, iLoadCallback);

                delete newUrl;
                }
            else
				{
                    // No response sent with this content type string,
                    // (so no subsequent delete) delete it here.
                    delete contentTypeString;
                }
			}
			
            break;

        default:
        {
            // Send an error response back
            iFileLoader->PartialResponse(iTransId, iStatus.Int(), iLoadContext, iLoadCallback);
        }
        break;
    }	// end of switch

    delete this;
}


// -----------------------------------------------------------------------------
// CFileHandler::DoCancel
// Noop. File loading cannot be cancelled.
// -----------------------------------------------------------------------------
//
void CFileHandler::DoCancel()
{
}


// -----------------------------------------------------------------------------
// CFileHandler::LoadFileL
// Create a CFileHandler object and initiate the load.
// -----------------------------------------------------------------------------
//
void CFileHandler::LoadFileL(const TUint16 *aUrl,
                             TUint16 aTransId,
                             TUint8 aLoadType,
                             void *aLoadContext,
                             NW_Url_RespCallback_t *aLoadCallback,
                             CKFileLoader* aFileLoader)
{
    __ASSERT_DEBUG(aUrl != NULL, LoaderUtils::PanicLoader());
    __ASSERT_DEBUG(aLoadCallback != NULL, LoaderUtils::PanicLoader());

    // Create a file handler object
    CFileHandler* handler = CFileHandler::NewL(aUrl, NW_URL_METHOD_GET,
            aTransId, aLoadType, aLoadContext, aLoadCallback, aFileLoader);

    // Start reading the file
    if (handler->iSize > 0)
    {
        TUint8* data = NULL;
        data = new TUint8 [handler->iSize];
        User::LeaveIfNull(data);
        handler->iData.Set(data, 0, handler->iSize);
        handler->iFile.Read(handler->iData, handler->iStatus);
    }

    handler->SetActive();
}


// -----------------------------------------------------------------------------
// CFileHandler::LoadFileL
// Create a CFileHandler object and initiate the load.
// -----------------------------------------------------------------------------
//
void CFileHandler::GetFileInfoL(const TUint16 *aUrl,
                                TUint16 aTransId,
                                TUint8 aLoadType,
                                void *aLoadContext,
                                NW_Url_RespCallback_t *aLoadCallback,
                                CKFileLoader* aFileLoader)
{
    __ASSERT_DEBUG(aUrl != NULL, LoaderUtils::PanicLoader());
    __ASSERT_DEBUG(aLoadCallback != NULL, LoaderUtils::PanicLoader());

    // Create a file handler object
    CFileHandler* handler = CFileHandler::NewL(aUrl, NW_URL_METHOD_HEAD, 
            aTransId, aLoadType, aLoadContext, aLoadCallback, aFileLoader);

    // Start reading the file
    if (handler->iSize > 0)
    {
        TUint8* data = NULL;
        data = new TUint8 [handler->iSize];
        User::LeaveIfNull(data);
        handler->iData.Set(data, 0, handler->iSize);
        handler->iFile.Read(handler->iData, handler->iStatus);
    }

    handler->SetActive();
}


// -----------------------------------------------------------------------------
// CFileHandler::ContentTypeL
// Determine the content type of the file.
// -----------------------------------------------------------------------------
void CFileHandler::ContentTypeL(TUint8** aContentTypeString)
    {
    // part of string defined in "Exported mimetypes" section in BrowserRec.h
    __ASSERT_DEBUG(aContentTypeString != NULL, LoaderUtils::PanicLoader());
    
    TDataRecognitionResult dataType;
    RApaLsSession apaSession;
    TInt ret;
    
    *aContentTypeString = NULL;
    User::LeaveIfError(apaSession.Connect());
    // Ask the application architecture to find the file type
    ret = apaSession.RecognizeData(iFileName, iData, dataType);
    apaSession.Close();
    
    if (ret == KErrNone &&
        (dataType.iConfidence == CApaDataRecognizerType::ECertain) ||
        (dataType.iConfidence == CApaDataRecognizerType::EProbable))
        {
        // If the file type was found, try to match it to a known file type
        TPtrC8 mimeTypePtr = dataType.iDataType.Des8();
        TInt len = mimeTypePtr.Length() + 1;
        *aContentTypeString = new(ELeave) TUint8 [len]; 
        
        TPtr8 contentTypeStringPtr(*aContentTypeString, len);
        contentTypeStringPtr.Copy(mimeTypePtr);
        contentTypeStringPtr.ZeroTerminate();
        return;
        }
    
    // Check if it is css
    _LIT(KCssExt, ".css");
    TPtrC extPtr (iFileName.Right(iFileName.Length() -  iFileName.LocateReverse('.')));
    if (!extPtr.CompareF(KCssExt()))
        {
        TPtrC8 mimeTypePtr(HTTP_text_css_string);
        TInt len = mimeTypePtr.Length() + 1;
        *aContentTypeString = new(ELeave) TUint8 [len]; 
        
        TPtr8 contentTypeStringPtr(*aContentTypeString, len);
        contentTypeStringPtr.Copy(mimeTypePtr);
        contentTypeStringPtr.ZeroTerminate();
        return;
        }
    
    // Check if it is wbmp
    _LIT(KWbmpExt, ".wbmp");
    extPtr.Set(iFileName.Right(iFileName.Length() -  iFileName.LocateReverse('.')));
    if (!extPtr.CompareF(KWbmpExt()))
        {
        TPtrC8 mimeTypePtr(HTTP_image_vnd_wap_wbmp_string);
        TInt len = mimeTypePtr.Length() + 1;
        *aContentTypeString = new(ELeave) TUint8 [len]; 
        
        TPtr8 contentTypeStringPtr(*aContentTypeString, len);
        contentTypeStringPtr.Copy(mimeTypePtr);
        contentTypeStringPtr.ZeroTerminate();
        return;
        }
    //R->ecma
    // Check if it is ecma
    /*
    _LIT(KEcmaScriptExt, ".es");
    _LIT(KJavaScriptExt, ".js");
    extPtr.Set(iFileName.Right(iFileName.Length() -  iFileName.LocateReverse('.')));
    if (!extPtr.CompareF(KEcmaScriptExt()) || !extPtr.CompareF(KJavaScriptExt()))
        {
        TPtrC8 mimeTypePtr(HTTP_text_ecmascript_string);
        TInt len = mimeTypePtr.Length() + 1;
        *aContentTypeString = new(ELeave) TUint8 [len]; 
        
        TPtr8 contentTypeStringPtr(*aContentTypeString, len);
        contentTypeStringPtr.Copy(mimeTypePtr);
        contentTypeStringPtr.ZeroTerminate();
        return;
        }
    */
    // Check if it is a supported plugin
    //R->embed
    //CPluginHandler* pluginHandler = CPluginHandler::GetSingleton();
    //NW_ASSERT (pluginHandler != NULL); // we should always have a plugin handler
    /* //R
    TUint16* mimeType16 = pluginHandler->GetPluginMimeTypeL(iFileName);
    if (mimeType16 != NULL)
        {
        // This file's extension is supported
        CleanupStack::PushL(mimeType16);
        TPtrC16 mimeTypePtr16(mimeType16);
        TUint8* mimeType8 = new(ELeave) TUint8 [mimeTypePtr16.Length() + 1];
        TPtr8 mimeTypePtr8(mimeType8, 0, mimeTypePtr16.Length() + 1);
        mimeTypePtr8.Copy(mimeTypePtr16);
        mimeTypePtr8.ZeroTerminate();
        CleanupStack::PopAndDestroy(); // mimeType16
        *aContentTypeString = mimeType8;
        return;
        }
	*/
    User::Leave(KBrsrWmlbrowserBadContentType);
    }


// -----------------------------------------------------------------------------
// CFileHandler::ContentEncoding
// Determine the content encoding of the file.
// -----------------------------------------------------------------------------
//
TUint16 CFileHandler::ContentEncoding(TUint8* aContentTypeString)
{
    // Assume Latin-1 for xhtml and wml. ucs2 for any other
    TUint16 charset = HTTP_iso_8859_1;

	TPtrC8 httpAppString(HTTP_application_vnd_wap_wmlc_string);
	TPtrC8 contentString(aContentTypeString);

	// Is the contentType a HTTP_application_vnd_wap_wmlc_string
	TUint index = contentString.FindF(httpAppString);
	if (index == 0)
    {
		// This is a HTTP_application_vnd_wap_wmlc_string
		charset = HTTP_iso_10646_ucs_2;
    }

    return charset;
}


// -----------------------------------------------------------------------------
// CFileHandler::GetFileNameL
// Translate the file name from a URL to a valid file name in the system.
// -----------------------------------------------------------------------------
//
TBool CFileHandler::GetFileNameL()
{
    // This function accepts URLs in the following format:
    // file://filename.xxx
    // file:///filename.xxx
    // file://c:/filename.xxx
    // file:///c:/filename.xxx
    //
    _LIT(KFileScheme, "file://");
    _LIT(KDefaultDrivePath, "C:\\");
    _LIT(KDefaultDriveInUrl, "C:/");
    _LIT(KPathChar, "\\");
    
	TUint16* name = NULL;
    TInt count;
    TInt index = 0;
    TBool drvLetter = EFalse;
    TUint16 c;

    // Verify the file scheme
    TPtrC urlPtr(iUrl);
    if (urlPtr.FindF(KFileScheme) != 0)
    {
        return EFalse;
    }
    urlPtr.Set(urlPtr.Mid(KFileScheme().Length()));

    // make sure there are enough characters in the filename before
    // trying to check them
    count = urlPtr.Length();
    if(count == 0)
    {
      return EFalse;            // no filename, so can't look at urlPtr[0]
    }

    // Skip the first '/' if there is one
	  if (urlPtr[0] == '/')
    {
        urlPtr.Set(urlPtr.Mid(1));
    }
    count = urlPtr.Length();

	// Is there a drive letter?
    if(count > 1)
    {
      // can check for drive letter
      if (urlPtr[1 + index] == ':')
      {
          drvLetter = ETrue;
      }
    }
    if(drvLetter == EFalse)
    {
		// 3 additional characters for the string "c:\"
        count = urlPtr.Length() + 3;
    }
    name = new(ELeave) TUint16 [count];
    CleanupStack::PushL(name);
    iFileName.Set(name, 0, count);
    if (!drvLetter)
    {
        // If there is no drive letter, add "C:\"
        iRedirectedUrl = new(ELeave) TUint16[count + 1 + KFileScheme().Length()];
        TPtr redirectedUrlPtr(iRedirectedUrl, count + 1 + KFileScheme().Length());
        redirectedUrlPtr.Copy(KFileScheme());
        redirectedUrlPtr.Append(KDefaultDriveInUrl);
        redirectedUrlPtr.Append(urlPtr);
        redirectedUrlPtr.ZeroTerminate();
        iFileName.Append(KDefaultDrivePath);
    }

    TBool fragment(EFalse);
    // Convert relative path containing /./ and /../ to absolute path
    for (; index < urlPtr.Length() && !fragment; index ++)
    {
        switch(urlPtr[index])
        {
        case '#':    //Check if there is a fragment '#'
            {
            fragment = ETrue;
            continue; // Just stop there
            }

        case '/':
            {
                iFileName.Append(KPathChar);
                break;
            }
        case '.':
            {
                if (index > 1 && urlPtr[index - 1] == '/')
                {
                    if (index < count - 1 && urlPtr[index + 1] == '/')
                    {
                        index ++; // skip  ./
                        break;
                    }
                    if (index > 2 && index < count - 3 &&
						urlPtr[index + 1] == '.' && urlPtr[index + 2] == '/')
                    {
                        TInt i = index - 2;

                        for (; i > 0 && urlPtr[i] != '/'; i--) {} // skip  /../
                        
                        iFileName.SetLength(iFileName.Length() - (index - i));
                        index += 2;
                        break;
                    }
                }
            }
            // no break
            //lint -fallthrough

        default:
            {
                c = urlPtr[index];
                iFileName.Append(&c, 1);
                break;
            }
        }	// end of switch
    }
    CleanupStack::Pop(); // name
    return ETrue;
}


// -----------------------------------------------------------------------------
// CFileHandler::ParseSavedDeck
// Determine if the file is a saved deck or not. If it is saved deck, parse the file.
// -----------------------------------------------------------------------------
//
TBool CFileHandler::ParseSavedDeck()
{
    TPtr8 responseData(NULL,0,0);
    TPtr responseUrl(NULL, 0, 0);
    TPtr8 contentTypeString(NULL, 0, 0);
    TUint charset;
    TBool isSavedDeck;
    TPtrC8 dataPtr(iData.Ptr(), iData.Length());
    TPtrC16 urlPtr(iUrl, User::StringLength(iUrl));

    // Create a CSavedDeckHandler object to parse the file
    TInt ret = CSavedDeckHandler::ParseSavedDeck(dataPtr, urlPtr, responseData,
               responseUrl, contentTypeString, charset, isSavedDeck);
  
    if (isSavedDeck)
      {
      // It is a saved deck
      if (ret == KErrNone)
        {
        TUint8* data = (TUint8*)iData.Ptr();
        delete data;
        // Transfer ownership before calling Response
        iData.Set(NULL, 0, 0);
        // copy contentTypeString for the second (closing) response
        TUint8* tempContentTypeString = NULL;
        tempContentTypeString = (TUint8*)NW_Mem_Malloc( contentTypeString.Length() + 1 );
        if( tempContentTypeString )
          {
           NW_Mem_memcpy( tempContentTypeString, contentTypeString.Ptr(), contentTypeString.Length() );
           tempContentTypeString[ contentTypeString.Length() ] = 0;
           // Send the first part of the file as the response
           iFileLoader->PartialResponse((TUint16*)responseUrl.Ptr(), responseData, NULL,
             (TUint8*)contentTypeString.Ptr(),  NULL, NW_FALSE, // multipart information is missing.
             NULL, NULL, (TUint16)charset, NULL, Success, 0, iTransId, 0 /*first chunk*/, NULL, responseData.Length(),
             KErrNone, iLoadContext, iLoadCallback);
           
           // Send closing response. pass tempContentTypeString ownership
           TPtr8 emptyResponseData(NULL,0,0);        
           iFileLoader->PartialResponse((TUint16*)responseUrl.Ptr(), emptyResponseData, NULL,
             tempContentTypeString, NULL, NW_FALSE, // multipart information is missing.
             NULL, NULL, (TUint16)charset, NULL, Success, 0, iTransId, -1/*last chunk*/, NULL, 0,
             KErrNone, iLoadContext, iLoadCallback);
          }
        delete (TUint16*)responseUrl.Ptr();
        }
      else
        {
        // Send an error response
        iFileLoader->PartialResponse(iTransId, ret, iLoadContext, iLoadCallback);
        }
      }
    return isSavedDeck;
  }


// ========================== OTHER EXPORTED FUNCTIONS =========================

//  End of File