diff -r 000000000000 -r f5a58ecadc66 upnp/upnpstack/dlnawebserver/src/upnphttpsession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/upnp/upnpstack/dlnawebserver/src/upnphttpsession.cpp Tue Feb 02 01:12:20 2010 +0200 @@ -0,0 +1,1818 @@ +/** @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 +#include +#include // For RApaLsSession +#include +#include +#include +#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 ( 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 addrTmp; + resourceServerAddress.Output( addrTmp ); + HBufC8* addr = UpnpString::FromUnicodeL( addrTmp ); + CleanupStack::PushL( addr ); + + TBuf8 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