/** @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: Declares HttpServer class.
*
*/
// INCLUDE FILES
#include <in_sock.h>
#include <e32std.h>
#include <apgcli.h> // For RApaLsSession
#include <apmstd.h>
#include <escapeutils.h>
#include <bautils.h>
#include "upnphttpserver.h"
#include "upnpstring.h"
#include "upnpcons.h"
#include "upnphttpsession.h"
#include "upnphttpbuffer.h"
#include "upnphttpfiletransferreader.h"
#include "upnphttpfiletransferwriter.h"
#include "upnphttpmessagefactory.h"
#include "upnphttpheader.h"
#include "upnperrors.h"
#include "upnpcommonupnplits.h"
#include "upnpfileutils.h"
#define KLogFile _L("DLNAWebServer.txt")
#include "upnpcustomlog.h"
#include "upnphttpfileaccess.h"
#include "httperr.h"
#include "upnphttpservertransactioncreator.h"
#include "upnprangeheaderparser.h"
#include "upnphttpservertransaction.h"
// CONSTANTS
_LIT8( KTransferPending801, "HTTP/1.1 801 Transfer Pending");
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CUpnpHttpSession::NewL
// Two-phased constructor
// -----------------------------------------------------------------------------
//
CUpnpHttpSession* CUpnpHttpSession::NewL( RSocket aSocket,
CUpnpHttpServer* aServer, TInt aSessionId, TThreadPriority aPriority )
{
LOGS1( "%i, CUpnpHttpSession::NewL - creating session for incoming connection",
aSessionId );
CUpnpHttpSession* self = new (ELeave) CUpnpHttpSession( aSocket, aServer,
aSessionId, aPriority );
CleanupStack::PushL( self );
self->TcpConstructL( aSocket, KRcvBufSizeDefault,
aServer->FileReadBufferSize() );
self->ConstructL();
CleanupStack::Pop( self );
LOGS1( "%i, CUpnpHttpSession::NewL - HTTP *** Created new session.",
self->Id( ) );
return self;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::CUpnpHttpSession
// C++ default constructor
// -----------------------------------------------------------------------------
//
CUpnpHttpSession::CUpnpHttpSession( RSocket aSocket,
CUpnpHttpServer* aServer, TInt aSessionId, TThreadPriority aPriority ) :
CUpnpTcpSession( aSocket, aPriority )
{
iId = aSessionId;
iServer = aServer;
iRequestedTransferNotifySent = EFalse;
// Assume that session should be kept alive unless the request
// with HTTP header "Connection: close" comes.
iSessionKeepAlive = ETrue;
iSessionIsDeletedAfterResponse = EFalse;
iUsesConnectionClose = EFalse;
iSaveToFile = EFalse;
iOverwriteExisting = EFalse;
iOffset = 0;
iLength = 0;
iSaveAtOffset = EFalse;
iMaximumSizeChecked = EFalse;
iHeadersCompleted = EFalse;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::ConstructL
// Two-phased constructor
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::ConstructL()
{
LOGS1( "%i, CUpnpHttpSession::ConstructL", iId );
iFileServe = NULL;
iDestinationPath = HBufC8::NewL( 0 );
iSenderPath = HBufC8::NewL( 0 );
iInFilename = HBufC8::NewL( 0 );
iOutFilename = HBufC8::NewL( 0 );
iPendingRequests = new (ELeave) RPointerArray<CUpnpHttpMessage> ( 1 );
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::~CUpnpHttpSession
// C++ default destructor
// -----------------------------------------------------------------------------
//
CUpnpHttpSession::~CUpnpHttpSession()
{
LOGS1( "%i, CUpnpHttpSession::~CUpnpHttpSession()", iId );
delete iFileServe;
delete iInFilename;
delete iOutFilename;
delete iDestinationPath;
delete iSenderPath;
if ( iPendingRequests )
{
iPendingRequests->ResetAndDestroy();
iPendingRequests->Close();
delete iPendingRequests;
}
// no deleting of iPendingRequest, it's not owned
iPendingRequest = NULL;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::SendL
// Send HTTP message.
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::SendL( CUpnpHttpMessage* aMessage )
{
LOGS1( "%i, CUpnpHttpSession::SendL(CUpnpHttpMessage*)", iId );
if ( !IsConnected() )
{
return;
}
iSessionNeedsErrorReply = EFalse;
// Set senders and destination path
delete iSenderPath;
iSenderPath = NULL;
delete iDestinationPath;
iDestinationPath = NULL;
if ( aMessage->Method().Find( KHttp11WithoutSpace ) == 0 )
{
iSenderPath = HBufC8::NewL( 0 );
aMessage->AddPairL( UpnpHTTP::KHdrServer(),
iServer->ServerDescription() );
}
else
{
iSenderPath = aMessage->SenderPathFromHeader().AllocL();
}
iDestinationPath = aMessage->SenderPath().AllocL();
// Set other properties
iRequestType = aMessage->Type();
iRetryCounter = aMessage->RetryCounter();
if ( aMessage->PendingRequest() )
{
iPendingRequest = aMessage->PendingRequest();
}
//we assume that converting to UTF8 is already done by upper layers
HBufC8* buf = aMessage->ToStringL();
CleanupStack::PushL( buf );
WriteL( *buf );
CleanupStack::PopAndDestroy( buf );
if ( !iIsPersistent )
{
iSessionKeepAlive = EFalse;
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::DeleteThisSessionL
// Delete the session.
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::DeleteThisSessionL( CUpnpTcpSession* /*aSession*/)
{
LOGS1( "%i, CUpnpHttpSession::DeleteThisSessionL", iId );
if ( iReceivedMessage )
{
if ( iReceivedMessage->BytesInBuffer() > 0
&& iReceivedMessage->IsReadyL() )
{
TPtrC8 content = iReceivedMessage->Content();
CUpnpHttpMessage* msg = CUpnpHttpMessage::NewL( content,
RemoteHost(), iId );
CleanupStack::PushL( msg );
msg->SetType( iRequestType );
msg->SetRetryCounter( iRetryCounter );
THttpInvalidMessage aVal;
aVal = IsValidMessage( msg );
switch ( aVal )
{
case EMessageOk:
//HandleQuery will take ownership of msg object
CleanupStack::Pop( msg );
// Pass the message forward
HandleQueryL( msg );
break;
default:
CleanupStack::PopAndDestroy( msg );
break;
}
}
}
ShutdownStop();
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::DeleteFileIfExists
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::DeleteFileIfExists( TDesC16& aFilename )
{
iServer->FileSession().Delete( aFilename );
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::MatchHttpError
//
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpSession::MatchHttpError( TInt error )
{
TInt httpError = KErrNone;
if ( error == KErrDiskFull )
httpError = EHttpInsufficientStorage;
else if ( error == KErrOverflow ) //one of the reason can be if chunk value is > 2^32
httpError = EHttpInsufficientStorage;
else if ( error == KErrAbort ) //POST HTTP/1.1
httpError = EHttpBadRequest;
else if ( error == KErrGeneral || error == KErrHttpUnknownParseState ) // this error may occur e.g when ContentLengthL() leaves
httpError = EHttpBadRequest;
else if ( -error >= EHttpBadRequest ) // HTTP errors
httpError = -error;
else if ( error == KErrNoMemory )
httpError = EHttpEntityTooLarge; // OOM handling
else if ( error == KErrNotSupported )
httpError = EHttpNotFound; // no transaction
else
httpError = EHttpInternalServerError;
return httpError;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::BufferReceivedL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::BufferReceivedL( TDesC8& aBuffer )
{
TInt index = 0;
TPtrC8 ptrIn( aBuffer );
iPendingPostRequests = ETrue;
//handling requests on the server-side
if ( ptrIn.Length() > KHttpPost().Length() )
{
TPtrC8 ptrInOffset( ptrIn.Mid( KHttpPost().Length() ) );
//this loop splits buffer if it includes more than one POST message
while ( (index = ptrInOffset.Find( KHttpPost() )) >= 0 )
{
TPtrC8 ptrL = ptrIn.Left( index + KHttpPost().Length() );
SinglePostBufferReceivedL( ptrL );
ptrIn.Set( ptrIn.Mid( index + KHttpPost().Length() ) );
ptrInOffset.Set( ptrIn.Mid( KHttpPost().Length() ) );
}
}
SinglePostBufferReceivedL( ptrIn );
iPendingPostRequests = EFalse;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::SinglePostBufferReceivedL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::SinglePostBufferReceivedL( TDesC8& aBuffer )
{
TInt error = KErrNone;
TRAP( error, BufferReceivedProcessL( aBuffer ) )
LOGS2( "%i, CUpnpHttpSession::BufferReceivedL finished with error %i", iId, error );
if ( error != KErrNone )
{
//if session left - no continuation of file transfer
if ( iFTReader && iFTReader->Activated() )
{
iFTReader->SetActivated( EFalse );
if ( iFileServe )
iFileServe->DeleteFile();
}
TInt httpError = MatchHttpError( error );
if ( httpError != KErrNone )
{// If we act as a server side
ResponseErrorL( httpError );
if ( httpError == EHttpEntityTooLarge )
{
NotifyErrorL( httpError, error );
}
ShutdownStop();
return;
}
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::BufferReceivedCheckingHeadersL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::BufferReceivedCheckingHeadersL( TDesC8& aBuffer )
{
// If iInFilename is defined, data should be saved in to a file,
// this is the case of incoming GET response and for following parts of POST request.
if ( iInFilename && iInFilename->Length() > 0 )
{
iSaveToFile = ETrue;
// If this flag was set it means that even previously message was not ment
// to be saved to file, now when the body is downloaded it will be saved to file.
if ( iContinuedMessageDownload && !iReceivedMessage->IsToFile() )
{
iReceivedMessage->SetToFile( ETrue );
}
// Check Maximum Size requirement, but do this only once
if ( !iMaximumSizeChecked )
{
//Make temp buffer to check content of incoming data,
//its possible that content-Length is too huge (>2^32)
CUpnpHttpBuffer* checkBuf = CUpnpHttpBuffer::NewL( this, EFalse );
CleanupStack::PushL( checkBuf );
//leaves in case of problems with string operation, no HTTP error
checkBuf->AppendHeadersL( aBuffer, iSaveToFile );
if ( checkBuf->IsHeaderReady() )
{
// Now headers were checked
iHeadersCompleted = ETrue;
TRAPD( error, checkBuf->ContentLengthL( ) );
if ( error )
{
iSaveToFile = EFalse;
}
iMaximumSizeChecked = ETrue;
//mark chunked encoding
iIsChunked = checkBuf->IsChunked();
//mark if persistent connection
if ( IsPersistentConnection() )
iIsPersistent = !checkBuf->UsesConnectionClose();
}
else
{
iSaveToFile = EFalse;
}
CleanupStack::PopAndDestroy( checkBuf );
}
}
// Checking that if file is a POST that needs to be saved to a file. Only check this
// for the first time (iFileServe does not exist only on receiving the first buffer of data)
else if ( !iFileServe )
{
// making temp buffer to check content of incoming data
CUpnpHttpBuffer* checkBuf = CUpnpHttpBuffer::NewL( this, EFalse );
CleanupStack::PushL( checkBuf );
//leaves in case of problems with string operation, no HTTP error
checkBuf->AppendHeadersL( aBuffer, iSaveToFile );
if ( checkBuf->IsHeaderReady() )
{
// Now headers were checked
iHeadersCompleted = ETrue;
TPtrC8 headers = checkBuf->Headers();
CUpnpHttpMessage* tempMsg = NULL;
TRAPD( err, tempMsg = CUpnpHttpMessage::NewL( (TDesC8&) headers,
RemoteHost( ), iId ) );
//POST HTTP/1.1
if ( err == KErrAbort )
{
if ( checkBuf->Method().Find( KHttpPost ) == 0 )
//leaves in case of HTTP error for a POST
User::Leave( KErrAbort );
}
else if ( err < KErrNone )
{
User::Leave( err );
}
else if ( err == KErrNone )
{
CleanupStack::PushL( tempMsg );
// Check method and make decision about handling message.
// It's a POST message
if ( tempMsg->Method().Find( KHttpPost ) == 0 )
{
// 100-Continue check should be done for all types of POST reqests, even for GENAs and SOAPs
// First thing to do in case of upload is to chceck if there
// is sufficient disk space to save incoming file.
TUint fileSize = 0;
TBool hasCL;
TLex8 cntLength( tempMsg->IsHeader(
UpnpHTTP::KHdrContentLength, hasCL ) );
if ( hasCL )
{
TInt errorLength = cntLength.Val( fileSize );
if ( errorLength == KErrOverflow )
{
iSaveToFile = EFalse;
//leaves in case of HTTP error
User::Leave( -EHttpInsufficientStorage );
}
else if ( errorLength != KErrNone )
{
iSaveToFile = EFalse;
//leaves in case of HTTP error
User::Leave( errorLength );
}
}
//First check URI, because there is no sense in sending 100 continue for invalid URI
if (!(tempMsg->IsGena()) && !(tempMsg->IsSoap()))
{
//response is sent inside function
delete iInFilename;
iInFilename = NULL;
if ( !iServer->TransactionCreator() )
{
User::Leave( KErrNotSupported );
}
if ( UpnpFileUtil::ParseUri( tempMsg->SenderPathFromHeader() )
!= KErrNone )
{
iInFilename = KNullDesC8().AllocL();
iSaveToFile = EFalse;
User::Leave( -EHttpBadRequest );
}
TPtrC8 relativeUri = PrepareRelativeUriL( tempMsg->SenderPathFromHeader() );
CUpnpHttpServerTransaction* transactionOut;
iServer->TransactionCreator()->NewTransactionL(
tempMsg->Method(), relativeUri,
tempMsg->Sender(), transactionOut );
CleanupStack::PushL( transactionOut );
transactionOut->SetRequest(tempMsg);
transactionOut->OnCallbackL( CUpnpHttpServerTransaction::EOnRequestStart );
iSaveToFile = EFalse;
User::LeaveIfError( transactionOut->Error() );
RBuf fileName;
fileName.CreateL( KMaxFileName );
CleanupClosePushL( fileName );
User::LeaveIfError( transactionOut->DataSink().FullName( fileName ) );
iInFilename = UpnpString::FromUnicodeL( fileName );
iSaveToFile = ETrue;
CleanupStack::PopAndDestroy(&fileName);
transactionOut->OnCallbackL( CUpnpHttpServerTransaction::EOnComplete );
CleanupStack::PopAndDestroy( transactionOut );
}
//Maximum size was checked already so don't do this again
iMaximumSizeChecked = ETrue;
// If client sends Expect: 100-continue header then it must be checked
// if file can be saved and if so, server should responds with 100.
if ( tempMsg->GetHeaderValue( UpnpHTTP::KHdrExpect ).FindC(
UpnpHTTP::K100Continue ) == 0 )
{
// Check disk space and ContentLength limit (2^32) and if it's not sufficient send 507 response and
// close connection - sugested behaviour from DLNA 1.5 spec.
HBufC16* pathTmp = NULL;
pathTmp = UpnpString::ToUnicodeL( iInFilename->Des() );
CleanupStack::PushL( pathTmp );
TBool noSpace = UpnpFileUtil::CheckDiskSpaceShortL(
pathTmp->Des(), fileSize, iServer->FileSession() );
CleanupStack::PopAndDestroy( pathTmp );
if ( noSpace )
{
iSaveToFile = EFalse;
//leaves in case of HTTP error
User::Leave( -EHttpInsufficientStorage );
}
else
{
// Set the flag informing that current message's body will
// should be downloaded in some time
iContinuedMessageDownload = ETrue;
// If there is enough space to save incoming file send response 100,
// which means that client can continue with sending the body.
CUpnpHttpMessage* reply =
RUpnpHttpMessageFactory::Http11ResponseL(
tempMsg, EHttpContinue );
CleanupStack::PushL( reply );
HBufC8* sendBuf = reply->ToStringL();
CleanupStack::PushL( sendBuf );
WriteL( *sendBuf );
CleanupStack::PopAndDestroy( sendBuf );
CleanupStack::PopAndDestroy( reply );
}
}
}
if ( iSaveToFile )
{
CleanupStack::Pop( tempMsg );
tempMsg->SetType( ETransferStart );
iServer->ToReceiveStackD( tempMsg );
}
else
{
CleanupStack::PopAndDestroy( tempMsg );
}
}
}
//mark if chunked encoding
iIsChunked = checkBuf->IsChunked();
//mark if persistent connection
if ( IsPersistentConnection() )
iIsPersistent = !checkBuf->UsesConnectionClose();
CleanupStack::PopAndDestroy( checkBuf );
}
else
{
iSaveToFile = EFalse;
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::BufferReceivedProcessL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::BufferReceivedProcessL( TDesC8& aBuffer )
{
TInt httpError;
LOGS1( "%i, CUpnpHttpSession::BufferReceivedProcessL", iId );
if ( !iHeadersCompleted && iReceivedMessage )
{
// If all headers aren't completed after receiving a few data chunks,
// enlarge the buffer and try again.
HBufC8* headers = HBufC8::NewLC( iReceivedMessage->Content().Length()
+ aBuffer.Length() );
headers->Des().Zero();
headers->Des().Append( iReceivedMessage->Content() );
headers->Des().Append( aBuffer );
//returns HTTP error only in case of a POST
BufferReceivedCheckingHeadersL( *headers );
CleanupStack::PopAndDestroy( headers );
}
else if ( !iHeadersCompleted && !iReceivedMessage )
{
// The first data chunk, both variables are not set. returns HTTP error only in case of a POST
BufferReceivedCheckingHeadersL( aBuffer );
}
// If message content should be saved to file then create a file access object
// that takes care of this operation.
if ( iSaveToFile && !iFileServe )
{
HBufC16* name = NULL;
name = UpnpString::ToUnicodeL( *iInFilename );
CleanupStack::PushL( name );
iFileServe = CUpnpHttpFileAccess::NewL( this, *name );
CleanupStack::PopAndDestroy( name );
// If it's response for Range reqest then setup range saving parameters in iFileServe
if ( iSaveAtOffset )
{
iFileServe->SetPosOfFile( iOffset );
iFileServe->SetEndPosOfFile( iOffset + Length() - 1 );
}
delete iInFilename;
iInFilename = NULL;
iInFilename = UpnpString::FromUnicodeL( iFileServe->FileToServe() );
}
//initiate filetransfer component
if ( iSaveToFile && iFileServe )
{
//file transfer reader
iFileServe->SetEncodingMode( iIsChunked );
FileTransferReaderConstructL();
}
if ( !iReceivedMessage )
{
iReceivedMessage = CUpnpHttpBuffer::NewL( this, iSaveToFile );
}
//leaves in case of problems with string operation, no HTTP error
User::LeaveIfError( iReceivedMessage->AppendL( aBuffer, iSaveToFile ) );
// This 'if statement' is required for proper deleting partial file
// when 'stop transfer' was invoked during exporting the resource from other MS.
if ( iFileServe && iReceivedMessage )
iFileServe->SetTotalSize( iReceivedMessage->ContentLengthL() );
if ( FileTransferReader() && FileTransferReader()->Activated() )
return;
// Finish receiving message and handle query contained in message.
// Processing goes on and on till the incoming buffer is empty -
// this is the way the pipelining is handled.
while ( iReceivedMessage->IsReadyL() )
{
TPtrC8 buffer = iReceivedMessage->Content();
CUpnpHttpMessage* msg = NULL;
TInt err( KErrNone );
TRAP( err, msg = CUpnpHttpMessage::NewL( buffer, RemoteHost( ), iId ) );
CleanupStack::PushL( msg );
if ( err < KErrNone )
{
LOGS1(
"%i, CUpnpHttpSession::BufferReceivedProcessL - failed", iId );
// sending response to remote host: bad request
httpError = MatchHttpError( -EHttpBadRequest );
if ( httpError != KErrNone )
{// If we act as a server side
ResponseErrorL( httpError );
}
CleanupStack::PopAndDestroy( msg );
}
else
{
iSessionKeepAlive = ETrue;
if ( IsPersistentConnection() )
if ( !iFileServe && iPendingRequests->Count() == 0 )
if ( msg->GetHeaderValue( UpnpHTTP::KConnection() ).FindC(
UpnpHTTP::KClose() ) >= 0
|| msg->RequestHTTPVersion() == KHttp10() )
{
iIsPersistent = EFalse;
}
if ( !IsPersistentConnection() && !msg->IsSoap()
&& !msg->IsGena() )
{
iSessionKeepAlive = EFalse;
}
msg->SetType( iRequestType );
msg->SetSessionId( iId );
msg->SetRetryCounter( iRetryCounter );
if ( (iSaveToFile) && (iInFilename) )
{
msg->SetInFilenameL( iInFilename->Des() );
}
THttpInvalidMessage aVal;
aVal = IsValidMessage( msg );
switch ( aVal )
{
case EMessageOk:
//HandleQueryL will take ownership of msg object
CleanupStack::Pop( msg );
TRAP( err, HandleQueryL( msg ) );
if ( err < KErrNone )
{
httpError = MatchHttpError( err );
if ( httpError != KErrNone )
{// If we act as a server side
ResponseErrorL( httpError );
}
}
break;
case EUnknownMethod:
{
LOGS1H(
iHandle,
"%i, CUpnpHttpSession::BufferReceivedL - Unknown method",
iId );
httpError = MatchHttpError( -EHttpMethodNotAllowed );
if ( httpError != KErrNone )
{// If we act as a server side
ResponseErrorL( httpError );
}
CleanupStack::PopAndDestroy( msg );
}
break;
default:
LOGS1(
"%i, CUpnpHttpSession::BufferReceivedL - failed", iId );
CleanupStack::PopAndDestroy( msg );
break;
};
}
// No continued message download is expected because
// the message processing is finished
iContinuedMessageDownload = EFalse;
iReceivedMessage->RemoveL( buffer.Length() );
iHeadersCompleted = EFalse;
delete iInFilename;
iInFilename = NULL;
iInFilename = HBufC8::NewL( 0 );
if ( iSessionIsDeletedAfterResponse )
{
StartDisconnect();
}
}
if ( iReceivedMessage->BytesInBuffer() <= 0 )
{
delete iReceivedMessage;
iReceivedMessage = NULL;
if ( iSessionIsDeletedAfterResponse )
{
StartDisconnect();
}
else
{
StartTimeoutTimer( iSessionNeedsErrorReply );
}
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::ResponseErrorL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::ResponseErrorL( TInt aStatus )
{
LOGS2( "%i, CUpnpHttpSession::ResponseErrorL - error code %i",
iId, aStatus );
CUpnpHttpMessage* reply = NULL;
reply = RUpnpHttpMessageFactory::HttpResponseErrorL( RemoteHost(),
aStatus );
CleanupStack::PushL( reply );
reply->AddPairL( UpnpHTTP::KHdrServer(), iServer->ServerDescription() );
reply->SetSessionId( Id() );
reply->SetDestinationPathL( *iDestinationPath );
reply->SetSenderPathL( *iSenderPath );
HBufC8* sendBuf = reply->ToStringL();
CleanupStack::PushL( sendBuf );
WriteL( *sendBuf );
CleanupStack::PopAndDestroy( sendBuf );
CleanupStack::PopAndDestroy( reply );
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::HandleQueryL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::HandleQueryL( CUpnpHttpMessage* aMsg )
{
LOGS1( "%i, CUpnpHttpSession::HandleQueryL", iId );
CleanupStack::PushL( aMsg );
// Handle GET and HEAD requests
if ( aMsg->Method().Find( KHttpGet ) == 0 || aMsg->Method().Find(
KHttpHead ) == 0 )
{
// method starts with GET or HEAD
if ( FileServeExists() || (FileTransferWriter()
&& FileTransferWriter()->IsActive()) )
{
User::LeaveIfError( iPendingRequests->Append( aMsg ) );
CleanupStack::Pop( aMsg );
}
else
{
User::LeaveIfError( PrepareToServeFileL( aMsg ) );
CleanupStack::PopAndDestroy( aMsg );
aMsg = NULL;
}
}
// Handle GENA, SOAP, responses, other messages etc.
else
{
aMsg->SetInFilenameL( *iInFilename );
delete iInFilename;
iInFilename = NULL;
iInFilename = HBufC8::NewL( 0 );
if ( !aMsg->Is1xx() )
{
CleanupStack::Pop( aMsg );
NotifyUpperLayerLD( aMsg );
iPendingRequest = NULL;
}
else
{
CleanupStack::PopAndDestroy( aMsg );
}
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::PrepareToServeFileL
//
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpSession::PrepareToServeFileL( CUpnpHttpMessage* aMsg )
{
LOGS1( "%i, CUpnpHttpSession::PrepareToServeFileL", iId );
if ( !iServer->TransactionCreator() )
{
User::Leave( KErrNotSupported );
}
CheckSessionPersistence( aMsg );
TInt parseUrlError = UpnpFileUtil::ParseUri( aMsg->SenderPathFromHeader() );
if ( parseUrlError != KErrNone )
{
return -EHttpBadRequest;
}
TPtrC8 relativeUri = PrepareRelativeUriL( aMsg->SenderPathFromHeader() );
CUpnpHttpServerTransaction* transactionOut;
iServer->TransactionCreator()->NewTransactionL( aMsg->Method() ,
relativeUri, aMsg->Sender(), transactionOut );
CleanupStack::PushL( transactionOut );
transactionOut->SetRequest( aMsg );
transactionOut->OnCallbackL( CUpnpHttpServerTransaction::EOnRequestStart );
TInt error = transactionOut->Error();
if( error != KErrNone )
{
CleanupStack::PopAndDestroy( transactionOut );
return error;
}
// 2. Try to open requested file
RFile& file = transactionOut->DataSource();
TInt fileSize = -1;
if( file.Size( fileSize ) != KErrNone )
{
fileSize = -1;
}
TBool servingOutFilename = ( aMsg->OutFilename().Length() > 0 );
TInt result( KErrNone );
// 3. If file was opened it means it exists and might be served
if ( fileSize >= 0 )
{
TInt rangeStatus;
TInt startPos;
TInt endPos;
TInt errorValue;
errorValue = PrepareRangeHeaderL(
aMsg, servingOutFilename, fileSize, *transactionOut,
rangeStatus, startPos, endPos );
if ( errorValue == KErrNone )
{
if ( EHttpNoContent == rangeStatus )
{
transactionOut->AddResponseHeaderL( UpnpHTTP::KHdrServer(),
iServer->ServerDescription() );
WriteL( transactionOut->QueryResponseHeader() );
}
else
{
transactionOut->OnCallbackL( CUpnpHttpServerTransaction::EOnResponseStart );
//last header fiished by double CRLF so we must add last CRLF
errorValue = transactionOut->Error();
if ( errorValue != KErrNone )
{
CleanupStack::PopAndDestroy( transactionOut );
return errorValue;
}
if ( transactionOut->QueryResponseHeader().Length() > 0 )
{
transactionOut->AddResponseHeaderL( UpnpHTTP::KHdrServer(),
iServer->ServerDescription() );
RBuf fileName;
fileName.CreateL( KMaxFileName );
CleanupClosePushL( fileName );
User::LeaveIfError( file.FullName( fileName ) );
WriteMsgAndHeaderL( aMsg, transactionOut->QueryResponseHeader(),
fileName, fileSize, rangeStatus, startPos, endPos );
CleanupStack::PopAndDestroy( &fileName );
}
}
}
result = errorValue;
}
else // 4. File was not found, so just respose with HTTP 404 error.
{
if ( !iSaveToFile )
{
//error. No such file or folder found. Send error message.
result = -EHttpNotFound;
}
}
if ( KErrNone == result )
{
result = transactionOut->Error();
}
transactionOut->OnCallbackL( CUpnpHttpServerTransaction::EOnComplete );
CleanupStack::PopAndDestroy( transactionOut );
return result;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::WriteMsgAndHeaderL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::WriteMsgAndHeaderL( CUpnpHttpMessage* aMsg,
const TDesC8& aHeaderToWrite, const TDesC& aPathWithNewMethod,
TInt aFileSize, TInt aRangeStatus, const TInt aStartPos,
const TInt aEndPos )
{
if ( aMsg->Method().Find( KHttpHead ) == 0 ) // HEAD - just header
{
WriteL( aHeaderToWrite );
DeleteServeFileL();
}
else // GET response and also sending POST message
{
if ( iFileServe )
{
delete iFileServe;
iFileServe = NULL;
}
iFileServe = CUpnpHttpFileAccess::NewL( this, aHeaderToWrite,
aPathWithNewMethod, aFileSize );
if ( aStartPos != KErrNotFound )
iFileServe->SetPosOfFile( aStartPos );
if ( aEndPos != KErrNotFound )
iFileServe->SetEndPosOfFile( aEndPos );
if ( !FileTransferWriter() )
{
TInt requestedBytes = aRangeStatus == EHttpPartialContent
? aEndPos - aStartPos + 1 : aFileSize;
if ( requestedBytes <= HttpServer()->FileWriteBufferSize() )
{
FileTransferWriterConstructL( requestedBytes
+ aHeaderToWrite.Length() );
}
else
{
FileTransferWriterConstructL(
HttpServer()->FileWriteBufferSize() );
}
}
FileTransferWriter()->Reset();
if ( iOutFilename->Length() > 0 && iDestinationPath->Length() > 0 )
{
FileTransferWriter()->SetPostNotify();
}
FileTransferWriter()->StartL();
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::FileServeExists
//
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpSession::FileServeExists()
{
return iFileServe ? ETrue : EFalse;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::DeleteServeFileL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::DeleteServeFileL()
{
LOGS1( "%i, CUpnpHttpSession::DeleteServeFileL()", iId );
CUpnpHttpMessage* msg = RUpnpHttpMessageFactory::HttpResponseErrorL(
iAddr, EHttp200Ok );
CleanupStack::PushL( msg );
msg->SetType( EExportComplete );
msg->SetSessionId( Id() );
CleanupStack::Pop( msg );
iServer->ToReceiveStackD( msg );
delete iFileServe;
iFileServe = NULL;
if ( iPendingRequests->Count() > 0 )
{
CUpnpHttpMessage* request = (*iPendingRequests)[0];
iPendingRequests->Remove( 0 );
CleanupStack::PushL( request );
User::LeaveIfError( PrepareToServeFileL( request ) );
CleanupStack::PopAndDestroy( request );
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::NotifyErrorL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::NotifyErrorL( const TInt aError, TInt aInternalError )
{
LOGS2( "%i, CUpnpHttpSession::NotifyErrorL error = %i", iId,
aError );
CUpnpHttpMessage* msg = NULL;
msg = RUpnpHttpMessageFactory::HttpResponseErrorL( RemoteHost(), aError );
msg->SetInternalError( aInternalError );
NotifyUpperLayerLD( msg );
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::NotifyDisconnectL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::NotifyDisconnectL( TInetAddr aAddr )
{
LOGS1( "%i, CUpnpHttpSession::NotifyDisconnectL", iId );
if ( iSenderPath->Length() > 0 && iDestinationPath->Length() > 0 )
{
CUpnpHttpMessage* msg = RUpnpHttpMessageFactory::HttpResponseErrorL(
aAddr, EHttpRequestTimeout );
CleanupStack::PushL( msg );
msg->SetInFilenameL( *iInFilename );
msg->SetInternalError( iSessionError );
CleanupStack::Pop( msg );
NotifyUpperLayerLD( msg );
if ( iReceivedMessage && iFileServe )
{
iFileServe->SetTotalSize( iReceivedMessage->ContentLengthL() );
}
}
else if ( iReceivedMessage && iReceivedMessage->Method() == KHttpPost )
{
if ( !iErrorNotified )
{
// incoming post failed
CUpnpHttpMessage* msg =
RUpnpHttpMessageFactory::HttpResponseErrorL( iAddr,
EHttpRequestTimeout );
CleanupStack::PushL( msg );
msg->SetType( ETransferError );
msg->SetSessionId( Id() );
// get destination path
msg->SetDestinationPathL( iReceivedMessage->Target() );
CleanupStack::Pop( msg );
iServer->ToReceiveStackD( msg );
iErrorNotified = ETrue;
}
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::NotifyTimeoutL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::NotifyTimeoutL()
{
if ( iReceivedMessage )
{
if ( iReceivedMessage->Method() == KHttpPost )
{
// incoming post failed
CUpnpHttpMessage* msg =
RUpnpHttpMessageFactory::HttpResponseErrorL( iAddr,
EHttpRequestTimeout );
CleanupStack::PushL( msg );
msg->SetType( ETransferError );
msg->SetSessionId( Id() );
// get destination path
msg->SetDestinationPathL( iReceivedMessage->Target() );
CleanupStack::Pop( msg );
iServer->ToReceiveStackD( msg );
iErrorNotified = ETrue;
if ( iFileServe )
iFileServe->DeleteFile();
}
else if ( iReceivedMessage->Method().Find( KHttp8 ) != KErrNotFound
&& iReceivedMessage->Target() == KHttpOkCode8 )
{ // incoming response failed
CUpnpHttpMessage* msg =
RUpnpHttpMessageFactory::HttpResponseErrorL( iAddr,
EHttpRequestTimeout );
CleanupStack::PushL( msg );
msg->SetType( ETransferError );
// get destination path
msg->SetDestinationPathL( KNullDesC8 );
msg->SetSessionId( Id() );
CleanupStack::Pop( msg );
iServer->ToReceiveStackD( msg );
iErrorNotified = ETrue;
}
else
{ // incoming response failed
CUpnpHttpMessage* msg =
RUpnpHttpMessageFactory::HttpResponseErrorL( iAddr,
EHttpRequestTimeout );
CleanupStack::PushL( msg );
msg->SetType( ETransferError );
// get destination path
msg->SetDestinationPathL( iReceivedMessage->Target() );
msg->SetSessionId( Id() );
if ( iInFilename )
{
msg->SetInFilenameL( *iInFilename );
}
CleanupStack::Pop( msg );
iServer->ToReceiveStackD( msg );
iErrorNotified = ETrue;
}
}
else
{
CUpnpHttpMessage* msg = RUpnpHttpMessageFactory::HttpResponseErrorL(
iAddr, EHttpRequestTimeout );
CleanupStack::PushL( msg );
msg->SetType( ETransferError );
// get destination path
msg->SetDestinationPathL( KNullDesC8 );
msg->SetSessionId( Id() );
CleanupStack::Pop( msg );
iServer->ToReceiveStackD( msg );
iErrorNotified = ETrue;
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::SocketServerBusyL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::SocketServerBusyL( const TInetAddr& aAddr )
{
CUpnpHttpMessage* msg = RUpnpHttpMessageFactory::HttpResponseErrorL(
aAddr, EHttpExpectationFailed );
CleanupStack::PushL( msg );
msg->SetInFilenameL( *iInFilename );
CleanupStack::Pop( msg );
NotifyUpperLayerLD( msg );
if ( iReceivedMessage && iFileServe )
{
iFileServe->SetTotalSize( iReceivedMessage->ContentLengthL() );
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::NotifyUpperLayerL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::NotifyUpperLayerLD( CUpnpHttpMessage* aMessage )
{
LOGS2( "%i, CUpnpHttpSession::NotifyUpperLayerL %i", iId,
aMessage->Error( ) );
CleanupStack::PushL( aMessage );
aMessage->SetSessionId( iId );
if ( iPendingRequest )
{
aMessage->SetPendingRequest( iPendingRequest );
}
aMessage->SetSenderPathL( *iSenderPath );
if ( aMessage->Method().FindC( KHttp11WithoutSpace ) == 0
|| aMessage->Method().FindC( KHttp10 ) == 0 )
{
aMessage->SetDestinationPathL( *iDestinationPath );
}
else
{
TPtrC8 path = aMessage->SenderPathFromHeader();
aMessage->SetDestinationPathL( path );
}
aMessage->SetType( iRequestType );
aMessage->SetRetryCounter( iRetryCounter );
iDisconnectNotification = EFalse;
aMessage->SetOutFilenameL( *iOutFilename );
CleanupStack::Pop( aMessage );
iServer->ToReceiveStackD( aMessage );
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::IsValidMessage
//
// -----------------------------------------------------------------------------
//
CUpnpHttpSession::THttpInvalidMessage CUpnpHttpSession::IsValidMessage(
CUpnpHttpMessage* aMsg )
{
// Checking method. METHOD NAMES ARE CASE SENSITIVE,
// so checking that method is OK.
// http://www.w3.org/Protocols/HTTP/Methods.html
if ( aMsg->Method().Find( KHttpGet() ) != 0 && aMsg->Method().Find(
KHttpPost() ) != 0 && aMsg->Method().Find( KHttpHead() ) != 0
&& aMsg->Method().Find( KHttpOptions() ) != 0
&& aMsg->Method().Find( KHttpPut() ) != 0 && aMsg->Method().Find(
KHttpDelete() ) != 0 && aMsg->Method().Find( KHttpTrace() ) != 0
&& aMsg->Method().Find( KHttpConnect() ) != 0
&& aMsg->Method().Find( KHttp11WithoutSpace() ) != 0
&& aMsg->Method().Find( KHttp10() ) != 0 && aMsg->Method().Find(
UpnpGENA::KGenaSubscribe() ) != 0 && aMsg->Method().Find(
UpnpGENA::KGenaUnSubscribe() ) != 0 && aMsg->Method().Find(
UpnpGENA::KGenaNotify() ) != 0 )
{
return EUnknownMethod;
}
return EMessageOk;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::FileAccess
//
// -----------------------------------------------------------------------------
//
CUpnpHttpFileAccess* CUpnpHttpSession::FileAccess()
{
return iFileServe;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::OverwriteExisting
//
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpSession::OverwriteExisting()
{
return iOverwriteExisting;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::Offset
//
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpSession::Offset()
{
return iOffset;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::Length
//
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpSession::Length()
{
return iLength;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::SaveAtOffset
//
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpSession::SaveAtOffset()
{
return iSaveAtOffset;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::ServerPort
//
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpSession::ServerPort()
{
return iServer->ServerPort();
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::CheckConnectionClose
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::CheckConnectionCloseL()
{
LOGS1( "%i, CUpnpHttpSession::CheckConnectionCloseL", iId );
if ( iReceivedMessage )
{
if ( iReceivedMessage->IsHeaderReady()
&& iReceivedMessage->UsesConnectionClose() )
{
TPtrC8 buffer = iReceivedMessage->Content();
CUpnpHttpMessage* msg = NULL;
TInt err;
TRAP( err, msg = CUpnpHttpMessage::NewL( buffer, RemoteHost( ),
iId ) );
CleanupStack::PushL( msg );
// If parsing error occurs, or 'stop transfer' occurs during export from other MS to this MS
// and the resource [file] isn't completely downloaded -> don't notify upper layers
if ( err < KErrNone || (err == KErrNone
&& (iReceivedMessage->Method().Find( KHttpPost ) == 0)
&& !iReceivedMessage->IsReadyL()) )
{
LOGS1H(
iHandle,
"%i, CUpnpHttpSession::CheckConnectionCloseL - parsing error",
iId );
iReceivedMessage->RemoveL( buffer.Length() );
StartDisconnect();
CleanupStack::PopAndDestroy( msg );
return;
}
msg->SetInFilenameL( *iInFilename );
if ( !iReceivedMessage->IsToFile()
|| (iReceivedMessage->IsToFile() && iFileServe
&& iFileServe->FileExist()) )
{
CleanupStack::Pop( msg );
NotifyUpperLayerLD( msg );
}
else
{
CleanupStack::PopAndDestroy( msg );
}
iPendingRequest = NULL;
}
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::NotifyUpperLayersOnPostL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::NotifyUpperLayersOnPostL()
{
CUpnpHttpMessage* msg = RUpnpHttpMessageFactory::HttpResponseOkL(
RemoteHost() );
CleanupStack::PushL( msg );
CUpnpHttpHeaderList* List = NULL;
List = msg->HeaderList();
CUpnpHttpHeader* hdr = List->First();
if(hdr != NULL)
{
HBufC8* newHeader = NULL;
newHeader = HBufC8::NewLC( KTransferPending801().Length() );
newHeader->Des().Zero();
newHeader->Des().Append( KTransferPending801() );
hdr->SetNameL( *newHeader );
CleanupStack::PopAndDestroy( newHeader );
}
msg->SetOutFilenameL( *iOutFilename );
CleanupStack::Pop( msg );
NotifyUpperLayerLD( msg );
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::PostingFileCompleteL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::PostingFileCompleteL()
{
CUpnpHttpMessage* msg = RUpnpHttpMessageFactory::HttpResponseOkL(
RemoteHost() );
CleanupStack::PushL( msg );
msg->SetOutFilenameL( *iOutFilename );
CleanupStack::Pop( msg );
NotifyUpperLayerLD( msg );
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::IsMsgReady
//
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpSession::IsMsgReady()
{
TBool ret = EFalse;
if ( iReceivedMessage )
{
TRAPD( err, ret = iReceivedMessage->IsReadyL( ) );
if ( err != KErrNone )
return EFalse;
return ret;
}
else
return EFalse;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::HttpServer()
// Returns pointer to the CUpnpHttpServer object
// -----------------------------------------------------------------------------
//
CUpnpHttpServer* CUpnpHttpSession::HttpServer()
{
return iServer;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::FileTransferReaderDoneL()
// Callback from file transfer reader
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::FileTransferReaderDoneL()
{
LOGS1( "%i, CUpnpHttpSession::FileTransferReaderDoneL", iId );
//notify import completed to upper layers
CUpnpHttpMessage* msg = RUpnpHttpMessageFactory::HttpResponseErrorL(
iAddr, EHttp200Ok );
CleanupStack::PushL( msg );
msg->SetType( EImportComplete );
msg->SetSessionId( Id() );
//setting it only for a POST request
msg->SetDestinationPathL( KNullDesC8 );
CleanupStack::Pop( msg );
iServer->ToReceiveStackD( msg );
TPtrC8 headers = iReceivedMessage->Headers();
//original message received from the remote MS
CUpnpHttpMessage* original = CUpnpHttpMessage::NewL( (TDesC8&) headers,
RemoteHost(), iId );
CleanupStack::PushL( original );
original->SetInFilenameL( *iInFilename );
delete iFileServe;
iFileServe = NULL;
//notify POST is finished
//prepare reply 200 Ok for the remote MS
CUpnpHttpMessage* reply = RUpnpHttpMessageFactory::HttpResponseOkL(
original );
CleanupStack::PushL( reply );
reply->AddPairL( UpnpHTTP::KHdrServer(), iServer->ServerDescription() );
reply->AddPairL( UpnpHTTP::KConnection(), UpnpHTTP::KClose() );
HBufC8* sendBuf = reply->ToStringL();
CleanupStack::PopAndDestroy( reply );
CleanupStack::Pop( original );
//inform the upper layer
iServer->ToReceiveStackD( original );
CleanupStack::PushL( sendBuf );
//send reply to the client
WriteL( *sendBuf );
CleanupStack::PopAndDestroy( sendBuf );
ResetSettingsL();
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::FileTransferReaderDoneL()
// Callback from file transfer reader
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::FileTransferReaderErrorL( TInt aError )
{
LOGS1( "CUpnpHttpSession::FileTransferReaderErrorL %d", aError );
if ( iFileServe )
iFileServe->DeleteFile();
NotifyErrorL( aError );
if ( aError > 0 )
aError = -aError;
TInt httpError = MatchHttpError( aError );
if ( httpError != KErrNone )
{// If we act as a server side
ResponseErrorL( httpError );
ShutdownStop();
return;
}
ResetSettingsL();
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::ResetSettingsL()
// Callback from file transfer reader
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::ResetSettingsL()
{
LOGS1( "%d, CUpnpHttpSession::ResetSettingsL", iId );
iContinuedMessageDownload = EFalse;
iHeadersCompleted = EFalse;
delete iFileServe;
iFileServe = NULL;
delete iReceivedMessage;
iReceivedMessage = NULL;
delete iInFilename;
iInFilename = NULL;
iInFilename = HBufC8::NewMaxL( 0 );
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::FileTransferWriterDoneL
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::FileTransferWriterDoneL()
{
LOGS1( "%i, CUpnpHttpSession::FileTransferWriterDoneL()", iId );
CUpnpHttpMessage* msg = RUpnpHttpMessageFactory::HttpResponseErrorL(
iAddr, EHttp200Ok );
CleanupStack::PushL( msg );
msg->SetType( EExportComplete );
msg->SetSessionId( Id() );
CleanupStack::Pop( msg );
iServer->ToReceiveStackD( msg );
delete iFileServe;
iFileServe = NULL;
iSessionNeedsErrorReply = EFalse;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::FileTransferWriterHandleMoreL()
// Callback from file transfer writer
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::FileTransferWriterHandleMoreL()
{
LOGS1( "%i, CUpnpHttpSession::FileTransferWriterHandleMoreL()",
iId );
if ( FileTransferWriter() )
FileTransferWriter()->Reset();
if ( !IsPersistentConnection() )
{
StartClosingSession();
return;
}
while ( iPendingRequests->Count() > 0 )
{
iSessionNeedsErrorReply = ETrue;
CUpnpHttpMessage* request = (*iPendingRequests)[0];
iPendingRequests->Remove( 0 );
CleanupStack::PushL( request );
TInt error = PrepareToServeFileL( request );
CleanupStack::PopAndDestroy( request );
if ( error )
{
NotifyErrorL( error );
if ( error > 0 )
error = -error;
TInt httpError = MatchHttpError( error );
if ( httpError != KErrNone )
{// If we act as a server side
if ( iSessionNeedsErrorReply )
{
ResponseErrorL( httpError );
}
}
if ( !IsPersistentConnection() )
{
StartClosingSession();
}
}
else
{
break;
}
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::CheckSessionPersistence
// Checks if message contains CONNECTION:CLOSE
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::CheckSessionPersistence( CUpnpHttpMessage* aMsg )
{
if ( aMsg->GetHeaderValue( UpnpHTTP::KConnection() ).FindC(
UpnpHTTP::KClose() ) >= 0 || aMsg->RequestHTTPVersion() == KHttp10() )
{
iIsPersistent = EFalse;
}
else
{
iIsPersistent = ETrue;
}
if ( !IsPersistentConnection() )
{
iSessionKeepAlive = EFalse;
}
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::DestroyIt()
//
// -----------------------------------------------------------------------------
//
void CUpnpHttpSession::DestroyIt( CUpnpTcpSession* aSession )
{
iServer->DeleteSession( aSession );
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::PrepareRangeHeaderL()
//
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpSession::PrepareRangeHeaderL( CUpnpHttpMessage* aMsg,
TBool aServingOutFileName, TInt aFileSize,
CUpnpHttpServerTransaction &aTransaction, TInt& aRangeStatus, TInt& aStartPos, TInt& aEndPos )
{
// Generating headers
aStartPos = KErrNotFound;
aEndPos = KErrNotFound;
// Check if there is a Range header in request and if it's correct
CUpnpRangeHeaderParser* rangeParser = CUpnpRangeHeaderParser::NewLC(
aTransaction, aStartPos, aEndPos );
aRangeStatus = rangeParser->ParseRangeL( aMsg, aFileSize );
CleanupStack::PopAndDestroy( rangeParser );
if ( aRangeStatus != EHttpOk )
{
if ( aRangeStatus <= -EHttpBadRequest )
{
return aRangeStatus;
}
else if ( aRangeStatus == EHttpNoContent )
{
return KErrNone;
}
}
else
{
// Serve whole file
if ( !aServingOutFileName )
{
// If OutFilename() was set in msg
TBuf8<2 * KMaxIntegerLength> sizeBuffer;
sizeBuffer.Num( aFileSize );
aTransaction.AddResponseHeaderL( KNullDesC8(), UpnpHTTP::KHTTPOk() );
aTransaction.AddResponseHeaderL( UpnpHTTP::KHdrContentLength(), sizeBuffer );
}
else
{
// If file path was extracted from header
HBufC8* tempBuffer = aMsg->HeadersToStringL();
CleanupStack::PushL( tempBuffer );
aTransaction.AddResponseHeaderL( KNullDesC8(), *tempBuffer );
CleanupStack::PopAndDestroy( tempBuffer );
}
}
return KErrNone;
}
// -----------------------------------------------------------------------------
// CUpnpHttpSession::PrepareRelativeUriL
//
// -----------------------------------------------------------------------------
//
TPtrC8 CUpnpHttpSession::PrepareRelativeUriL( const TDesC8& aUri )
{
TInetAddr resourceServerAddress;
iServer->ServerAddress( resourceServerAddress );
TInt portNo = iServer->ServerPort();
TBuf<KMaxName> addrTmp;
resourceServerAddress.Output( addrTmp );
HBufC8* addr = UpnpString::FromUnicodeL( addrTmp );
CleanupStack::PushL( addr );
TBuf8<KMaxName> port;
port.Num( portNo );
TInt addrLength = UpnpHTTP::KHTTPUrl().Length() + addr->Length( ) + UpnpString::KColon().Length( ) + port.Length( );
HBufC8* temp = HBufC8::NewLC( addrLength );
TPtr8 tempPtr( temp->Des() );
tempPtr.Append( UpnpHTTP::KHTTPUrl );
tempPtr.Append( *addr );
tempPtr.Append( UpnpString::KColon );
tempPtr.Append( port );
CleanupStack::Pop( temp );
CleanupStack::PopAndDestroy( addr );
if ( aUri.Find( *temp ) == 0 )
{
delete temp;
return aUri.Mid( addrLength );
}
delete temp;
return aUri;
}
// End Of File