webengine/osswebengine/WebKit/s60/plugins/PluginLoader.cpp
changeset 0 dd21522fd290
child 13 10e98eab6f85
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebKit/s60/plugins/PluginLoader.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,676 @@
+/*
+* Copyright (c) 2006 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:  
+*
+*/
+#include "PluginLoader.h"
+#include "PluginWin.h"
+#include "PluginSkin.h"
+#include "UrlRequestInfo.h"
+#include "UrlResponseInfo.h"
+#include "UrlResponseHeaderInfo.h"
+#include "WebCoreUrlResponseInfo.h"
+#include "WebCoreFormData.h"
+#include "WebKitBridge.h"
+#include "WebKitControl.h"
+#include "WebKitLoader.h"
+#include "PluginHandler.h"
+
+const TInt KHttpStatusNotFound = 404;
+const TInt KHttpStatusOk = 200;
+
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::NewL
+//
+// Initializes a new plugin loader
+// -----------------------------------------------------------------------------
+//
+CPluginLoader* CPluginLoader::NewL(CPluginSkin &aPluginSkin,
+                                   CWebKitFrame& aWebKitFrame,
+                                   const TDesC8& aBaseUrl)
+    {
+    CPluginLoader* self = new (ELeave) CPluginLoader(aPluginSkin,aWebKitFrame);
+    CleanupStack::PushL( self );
+    self->ConstructL(aBaseUrl);
+    CleanupStack::Pop();    // self
+    return self;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::~CPluginLoader
+//
+// Destructor for CPluginLoader
+// -----------------------------------------------------------------------------
+//
+CPluginLoader::~CPluginLoader()
+    {
+    // cancel pending loads
+    CancelAllTransactions();
+    delete iPluginLoadDataArray;
+    delete iBaseUrl;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::LoadPluginContentL
+//
+// Method to load plugin content, as requested by constructor and other
+// webkit-plugin code
+// -----------------------------------------------------------------------------
+//
+void CPluginLoader::LoadPluginContentL( const TDesC8& aUrl, TPluginLoadMode aLoadMode )
+    {
+    CUrlRequestInfo* requestInfo = CUrlRequestInfo::NewL();
+    CleanupClosePushL( *requestInfo );
+
+    // Get the base and relative url resolved by the webcore
+    HBufC8* newUrl = CWebCoreFrameBridge::ResolveUrlL( iBaseUrl->Des(), aUrl );
+    CleanupStack::PushL( newUrl );
+    requestInfo->SetUrlL( newUrl->Des() );
+    CleanupStack::PopAndDestroy();    // newUrl
+
+    if ( aLoadMode != ELoadModeTop )
+        {
+        MContentLoaderInterface* urlLoader;
+        if ( iWebKitFrame->WebKitBridge().Loader().LoadPluginL( requestInfo,
+                                                                *this,
+                                                                urlLoader ) == KErrNone )
+            {
+            CPluginLoadData* loadData = CPluginLoadData::NewL( requestInfo->TransId() );
+            CleanupStack::PushL( loadData );
+            loadData->SetLoadMode( aLoadMode );
+            loadData->SetUrlLoader( urlLoader );
+            loadData->SetHttpStatus( KHttpStatusOk );
+            iPluginLoadDataArray->AppendL( *loadData );
+            CleanupStack::Pop();// CPluginLoadData
+            }
+        }
+    else    // aLoadMode == ELoadModeTop
+        {
+        // We received a top-level load request from webkit-plugin (Constructor, etc)
+        requestInfo->SetCacheMode( iWebKitFrame->WebKitView().WebKitControl().CacheMode() );
+        // zalan 
+        // iWebKitFrame->WebKitBridge().Loader().LoadPageL( requestInfo );
+        }
+
+    CleanupStack::Pop(); // requestInfo
+    requestInfo->Close();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::LoadPluginContentL
+//
+// Method to load additional plugin content, as requested by the plugin
+// -----------------------------------------------------------------------------
+//
+void CPluginLoader::LoadPluginContentL( const TDesC8& aUrl,
+                                        TUrlLoadMethod aMethod,
+                                        TPluginLoadMode aLoadMode,
+                                        const TPtr8& aBody, TInt &aTrId )
+    {
+
+    _LIT8(KJavaScript, "javascript:");
+
+    // Pass javascript urls to the ecmascript engine instead...
+    if ( aUrl.FindF( KJavaScript ) == 0 )
+        {
+        HBufC8* newUrl = CWebCoreFrameBridge::ResolveUrlL(iBaseUrl->Des(), aUrl);
+        CleanupStack::PushL( newUrl );
+        iWebKitFrame->WebKitBridge().WebCoreBridge().ExecuteScript( *newUrl );
+        CleanupStack::PopAndDestroy( newUrl );
+        }
+
+    CUrlRequestInfo* requestInfo = CUrlRequestInfo::NewL();
+    CleanupClosePushL( *requestInfo );
+
+    // Get the base and relative url resolved by the webcore
+    HBufC8* newUrl = CWebCoreFrameBridge::ResolveUrlL( iBaseUrl->Des(), aUrl );
+    CleanupStack::PushL( newUrl );
+    requestInfo->SetUrlL( newUrl->Des() );
+    CleanupStack::PopAndDestroy();    // newUrl
+
+    requestInfo->SetLoadMethod( aMethod );
+
+    if ( aMethod == EUrlPost && aBody.Length() > 0 )
+       {
+       RArray<TWebCoreFormDataItem> postDataItems;
+       TWebCoreFormDataItem webCoreFormData( aBody );
+       postDataItems.Append( webCoreFormData );
+       requestInfo->SetPostDataL( postDataItems );
+       postDataItems.Close();
+       }
+
+    if ( aLoadMode == ELoadModePlugin )
+        {
+        // To redirect the response back here, set the listener as *this
+        MContentLoaderInterface* urlLoader;
+        requestInfo->SetTopLevel( EFalse );
+        if ( iWebKitFrame->WebKitBridge().Loader().LoadPluginL( requestInfo,
+                                                                *this,
+                                                                urlLoader ) == KErrNone )
+            {
+            CPluginLoadData* loadData = CPluginLoadData::NewL( requestInfo->TransId() );
+
+            CleanupStack::PushL( loadData );
+            loadData->SetLoadMode( aLoadMode );
+            loadData->SetUrlLoader( urlLoader );
+            loadData->SetHttpStatus( KHttpStatusOk );
+            iPluginLoadDataArray->AppendL( *loadData );
+            CleanupStack::Pop(); // loadData
+            }
+        }
+    else    // aLoadMode == ELoadModeTop
+        {
+        // We have received a top-level load request from a plugin (see NPN_GetUrl).
+        // We currently only support window target=_Top, see NpnImplementation.cpp.
+        // Dispatch to WebKitLoader, so that it is the listener.
+        requestInfo->SetTopLevel( ETrue );
+        requestInfo->SetCacheMode( iWebKitFrame->WebKitView().WebKitControl().CacheMode() );
+        // zalan
+        //iWebKitFrame->WebKitBridge().Loader().LoadPageL( requestInfo );
+        }
+
+    aTrId = requestInfo->TransId();
+    CleanupStack::PopAndDestroy(); // requestInfo
+
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::Headers
+// From MContentListener
+//
+// This method is called in two circumstances:
+// One is during construction of the Plugin and it's initial load request.
+// The initial load request returns here when the content arrives. This method
+// then needs to create the PluginWin (plugin) in reponse to the first request
+// for content.
+// The second is that Plugins can request additional content. This method can
+// be called numerous times in response to plugin's request (see NPN_GetURL).
+//
+// This method needs to handle the initial creation of the PluginWin for the first
+// request for content. But also handle the additional calls for content correctly.
+// For example, a Flash plugin might be loaded because the html page has an
+// object tag with content of .swf. Then that same flash plugin can request
+// additonal content that is .swf or .xml.
+// -----------------------------------------------------------------------------
+TInt CPluginLoader::HeadersL( TInt aTransactionId,
+                              CUrlResponseInfo& aResponse )
+    {
+  CUrlResponseHeaderInfo& headerInfo = aResponse.HeaderInfo();
+
+    iWebKitFrame->WebKitBridge().Loader().IncomingContentInfo( aTransactionId,
+                                                               ELoadStarted,
+                                                               EFalse,
+                                                               aResponse );
+
+    CPluginLoadData* pluginLoadData = GetPluginLoadData( aTransactionId );
+
+    // Check the returned http status code
+    TUint32 httpStatus( headerInfo.HttpStatus() );
+    switch ( httpStatus )
+        {
+        // If we have a successful code, continue
+        case KHttpStatusOk:
+            {
+            break;
+            }
+
+        // If we have an http error code, return noting that plugin content
+        // not supported
+        default:
+            {
+            if( !pluginLoadData )
+                {
+                // If no content returned, just show the place holder
+                iPluginSkin->InvalidContent();
+                }
+            else
+                {
+                pluginLoadData->SetHttpStatus( KHttpStatusNotFound );
+                }
+            return KErrNone;
+            }
+        }   // end of switch
+
+    // Find the plugin load mode
+    TPluginLoadMode loadMode = ELoadModeNone;
+    if ( pluginLoadData )
+        {
+        loadMode = pluginLoadData->LoadMode();
+        }
+
+    // Get plugin handler, so we can find a plugin handle for a plugin that
+    // supports the incoming content (by mimetype or extension)
+    CPluginHandler& pluginHandler = iWebKitFrame->WebKitView().WebKitControl().PluginHandler();
+    TInt handle = pluginHandler.FindPlugin( headerInfo.ContentType() );
+    if ( handle == KErrNotFound )
+        {
+        handle = pluginHandler.FindPluginByExtension( headerInfo.ResponseUrl() );
+        }
+
+    if ( handle != KErrNotFound )
+        {
+        // We found a plugin that understands the content, so let's create the
+        // PluginWin. This method determines if we keep the current PluginWin
+        // or create a new PluginWin.
+        iPluginSkin->CreatePluginWinL( headerInfo.ContentType(),
+                                       handle, loadMode );
+        }
+
+    // At this point, we need a valid PluginWin (aka Plugin) to be created, or
+    // use the already existing plugin, to handle the incoming content.  The
+    // content type, or extension is only used to create the initial instance of
+    // plugin. Note, a plugin can request additional content that is not of the
+    // same type, or extension as the initial content, so we must let that content
+    // be passed to the existing plugin that requested it.
+    CPluginWin* pluginWin = iPluginSkin->PluginWin();
+    if ( pluginWin )
+        {
+        // Do we have a PluginWin and save as file (soundstart)
+        if (loadMode == ELoadModeSaveAsFile)
+            {
+            SaveResponseHeader( headerInfo.TransId(),
+                                headerInfo );
+            }
+        TRAPD( err, pluginWin->CreateStreamL( headerInfo.ResponseUrl(),
+                                              headerInfo.ContentType(),
+                                              headerInfo.TransId(),
+                                              headerInfo.ContentLength()) );
+        if ( err != KErrNone )
+           {
+           iPluginSkin->HandlePluginError( err );
+           CancelAllTransactions();
+           }
+        }
+    else
+        {
+        // If the plugin is not supported, just show the place holder
+        iPluginSkin->InvalidContent();
+        }
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginSkin::ResponseL
+// From MContentListener
+// -----------------------------------------------------------------------------
+void CPluginLoader::ResponseL( TInt aTransactionId, CUrlResponseInfo& aResponse )
+    {
+    // Call our super class
+    iWebKitFrame->WebKitBridge().Loader().IncomingContentInfo( aTransactionId,
+                                                               EMoreContent,
+                                                               ETrue, aResponse );
+
+    // Do not write to the plugin if the load request was bad
+    CPluginLoadData* pluginLoadData = GetPluginLoadData( aTransactionId );
+    if ( pluginLoadData && pluginLoadData->HttpStatus() == KHttpStatusNotFound )
+        {
+        return;
+        }
+
+    // Pass the data to the plugin. A plugin should make its own copy of the data
+    CPluginWin* pluginWin = iPluginSkin->PluginWin();
+    if ( pluginWin )
+        {
+        TRAPD( err, pluginWin->WriteStreamL( aTransactionId, aResponse.Body() ) );
+        if ( err != KErrNone )
+           {
+           iPluginSkin->HandlePluginError( err );
+           CancelAllTransactions();
+           }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginSkin::Complete
+// From MContentListener
+// -----------------------------------------------------------------------------
+void CPluginLoader::Complete(
+    TInt aTransactionId,
+  CUrlResponseInfo& aResponse,
+    TInt aError )
+    {
+
+    iWebKitFrame->WebKitBridge().Loader().IncomingContentInfo( aTransactionId, ELoadComplete, ETrue, aResponse );
+
+    CPluginLoadData* pluginLoadData = GetPluginLoadData(aTransactionId);
+    //Donot write to the plugin if the load request was bad
+    if(pluginLoadData && pluginLoadData->HttpStatus() == KHttpStatusNotFound)
+        {
+        RemovePluginLoadData( aTransactionId );
+        return;
+        }
+
+    CPluginWin* pluginWin = iPluginSkin->PluginWin();
+    if (aError == KErrNone && pluginWin)
+       {
+        if ( GetLoadMode(aTransactionId) == ELoadModeSaveAsFile )
+            {
+            // Soundstart case, don't play and delete content (aka DestroyStream)
+            SaveCompleteError(aTransactionId, aError);
+            }
+        else
+            {
+            // Plays content and then deletes it
+            pluginWin->DestroyStream(aTransactionId, aError);
+            }
+        }
+
+    iWebKitFrame->WebKitBridge().Loader().IncomingContentInfo( aTransactionId, ELoadComplete, ETrue, aResponse );
+
+    if ( GetLoadMode(aTransactionId) != ELoadModeSaveAsFile )
+        {
+        // If not soundstart case, the content was deleted (by DestroyStream),
+        // so we can delete CPluginLoadData. If soundstart, the content is
+        // still around, so keep CPluginLoadData so we can find it.
+        RemovePluginLoadData( aTransactionId );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginSkin::HandleError
+// From MContentListener
+// -----------------------------------------------------------------------------
+void CPluginLoader::HandleError( TInt /*aTransactionId*/,  TInt /*aError*/ )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::CPluginLoader
+//
+// Constructor for CPluginLoader
+// -----------------------------------------------------------------------------
+//
+CPluginLoader::CPluginLoader(CPluginSkin &aPluginSkin,CWebKitFrame& aWebKitFrame):
+    iWebKitFrame(&aWebKitFrame),
+    iPluginSkin(&aPluginSkin)
+    {
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::~CPluginLoader
+//
+// Symbian two phase constructor
+// -----------------------------------------------------------------------------
+//
+void CPluginLoader::ConstructL(const TDesC8& aBaseUrl)
+    {
+    iBaseUrl = HBufC8::NewL(aBaseUrl.Length());
+    iBaseUrl->Des().Copy(aBaseUrl);
+    iPluginLoadDataArray = new(ELeave) CArrayFixFlat<CPluginLoadData>( 2 );
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::GetTransactionId
+// Public method
+// Method to return transaction Id, using the request url
+// -----------------------------------------------------------------------------
+TInt CPluginLoader::GetTransactionId( const TDesC8& aRequestUrl )
+    {
+  for (TInt i = 0;i < iPluginLoadDataArray->Count(); i++)
+      {
+      CPluginLoadData& loadData = iPluginLoadDataArray->At(i);
+      if (loadData.RequestUrlL())
+          {
+        if (aRequestUrl.Compare(*loadData.RequestUrlL()) == 0)
+            {
+          return loadData.TransactionId();
+            }
+          }
+      }
+  return KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::GetCompleteError
+// Public method
+// Method to return complete error code for a transaction
+// -----------------------------------------------------------------------------
+TInt CPluginLoader::GetCompleteError( TInt aTrId )
+    {
+  for (TInt i = 0;i < iPluginLoadDataArray->Count(); i++)
+      {
+      CPluginLoadData& loadData = iPluginLoadDataArray->At(i);
+    if (loadData.TransactionId() == aTrId)
+        {
+      return loadData.CompleteError();
+        }
+      }
+  return KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::GetLoadData
+// Public method
+// Method to return load data for a transaction
+// -----------------------------------------------------------------------------
+CPluginLoadData* CPluginLoader::GetPluginLoadData(TInt aTrId)
+    {
+    for (TInt i = 0;i < iPluginLoadDataArray->Count(); i++)
+        {
+        if (iPluginLoadDataArray->At(i).TransactionId() == aTrId)
+            {
+            return &(iPluginLoadDataArray->At(i));
+            }
+        }
+    return 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::RemovePluginLoadData
+//
+// -----------------------------------------------------------------------------
+void CPluginLoader::RemovePluginLoadData(
+    TInt aTransactionId )
+    {
+    for (TInt i = 0;i < iPluginLoadDataArray->Count(); i++)
+        {
+        if (iPluginLoadDataArray->At(i).TransactionId() == aTransactionId)
+            {
+            iPluginLoadDataArray->Delete( i );
+            return;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::CancelAllTransactions
+//
+// -----------------------------------------------------------------------------
+void CPluginLoader::CancelAllTransactions()
+    {
+    // cancel pending loads
+    TRAP_IGNORE(
+        for ( TInt i = 0; i < iPluginLoadDataArray->Count(); i++)
+              {
+              iPluginLoadDataArray->At(i).UrlLoader()->CancelL( iPluginLoadDataArray->At(i).TransactionId() );
+              }
+        );
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::GetLoadMode
+// Public method
+// Method to return load mode for a transaction
+// -----------------------------------------------------------------------------
+TPluginLoadMode CPluginLoader::GetLoadMode(TInt aTrId)
+    {
+  for (TInt i = 0;i < iPluginLoadDataArray->Count(); i++)
+      {
+      CPluginLoadData& loadData = iPluginLoadDataArray->At(i);
+    if (loadData.TransactionId() == aTrId)
+        {
+      return loadData.LoadMode();
+        }
+      }
+  return ELoadModeNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::SaveCompleteError
+// Save the request complete error code for a transaction. Use Transaction Id
+// as the index into the PluginLoadDataArray.
+// -----------------------------------------------------------------------------
+TBool CPluginLoader::SaveCompleteError(
+    TInt aTrId,
+    TInt aError)
+    {
+  for (TInt i = 0;i < iPluginLoadDataArray->Count(); i++)
+      {
+      CPluginLoadData& loadData = iPluginLoadDataArray->At(i);
+    if (loadData.TransactionId() == aTrId)
+        {
+        loadData.SetCompleteError(aError);
+      return ETrue;
+        }
+      }
+
+  return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoader::SaveResponseHeader
+// Save the response header for a transaction. Use Transaction Id
+// as the index into the PluginLoadDataArray.
+// -----------------------------------------------------------------------------
+TBool CPluginLoader::SaveResponseHeader( TInt aTrId,
+                                         CUrlResponseHeaderInfo& aResponseHeader )
+    {
+  for (TInt i = 0;i < iPluginLoadDataArray->Count(); i++)
+      {
+      CPluginLoadData& loadData = iPluginLoadDataArray->At(i);
+    if (loadData.TransactionId() == aTrId)
+        {
+        loadData.SetRequestUrlL(aResponseHeader.RequestUrl());
+        return ETrue;
+        }
+      }
+
+  return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoadData - A helper class for CPluginLoader
+// -----------------------------------------------------------------------------
+// CPluginLoadData::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CPluginLoadData* CPluginLoadData::NewL(TInt aTrId)
+    {
+    CPluginLoadData* self = new( ELeave ) CPluginLoadData(aTrId);
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoadData::CPluginLoadData
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CPluginLoadData::CPluginLoadData(TInt aTrId)
+    : iTransId(aTrId),
+      iCompleteError(-1)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoadData::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CPluginLoadData::ConstructL()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoadData::~CPluginLoadData
+// Deconstructor.
+// -----------------------------------------------------------------------------
+//
+CPluginLoadData::~CPluginLoadData()
+    {
+    delete iRequestUrl;
+    iRequestUrl = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoadData::SetHttpStatus
+// Public method
+// Save the http staus
+// -----------------------------------------------------------------------------
+//
+void CPluginLoadData::SetHttpStatus(TInt aHttpStatus)
+{
+  iHttpStatus = aHttpStatus;
+}
+
+// -----------------------------------------------------------------------------
+// CPluginLoadData::SetLoadMode
+// Public method
+// Save the load mode.
+// -----------------------------------------------------------------------------
+//
+void CPluginLoadData::SetLoadMode(TPluginLoadMode aLoadMode)
+    {
+    iLoadMode = aLoadMode;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoadData::SetCompleteError
+// Public method
+// Save the completion error from response complete
+// -----------------------------------------------------------------------------
+//
+void CPluginLoadData::SetCompleteError(TInt aCompleteError)
+    {
+    iCompleteError = aCompleteError;
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoadData::SetRequestUrlL
+// Public method
+// Save the request url. We take ownership of the url.
+// -----------------------------------------------------------------------------
+//
+void CPluginLoadData::SetRequestUrlL(const TDesC8& aRequestUrl)
+    {
+    if (iRequestUrl)
+        {
+        delete iRequestUrl;
+        iRequestUrl = NULL;
+        }
+
+    iRequestUrl = aRequestUrl.AllocL();
+    }
+
+// -----------------------------------------------------------------------------
+// CPluginLoadData::SetUrlLoader()
+// Public method
+// Save the url loader
+// -----------------------------------------------------------------------------
+//
+void CPluginLoadData::SetUrlLoader(MContentLoaderInterface* aUrlLoader)
+    {
+    iUrlLoader = aUrlLoader;
+    }