upnp/upnpstack/dlnawebserver/src/upnphttpbuffer.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 16:06:48 +0300
branchRCL_3
changeset 9 5c72fd91570d
parent 0 f5a58ecadc66
child 10 594d15129e2c
permissions -rw-r--r--
Revision: 201029 Kit: 201035

/** @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 <libc/limits.h>
#include "upnphttpbuffer.h"
#include "upnphttpserver.h"
#include "upnpcons.h"
#include "upnphttpsession.h"
#include "upnphttpfileaccess.h"
#include "upnphttpfiletransferreader.h"
#include "upnphttpchunkparser.h"
#define KLogFile _L("DLNAWebServer.txt")
#include "upnpcustomlog.h"
#include "upnpcons.h"
#include "httperr.h"
// CONSTANTS

const TInt KMaxBufferLength = 10240;

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::NewL
// Two-phased constructor
// -----------------------------------------------------------------------------
//
CUpnpHttpBuffer* CUpnpHttpBuffer::NewL( CUpnpHttpSession* aSession, TBool aToBeSavedInFile )
	{
LOGS("CUpnpHttpBuffer::NewL(CUpnpHttpSession*, TBool)");
	CUpnpHttpBuffer* self = new (ELeave) CUpnpHttpBuffer( aSession, aToBeSavedInFile );
	CleanupStack::PushL( self );
	self->ConstructL();
	CleanupStack::Pop( self );
	
	return self;
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::~CUpnpHttpBuffer
// C++ default destructor
// -----------------------------------------------------------------------------
//
CUpnpHttpBuffer::~CUpnpHttpBuffer()
	{
LOGS("CUpnpHttpBuffer::~CUpnpHttpBuffer()");

	iBuffer.Close();
    delete iChunkParser;
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::CUpnpHttpBuffer
// C++ default constructor
// -----------------------------------------------------------------------------
//
CUpnpHttpBuffer::CUpnpHttpBuffer( CUpnpHttpSession* aSession, TBool aToBeSavedInFile )
	{
	iContentLength = -1;
	iSession = aSession;
	iToFile = aToBeSavedInFile;
	iContentLengthCounter = 0;
	iErrorCodeCheckedForSaving = EFalse;
	iOkToSaveToFile = EFalse;
	iFileReadBufferSize = aSession->HttpServer()->FileReadBufferSize();
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::ConstructL
// Two-phased constructor
// -----------------------------------------------------------------------------
//
void CUpnpHttpBuffer::ConstructL()
	{
	iBuffer.CreateL( 0 );
	iChunkParser = CUpnpHttpChunkParser::NewL();
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::AppendHeadersL
// 
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpBuffer::AppendHeadersL( TDesC8& aBuffer, TBool aToBeSavedInFile )
{
	TInt PosOfDoubleLineFeed ( KErrNotFound );
	
	LOGS("CUpnpHttpBuffer::AppendL(TDesC8&)");
	
	if ( !IsHeaderReady() )
		{
		 iToFile = aToBeSavedInFile;
		// header not yet ready. Checking if it gets ready with this received buffer
		PosOfDoubleLineFeed = aBuffer.FindF( UpnpString::KDoubleLineFeed );
		
//trying to find double linefeed by spliiitng line
		
			if (iBuffer.Length() > 0)
				{
				if( !iBuffer.Right(UpnpString::KLineFeedLength).CompareF( UpnpString::KLineFeed) 
					&& !aBuffer.FindF(UpnpString::KLineFeed) )
					{
					PosOfDoubleLineFeed = iBuffer.Length() - UpnpString::KLineFeedLength;
					}				
				else if	(!iBuffer.Right(UpnpString::KCRLength).CompareF(UpnpString::KCR) 
					&& !aBuffer.FindF(UpnpString::KLFCRLF))				
					{
					PosOfDoubleLineFeed = iBuffer.Length() - UpnpString::KCRLength;
					}
				else if	(!iBuffer.Right(UpnpString::KCRLFCRLength).CompareF(UpnpString::KCRLFCR)  
					&& !aBuffer.FindF(UpnpString::KLinefeed))				
					{
					PosOfDoubleLineFeed = iBuffer.Length() - UpnpString::KCRLFCRLength;
					}
				//if double linefeed there are not found by splitting line
				//may be it (all double linefeed) is in ne line	
				else if ( PosOfDoubleLineFeed != KErrNotFound )
					{
					PosOfDoubleLineFeed += 	iBuffer.Length();			
					}
				}
		
		if ( PosOfDoubleLineFeed == KErrNotFound )
			{
			// double linefeed not found, so only adding unfinished headers to 
			// iBuffer
			
			if (iBuffer.Length() <= KMaxBufferLength )    //10kb
				{
				    iBuffer.ReAllocL( iBuffer.Length() + aBuffer.Length() );
					iBuffer.Append( aBuffer );
				}
			
			}
		else
			{
			//  Double linefeed found. Appending headers and then checking if 
			// response is OK.
			TInt afterDoubleLineFeed = PosOfDoubleLineFeed + UpnpString::KDoubleLineFeedLength - iBuffer.Length();
			iBuffer.ReAllocL(PosOfDoubleLineFeed + UpnpString::KDoubleLineFeedLength);
			iBuffer.Append( aBuffer.Left(afterDoubleLineFeed));

            // is headers checked
    		if( !iErrorCodeCheckedForSaving )
    		    {
    		    TInt messageError = MessageErrorCode( iBuffer );
    		    TPtrC8 method = Method();
    		    TPtrC8 target = Target();
    		    
    		    if(method == KHttpPost ) 
    		        {
    		        messageError = EHttpOk;
    		        }
    		    
    		    _LIT8( KControl, "/control");
    		    
    		    if( method.FindC( KHttpPost() ) == 0 && 
    		        method.Length() == KHttpPost().Length() 
    		        )
    		        {
        		    TInt lastSlash = target.LocateReverse('/');
        		    if( lastSlash > KErrNotFound )
        		        {
            		    target.Set( target.Mid( lastSlash ) );
            		    }
                    }
    		    
    		    if ( messageError == EHttpOk || messageError == EHttpPartialContent )
    		        {
                    iOkToSaveToFile = ETrue;
    		        }
    		        
    		    // if EXPORTING, then saving to file
    		    else if( method.FindC( KHttpPost() ) == 0 &&
                            method.Length() == KHttpPost().Length() &&
                            target.FindC( KControl ) != 0 )
                    {
                    iOkToSaveToFile = ETrue;
    		        }
    		    else
    		        {
    		        iOkToSaveToFile = EFalse;
    		        CUpnpHttpFileAccess* temp = iSession->FileAccess();
    		        // Delete only downloaded file if it is not complete.
       		        if( temp && temp->Download() )
	       		        {
                        temp->DeleteFile();
	                    // no delete, not owned
	        		    temp = NULL;
	       		        }
    		        }
    		    // error code checked, no need to check it again.
    	        iErrorCodeCheckedForSaving = ETrue;
    		    }

    		return afterDoubleLineFeed;
			}
		}

	return PosOfDoubleLineFeed;
}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::AppendL
// This function appends the aBuffer data at the end of this HTTPBuffer.
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpBuffer::AppendL( TDesC8& aBuffer, TBool aToBeSavedInFile)
	{
	TInt retVal ( KErrNone );
	
	LOGS("CUpnpHttpBuffer::AppendL(TDesC8&)");
	
	if ( !IsHeaderReady() )
		{
		TInt PosOfDoubleLineFeed = AppendHeadersL( aBuffer, aToBeSavedInFile );

		if ( PosOfDoubleLineFeed > KErrNotFound )
		{
			TInt afterDoubleLineFeed = PosOfDoubleLineFeed + UpnpString::KDoubleLineFeedLength - iBuffer.Length();
    		TPtrC8 AppendPointer( aBuffer.Right( aBuffer.Length() - PosOfDoubleLineFeed ) );
			//for file upload, data copied to the file transfer reader
			if(iToFile && iOkToSaveToFile 
				&& iSession->FileTransferReader() && iSession->FileTransferReader()->Activated())
				{
				if(AppendPointer.Length() > 0)
					iSession->FileTransferReader()->AppendL(AppendPointer);
				}
			else if ( IsChunked() )
				{
				iPos =  iBuffer.Length();											
				retVal = ParseL( AppendPointer );
				}
			else
				{
				iBuffer.ReAllocL( iBuffer.Length() + aBuffer.Length() );
				iBuffer.Append( AppendPointer );				
				}
			}
		}
	else
		{
		if( !iErrorCodeCheckedForSaving )
		    {
		    TInt messageError = MessageErrorCode( iBuffer );
		    if ( messageError == EHttpOk || messageError == EHttpPartialContent )
		        {
                iOkToSaveToFile = ETrue;
		        }
		    else
		        {
		        iOkToSaveToFile = EFalse;
   		        CUpnpHttpFileAccess* temp = iSession->FileAccess();
   		        if( temp )
   		            {
    		        temp->DeleteFile();
                    // no delete, not owned
    		        temp = NULL;
    		        }
		        }
		    // error code checked, no need to check it again.
	        iErrorCodeCheckedForSaving = ETrue;
		    }
		
		//for file upload, data copied to the file transfer reader
		if(iToFile && iOkToSaveToFile &&
			iSession->FileTransferReader() && iSession->FileTransferReader()->Activated())
			{
			if(aBuffer.Length() > 0)
				iSession->FileTransferReader()->AppendL(aBuffer);
			return retVal;
			}
			    
		if ( IsChunked() )
			{
			retVal = ParseL( aBuffer );
			}
		else
			{
			iBuffer.ReAllocL( iBuffer.Length() + aBuffer.Length() );
			iBuffer.Append( aBuffer );
			}
	    }
	return retVal;
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::ParseL
// Decodes chunked messages.
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpBuffer::ParseL( TDesC8& aBuffer )
    {
    iBuffer.ReAllocL( iBuffer.Length() + aBuffer.Length() );
    iBuffer.Append( aBuffer );
    return Parse( iBuffer, iPos ) < 0 ? KErrHttpUnknownParseState: KErrNone;                  
    }

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::Parse
// Decodes chunked-encoded buffer
// -----------------------------------------------------------------------------
//	
TInt CUpnpHttpBuffer::Parse(TDes8& aBuffer, TInt& aPos)
    {    
    if( aPos >= aBuffer.Length() )
        {
        iChunkParser->Reset();
        return KErrNone;
        }
    return iChunkParser->Parse( aBuffer, aPos );		
    }

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::IsReady
// Returns ETrue, if buffer is ready to be converted to HTTPMessage 
// else returns EFalse.
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpBuffer::IsReadyL()
	{
LOGS("CUpnpHttpBuffer::IsReady()");
	if ( IsHeaderReady() )
		{
		//Assuming here that HTTP GET -requests may not have a body.
		//So if a HTTP GET request arrives and it has a CONTENT-TYPE or a 
		//CONTENT-LENGHT header we may still serve the file
		TPtrC8 method = Method();
		if ( method.FindC( KHttpGet() ) == 0 )
		    {
		    return ETrue;
		    }
		if ( HasBody() )
			{
			return IsBodyReadyL();
			}
		else 
			{
			return ETrue;
			}
		}
	return EFalse;
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::IsHeaderReady
// Returns ETrue, if header part of HTTPMessage is ready, else returns EFalse.
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpBuffer::IsHeaderReady()
	{
LOGS("CUpnpHttpBuffer::IsHeaderReady()");
	if ( iBuffer.Find( UpnpString::KDoubleLineFeed() ) > KErrNotFound )
		{
		return ETrue;
		}
	else
		{
		return EFalse;
		}
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::IsBodyReadyL
// Returns ETrue, if body part of HTTPMessage is ready, else returns EFalse.
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpBuffer::IsBodyReadyL()
	{
LOGS("CUpnpHttpBuffer::IsBodyReadyL()");
	TInt bodyStart = iBuffer.FindF( UpnpString::KDoubleLineFeed );
	TInt contLength = ContentLengthL();
	if ( IsChunked() )
		{
		return ChunkTransferFinished();
		}
	else
		{
		if ( iHasContentType )
			{	
			TPtrC8 body = iBuffer.Mid( bodyStart + 
                UpnpString::KDoubleLineFeed().Length() );
			return body.Find( UpnpString::KDoubleLineFeed() ) != KErrNotFound;
			}
		}

	TPtrC8 tempPtr;
	if ( iToFile && iOkToSaveToFile )
		{
		if ( iContentLengthCounter >= contLength )
			{
			return !(IsChunked() && !ChunkTransferFinished());
			}
		else
			{
			return EFalse;		
			}
		}
	else
		{
		tempPtr.Set( iBuffer.Mid( bodyStart + UpnpString::KDoubleLineFeedLength ) );		
		if (  tempPtr.Length() >= contLength )
			{
			return !(IsChunked() && !ChunkTransferFinished());
			}
		else
			{
			return EFalse;
			}
		}
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::BytesInBuffer
// Returns the length of entire buffer.
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpBuffer::BytesInBuffer()
	{
LOGS("CUpnpHttpBuffer::BytesInBuffer()");
	return iBuffer.Length();
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::RemoveL
// This function deletes aLength bytes from the beginning of HTTPBuffer.
// -----------------------------------------------------------------------------
//
void CUpnpHttpBuffer::RemoveL( TInt aLength )
	{
LOGS1("CUpnpHttpBuffer::RemoveL(%i)", aLength);
	if ( aLength <= iBuffer.Length() )
		{
		iBuffer.Delete( 0, aLength );
		}
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::ChunkTransferFinished
// Returns ETrue, if chunk encoded message is finished.
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpBuffer::ChunkTransferFinished()
	{
LOGS("CUpnpHttpBuffer::ChunkTransferFinished()");
	return iChunkParser->IsFinished();
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::HasBody
// Returns ETrue, if message has body, else returns EFalse.
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpBuffer::HasBody()
	{
LOGS("CUpnpHttpBuffer::HasBody()");
	if( IsChunked() )
		{
		return ETrue;
		}
TInt endOfHeader = iBuffer.Find( UpnpString::KDoubleLineFeed );
if (endOfHeader>0)
	{TPtrC8 tmp = iBuffer.Mid(0, endOfHeader);
	if ( tmp.FindC( UpnpHTTP::KContentLength() ) > -1 )
		{
		iHasContentType = EFalse;
		return ETrue;
		}
	else if ( tmp.FindC( UpnpHTTP::KContentType() ) > -1)
		{
		iHasContentType = ETrue;
		return ETrue;
		}
	else 
		{
		iHasContentType = EFalse;
		return EFalse;
		}
	}
else
	{
	iHasContentType = EFalse;
	return EFalse; //no end of the header, not possible to judge if there is a body	
	}
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::IsChunked
// Returns ETrue, if message's header contains "Transfer-encoding: 
// Chunked" -header.
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpBuffer::IsChunked()
	{
	LOGS("CUpnpHttpBuffer::IsChunked()");	
	TInt endOfHeader = iBuffer.Find( UpnpString::KDoubleLineFeed );	
		
	// to check only first 2k of data or whole portion with all headers 
	// if they are bigger	
	TPtrC8 TranferCodingPointer;
	if (endOfHeader <= UpnpSSDP::KMaxMessageLength)
		TranferCodingPointer.Set( iBuffer.Left( endOfHeader + UpnpString::KLineFeedLength ) ); 
	else 
		TranferCodingPointer.Set( iBuffer.Left( UpnpSSDP::KMaxMessageLength ) ); 

	TInt TransferEncodingIndex = 
        TranferCodingPointer.FindC( UpnpHTTP::TransferEncoding );

	if ( TransferEncodingIndex == KErrNotFound ) 
		{
		return EFalse;
		}
	else
		{
		TInt correct = 0;
		TInt transferHeaderLength = 0;
		correct = TransferEncodingIndex;
		transferHeaderLength = UpnpHTTP::TransferEncoding().Length();

		TPtrC8 tempPtr = iBuffer.Mid( correct + transferHeaderLength, 
            iBuffer.Length() - correct - transferHeaderLength );
	
		TInt LineFeedAfterTransferCoding = tempPtr.FindF( UpnpString::KLineFeed );

		TPtrC8 codingPtr = tempPtr.Left( LineFeedAfterTransferCoding );
		if ( codingPtr.FindC( UpnpHTTP::Chunked ) != KErrNotFound )
			{
			return ETrue;
			}
		else
			{
			return EFalse;
			}
		}
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::Headers
// Returns Headers of the first message in the buffer.
// -----------------------------------------------------------------------------
//
TPtrC8 CUpnpHttpBuffer::Headers()
	{
LOGS("CUpnpHttpBuffer::Headers()");
	TInt EndOfHeaders = iBuffer.FindC( UpnpString::KDoubleLineFeed );
	TPtrC8 headers = iBuffer.Left( EndOfHeaders + UpnpString::KDoubleLineFeedLength  );	
	return headers;
	}


// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::L
// Returns the content of buffer.
// -----------------------------------------------------------------------------
//
TPtrC8 CUpnpHttpBuffer::Content()
	{
LOGS("CUpnpHttpBuffer::Content()");
	TInt PosOfContLength = iBuffer.FindC( UpnpHTTP::KHdrContentLength() );
	TInt contLen = 0;
	
	if ( PosOfContLength > 0 )
		{
		TRAPD(error, contLen = ContentLengthL());
		if (error)
			{
			contLen = 0;
			}
		}
	else if ( iHasContentType )
		{
		return TPtrC8( iBuffer );
		}
	else if( IsChunked() )
		{
		TInt StartOfMessage = iBuffer.FindC( UpnpString::KDoubleLineFeed );
		contLen = iBuffer.Length() - StartOfMessage;	
		}
	/*else
		{
		TInt StartOfMessage = iBuffer.FindC( UpnpString::KDoubleLineFeed );
		contLen = iBuffer.Des().Length() - StartOfMessage;
		}*/	

	TInt endOfHeader = iBuffer.Find( UpnpString::KDoubleLineFeed );
	TInt length = 0;
	// Probably not all headers were sent
	
	if( endOfHeader == KErrNotFound  )
		{
		length = iBuffer.Length();
		}
	else
		{
		length = endOfHeader + contLen + UpnpString::KDoubleLineFeedLength;	
		}

    if( length < 0 ) // in case of overflow of length value
        {
        length = INT_MAX;
        }

	TPtrC8 message = iBuffer.Left( length );
	return message;
	}	

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::ContentLengthL
// Returns the content length of first message in the buffer.
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpBuffer::ContentLengthL()
	{
	LOGS("CUpnpHttpBuffer::ContentLengthL()");
	
	TInt endOfHeader = iBuffer.Find( UpnpString::KDoubleLineFeed );	
    User::LeaveIfError(endOfHeader);
	TPtrC8 findptr;
	// to check only first 2k of data or whole portion with all headers 
	// if they are bigger	
	if (endOfHeader >= UpnpSSDP::KMaxMessageLength)
		findptr.Set( iBuffer.Left( endOfHeader + UpnpString::KLineFeedLength ) ); 
	else 
		findptr.Set( iBuffer.Left( UpnpSSDP::KMaxMessageLength ) ); 						

	TInt contentLengthIndex = findptr.FindC( UpnpHTTP::KHdrContentLength() );

	TInt lengthOfContentLength = UpnpHTTP::KHdrContentLength().Length() +
        UpnpString::KColon().Length();
	
	if ( contentLengthIndex <= 0 ) 
		{
	return KErrNotFound;
		}

	TPtrC8 rest;
	rest.Set( findptr );
	rest.Set( rest.Mid( contentLengthIndex + lengthOfContentLength ) );

	TInt lineEnd = rest.Find( UpnpString::KLineFeed );
	if ( lineEnd < 0 )
		{
		return KErrNotFound;
		}
	
	// LWS and spanning headers
	TInt indexLWS = 0;
	TPtrC8 clRest = rest;
	TInt contentLengthValueEnd = lineEnd;
	
	while( ETrue )
	    {
	    indexLWS = CUpnpHttpMessage::FindLWS( clRest );
	    if( indexLWS == lineEnd )
	        {	     
	        clRest.Set( clRest.Mid( lineEnd + UpnpString::KLineFeed().Length() ) );
	        lineEnd = clRest.Find( UpnpString::KLineFeed );
	        contentLengthValueEnd += lineEnd + UpnpString::KLineFeed().Length();
	        }
	    else
	        {
	        break;
	        }
	    }			
    
	TPtrC8 length = rest.Left( contentLengthValueEnd );
    
    if( !length.Compare( KNullDesC8() ) )
        return -1;
    
    // Unfold header
    HBufC8* clValueBuf = length.AllocLC();
    TPtr8 ptrCLValue = clValueBuf->Des();
    
    // Remove CRLFs
    TInt pos;
	while( ( pos = ptrCLValue.FindC( UpnpString::KLineFeed() ) ) != KErrNotFound)
	    {
		ptrCLValue.Delete(pos, UpnpString::KLineFeedLength);
	    }
	
    // Remove spaces
    while( ( pos = ptrCLValue.FindC( UpnpString::KSpace() ) ) != KErrNotFound)
	    {
		ptrCLValue.Delete(pos, 1);
	    }
	
	// Remove tabs
    while( ( pos = ptrCLValue.FindC( UpnpString::KTab() ) ) != KErrNotFound)
	    {
		ptrCLValue.Delete(pos, 1);
	    }
   
	TLex8 lex( ptrCLValue );
	TInt val = 0;
	User::LeaveIfError(lex.Val( val ));
	
	CleanupStack::PopAndDestroy( clValueBuf );

	iContentLength = val;

	return val;
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::UsesConnectionClose
// Returns ETrue, if message's header contains "Connection: close" -header.
// -----------------------------------------------------------------------------
//
TBool CUpnpHttpBuffer::UsesConnectionClose()
	{
LOGS("CUpnpHttpBuffer::UsesConnectionClose()");
	if(IsHeaderReady())
		{
		TPtrC8 headers=Headers();
		TInt posOfConn=headers.FindC(UpnpHTTP::KConnection());
		TInt posOfHttp10 = headers.FindC(KHttp10); 	
		
		if( posOfConn != KErrNotFound )
			{
			TPtrC8 conn=headers.Mid(posOfConn+UpnpHTTP::KConnection().Length() +
                UpnpString::KColon().Length());
			
			TInt posOfLineFeed=conn.FindC(UpnpString::KLineFeed());
			if(posOfLineFeed != KErrNotFound)
				{
				conn.Set(conn.Left(posOfLineFeed));
				
				while((conn.Left(1)).CompareC(UpnpString::KSpace()) == 0)
					{
					conn.Set(conn.Mid(1)); // removing spaces in front of value
					}
					
				if(conn.FindC(UpnpHTTP::KClose()) >= 0)
					{
					return ETrue;
					}
				else
					{
					return EFalse;
					}
				}
			else
				{
				// If rsp = 'HTTP/1.0', we can assume that it contains 'connection:close' header, even if it doesn't!	
		                   if( posOfHttp10 != KErrNotFound )
		                        return ETrue;
				return EFalse;
				}
			}
		else
			{
		         // If rsp = 'HTTP/1.0', we can assume that it contains 'connection:close' header, even if it doesn't!	
		         if( posOfHttp10 != KErrNotFound )
		             return ETrue;
			return EFalse;
			}
		}
	return EFalse;
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::MessageErrorCode
// Checks error code of received message.
// -----------------------------------------------------------------------------
//
TInt CUpnpHttpBuffer::MessageErrorCode( TDesC8& aBuffer )
    {
    if( IsHeaderReady() )
        {
    	TInt posOfNextLine = aBuffer.Find(UpnpString::KLineFeed); 
    	if( posOfNextLine != KErrNotFound )
    		{
    		TPtrC8 spacePtr;
    		spacePtr.Set( aBuffer );
    		
    		// finding first space
    		TInt posOfFirstSpace = spacePtr.Find(UpnpString::KSpace);
            if ( posOfFirstSpace != KErrNotFound )
                {
    		    spacePtr.Set( spacePtr.Left( posOfFirstSpace ) );

                }

    		// back to basic handling
    		spacePtr.Set( aBuffer );
    		
    		if( posOfFirstSpace < posOfNextLine && posOfFirstSpace != KErrNotFound )
    			{
    			// if first space is found, it has to be before linefeed
    			// +1 comes from going over the first space, we are interested
    			// in what comes after it.
    			spacePtr.Set( spacePtr.Mid( posOfFirstSpace  + 1 ) );
    			TInt posOfSecondSpace = spacePtr.Find(UpnpString::KSpace);
    			if( posOfSecondSpace < posOfNextLine && posOfSecondSpace != KErrNotFound )
    				{
    				// check that length of path is longer than zero.
    				if( posOfSecondSpace > 0 )
    					{
                        // now setting spacePtr so that we have the error number in spacePrt
    					spacePtr.Set( spacePtr.Left( posOfSecondSpace ) );

                        // making conversion
          				TLex8 errorValue( spacePtr );
                        TInt messageErrorValue( 0 );                        
        				TInt convError = errorValue.Val( messageErrorValue );
        				
        				// checking that conversion was ok
        				if( convError == KErrNone )
        				    {
        				    return messageErrorValue;
        				    }
        				else
        				    {
        				    return KErrAbort;
        				    }
        				
    					}
    				else
    					{
    					// header too short. Invalid message
    					return KErrAbort;
    					}
    				}
    			else
    				{
    				// no second space found. Invalid message.
    				return KErrAbort;
    				}
    			}
    		else
    			{
    			// no space found before linefeed. Invalid message
    			return KErrAbort;
    			}
     		}
		else
			{
			// no linefeed found in headers. Invalid message
			return KErrAbort;
			}        
        }
    else
        {
        return KErrAbort;
        }
    }

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::Method
// returns the method of message
// -----------------------------------------------------------------------------
//
TPtrC8 CUpnpHttpBuffer::Method()
    {
    if( IsHeaderReady() )
        {
        TPtrC8 ret;
        ret.Set( Headers() );
        TInt posOfSpace = ret.Locate(' ');
        if( posOfSpace != KErrNotFound )
            {
            ret.Set( ret.Left( posOfSpace ) );
            return ret;
            }
        else
            {
            return KNullDesC8();
            }
        
        }
    else
        {
        return KNullDesC8();
        }
    }

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::Target
// 
// -----------------------------------------------------------------------------
//    
TPtrC8 CUpnpHttpBuffer::Target()
    {
    if( IsHeaderReady() )
        {
        TPtrC8 ret;
        ret.Set( Headers() );
        TInt posOfSpace = ret.Locate(' ');
        if( posOfSpace != KErrNotFound )
            {
            ret.Set( ret.Mid( posOfSpace +1 ) );
            posOfSpace = ret.Locate(' ');
            if( posOfSpace != KErrNotFound )
                {
                ret.Set( ret.Left( posOfSpace ) );
                return ret;
                }
            else
                {
                return KNullDesC8();
                }
            }
        else
            {
            return KNullDesC8();
            }
        
        }
    else
        {
        return KNullDesC8();
        }    
    }

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::IsToFile
// Returns True if message content is going to be saved in file.
// -----------------------------------------------------------------------------
//    
TBool CUpnpHttpBuffer::IsToFile()
	{
	return iToFile;		
	}

// -----------------------------------------------------------------------------
// CUpnpHttpBuffer::SetToFile
// Sets if body of message contained in buffer should be saved in file.
// -----------------------------------------------------------------------------
//        
void CUpnpHttpBuffer::SetToFile( TBool aToFile )
	{
	iToFile = aToFile;			
	}


// End Of File