diff -r 000000000000 -r dd21522fd290 webengine/osswebengine/WebKit/s60/plugins/PluginLoader.cpp --- /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 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( 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; + }