--- a/upnpmediaserver/contentdirectoryservice/src/dlna/upnpdlnafilter.cpp Fri Sep 17 08:31:21 2010 +0300
+++ b/upnpmediaserver/contentdirectoryservice/src/dlna/upnpdlnafilter.cpp Mon Nov 01 12:37:49 2010 +0200
@@ -1,901 +1,910 @@
-/** @file
- * Copyright (c) 2005-2006 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: CUpnpDlnaFilter implementation.
- *
- */
-// INCLUDES
-#include <bautils.h>
-#include "upnpdlnafilter.h"
-#include "upnpstring.h"
-#include "upnpcons.h"
-#include "upnpcontentdirectorydatafinder.h"
-#include "upnphttpmessage.h"
-#include "upnpdlnaprotocolinfo.h"
-#include "upnpfileutils.h"
-#include "upnpsecuritymanager.h"
-#define KLogFile _L("DLNAWebServer.txt")
-#include "upnpcustomlog.h"
-#include "upnphttpfilereceivetransaction.h"
-#include "upnphttpfileservetransaction.h"
-#include "upnpdlnafilterheaders.h"
-#include "upnpcommonupnplits.h"
-#include "upnpdlnacorelation.h"
-
-// CONSTANTS
-_LIT8( KDlnaFilter, "DLNA");
-_LIT8( KIpPortPlaceholder8, "___.___.___.___:_____" );
-
-// ============================ MEMBER FUNCTIONS ===============================
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::CUpnpDlnaFilter
-// C++ default constructor.
-// -----------------------------------------------------------------------------
-//
-CUpnpDlnaFilter::CUpnpDlnaFilter( MUpnpContentDirectoryDataFinder* aFinder,
- CUpnpSecurityManager* aSecurityManager ) :
- iCdDataFinder( aFinder ), iSecurityManager( aSecurityManager )
- {
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::~CUpnpDlnaFilter
-// C++ default destructor.
-// -----------------------------------------------------------------------------
-//
-CUpnpDlnaFilter::~CUpnpDlnaFilter()
- {
- iFs.Close();
- delete iProtocolInfo;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::NewLC
-// Two-phased constructor.
-// -----------------------------------------------------------------------------
-//
-CUpnpDlnaFilter* CUpnpDlnaFilter::NewLC(
- MUpnpContentDirectoryDataFinder* aFinder,
- CUpnpSecurityManager* aSecurityManager )
- {
- CUpnpDlnaFilter* self = new (ELeave) CUpnpDlnaFilter( aFinder,
- aSecurityManager );
- CleanupStack::PushL( self );
- self->ConstructL();
- return self;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::NewL
-// Two-phased constructor.
-// -----------------------------------------------------------------------------
-//
-CUpnpDlnaFilter* CUpnpDlnaFilter::NewL(
- MUpnpContentDirectoryDataFinder* aFinder,
- CUpnpSecurityManager* aSecurityManager )
- {
- CUpnpDlnaFilter* self =
- CUpnpDlnaFilter::NewLC( aFinder, aSecurityManager );
- CleanupStack::Pop( self );
- return self;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::ConstructL
-// EPOC default constructor for performing 2nd stage construction.
-// -----------------------------------------------------------------------------
-//
-void CUpnpDlnaFilter::ConstructL()
- {
- User::LeaveIfError( iFs.Connect() );
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::SecurityManager
-//
-// -----------------------------------------------------------------------------
-//
-CUpnpSecurityManager* CUpnpDlnaFilter::SecurityManager()
- {
- return iSecurityManager;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::CheckImportUriL
-// Checks if specified URI exists in database and returns object id for
-// given URI or KErrNotFound if URI is no registered in database.
-// -----------------------------------------------------------------------------
-//
-TInt CUpnpDlnaFilter::CheckImportUriL( TDesC8& aImportUri )
- {
- TInt lastPosOfSlash = aImportUri.LocateReverse( '/' );
- if ( lastPosOfSlash < 0 )
- {
- return KErrGeneral;
- }
- HBufC8* path = aImportUri.AllocLC();
- TInt result = KErrNone;
- result = iCdDataFinder->CheckImportUriL( path->Des() );
- CleanupStack::PopAndDestroy( path );
- return result;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::Get3rdFieldFromCdL
-// Find protocolInfo by contentUri (Not by importUri) and extract 3rd field,
-// using ContentDirectory.
-// -----------------------------------------------------------------------------
-//
-HBufC8* CUpnpDlnaFilter::ThirdFieldFromCdL( const TDesC8& aContentUri )
- {
- HBufC8* result = NULL;
- CUpnpDlnaProtocolInfo* protocolInfo = ProtocolInfoL( aContentUri );
- if ( protocolInfo )
- {
- TPtrC8 thirdField = protocolInfo->ThirdField();
- if ( thirdField != KNullDesC8() )
- {
- result = thirdField.AllocL();
- }
- }
- delete protocolInfo;
- return result;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::ProtocolInfoL
-//
-// -----------------------------------------------------------------------------
-//
-CUpnpDlnaProtocolInfo* CUpnpDlnaFilter::ProtocolInfoL( const TDesC8& aContentUri )
- {
- // "http:/:/" prefix is added to content path to provide backward
- // compatibility with old testing tools
- HBufC8* fullContentUri = HBufC8::NewL( UpnpHTTP::KHTTPUrl().Length()
- + KIpPortPlaceholder8().Length() + aContentUri.Length() );
- CleanupStack::PushL( fullContentUri );
-
- fullContentUri->Des().Append( UpnpHTTP::KHTTPUrl );
- fullContentUri->Des().Append( KIpPortPlaceholder8 );
- fullContentUri->Des().Append( aContentUri );
-
- CUpnpDlnaProtocolInfo* protocolInfo = NULL;
- if ( iCdDataFinder->GetProtocolInfoL( *fullContentUri, protocolInfo ) != KErrNone )
- {
- delete protocolInfo;
- protocolInfo = NULL;
- }
- CleanupStack::PopAndDestroy( fullContentUri );
- return protocolInfo;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::GetMediaFileNameL
-// Gets name of file with content for given object's id.
-// -----------------------------------------------------------------------------
-//
-void CUpnpDlnaFilter::GetMediaFileNameL( TInt aObjectId, TPtr& aFileName )
- {
- if ( aObjectId <= KErrNone )
- {
- return;
- }
- iCdDataFinder->GetTitleForUriL( aObjectId, aFileName );
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::FindSharedFolderDBL
-// Find a folder shared from DB (ContentDirectory).
-// -----------------------------------------------------------------------------
-//
-TInt CUpnpDlnaFilter::FindSharedFolderDBL( const TDesC8& aUrlPath,
- const TDesC8& aFileName, HBufC8*& aSystemPath )
- {
- HBufC* unicodeSharedFolder = NULL;
- TInt result = KErrNone;
- HBufC16* urlPathUnicode = UpnpString::ToUnicodeL( aUrlPath );
- CleanupStack::PushL( urlPathUnicode );
- HBufC16* fileNameUnicode = UpnpString::ToUnicodeL( aFileName );
- CleanupStack::PushL( fileNameUnicode );
-
- result = iCdDataFinder->FindSharedFolderL( *urlPathUnicode,
- *fileNameUnicode, unicodeSharedFolder );
- if ( unicodeSharedFolder )
- {
- CleanupStack::PushL( unicodeSharedFolder );
- HBufC8* sharedFolder =
- UpnpString::FromUnicodeL( *unicodeSharedFolder );
- CleanupStack::PopAndDestroy( unicodeSharedFolder );
- aSystemPath = sharedFolder;
- }
-
- CleanupStack::PopAndDestroy( fileNameUnicode );
- CleanupStack::PopAndDestroy( urlPathUnicode );
- return result;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::CheckDLNAPostCorrelationsL
-//
-// -----------------------------------------------------------------------------
-//
-TInt CUpnpDlnaFilter::CheckDLNAPostCorrelationsL( CUpnpHttpFileReceiveTransaction& aTransaction )
- {
- TPtrC8 contentURI = aTransaction.SenderUri();
- HBufC8* decodedContentURI = HBufC8::NewLC( contentURI.Length() );
- TPtr8 ptrDecodedContentURI = decodedContentURI->Des();
- ptrDecodedContentURI.Copy( contentURI );
- UpnpString::ReplaceHttpCharacters( ptrDecodedContentURI );
-
- TBool streamingSupport = 0;
- TBool interactiveSupport = 0;
-
- CUpnpDlnaProtocolInfo* protocolInfo = NULL;
- TRAPD( error, protocolInfo =
- iCdDataFinder->GetProtocolInfoByImportUriL( *decodedContentURI ) );
- CleanupStack::PopAndDestroy( decodedContentURI );
- if ( error )
- {
- if ( error == ERestrictedObject || error == ERestrictedParentObject )
- {
- return -EHttpForbidden;
- }
- else if ( error == ENoSuchObject )
- {
- return -EHttpNotFound;
- }
- else
- {
- return -EHttpBadRequest;
- }
- }
- CleanupStack::PushL( protocolInfo );
- if ( protocolInfo->FourthField().Find( KDlnaFilter ) == KErrNotFound )
- {
- aTransaction.FilterHeaders().RemoveHeaderL( UpnpDLNA::KHdrTransferMode );
- CleanupStack::PopAndDestroy( protocolInfo );
- return KErrNone;
- }
- else
- {
- streamingSupport = protocolInfo->DlnaFlag(
- UpnpDlnaProtocolInfo::TM_S_FLAG );
- interactiveSupport = protocolInfo->DlnaFlag(
- UpnpDlnaProtocolInfo::TM_I_FLAG );
- CleanupStack::PopAndDestroy( protocolInfo );
- }
-
- TDesC8& transferMode = aTransaction.FilterHeaders().QueryHeader(
- UpnpDLNA::KHdrTransferMode );
-
- if ( transferMode.Length() > 0 )
- {
- if ( (transferMode.CompareC( UpnpDLNA::KTransferModeStreaming ) == 0
- && !streamingSupport) || (transferMode.CompareC(
- UpnpDLNA::KTransferModeInteractive ) == 0 && !interactiveSupport) )
- {
- return -EHttpNotAcceptable;
- }
-
- if ( transferMode.CompareC( UpnpDLNA::KTransferModeStreaming ) != 0
- && transferMode.CompareC( UpnpDLNA::KTransferModeInteractive )
- != 0 && transferMode.CompareC(
- UpnpDLNA::KTransferModeBackground ) != 0 )
- {
- return -EHttpBadRequest;
- }
- }
-
- return KErrNone;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::CheckDLNACorrelations
-//
-// -----------------------------------------------------------------------------
-//
-TInt CUpnpDlnaFilter::CheckDLNACorrelationsL( CUpnpHttpFileServeTransaction& aTransaction )
- {
- TPtrC8 contentURI = aTransaction.SenderUri() ;
- HBufC8* decodedContentURI = HBufC8::NewL( contentURI.Length() );
- TPtr8 ptrDecodedContentURI = decodedContentURI->Des();
- ptrDecodedContentURI.Copy( contentURI );
- UpnpString::ReplaceHttpCharacters( ptrDecodedContentURI );
- CleanupStack::PushL( decodedContentURI );
- delete iProtocolInfo;
- iProtocolInfo = NULL;
- iProtocolInfo = ProtocolInfoL( *decodedContentURI );
- CleanupStack::PopAndDestroy( decodedContentURI );
- TPtrC8 fourthField( KNullDesC8 );
- if ( iProtocolInfo )
- {
- fourthField.Set( iProtocolInfo->FourthField() );
- }
-
- if ( fourthField.Find( KDlnaFilter ) == KErrNotFound )
- {
- aTransaction.FilterHeaders().RemoveHeaderL( UpnpDLNA::KHdrTransferMode );
- return KErrNone;
- }
-
- TUpnpDlnaCorelation dlnaCorelation;
- dlnaCorelation.iFourthField.Set( fourthField );
-
- TInt corelationError = CheckCorelationL( aTransaction, dlnaCorelation );
- if ( corelationError != KErrNone )
- {
- return corelationError;
- }
- corelationError = CheckTransferModeL( aTransaction, dlnaCorelation );
- if ( corelationError != KErrNone )
- {
- return corelationError;
- }
- return KErrNone;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpHttpServer::CheckCorelationL
-// -----------------------------------------------------------------------------
-//
-TInt CUpnpDlnaFilter::CheckCorelationL( CUpnpHttpFileServeTransaction& aTransaction,
- TUpnpDlnaCorelation& aDlnaCorelation )
- {
- //-------------Checking DLNA correlations, response with HTTPerror if some problem occurs
- // DLNA v0.75, 7.3.31.1 checking Operations Parameter
- if (
- // We don't support timeSeek and playSpeed at the moment, so according to point 7.4.71.1 (ver 1.5 rev 0.96)
- ((aTransaction.QueryRequestHeader( UpnpDLNA::KHdrTimeSeekRange ) != KNullDesC8()
- || aTransaction.QueryRequestHeader( UpnpDLNA::KHdrPlaySpeed )
- != KNullDesC8()) &&
- // 7.4.71.2 - range takes precedence
- aTransaction.QueryRequestHeader( UpnpHTTP::KHdrRange ) == KNullDesC8())
- ||
- //
- // or if request mode is Streaming and
- (aTransaction.QueryRequestHeader( UpnpDLNA::KHdrTransferMode ). CompareC(
- UpnpDLNA::KTransferModeStreaming ) == 0 && (
- // if we have no protocolInfo (because for example there is no cdDataFinder )
- !iProtocolInfo ||
- // Streaming is not supported for this content type
- iProtocolInfo -> DlnaFlag(
- UpnpDlnaProtocolInfo::TM_S_FLAG ) == EFalse)) )
- {
- // we respond with 406 error code - Not Acceptable.
- return -EHttpNotAcceptable;
- }
-
- aDlnaCorelation.iStreamingSupport = EFalse;
- aDlnaCorelation.iInteractiveSupport = EFalse;
- aDlnaCorelation.iBackgrondSupport = EFalse;
- aDlnaCorelation.iGetContentFeaturesExist = EFalse;
- aDlnaCorelation.iGetContentFeaturesIsOK = ETrue;
-
- // We can only check for getcontentFeaturesExist if we have cdDataFinder ( protocolInfo is not null )
- if ( iProtocolInfo )
- {
- aDlnaCorelation.iBackgrondSupport = 1;
- aDlnaCorelation.iStreamingSupport = iProtocolInfo->DlnaFlag(
- UpnpDlnaProtocolInfo::TM_S_FLAG );
- aDlnaCorelation.iInteractiveSupport = iProtocolInfo->DlnaFlag(
- UpnpDlnaProtocolInfo::TM_I_FLAG );
- if( aTransaction.QueryRequestHeader( UpnpDLNA::KHdrGetcontentFeatures() ) != KNullDesC8() )
- {
- aDlnaCorelation.iGetContentFeaturesExist = ETrue;
- }
- if( aDlnaCorelation.iGetContentFeaturesExist )
- {
- TDesC8& cntHeaderValue = aTransaction.QueryRequestHeader(
- UpnpDLNA::KHdrGetcontentFeatures() );
- if ( cntHeaderValue != UpnpDLNA::KHdrGetcontentFeaturesValue() )
- {
- aDlnaCorelation.iGetContentFeaturesIsOK = EFalse;
- }
- }
- }
-
- // Append contentFeatures.dlna.org
- if ( aDlnaCorelation.iGetContentFeaturesExist )
- {
- if ( aDlnaCorelation.iFourthField.Length() > 0 )
- {
- aTransaction.FilterHeaders().AddHeaderL( UpnpDLNA::KHdrContentFeatures,
- aDlnaCorelation.iFourthField );
- }
- }
- return KErrNone;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpHttpServer::CheckTransferMode
-// -----------------------------------------------------------------------------
-//
-TInt CUpnpDlnaFilter::CheckTransferModeL( CUpnpHttpFileServeTransaction& aTransaction,
- TUpnpDlnaCorelation& aDlnaCorelation )
- {
- TDesC8& transferMode = aTransaction.QueryRequestHeader( UpnpDLNA::KHdrTransferMode );
- // Check if requested transfer mode is handled
- if (
- // if client requested for transfer is not empty
- (transferMode.Length() > 0 && (
- // and if client requested for transfer is different than Background, Streaming or Interactive mode, reply with 400 error
- (transferMode.CompareC( UpnpDLNA::KTransferModeStreaming ) != 0
- && transferMode.CompareC(
- UpnpDLNA::KTransferModeInteractive ) != 0
- && transferMode.CompareC(
- UpnpDLNA::KTransferModeBackground ) != 0) ||
- // If Background or Interactive mode was requested, check if request doesn;t contain forbidden headers
- ((transferMode.CompareC(
- UpnpDLNA::KTransferModeBackground ) == 0
- || transferMode.CompareC(
- UpnpDLNA::KTransferModeInteractive ) == 0)
- && (aTransaction.QueryRequestHeader(
- UpnpDLNA::KHdrTimeSeekRange ) != KNullDesC8()
- || aTransaction.QueryRequestHeader(
- UpnpDLNA::KHdrPlaySpeed )
- != KNullDesC8()
- || aTransaction.QueryRequestHeader(
- UpnpDLNA::KHdrRealTimeInfo )
- != KNullDesC8())))) || (
-
- aTransaction.QueryRequestHeader( UpnpHTTP::KHdrRange ) == KNullDesC8()
- && transferMode.Length() == 0 && (aTransaction.QueryRequestHeader(
- UpnpDLNA::KHdrTimeSeekRange ) != KNullDesC8()
- || aTransaction.QueryRequestHeader( UpnpDLNA::KHdrPlaySpeed )
- != KNullDesC8() || aTransaction.QueryRequestHeader(
- UpnpDLNA::KHdrRealTimeInfo ) != KNullDesC8()))
- || !aDlnaCorelation.iGetContentFeaturesIsOK
-
- )
- {
- return -EHttpBadRequest ;
- }
-
- return AppendCorelationHeadersL( aTransaction, aDlnaCorelation, transferMode );
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpHttpServer::AppendCorelationHeaders
-// -----------------------------------------------------------------------------
-//
-TInt CUpnpDlnaFilter::AppendCorelationHeadersL( CUpnpHttpFileServeTransaction& aTransaction,
- TUpnpDlnaCorelation& aDlnaCorelation, TDesC8& aTransferMode )
- {
- if ( aTransferMode.Length() > 0 && ((aTransferMode.CompareC(
- UpnpDLNA::KTransferModeStreaming ) == 0 && !aDlnaCorelation.iStreamingSupport)
- || (aTransferMode.CompareC( UpnpDLNA::KTransferModeInteractive )
- == 0 && !aDlnaCorelation.iInteractiveSupport)) )
- {
- return -EHttpNotAcceptable ;
- }
- else if ( aTransferMode.Length() <= 0 )
- {
- if ( aDlnaCorelation.iStreamingSupport )
- {
- aTransaction.FilterHeaders().AddHeaderL( UpnpDLNA::KHdrTransferMode,
- UpnpDLNA::KTransferModeStreaming );
- }
- else if ( aDlnaCorelation.iInteractiveSupport )
- {
- aTransaction.FilterHeaders().AddHeaderL( UpnpDLNA::KHdrTransferMode,
- UpnpDLNA::KTransferModeInteractive );
- }
- else if ( aDlnaCorelation.iBackgrondSupport )
- {
- aTransaction.FilterHeaders().AddHeaderL( UpnpDLNA::KHdrTransferMode,
- UpnpDLNA::KTransferModeBackground );
- }
- }
- return KErrNone;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpHttpSession::FormatPathL
-//
-// -----------------------------------------------------------------------------
-//
-void CUpnpDlnaFilter::FormatPathL( CUpnpHttpFileServeTransaction *aTransaction, TDes &aPath )
- {
- LOGS( "%i, CUpnpHttpSession::FormatPathL " );
-
- TPtrC8 contentURI = aTransaction->SenderUri();
-
- HBufC8* decodedContentURI = HBufC8::NewL( contentURI.Length() );
- TPtr8 ptrDecodedContentURI = decodedContentURI->Des();
- ptrDecodedContentURI.Copy( contentURI );
- UpnpString::ReplaceHttpCharacters( ptrDecodedContentURI );
- CleanupStack::PushL( decodedContentURI );
-
- //extracting URLpath (so removing IP, port )
- TPtrC8 fileName;
- TInt parseError( KErrNone );
- TPtrC8 urlPath = UpnpFileUtil::ExtractUrlPath( ptrDecodedContentURI,
- fileName, parseError );
- if ( parseError )
- {
- User::Leave( -EHttpBadRequest );
- }
-
- HBufC8* sharedFolder = NULL;
- TInt error = FindSharedFolderDBL( urlPath, fileName, sharedFolder );
- CleanupStack::PushL( sharedFolder );
- if ( error == KErrNotFound || !sharedFolder )
- {
- User::Leave( -EHttpNotFound );
- }
-
- //sharedFolder includes file name
- ASSERT( (*sharedFolder).Mid( (*sharedFolder).Length()
- - UpnpString::KDoubleBackSlash().Length() )
- != UpnpString::KDoubleBackSlash() );
-
- HBufC* path16 = UpnpString::ToUnicodeL( *sharedFolder );
- aPath.Copy( *path16 );
- delete path16;
-
- CleanupStack::PopAndDestroy( sharedFolder );
- CleanupStack::PopAndDestroy( decodedContentURI );
- }
-
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::GetContentTypeL()
-// Retrieves a mime type from the third field of the protocol info read from CD
-// -----------------------------------------------------------------------------
-//
-TInt CUpnpDlnaFilter::GetContentTypeL( CUpnpHttpFileServeTransaction &aTransaction,
- HBufC8*& aMime, const TDesC16& aFilename )
- {
- TInt error = KErrNone;
-
- TParse parse;
- parse.Set( aFilename, NULL, NULL );
- TBufC16<KMaxName> ext( parse.Ext() );
- //XML mime type has to be set seperately
- if ( ext.FindC( KXml16 ) == 0 && ext.Length() == KXml16().Length() )
- {
- // Extension says that's XML but we check content to be sure and get encoding
- _LIT8( KXmlUtf8, "text/xml; charset=\"utf-8\"" );
- aMime = HBufC8::NewL( KXmlUtf8().Length() );
- aMime->Des().Zero();
- aMime->Des().Append( KXmlUtf8() );
- return error;
- }
-
- //decoding content URI
- TPtrC8 contentURI = aTransaction.SenderUri();
- HBufC8* decodedContentURI = HBufC8::NewL( contentURI.Length() );
- TPtr8 ptrDecodedContentURI = decodedContentURI->Des();
- ptrDecodedContentURI.Copy( contentURI );
- UpnpString::ReplaceHttpCharacters( ptrDecodedContentURI );
- CleanupStack::PushL( decodedContentURI );
-
- //getting 3rd field
- aMime = ThirdFieldFromCdL( *decodedContentURI );
- CleanupStack::PopAndDestroy( decodedContentURI );
- // asterick as mime type is not good - so error is KErrNotFound
- _LIT8( KAseriskType, "*" );
- if ( (NULL == aMime) || ((*aMime) == KAseriskType()) )
- {
- delete aMime;
- aMime = NULL;
- error = KErrNotFound;
- }
- return error;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::DetermineDownloadPathL
-//
-// -----------------------------------------------------------------------------
-//
-HBufC* CUpnpDlnaFilter::DetermineDownloadPathL(
- CUpnpHttpFileReceiveTransaction& aTransaction )
- {
- TPtrC8 path = aTransaction.SenderUri();
- TInt parseError( KErrNone );
- TPtrC8 urlPath = UpnpFileUtil::ExtractUrlPath( path, parseError );
- if ( parseError )
- {
- User::Leave( EHttpBadRequest );
- }
-
- // if importURI is bad then doesn't check shared folder just return error.
- TInt result = CheckImportUriL( path );
- if ( KErrNone == result )
- {
- return KNullDesC().AllocL();
- }
- if ( result < KErrNone && result != KErrGeneral )
- {
- return NULL;
- }
- HBufC* fileName = HBufC::NewLC( KMaxFileName );
- TPtr fileNamePtr( fileName->Des() );
- GetMediaFileNameL( result, fileNamePtr );
-
- HBufC8* sharedFolder = NULL;
- FindSharedFolderDBL( urlPath, KNullDesC8, sharedFolder );
- CleanupStack::PushL( sharedFolder );
-
- HBufC* folder = UpnpString::ToUnicodeL( *sharedFolder );
- CleanupStack::PushL( folder );
-
- if ( fileName->Length() == 0)
- {
- _LIT(KNoDcTitle, "no_dc_title");
- fileName->Des().Copy(KNoDcTitle);
- }
-
- HBufC* resultFileName = HBufC::NewL( folder->Length() + fileName->Length() );
- resultFileName->Des().Zero();
- resultFileName->Des().Append( *folder );
- resultFileName->Des().Append( *fileName );
-
- CleanupStack::PopAndDestroy( folder );
- CleanupStack::PopAndDestroy( sharedFolder );
- CleanupStack::PopAndDestroy( fileName );
-
- CleanupStack::PushL( resultFileName );
- HBufC* uniqueFileName = MakeFileNameUniqueL(*resultFileName, iFs );
- CleanupStack::PopAndDestroy( resultFileName );
-
- return uniqueFileName;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::PrepareHeaderL
-//
-// -----------------------------------------------------------------------------
-//
-TInt CUpnpDlnaFilter::PrepareHeaderL( CUpnpHttpFileServeTransaction& aTransaction )
- {
- HBufC8* mimetype = NULL;
- HBufC16* fileName = aTransaction.PathWithNewMethodL();
- CleanupStack::PushL( fileName );
-
- if ( GetContentTypeL( aTransaction, mimetype, *fileName ) != KErrNone )
- {
- //getting mime type from Symbian or by the extension
- mimetype = UpnpFileUtil::GetMimeTypeForFileL( *fileName );
- }
- CleanupStack::PushL( mimetype );
- aTransaction.AddResponseHeaderL( UpnpGENA::KContentType(), *mimetype );
- CleanupStack::PopAndDestroy( mimetype );
-
- // Checks if all DLNA correlations are ok and adds proper headers
- // only for GET response
-
- TInt dlnaCorrelationsError = CheckDLNACorrelationsL( aTransaction );
- if ( dlnaCorrelationsError < KErrNone )
- {
- CleanupStack::PopAndDestroy( fileName );
- return dlnaCorrelationsError;
- }
-
-
- AddHeaderIfNotEmptyL( UpnpDLNA::KHdrContentFeatures(), aTransaction );
-
- // 7.4.42.2 HTTP Server Endpoints that transfer Non-Cacheable Content using · HTTP/1.0, and· GET responses.
- // These devices must prevent intermediate caching by including among the HTTP response headers
- // the directive:· Pragma: no-cache
- aTransaction.AddResponseHeaderL( UpnpHTTP::KHdrPragma(),
- UpnpHTTP::KNoCache() );
- aTransaction.AddResponseHeaderL( UpnpHTTP::KHdrCacheControl(),
- UpnpHTTP::KNoCache() );
-
-
- // If Accept-Language header is present
- if ( aTransaction.QueryRequestHeader( UpnpHTTP::KHdrAcceptLanguage() ).Length() > 0 )
- {
- aTransaction.AddResponseHeaderL( UpnpHTTP::KHdrContentLanguage(),
- UpnpHTTP::KLanguageEn() );
- }
-
- // Transfer Mode
- // If Transfer Mode header is present
- AddHeaderIfNotEmptyL( UpnpDLNA::KHdrTransferMode, aTransaction );
-
- CleanupStack::PopAndDestroy( fileName );
- return KErrNone;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::AddHeaderIfNotEmptyL
-//
-// -----------------------------------------------------------------------------
-//
-void CUpnpDlnaFilter::AddHeaderIfNotEmptyL( const TDesC8& aHeaderName,
- CUpnpHttpFileServeTransaction& aTransaction )
- {
- if ( aTransaction.FilterHeaders().QueryHeader( aHeaderName ).Length() > 0 )
- {
- aTransaction.AddResponseHeaderL( aHeaderName,
- aTransaction.FilterHeaders().QueryHeader( aHeaderName ) );
- }
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::NewTransactionL
-//
-// -----------------------------------------------------------------------------
-//
-void CUpnpDlnaFilter::NewTransactionL( const TDesC8& aMethod, const TDesC8& aUri,
- const TInetAddr& aSender, CUpnpHttpServerTransaction*& aResultTrans )
- {
- if ( aMethod == KHttpPost() )
- {
- aResultTrans = CUpnpHttpFileReceiveTransaction::NewL( *this, aSender, aUri );
- }
- else
- {
- aResultTrans = CUpnpHttpFileServeTransaction::NewL( *this, aSender, aUri );
- }
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::AuthorizeRequestL
-//
-// -----------------------------------------------------------------------------
-//
-TInt CUpnpDlnaFilter::AuthorizeRequestL(
- const TDesC& aFileName, const TInetAddr& aSender )
- {
- TInt result( KErrNone );
- CUpnpHttpMessage* tempMessage = CUpnpHttpMessage::NewL( aSender );
- CleanupStack::PushL( tempMessage );
- if ( SecurityManager()
- && SecurityManager()->AuthorizeMessage( tempMessage,
- (TFileName&) aFileName ) != KErrNone )
- { //not showing why resource is refused
- result = -EHttpNotFound;
- }
- CleanupStack::PopAndDestroy( tempMessage );
- return result;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::FileSession
-// -----------------------------------------------------------------------------
-//
-RFs& CUpnpDlnaFilter::FileSession()
- {
- return iFs;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::PreparePostfixToMakeFileUniqueL
-// -----------------------------------------------------------------------------
-//
-HBufC* CUpnpDlnaFilter::PreparePostfixToMakeFileUniqueL( const TDesC& aFilename, RFs& aFs )
- {
- _LIT( KUnderScore, "_" );
- const TInt KDotLength = 1; // when aFileName is without extension
-
- HBufC16* newFile = HBufC16::NewLC( aFilename.Length() + KUnderScore().Length()
- + UpnpString::KMaxTUintLength + KDotLength );
-
- TParse parse;
- parse.Set( aFilename, NULL, NULL );
- TPtrC fileName = parse.Name();
- TPtrC fileExt = parse.Ext();
- TPtrC filePath = parse.DriveAndPath();
-
- TUint64 postfixNumber = 1;
-
- do
- {
- TBuf<UpnpString::KMaxTUintLength + 1> buf;
- buf.AppendNum( postfixNumber++ );
- if ( buf.Length() > UpnpString::KMaxTUintLength )
- {
- User::Leave( KErrOverflow );
- }
- newFile->Des().Copy( filePath );
- newFile->Des().Append( fileName );
- newFile->Des().Append( KUnderScore() );
- newFile->Des().Append( buf );
- newFile->Des().Append( fileExt );
- }
- while ( BaflUtils::FileExists( aFs, newFile->Des() ) );
-
- CleanupStack::Pop( newFile );
- return newFile;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::PrepareBaseFileNameL
-// -----------------------------------------------------------------------------
-//
-HBufC* CUpnpDlnaFilter::PrepareBaseFileNameL( const TDesC& aFilename, RFs& aFs )
- {
- HBufC* fileToServe;
- if ( aFilename.LocateReverse( '\\' ) == aFilename.Length() - 1 )
- {
- _LIT( KNoName0, "noName_0" );
- const TInt KZeroPostfixLen = 2; //_0
-
- fileToServe = HBufC::NewL( aFilename.Length() + KNoName0().Length() );
- fileToServe->Des().Copy( aFilename );
- fileToServe->Des().Append( KNoName0() );
-
- if ( BaflUtils::FileExists( aFs, *fileToServe ) )
- {
- fileToServe->Des().Delete( fileToServe->Length() - KZeroPostfixLen, KZeroPostfixLen );
- }
- }
- else
- {
- fileToServe = HBufC::NewL( aFilename.Length() );
- fileToServe->Des().Copy( aFilename );
- }
-
- if ( BaflUtils::FileExists( aFs, *fileToServe ) )
- {
- CleanupStack::PushL( fileToServe );
- HBufC* newFileName = PreparePostfixToMakeFileUniqueL( *fileToServe, aFs );
- CleanupStack::PopAndDestroy( fileToServe );
- fileToServe = newFileName;
- }
- return fileToServe;
- }
-
-// -----------------------------------------------------------------------------
-// CUpnpDlnaFilter::MakeFileNameUniqueL
-// -----------------------------------------------------------------------------
-//
-HBufC* CUpnpDlnaFilter::MakeFileNameUniqueL( const TDesC& aFilename, RFs& aFs )
- {
- HBufC* fileToServe = PrepareBaseFileNameL( aFilename, aFs );
-
- TPtrC questionmark;
- questionmark.Set( *fileToServe );
- TInt lastSlash = questionmark.LocateReverse( '\\' );
- TInt lastQuestionMark = questionmark.LocateReverse( '?' );
- if ( lastQuestionMark != KErrNotFound && lastSlash < lastQuestionMark )
- {
- CleanupStack::PushL( fileToServe );
- questionmark.Set( questionmark.Left( lastQuestionMark ) );
-
- // now setting new name for file
- HBufC* newFileName; //necessary not to loose current fileToServe
- newFileName = HBufC::NewL( questionmark.Length() );
- newFileName->Des().Copy( questionmark );
- CleanupStack::PopAndDestroy( fileToServe );
- fileToServe = newFileName;
- }
-
- TPtrC path;
- path.Set( *fileToServe );
- TInt lastPosOfSlash = 0;
- TInt posOfBackSlash = path.Find( KDoubleBackSlash );
-
- while ( posOfBackSlash != KErrNotFound )
- {
- path.Set( path.Mid( posOfBackSlash + 1 ) );
- lastPosOfSlash = lastPosOfSlash + posOfBackSlash + 1;
- posOfBackSlash = path.Find( KDoubleBackSlash );
- }
-
- if ( lastPosOfSlash > 0 )
- {
- path.Set( *fileToServe );
- path.Set( path.Left( lastPosOfSlash ) );
- }
-
- return fileToServe;
- }
-
-
-// End of File
+/** @file
+ * Copyright (c) 2005-2009 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: CUpnpDlnaFilter implementation.
+ *
+ */
+// INCLUDES
+#include <bautils.h>
+#include "upnpdlnafilter.h"
+#include "upnpstring.h"
+#include "upnpcons.h"
+#include "upnpcontentdirectorydatafinder.h"
+#include "upnphttpmessage.h"
+#include "upnpdlnaprotocolinfo.h"
+#include "upnpfileutils.h"
+#include "upnpsecuritymanager.h"
+#define KLogFile _L("DLNAWebServer.txt")
+#include "upnpcustomlog.h"
+#include "upnphttpfilereceivetransaction.h"
+#include "upnphttpdataservetransaction.h"
+#include "upnpdlnafilterheaders.h"
+#include "upnpcommonupnplits.h"
+#include "upnpdlnacorelation.h"
+
+
+// CONSTANTS
+_LIT8( KDlnaFilter, "DLNA");
+_LIT8( KIpPortPlaceholder8, "___.___.___.___:_____" );
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CUpnpDlnaFilter* CUpnpDlnaFilter::NewL(
+ MUpnpContentDirectoryDataFinder* aFinder,
+ CUpnpSecurityManager* aSecurityManager )
+ {
+ CUpnpDlnaFilter* self =
+ CUpnpDlnaFilter::NewLC( aFinder, aSecurityManager );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::NewTransactionL
+//
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpDlnaFilter::NewTransactionL( const TDesC8& aMethod, const TDesC8& aUri,
+ const TInetAddr& aSender, CUpnpHttpServerTransaction*& aResultTrans )
+ {
+ if ( aMethod == KHttpPost() )
+ {
+ aResultTrans = CUpnpHttpFileReceiveTransaction::NewL( *this, aSender, aUri );
+ }
+ else
+ {
+ aResultTrans = CUpnpHttpDataServeTransaction::NewL( *this, aSender, aUri );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CUpnpDlnaFilter* CUpnpDlnaFilter::NewLC(
+ MUpnpContentDirectoryDataFinder* aFinder,
+ CUpnpSecurityManager* aSecurityManager )
+ {
+ CUpnpDlnaFilter* self = new (ELeave) CUpnpDlnaFilter( aFinder,
+ aSecurityManager );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::CUpnpDlnaFilter
+// C++ default constructor.
+// -----------------------------------------------------------------------------
+//
+CUpnpDlnaFilter::CUpnpDlnaFilter( MUpnpContentDirectoryDataFinder* aFinder,
+ CUpnpSecurityManager* aSecurityManager ) :
+ iCdDataFinder( aFinder ), iSecurityManager( aSecurityManager )
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::~CUpnpDlnaFilter
+// C++ default destructor.
+// -----------------------------------------------------------------------------
+//
+CUpnpDlnaFilter::~CUpnpDlnaFilter()
+ {
+ iFs.Close();
+ delete iProtocolInfo;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::ConstructL
+// EPOC default constructor for performing 2nd stage construction.
+// -----------------------------------------------------------------------------
+//
+void CUpnpDlnaFilter::ConstructL()
+ {
+ User::LeaveIfError( iFs.Connect() );
+ User::LeaveIfNull(iCdDataFinder);
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::SecurityManager
+//
+// -----------------------------------------------------------------------------
+//
+CUpnpSecurityManager* CUpnpDlnaFilter::SecurityManager()
+ {
+ return iSecurityManager;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::CheckImportUriL
+// Checks if specified URI exists in database and returns object id for
+// given URI or KErrNotFound if URI is no registered in database.
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpDlnaFilter::CheckImportUriL( TDesC8& aImportUri )
+ {
+ TInt lastPosOfSlash = aImportUri.LocateReverse( '/' );
+ if ( lastPosOfSlash < 0 )
+ {
+ return KErrGeneral;
+ }
+ HBufC8* path = aImportUri.AllocLC();
+ TInt result = KErrNone;
+ result = iCdDataFinder->CheckImportUriL( path->Des() );
+ CleanupStack::PopAndDestroy( path );
+ return result;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::Get3rdFieldFromCdL
+// Find protocolInfo by contentUri (Not by importUri) and extract 3rd field,
+// using ContentDirectory.
+// -----------------------------------------------------------------------------
+//
+HBufC8* CUpnpDlnaFilter::ThirdFieldFromCdL( const TDesC8& aContentUri )
+ {
+ HBufC8* result = NULL;
+ CUpnpDlnaProtocolInfo* protocolInfo = ProtocolInfoL( aContentUri );
+ CleanupStack::PushL(protocolInfo);
+ if ( protocolInfo )
+ {
+ TPtrC8 thirdField = protocolInfo->ThirdField();
+ if ( thirdField != KNullDesC8() )
+ {
+ result = thirdField.AllocL();
+ }
+ }
+ CleanupStack::PopAndDestroy(protocolInfo);
+ return result;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::ProtocolInfoL
+//
+// -----------------------------------------------------------------------------
+//
+CUpnpDlnaProtocolInfo* CUpnpDlnaFilter::ProtocolInfoL( const TDesC8& aContentUri )
+ {
+ // "http:/:/" prefix is added to content path to provide backward
+ // compatibility with old testing tools
+ HBufC8* fullContentUri = HBufC8::NewL( UpnpHTTP::KHTTPUrl().Length()
+ + KIpPortPlaceholder8().Length() + aContentUri.Length() );
+ CleanupStack::PushL( fullContentUri );
+
+ fullContentUri->Des().Append( UpnpHTTP::KHTTPUrl );
+ fullContentUri->Des().Append( KIpPortPlaceholder8 );
+ fullContentUri->Des().Append( aContentUri );
+
+ CUpnpDlnaProtocolInfo* protocolInfo = NULL;
+ if ( iCdDataFinder->GetProtocolInfoL( *fullContentUri, protocolInfo ) != KErrNone )
+ {
+ delete protocolInfo;
+ protocolInfo = NULL;
+ }
+ CleanupStack::PopAndDestroy( fullContentUri );
+ return protocolInfo;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::GetMediaFileNameL
+// Gets name of file with content for given object's id.
+// -----------------------------------------------------------------------------
+//
+void CUpnpDlnaFilter::GetMediaFileNameL( TInt aObjectId, TPtr& aFileName )
+ {
+ if ( aObjectId <= KErrNone )
+ {
+ return;
+ }
+ iCdDataFinder->GetTitleForUriL( aObjectId, aFileName );
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::FindSharedFolderDBL
+// Find a folder shared from DB (ContentDirectory).
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpDlnaFilter::FindSharedFolderDBL( const TDesC8& aUrlPath,
+ const TDesC8& aFileName, HBufC8*& aSystemPath )
+ {
+ HBufC* unicodeSharedFolder = NULL;
+ TInt result = KErrNone;
+ HBufC16* urlPathUnicode = UpnpString::ToUnicodeL( aUrlPath );
+ CleanupStack::PushL( urlPathUnicode );
+ HBufC16* fileNameUnicode = UpnpString::ToUnicodeL( aFileName );
+ CleanupStack::PushL( fileNameUnicode );
+
+ result = iCdDataFinder->FindSharedFolderL( *urlPathUnicode,
+ *fileNameUnicode, unicodeSharedFolder );
+ if ( unicodeSharedFolder )
+ {
+ CleanupStack::PushL( unicodeSharedFolder );
+ HBufC8* sharedFolder =
+ UpnpString::FromUnicodeL( *unicodeSharedFolder );
+ CleanupStack::PopAndDestroy( unicodeSharedFolder );
+ aSystemPath = sharedFolder;
+ }
+
+ CleanupStack::PopAndDestroy( fileNameUnicode );
+ CleanupStack::PopAndDestroy( urlPathUnicode );
+ return result;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::CheckDLNAPostCorrelationsL
+//
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpDlnaFilter::CheckDLNAPostCorrelationsL( CUpnpHttpFileReceiveTransaction& aTransaction )
+ {
+ HBufC8* decodedContentURI = DecodeContentUriLC(aTransaction.SenderUri());
+
+ TBool streamingSupport = 0;
+ TBool interactiveSupport = 0;
+
+ CUpnpDlnaProtocolInfo* protocolInfo = NULL;
+ TRAPD( error, protocolInfo =
+ iCdDataFinder->GetProtocolInfoByImportUriL( *decodedContentURI ) );
+ CleanupStack::PopAndDestroy( decodedContentURI );
+ if ( error )
+ {
+ if ( error == ERestrictedObject || error == ERestrictedParentObject )
+ {
+ return -EHttpForbidden;
+ }
+ else if ( error == ENoSuchObject )
+ {
+ return -EHttpNotFound;
+ }
+ else
+ {
+ return -EHttpBadRequest;
+ }
+ }
+ CleanupStack::PushL( protocolInfo );
+ if ( protocolInfo->FourthField().Find( KDlnaFilter ) == KErrNotFound )
+ {
+ aTransaction.FilterHeaders().RemoveHeaderL( UpnpDLNA::KHdrTransferMode );
+ CleanupStack::PopAndDestroy( protocolInfo );
+ return KErrNone;
+ }
+ else
+ {
+ streamingSupport = protocolInfo->DlnaFlag(
+ UpnpDlnaProtocolInfo::TM_S_FLAG );
+ interactiveSupport = protocolInfo->DlnaFlag(
+ UpnpDlnaProtocolInfo::TM_I_FLAG );
+ CleanupStack::PopAndDestroy( protocolInfo );
+ }
+
+ TDesC8& transferMode = aTransaction.FilterHeaders().QueryHeader(
+ UpnpDLNA::KHdrTransferMode );
+
+ if ( transferMode.Length() > 0 )
+ {
+ if ( (transferMode.CompareC( UpnpDLNA::KTransferModeStreaming ) == 0
+ && !streamingSupport) || (transferMode.CompareC(
+ UpnpDLNA::KTransferModeInteractive ) == 0 && !interactiveSupport) )
+ {
+ return -EHttpNotAcceptable;
+ }
+
+ if ( transferMode.CompareC( UpnpDLNA::KTransferModeStreaming ) != 0
+ && transferMode.CompareC( UpnpDLNA::KTransferModeInteractive )
+ != 0 && transferMode.CompareC(
+ UpnpDLNA::KTransferModeBackground ) != 0 )
+ {
+ return -EHttpBadRequest;
+ }
+ }
+
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::CheckDLNACorrelations
+//
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpDlnaFilter::CheckDLNACorrelationsL( CUpnpHttpDataServeTransaction& aTransaction )
+ {
+ HBufC8* decodedContentURI = DecodeContentUriLC(aTransaction.SenderUri());
+ delete iProtocolInfo;
+ iProtocolInfo = NULL;
+ iProtocolInfo = ProtocolInfoL( *decodedContentURI );
+ CleanupStack::PopAndDestroy( decodedContentURI );
+ TPtrC8 fourthField( KNullDesC8 );
+ if ( iProtocolInfo )
+ {
+ fourthField.Set( iProtocolInfo->FourthField() );
+ }
+
+ if ( fourthField.Find( KDlnaFilter ) == KErrNotFound )
+ {
+ aTransaction.FilterHeaders().RemoveHeaderL( UpnpDLNA::KHdrTransferMode );
+ return KErrNone;
+ }
+
+ TUpnpDlnaCorelation dlnaCorelation;
+ dlnaCorelation.iFourthField.Set( fourthField );
+
+ TInt corelationError = CheckCorelationL( aTransaction, dlnaCorelation );
+ if ( corelationError != KErrNone )
+ {
+ return corelationError;
+ }
+ corelationError = CheckTransferModeL( aTransaction, dlnaCorelation );
+ if ( corelationError != KErrNone )
+ {
+ return corelationError;
+ }
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpHttpServer::CheckCorelationL
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpDlnaFilter::CheckCorelationL( CUpnpHttpDataServeTransaction& aTransaction,
+ TUpnpDlnaCorelation& aDlnaCorelation )
+ {
+ //-------------Checking DLNA correlations, response with HTTPerror if some problem occurs
+
+ aDlnaCorelation.iStreamingSupport = EFalse;
+ aDlnaCorelation.iInteractiveSupport = EFalse;
+ aDlnaCorelation.iBackgrondSupport = EFalse;
+ aDlnaCorelation.iGetContentFeaturesExist = EFalse;
+ aDlnaCorelation.iGetContentFeaturesIsOK = ETrue;
+
+ /* We can only check for getcontentFeaturesExist if we have cdDataFinder
+ * ( protocolInfo is not null )*/
+ if ( iProtocolInfo )
+ {
+ aDlnaCorelation.iBackgrondSupport = 1;
+ aDlnaCorelation.iStreamingSupport = iProtocolInfo->DlnaFlag(
+ UpnpDlnaProtocolInfo::TM_S_FLAG );
+ aDlnaCorelation.iInteractiveSupport = iProtocolInfo->DlnaFlag(
+ UpnpDlnaProtocolInfo::TM_I_FLAG );
+ if( aTransaction.QueryRequestHeader( UpnpDLNA::KHdrGetcontentFeatures() ) != KNullDesC8() )
+ {
+ aDlnaCorelation.iGetContentFeaturesExist = ETrue;
+ }
+ if( aDlnaCorelation.iGetContentFeaturesExist )
+ {
+ TDesC8& cntHeaderValue = aTransaction.QueryRequestHeader(
+ UpnpDLNA::KHdrGetcontentFeatures() );
+ if ( cntHeaderValue != UpnpDLNA::KHdrGetcontentFeaturesValue() )
+ {
+ aDlnaCorelation.iGetContentFeaturesIsOK = EFalse;
+ }
+ }
+ }
+
+ // DLNA v0.75, 7.3.31.1 checking Operations Parameter
+ if (
+ /* We don't support timeSeek and playSpeed at the moment, so according to
+ * point 7.4.71.1 (ver 1.5 rev 0.96)*/
+ aDlnaCorelation.iGetContentFeaturesIsOK &&
+ (( (aTransaction.QueryRequestHeader( UpnpDLNA::KHdrTimeSeekRange ) != KNullDesC8()
+ || aTransaction.QueryRequestHeader( UpnpDLNA::KHdrPlaySpeed )!= KNullDesC8())
+ &&
+ // 7.4.71.2 - range takes precedence
+ aTransaction.QueryRequestHeader( UpnpHTTP::KHdrRange ) == KNullDesC8() )
+ ||
+ // or if request mode is Streaming and
+ ( aTransaction.QueryRequestHeader( UpnpDLNA::KHdrTransferMode ). CompareC(
+ UpnpDLNA::KTransferModeStreaming ) == 0
+ &&
+ (
+ /* if we have no protocolInfo (because for example there is
+ no cdDataFinder )*/
+ !iProtocolInfo ||
+ // Streaming is not supported for this content type
+ iProtocolInfo -> DlnaFlag(UpnpDlnaProtocolInfo::TM_S_FLAG ) == EFalse) ))
+ )
+ {
+ // we respond with 406 error code - Not Acceptable.
+ return -EHttpNotAcceptable;
+ }
+
+
+ // Append contentFeatures.dlna.org
+ if ( aDlnaCorelation.iGetContentFeaturesExist )
+ {
+ if ( aDlnaCorelation.iFourthField.Length() > 0 )
+ {
+ aTransaction.FilterHeaders().AddHeaderL( UpnpDLNA::KHdrContentFeatures,
+ aDlnaCorelation.iFourthField );
+ }
+ }
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpHttpServer::CheckTransferMode
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpDlnaFilter::CheckTransferModeL( CUpnpHttpDataServeTransaction& aTransaction,
+ TUpnpDlnaCorelation& aDlnaCorelation )
+ {
+ TDesC8& transferMode = aTransaction.QueryRequestHeader( UpnpDLNA::KHdrTransferMode );
+ // Check if requested transfer mode is handled
+ if (
+ // if client requested for transfer is not empty
+ (transferMode.Length() > 0 && (
+ // and if client requested for transfer is different than Background, Streaming or Interactive mode, reply with 400 error
+ (transferMode.CompareC( UpnpDLNA::KTransferModeStreaming ) != 0
+ && transferMode.CompareC(
+ UpnpDLNA::KTransferModeInteractive ) != 0
+ && transferMode.CompareC(
+ UpnpDLNA::KTransferModeBackground ) != 0) ||
+ // If Background or Interactive mode was requested, check if request doesn;t contain forbidden headers
+ ((transferMode.CompareC(
+ UpnpDLNA::KTransferModeBackground ) == 0
+ || transferMode.CompareC(
+ UpnpDLNA::KTransferModeInteractive ) == 0)
+ && (aTransaction.QueryRequestHeader(
+ UpnpDLNA::KHdrTimeSeekRange ) != KNullDesC8()
+ || aTransaction.QueryRequestHeader(
+ UpnpDLNA::KHdrPlaySpeed )
+ != KNullDesC8()
+ || aTransaction.QueryRequestHeader(
+ UpnpDLNA::KHdrRealTimeInfo )
+ != KNullDesC8())))) || (
+
+ aTransaction.QueryRequestHeader( UpnpHTTP::KHdrRange ) == KNullDesC8()
+ && transferMode.Length() == 0 && (aTransaction.QueryRequestHeader(
+ UpnpDLNA::KHdrTimeSeekRange ) != KNullDesC8()
+ || aTransaction.QueryRequestHeader( UpnpDLNA::KHdrPlaySpeed )
+ != KNullDesC8() || aTransaction.QueryRequestHeader(
+ UpnpDLNA::KHdrRealTimeInfo ) != KNullDesC8()))
+ || !aDlnaCorelation.iGetContentFeaturesIsOK
+
+ )
+ {
+ return -EHttpBadRequest ;
+ }
+
+ return AppendCorelationHeadersL( aTransaction, aDlnaCorelation, transferMode );
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpHttpServer::AppendCorelationHeaders
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpDlnaFilter::AppendCorelationHeadersL( CUpnpHttpDataServeTransaction& aTransaction,
+ TUpnpDlnaCorelation& aDlnaCorelation, TDesC8& aTransferMode )
+ {
+ if ( aTransferMode.Length() > 0 && ((aTransferMode.CompareC(
+ UpnpDLNA::KTransferModeStreaming ) == 0 && !aDlnaCorelation.iStreamingSupport)
+ || (aTransferMode.CompareC( UpnpDLNA::KTransferModeInteractive )
+ == 0 && !aDlnaCorelation.iInteractiveSupport)) )
+ {
+ return -EHttpNotAcceptable ;
+ }
+ else if ( aTransferMode.Length() <= 0 )
+ {
+ if ( aDlnaCorelation.iStreamingSupport )
+ {
+ aTransaction.FilterHeaders().AddHeaderL( UpnpDLNA::KHdrTransferMode,
+ UpnpDLNA::KTransferModeStreaming );
+ }
+ else if ( aDlnaCorelation.iInteractiveSupport )
+ {
+ aTransaction.FilterHeaders().AddHeaderL( UpnpDLNA::KHdrTransferMode,
+ UpnpDLNA::KTransferModeInteractive );
+ }
+ else if ( aDlnaCorelation.iBackgrondSupport )
+ {
+ aTransaction.FilterHeaders().AddHeaderL( UpnpDLNA::KHdrTransferMode,
+ UpnpDLNA::KTransferModeBackground );
+ }
+ }
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpHttpSession::FormatPathL
+//
+// -----------------------------------------------------------------------------
+//
+void CUpnpDlnaFilter::FormatPathL( CUpnpHttpDataServeTransaction *aTransaction, TDes &aPath )
+ {
+ LOGS( "%i, CUpnpHttpSession::FormatPathL " );
+
+ TPtrC8 contentURI = aTransaction->SenderUri();
+
+ HBufC8* decodedContentURI = HBufC8::NewL( contentURI.Length() );
+ TPtr8 ptrDecodedContentURI = decodedContentURI->Des();
+ ptrDecodedContentURI.Copy( contentURI );
+ UpnpString::ReplaceHttpCharacters( ptrDecodedContentURI );
+ CleanupStack::PushL( decodedContentURI );
+
+ //extracting URLpath (so removing IP, port )
+ TPtrC8 fileName;
+ TInt parseError( KErrNone );
+ TPtrC8 urlPath = UpnpFileUtil::ExtractUrlPath( ptrDecodedContentURI,
+ fileName, parseError );
+ if ( parseError )
+ {
+ User::Leave( -EHttpBadRequest );
+ }
+
+ HBufC8* sharedFolder = NULL;
+ TInt error = FindSharedFolderDBL( urlPath, fileName, sharedFolder );
+ CleanupStack::PushL( sharedFolder );
+ if ( error == KErrNotFound || !sharedFolder )
+ {
+ User::Leave( -EHttpNotFound );
+ }
+
+ //sharedFolder includes file name
+ ASSERT( (*sharedFolder).Mid( (*sharedFolder).Length()
+ - UpnpString::KDoubleBackSlash().Length() )
+ != UpnpString::KDoubleBackSlash() );
+
+ HBufC* path16 = UpnpString::ToUnicodeL( *sharedFolder );
+ aPath.Copy( *path16 );
+ delete path16;
+
+ CleanupStack::PopAndDestroy( sharedFolder );
+ CleanupStack::PopAndDestroy( decodedContentURI );
+ }
+
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::GetContentTypeL()
+// Retrieves a mime type from the third field of the protocol info read from CD
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpDlnaFilter::GetContentTypeL( CUpnpHttpDataServeTransaction &aTransaction,
+ HBufC8*& aMime, const TDesC16& aFilename )
+ {
+ TInt error = KErrNone;
+
+ TParse parse;
+ parse.Set( aFilename, NULL, NULL );
+ TBufC16<KMaxName> ext( parse.Ext() );
+ //XML mime type has to be set seperately
+ if ( ext.FindC( KXml16 ) == 0 && ext.Length() == KXml16().Length() )
+ {
+ // Extension says that's XML but we check content to be sure and get encoding
+ _LIT8( KXmlUtf8, "text/xml; charset=\"utf-8\"" );
+ aMime = HBufC8::NewL( KXmlUtf8().Length() );
+ aMime->Des().Zero();
+ aMime->Des().Append( KXmlUtf8() );
+ return error;
+ }
+
+ //decoding content URI
+ HBufC8* decodedContentURI = DecodeContentUriLC( aTransaction.SenderUri());
+
+ //getting 3rd field
+ aMime = ThirdFieldFromCdL( *decodedContentURI );
+ CleanupStack::PopAndDestroy( decodedContentURI );
+ // asterick as mime type is not good - so error is KErrNotFound
+ _LIT8( KAseriskType, "*" );
+ if ( (NULL == aMime) || ((*aMime) == KAseriskType()) )
+ {
+ delete aMime;
+ aMime = NULL;
+ error = KErrNotFound;
+ }
+ return error;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::DetermineDownloadPathL
+//
+// -----------------------------------------------------------------------------
+//
+HBufC* CUpnpDlnaFilter::DetermineDownloadPathL(
+ CUpnpHttpFileReceiveTransaction& aTransaction )
+ {
+ TPtrC8 path = aTransaction.SenderUri();
+ TInt parseError( KErrNone );
+ TPtrC8 urlPath = UpnpFileUtil::ExtractUrlPath( path, parseError );
+ if ( parseError )
+ {
+ User::Leave( EHttpBadRequest );
+ }
+
+ // if importURI is bad then doesn't check shared folder just return error.
+ TInt result = CheckImportUriL( path );
+ if ( KErrNone == result )
+ {
+ return KNullDesC().AllocL();
+ }
+ if ( result < KErrNone && result != KErrGeneral )
+ {
+ return NULL;
+ }
+ HBufC* fileName = HBufC::NewLC( KMaxFileName );
+ TPtr fileNamePtr( fileName->Des() );
+ GetMediaFileNameL( result, fileNamePtr );
+
+ HBufC8* sharedFolder = NULL;
+ FindSharedFolderDBL( urlPath, KNullDesC8, sharedFolder );
+ CleanupStack::PushL( sharedFolder );
+
+ HBufC* folder = UpnpString::ToUnicodeL( *sharedFolder );
+ CleanupStack::PushL( folder );
+
+ if ( fileName->Length() == 0)
+ {
+ _LIT(KNoDcTitle, "no_dc_title");
+ fileName->Des().Copy(KNoDcTitle);
+ }
+
+ HBufC* resultFileName = HBufC::NewL( folder->Length() + fileName->Length() );
+ resultFileName->Des().Zero();
+ resultFileName->Des().Append( *folder );
+ resultFileName->Des().Append( *fileName );
+
+ CleanupStack::PopAndDestroy( folder );
+ CleanupStack::PopAndDestroy( sharedFolder );
+ CleanupStack::PopAndDestroy( fileName );
+
+ CleanupStack::PushL( resultFileName );
+ HBufC* uniqueFileName = MakeFileNameUniqueL(*resultFileName, iFs );
+ CleanupStack::PopAndDestroy( resultFileName );
+
+ return uniqueFileName;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::PrepareHeaderL
+//
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpDlnaFilter::PrepareHeaderL( CUpnpHttpDataServeTransaction& aTransaction )
+ {
+ HBufC8* mimetype = NULL;
+ HBufC16* fileName = aTransaction.PathWithNewMethodL();
+ CleanupStack::PushL( fileName );
+
+ if ( GetContentTypeL( aTransaction, mimetype, *fileName ) != KErrNone )
+ {
+ //getting mime type from Symbian or by the extension
+ mimetype = UpnpFileUtil::GetMimeTypeForFileL( *fileName );
+ }
+ CleanupStack::PushL( mimetype );
+ aTransaction.AddResponseHeaderL( UpnpGENA::KContentType(), *mimetype );
+ CleanupStack::PopAndDestroy( mimetype );
+
+ // Checks if all DLNA correlations are ok and adds proper headers
+ // only for GET response
+
+ TInt dlnaCorrelationsError = CheckDLNACorrelationsL( aTransaction );
+ if ( dlnaCorrelationsError < KErrNone )
+ {
+ CleanupStack::PopAndDestroy( fileName );
+ return dlnaCorrelationsError;
+ }
+
+
+ AddHeaderIfNotEmptyL( UpnpDLNA::KHdrContentFeatures(), aTransaction );
+
+ // 7.4.42.2 HTTP Server Endpoints that transfer Non-Cacheable Content using ?HTTP/1.0, and?GET responses.
+ // These devices must prevent intermediate caching by including among the HTTP response headers
+ // the directive:?Pragma: no-cache
+ aTransaction.AddResponseHeaderL( UpnpHTTP::KHdrPragma(),
+ UpnpHTTP::KNoCache() );
+ aTransaction.AddResponseHeaderL( UpnpHTTP::KHdrCacheControl(),
+ UpnpHTTP::KNoCache() );
+
+
+ // If Accept-Language header is present
+ if ( aTransaction.QueryRequestHeader( UpnpHTTP::KHdrAcceptLanguage() ).Length() > 0 )
+ {
+ aTransaction.AddResponseHeaderL( UpnpHTTP::KHdrContentLanguage(),
+ UpnpHTTP::KLanguageEn() );
+ }
+
+ // Transfer Mode
+ // If Transfer Mode header is present
+ AddHeaderIfNotEmptyL( UpnpDLNA::KHdrTransferMode, aTransaction );
+
+ CleanupStack::PopAndDestroy( fileName );
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::AddHeaderIfNotEmptyL
+//
+// -----------------------------------------------------------------------------
+//
+void CUpnpDlnaFilter::AddHeaderIfNotEmptyL( const TDesC8& aHeaderName,
+ CUpnpHttpDataServeTransaction& aTransaction )
+ {
+ if ( aTransaction.FilterHeaders().QueryHeader( aHeaderName ).Length() > 0 )
+ {
+ aTransaction.AddResponseHeaderL( aHeaderName,
+ aTransaction.FilterHeaders().QueryHeader( aHeaderName ) );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::AuthorizeRequestL
+//
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpDlnaFilter::AuthorizeRequestL(
+ const TDesC& aFileName, const TInetAddr& aSender )
+ {
+ TInt result( KErrNone );
+ CUpnpHttpMessage* tempMessage = CUpnpHttpMessage::NewL( aSender );
+ CleanupStack::PushL( tempMessage );
+ if ( SecurityManager()
+ && SecurityManager()->AuthorizeMessage( tempMessage,
+ (TFileName&) aFileName ) != KErrNone )
+ { //not showing why resource is refused
+ result = -EHttpNotFound;
+ }
+ CleanupStack::PopAndDestroy( tempMessage );
+ return result;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::FileSession
+// -----------------------------------------------------------------------------
+//
+RFs& CUpnpDlnaFilter::FileSession()
+ {
+ return iFs;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::PreparePostfixToMakeFileUniqueL
+// -----------------------------------------------------------------------------
+//
+HBufC* CUpnpDlnaFilter::PreparePostfixToMakeFileUniqueL( const TDesC& aFilename, RFs& aFs )
+ {
+ _LIT( KUnderScore, "_" );
+ const TInt KDotLength = 1; // when aFileName is without extension
+
+ HBufC16* newFile = HBufC16::NewLC( aFilename.Length() + KUnderScore().Length()
+ + UpnpString::KMaxTUintLength + KDotLength );
+
+ TParse parse;
+ parse.Set( aFilename, NULL, NULL );
+ TPtrC fileName = parse.Name();
+ TPtrC fileExt = parse.Ext();
+ TPtrC filePath = parse.DriveAndPath();
+
+ TUint64 postfixNumber = 1;
+
+ do
+ {
+ TBuf<UpnpString::KMaxTUintLength + 1> buf;
+ buf.AppendNum( postfixNumber++ );
+ if ( buf.Length() > UpnpString::KMaxTUintLength )
+ {
+ User::Leave( KErrOverflow );
+ }
+ newFile->Des().Copy( filePath );
+ newFile->Des().Append( fileName );
+ newFile->Des().Append( KUnderScore() );
+ newFile->Des().Append( buf );
+ newFile->Des().Append( fileExt );
+ }
+ while ( BaflUtils::FileExists( aFs, newFile->Des() ) );
+
+ CleanupStack::Pop( newFile );
+ return newFile;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::PrepareBaseFileNameL
+// -----------------------------------------------------------------------------
+//
+HBufC* CUpnpDlnaFilter::PrepareBaseFileNameL( const TDesC& aFilename, RFs& aFs )
+ {
+ HBufC* fileToServe;
+ if ( aFilename.LocateReverse( '\\' ) == aFilename.Length() - 1 )
+ {
+ _LIT( KNoName0, "noName_0" );
+ const TInt KZeroPostfixLen = 2; //_0
+
+ fileToServe = HBufC::NewL( aFilename.Length() + KNoName0().Length() );
+ fileToServe->Des().Copy( aFilename );
+ fileToServe->Des().Append( KNoName0() );
+
+ if ( BaflUtils::FileExists( aFs, *fileToServe ) )
+ {
+ fileToServe->Des().Delete( fileToServe->Length() - KZeroPostfixLen, KZeroPostfixLen );
+ }
+ }
+ else
+ {
+ fileToServe = HBufC::NewL( aFilename.Length() );
+ fileToServe->Des().Copy( aFilename );
+ }
+
+ if ( BaflUtils::FileExists( aFs, *fileToServe ) )
+ {
+ CleanupStack::PushL( fileToServe );
+ HBufC* newFileName = PreparePostfixToMakeFileUniqueL( *fileToServe, aFs );
+ CleanupStack::PopAndDestroy( fileToServe );
+ fileToServe = newFileName;
+ }
+ return fileToServe;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::MakeFileNameUniqueL
+// -----------------------------------------------------------------------------
+//
+HBufC* CUpnpDlnaFilter::MakeFileNameUniqueL( const TDesC& aFilename, RFs& aFs )
+ {
+ HBufC* fileToServe = PrepareBaseFileNameL( aFilename, aFs );
+
+ TPtrC questionmark;
+ questionmark.Set( *fileToServe );
+ TInt lastSlash = questionmark.LocateReverse( '\\' );
+ TInt lastQuestionMark = questionmark.LocateReverse( '?' );
+ if ( lastQuestionMark != KErrNotFound && lastSlash < lastQuestionMark )
+ {
+ CleanupStack::PushL( fileToServe );
+ questionmark.Set( questionmark.Left( lastQuestionMark ) );
+
+ // now setting new name for file
+ HBufC* newFileName; //necessary not to loose current fileToServe
+ newFileName = HBufC::NewL( questionmark.Length() );
+ newFileName->Des().Copy( questionmark );
+ CleanupStack::PopAndDestroy( fileToServe );
+ fileToServe = newFileName;
+ }
+
+ TPtrC path;
+ path.Set( *fileToServe );
+ TInt lastPosOfSlash = 0;
+ TInt posOfBackSlash = path.Find( KDoubleBackSlash );
+
+ while ( posOfBackSlash != KErrNotFound )
+ {
+ path.Set( path.Mid( posOfBackSlash + 1 ) );
+ lastPosOfSlash = lastPosOfSlash + posOfBackSlash + 1;
+ posOfBackSlash = path.Find( KDoubleBackSlash );
+ }
+
+ if ( lastPosOfSlash > 0 )
+ {
+ path.Set( *fileToServe );
+ path.Set( path.Left( lastPosOfSlash ) );
+ }
+
+ return fileToServe;
+ }
+
+// -----------------------------------------------------------------------------
+// CUpnpDlnaFilter::DecodeContentUriLC
+// -----------------------------------------------------------------------------
+//
+HBufC8* CUpnpDlnaFilter::DecodeContentUriLC( const TPtrC8& contentURI)
+ {
+ HBufC8* decodedContentURI = HBufC8::NewL( contentURI.Length() );
+ TPtr8 ptrDecodedContentURI = decodedContentURI->Des();
+ ptrDecodedContentURI.Copy( contentURI );
+ UpnpString::ReplaceHttpCharacters( ptrDecodedContentURI );
+ CleanupStack::PushL( decodedContentURI );
+ return decodedContentURI;
+
+ }
+// End of File