Click here to Skip to main content
15,881,882 members
Articles / Desktop Programming / MFC

The Ultimate Toolbox - Updates and User Contributions

Rate me:
Please Sign up or sign in to vote.
4.79/5 (26 votes)
12 Feb 2013CPOL8 min read 254.5K   23.6K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
//=================================================================
//  class: CUT_HTTPClient
//  File:  HTTP_c.cpp
//
//  Purpose:
//
//  HTTP Client Class 
//  Implementation of Hypertext Transfer Protocol -- HTTP/1.0
//
//  RFC  1945
//	Updated to support RFC2817 May 2000
//      
//=================================================================
// Ultimate TCP/IP v4.2
// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
//=================================================================

#ifdef _WINSOCK_2_0_
    #define _WINSOCKAPI_    /* Prevent inclusion of winsock.h in windows.h   */
                            /* Remove this line if you are using WINSOCK 1.1 */
#endif

#include "stdafx.h"

#include <stdio.h>

#include    "HTTP_c.h"      // HTTP client header file
#include	"base64.h"

#include    "ut_strop.h"

// Suppress warnings for non-safe str fns. Transitional, for VC6 support.
#pragma warning (push)
#pragma warning (disable : 4996)

/*********************************************
Constructor
**********************************************/
CUT_HTTPClient::CUT_HTTPClient() :
        m_nPort(80),                // Set default connecting port
        m_lMaxBodyLines(16000),     // Set default body lines
        m_nTagCount(-1),            // Initialize tag count
        m_bUseProxy(FALSE),         // Set by default - not using proxy
        m_nConnectTimeout(5),        // Set default connection time out to 5 sec.
		m_lLastStatusCode(0)	,// nothing received from the server yet
		m_nProxyPort(80),
		m_bEnableTunnelling(FALSE)
{
    m_szServerName[0]   = 0;
    m_szServerAddr[0]   = 0;
    m_szProxyAddr[0]    = 0;
	m_szProxyUserName = NULL;
	m_szProxyPassword = NULL;


}

/*********************************************
Destructor
**********************************************/
CUT_HTTPClient::~CUT_HTTPClient()
{
    m_listSendHeader.ClearList();       // Clear send header list
    m_listReceiveHeader.ClearList();    // Clear receive header list
    m_listReceiveBody.ClearList();      // Clear receive body list
    m_listTags.ClearList();             // Clear tags list
	if(m_szProxyPassword != NULL)
		delete m_szProxyPassword ;
	if(m_szProxyUserName != NULL)
		delete m_szProxyUserName;


}

/*********************************************
SplitURL:
    (Internal Function )
    parses the url passed to find out the  target server and
    the requested file absolute path.  HTTP URL format:
	"http:" "//" host [ ":" port ] [ abs_path [ "?" query ]] 
PARAM:
    LPSTR url      - The origional url buffer
    LPSTR fileName - requested file name 
    int fileLen    - length of the file name    
Side Effects;
    - sets the server address
	- Sets the Port number if found
Return:
    UTE_SUCCESS                 - the operation was successfull
    UTE_SERVER_SET_NAME_FAILED  - Unable to set the server name 
**********************************************/
int CUT_HTTPClient::SplitURL(LPSTR url,LPSTR fileName,int fileLen){

    int     len = (int)strlen(url);
    int     index = 0;
    int     error = UTE_SUCCESS;
    char    server[MAX_PATH+1] ="";
	BOOL	bPortIncluded = FALSE;

    //put all the slashes in the same direction
    for(int loop = 0; loop < len;loop++){
        if(url[loop] == '\\')
            url[loop] = '/';
    }

    //check to see if there is a HTTP://
    if(strstr(url,"://") != NULL)
        index = 1;

    //parse the string to get the server name
    if(CUT_StrMethods::ParseString(url,"/?%%",index,server,sizeof(server)) != UTE_SUCCESS)
        error = UTE_SERVER_SET_NAME_FAILED;     // Unable to find the server in the string

	// At this point the "server" variable contains information on the server
	// as well as the port number that the client chooses to connect on (if specified).
	// Find the port number:
	if ( CUT_StrMethods::GetParseStringPieces (server,":") > 1 )
	{
		char temp[MAX_PATH];
		long port = m_nPort;
		// extract the port number from the server name
		if(CUT_StrMethods::ParseString(server,":",1,temp,MAX_PATH) == UTE_SUCCESS)
		{
			if(*temp != '/')
			{
				if (CUT_StrMethods::ParseString(temp,"/",0,&port)  == UTE_SUCCESS)
				{
					SetPort(port);
					bPortIncluded = TRUE;
					// Remove the port information from the server name
					CUT_StrMethods::ParseString(server,":",0,temp,MAX_PATH);
					strcpy( server, temp );
				}
			}
		}
	}
    
    //set the server name
    if( SetServer(server) != UTE_SUCCESS)
        error = UTE_SERVER_SET_NAME_FAILED;     // Unable to set the server name 

    //parse the string to get the filename name
    LPSTR buf = strstr(url,server) + strlen(server);
	
	// if the port number is included then lets move forward the pointer for the 
	// file name as many bytes as the port number digits + : 
	if (bPortIncluded )
	{		
		char portString[20];
		_itoa( m_nPort,portString, 10);
		buf = buf + strlen(portString) +1; // the port number number plus the : 
	}


    if(CUT_StrMethods::ParseString(buf,"#",0,fileName,fileLen) != UTE_SUCCESS)
        fileName[0] = 0;
    
    return OnError(error);
}

/*********************************************
SetServer
    Sets the name or address of the web server
    to use.
Params
    name - the name or address of the web server
            to use
Return
    UTE_SUCCESS             - success
    UTE_PARAMETER_TOO_LONG  - param too long
    UTE_ERROR               - failure
**********************************************/
int CUT_HTTPClient::SetServer(LPSTR name){

    //check to see if the same name was already set
    if(strcmp(name, m_szServerName) == 0)
        return UTE_SUCCESS;
        
    //check to see if the given name is too long
    if( strlen(name) > 255)
        return OnError(UTE_PARAMETER_TOO_LONG);
    
    //copy the given name
    strncpy(m_szServerName, name, sizeof(m_szServerName));

    //clear the address variable
    m_szServerAddr[0] = 0;

    //check to see if the name given is an IP address
    if(IsIPAddress(name) == TRUE){
        if(strlen(name) < sizeof(m_szServerAddr))
		{
			strcpy(m_szServerAddr,name);
			return OnError(UTE_SUCCESS);
		}
        else
            return OnError(UTE_PARAMETER_TOO_LONG);
    }

    if(GetAddressFromName(name, m_szServerAddr, sizeof(m_szServerAddr)) != UTE_SUCCESS)
        return OnError(UTE_ERROR);

    return OnError(UTE_SUCCESS);
}

/*********************************************
SetPort
    Sets a new communication port
Params
    port        - new port number (default 80)
Return
    UTE_SUCCESS - success
    UTE_ERROR   - failure
**********************************************/
int CUT_HTTPClient::SetPort(int port){
    
    if(port < 0)
        return UTE_ERROR;

    m_nPort = port;
    return UTE_SUCCESS;
}

/*********************************************
GetPort
    Sets a new communication port
Params
    none
Return
    communication port
**********************************************/
int CUT_HTTPClient::GetPort() const
{
    return m_nPort;
}

/*********************************************
AddSendHeaderTag
    Adds a tag to the list of MIME tags to send
    as part of any command sent
Params
    tag - tage string to add to the list
Return
    TRUE - SUCCESS
    FALSE - FAiled
**********************************************/
#if defined _UNICODE
int CUT_HTTPClient::AddSendHeaderTag(LPCWSTR tag){
	return AddSendHeaderTag(AC(tag));}
#endif
int CUT_HTTPClient::AddSendHeaderTag(LPCSTR tag){
    int ret = FALSE;

	//check for a CRLF
    int len = (int)strlen(tag);
    if(tag[len-1]!= '\n' && tag[len-2] !='\r'){
        LPSTR buf = new char[len+3];
        strcpy(buf,tag);
        strcat(buf,"\r\n");
        ret = m_listSendHeader.AddString(buf);
		delete buf;
		return ret;
    }
    else
        return m_listSendHeader.AddString(tag);
}

/*********************************************
ClearSendHeaderTags
    Clears all MIME tags from the tag list
Params
    none
Return
    TRUE    - success
    FALSE   - error
**********************************************/
int CUT_HTTPClient::ClearSendHeaderTags(){
    return m_listSendHeader.ClearList();
}

/*********************************************
MaxLinesToMemStore
    Sets the maximum number of lines to store
    in memory when retrieving information from
    a server. If more lines are sent then then
    are truncated.
Params
    count - max. lines to store
Return
    UTE_SUCCESS - success
    UTE_ERROR   - error   
**********************************************/
int CUT_HTTPClient::MaxLinesToStore(long count){
    
    if(count <=0)
        return UTE_ERROR;

    m_lMaxBodyLines = count;
    return UTE_SUCCESS;
}
/*********************************************
GetMaxLinesToMemStore
    Sets the maximum number of lines to store
    in memory when retrieving information from
    a server. If more lines are sent then then
    are truncated.
Params
    count - max. lines to store
Return
    UTE_SUCCESS - success
    UTE_ERROR   - error   
**********************************************/
long CUT_HTTPClient::GetMaxLinesToStore() const
{
    return m_lMaxBodyLines;
}
/*********************************************
Params
    none
Return
    UTE_SUCCESS - success
    UTE_ERROR   - error   
**********************************************/
int CUT_HTTPClient::ClearReceivedData(){
    
    int rt = UTE_SUCCESS;
    
    if(m_listReceiveBody.ClearList() == FALSE)
        rt = UTE_ERROR;
    if(m_listReceiveHeader.ClearList() == FALSE)
        rt = UTE_ERROR;

    m_nTagCount = -1;
    return rt;
}

/*********************************************
GetBodyLineCount
    Returns the number of lines in memory storage
Params
    none
Return
    the number of lines in memory storage
**********************************************/
long CUT_HTTPClient::GetBodyLineCount() const
{
    return m_listReceiveBody.GetCount();
}

/*********************************************
GetBodyLine
    Retrieve the servers answer line by line
Params
    index - 0 based index of line to get
Return
    pointer to the string or NULL
**********************************************/
LPCSTR CUT_HTTPClient::GetBodyLine(long index) const
{
    return m_listReceiveBody.GetString(index);
}
/*************************************************
GetBodyLine()
Retrieve the servers answer line by line
PARAM
header	- [out] pointer to buffer to receive title
maxSize - length of buffer
index	- index of the line
size    - [out] length of line

  RETURN				
  UTE_SUCCES			- ok - 
  UTE_NULL_PARAM		- body and/or size is a null pointer
  UTE_INDEX_OUTOFRANGE  - body not found
  UTE_BUFFER_TOO_SHORT  - space in body buffer indicated by maxSize insufficient, realloc 
  based on size returned.
  UTE_OUT_OF_MEMORY		- possible in wide char overload
**************************************************/
int CUT_HTTPClient::GetBodyLine(LPSTR body, size_t maxSize, int index, size_t *size) {
	
	int retval = UTE_SUCCESS;
	
	if(body == NULL || size == NULL) {
		retval = UTE_NULL_PARAM;
	}
	else {
		
		LPCSTR str = GetBodyLine(index);
		
		if(str == NULL) {
			retval = UTE_INDEX_OUTOFRANGE;
		}
		else {
			*size = strlen(str);
			if(*size >= maxSize) {
				++(*size);
				retval = UTE_BUFFER_TOO_SHORT; 
			}
			else {
				strcpy(body, str);
			}
		}
	}
	return retval;	
}
#if defined _UNICODE
int CUT_HTTPClient::GetBodyLine(LPWSTR body, size_t maxSize, int index, size_t *size) {
	
	int retval;
	
	if(maxSize > 0) {
		char * bodyA = new char [maxSize];
		
		if(bodyA != NULL) {
			retval = GetBodyLine( bodyA, maxSize, index, size);
			
			if(retval == UTE_SUCCESS) {
				CUT_Str::cvtcpy(body, maxSize, bodyA);
			}
			delete [] bodyA;
		}
		else {
			retval = UTE_OUT_OF_MEMORY;
		}
	}
	else {
		if(size == NULL) (retval = UTE_NULL_PARAM);
		else {
			LPCSTR lpStr = GetBodyLine(index);
			if(lpStr != NULL) {
				*size = strlen(lpStr)+1;
				retval = UTE_BUFFER_TOO_SHORT;
			}
			else {
				retval = UTE_INDEX_OUTOFRANGE;
			}
		}
	}
	return retval;

}
#endif

/*********************************************
SaveToFile
    Saves memory storage to a file
Params
    name - name of the file to create
Return
    UTE_SUCCESS             - success
    UTE_FILE_OPEN_ERROR     - file open error
    UTE_FILE_WRITE_ERROR    - file write error
**********************************************/
int CUT_HTTPClient::SaveToFile(LPCTSTR name)
{
    CUT_File fileData;
    int error = UTE_SUCCESS;
    
    if (fileData.Open(name, GENERIC_WRITE, CREATE_ALWAYS) != 0)
        return OnError(UTE_FILE_OPEN_ERROR);

    long count, loop;
    LPCSTR buf;
    DWORD len;

    count = GetBodyLineCount();

    // write the file
    for (loop = 0; loop < count ; loop++) {
        
        // Check if procedure is aborted
        if (IsAborted()) {  
            CloseConnection();
            return OnError(UTE_ABORTED);        // Abort
        }

        buf = GetBodyLine(loop);                
        len = (int)strlen(buf);
        
        // write to the file
        if (fileData.Write(buf, (UINT) len) < len) {
            error = UTE_FILE_WRITE_ERROR;
            break;
        }
        
        if (!CUT_StrMethods::IsWithCRLF(buf)) {
            if(fileData.Write("\r\n", 2) < 2) {
                error = UTE_FILE_WRITE_ERROR;
                break;
            }
        }
    }
    
    return OnError(error);
}

/*********************************************
GetLinkTagCount
    Returns the total number of link tags found
    in memory storage
Params
    none
Return
    number of links
**********************************************/
int CUT_HTTPClient::GetLinkTagCount(){

    //if the tag count was already calculated for this data then
    //just return the number, otherwise calc. the data
    if(m_nTagCount != -1)
        return m_nTagCount;
    else
        m_nTagCount = 0;

    m_listTags.ClearList();

    long count = 0;
	long loop = 0;
    int loop2 = 0;
	int len = 0;
    LPSTR tagString = {"<a href"};
    LPSTR tagUString = {"<A HREF"};
    LPCSTR buf;
    int comparePos = 0;
    int compareLen = (int)strlen(tagString);
        
    count = GetBodyLineCount();

    for(loop=0;loop<count;loop++){
    
        buf = GetBodyLine(loop);
        len = (int)strlen(buf);

        for(loop2=0;loop2<len;loop2++){
            if(tagString[comparePos] == buf[loop2] || tagUString[comparePos] == buf[loop2]){
                comparePos++;
                if(comparePos == compareLen){
                    m_nTagCount ++;
                    m_listTags.AddTagPos(loop,loop2);
                    comparePos = 0;
                }
            }
            else
                comparePos = 0;
        }
    }
        

    return m_nTagCount;
}

/*********************************************
GetLinkTag
    returns a link tag from memory storage
Params
    index - 0 based index of the tag
    tag - buffer where the tage is copied into
    maxLen - length of the buffer
Return
    UTE_SUCCESS             - success
    UTE_INDEX_OUTOFRANGE    - invalid index
    UTE_BUFFER_TOO_SHORT    - buffer too short
**********************************************/
#if defined _UNICODE
int CUT_HTTPClient::GetLinkTag(int index,LPWSTR tag,int maxLen){
	char * str = (char*) alloca(maxLen+1);
	int result = GetLinkTag(index, str, maxLen);
	if(result == UTE_SUCCESS) {
		CUT_Str::cvtcpy((_TCHAR*)tag, maxLen, str);
	}
	return result;
}
#endif
int CUT_HTTPClient::GetLinkTag(int index,LPSTR tag,int maxLen){

    if(m_nTagCount == -1)
        GetLinkTagCount();

    long line =0 ;
    int pos = 0;
    
    if(m_listTags.GetTagPos(index,&line,&pos) != TRUE)
        return OnError(UTE_INDEX_OUTOFRANGE);
    
    LPCSTR buf = GetBodyLine(line);
    if(CUT_StrMethods::ParseString(&buf[pos],">",0,tag,maxLen) != UTE_SUCCESS){
		return OnError(UTE_BUFFER_TOO_SHORT);
	}
	
	// now that wa have known where is the maximum of the link 
	// we need to mak sure that it is not including the = sign of the SRC tag
	// however we have to make sure that we are not removing any other equal signs the link may include
	
	// create a work buffer
	char *temp = new char[maxLen];
	
	// let's populate it 
	strcpy(temp,tag);

	// it must include an equal sign
	if(CUT_StrMethods::ParseString(temp,"=",0,tag,maxLen) != UTE_SUCCESS){
		delete []temp;
		return OnError(UTE_BUFFER_TOO_SHORT);
	}
	// we need the working one be starting from the equal sign since we may hav spaces before the 
	// first " 
	strcpy(temp,&temp[strlen(tag)]);

	// but just incase there is no " sign and no spaces we must make a copy of it 
	// which will be returned if the next if statement did not pass
	strcpy(tag,temp+1);

	if (CUT_StrMethods::GetParseStringPieces (temp,"\"'") > 1)
	{
		if(CUT_StrMethods::ParseString(temp,"\"'",1,tag,maxLen) != UTE_SUCCESS){
			delete []temp;
			return OnError(UTE_BUFFER_TOO_SHORT);
		}
	}

	// remove th working buffer
	delete []temp;
	       
    return OnError(UTE_SUCCESS);
}

/*********************************************
GetHeaderLineCount
    Returns the number of lines in the header
    of the data that was last received from 
    the server
Params
    none
Return
    number of header lines
**********************************************/
int CUT_HTTPClient::GetHeaderLineCount() const
{
    return m_listReceiveHeader.GetCount();
}

/*********************************************
GetHeaderLine
    Returns a header line from the header
    of the data that was last received from
    the server
Params
    index - 0 based index of a line in the header
Return
    pointer to the string or NULL
**********************************************/
LPCSTR CUT_HTTPClient::GetHeaderLine(int index) const
{
    return m_listReceiveHeader.GetString(index);
}
/*************************************************
GetHeaderLine()
Returns a header line from the header
    of the data that was last received from
    the server
PARAM
header	- [out] pointer to buffer to receive title
maxSize - length of buffer
index	- index of the header
size    - [out] length of title

  RETURN				
  UTE_SUCCES			- ok - 
  UTE_NULL_PARAM		- header and/or size is a null pointer
  UTE_INDEX_OUTOFRANGE  - header not found
  UTE_BUFFER_TOO_SHORT  - space in title buffer indicated by maxSize insufficient, realloc 
  based on size returned.
  UTE_OUT_OF_MEMORY		- possible in wide char overload
**************************************************/
int CUT_HTTPClient::GetHeaderLine(LPSTR header, size_t maxSize, int index, size_t *size) {
	
	int retval = UTE_SUCCESS;
	
	if(header == NULL || size == NULL) {
		retval = UTE_NULL_PARAM;
	}
	else {
		
		LPCSTR str = GetHeaderLine(index);
		
		if(str == NULL) {
			retval = UTE_INDEX_OUTOFRANGE;
		}
		else {
			*size = strlen(str);
			if(*size >= maxSize) {
				++(*size);
				retval = UTE_BUFFER_TOO_SHORT; 
			}
			else {
				strcpy(header, str);
			}
		}
	}
	return retval;	
}
#if defined _UNICODE
int CUT_HTTPClient::GetHeaderLine(LPWSTR header, size_t maxSize, int index, size_t *size) {
	
	int retval;
	
	if(maxSize > 0) {
		char * headerA = new char [maxSize];
		
		if(headerA != NULL) {
			retval = GetHeaderLine( headerA, maxSize, index, size);
			
			if(retval == UTE_SUCCESS) {
				CUT_Str::cvtcpy(header, maxSize, headerA);
			}
			delete [] headerA;
		}
		else {
			retval = UTE_OUT_OF_MEMORY;
		}
	}
	else {
		if(size == NULL) (retval = UTE_NULL_PARAM);
		else {
			LPCSTR lpStr = GetHeaderLine(index);
			if(lpStr != NULL) {
				*size = strlen(lpStr)+1;
				retval = UTE_BUFFER_TOO_SHORT;
			}
			else {
				retval = UTE_INDEX_OUTOFRANGE;
			}
		}
	}
	return retval;

}
#endif

/*********************************************
GetHeaderLine
    Returns a first header line from the header
    of the data that was last received from
    the server that contains specified substring
Params
    subString   - substring to serch for
    [pos]       - position of substring if found
Return
    pointer to the string or NULL
**********************************************/
LPCSTR CUT_HTTPClient::GetHeaderLine(LPCSTR subString, int *pos) const
{
    return m_listReceiveHeader.GetString(subString, pos);
}
/*************************************************
GetHeaderLine()
    Returns a first header line from the header
    of the data that was last received from
    the server that contains specified substring
PARAM
header	- [out] pointer to buffer to receive title
maxSize - length of buffer
subString   - substring to serch for
pos       - [out] position of substring if found {may be NULL if not wanted)
index	- index of the header
size    - [out] length of header

  RETURN				
  UTE_SUCCESS			- ok - 
  UTE_NULL_PARAM		- header and/or size is a null pointer
  UTE_INDEX_OUTOFRANGE  - header not found
  UTE_BUFFER_TOO_SHORT  - space in header buffer indicated by maxSize insufficient, realloc 
						  based on size returned.
  UTE_OUT_OF_MEMORY		- possible in wide char overload
**************************************************/
int CUT_HTTPClient::GetHeaderLine(LPSTR header, size_t maxSize, LPCSTR subString, size_t *size, int *pos) {
	
	int retval = UTE_SUCCESS;
	
	if(header == NULL || size == NULL) {
		retval = UTE_NULL_PARAM;
	}
	else {
		
		LPCSTR str = GetHeaderLine(subString, pos);
		
		if(str == NULL) {
			retval = UTE_INDEX_OUTOFRANGE;
		}
		else {
			*size = strlen(str);
			if(*size >= maxSize) {
				++(*size);
				retval = UTE_BUFFER_TOO_SHORT; 
			}
			else {
				strcpy(header, str);
			}
		}
	}
	return retval;	
}
#if defined _UNICODE
int CUT_HTTPClient::GetHeaderLine(LPWSTR header, size_t maxSize, LPCSTR subString, size_t *size, int *pos) {
	
	int retval;
	
	if(maxSize > 0) {
		char * headerA = new char [maxSize];
		
		if(headerA != NULL) {
			retval = GetHeaderLine( headerA, maxSize, subString, size, pos);
			
			if(retval == UTE_SUCCESS) {
				CUT_Str::cvtcpy(header, maxSize, headerA);
			}
			delete [] headerA;
		}
		else {
			retval = UTE_OUT_OF_MEMORY;
		}
	}
	else {
		if(size == NULL) (retval = UTE_NULL_PARAM);
		else {
			LPCSTR lpStr = GetHeaderLine(subString,pos);
			if(lpStr != NULL) {
				*size = strlen(lpStr)+1;
				retval = UTE_BUFFER_TOO_SHORT;
			}
			else {
				retval = UTE_INDEX_OUTOFRANGE;
			}
		}
	}
	return retval;

}
#endif

/*********************************************
GetModifiedDateFromHeader
    Return the "Last-modified" header received from the server
PARAM:
    NONE
RETURN:
    LPCSTR the whole "Last-modified: date " header.
    otherwise NULL
**********************************************/
LPCSTR CUT_HTTPClient::GetModifiedDateFromHeader(){
    //mime tage: Last-modified:
    
    int     count,loop;
    char    buf[64];

    count = GetHeaderLineCount();
    for(loop = 0; loop < count ; loop++){
        CUT_StrMethods::ParseString(GetHeaderLine(loop),": ",0,buf,sizeof(buf));
        if(_stricmp(buf,"Last-modified") == 0){
            return GetHeaderLine(loop);
        }
    }
    return NULL;
}
/***********************************************
GetModifiedDateFromHeader
	Return the "Last-modified:" header received from the server
PARAM:
	date		- [out] buffer to receive proxy address
	maxSize		- [in]  length of buffer in chars
	size		- [out] actual length of string returned or required.
RETURN:
  RETURN				
  UTE_SUCCES			- ok - 
  UTE_NULL_PARAM		- headerText and/or size is a null pointer
  UTE_INDEX_OUTOFRANGE  - not found
  UTE_BUFFER_TOO_SHORT  - space in length buffer indicated by maxSize insufficient, realloc 
							based on size returned.
  UTE_OUT_OF_MEMORY		- possible in wide char overload

************************************************/
int CUT_HTTPClient::GetModifiedDateFromHeader( LPSTR date, size_t maxSize, size_t *size) {
	
	int retval = UTE_SUCCESS;
	
	if(date == NULL || size == NULL) {
		retval = UTE_NULL_PARAM;
	}
	else {
		
		LPCSTR str = GetModifiedDateFromHeader();
		
		if(str == NULL) {
			retval = UTE_INDEX_OUTOFRANGE;
		}
		else {
			*size = strlen(str);
			if(*size >= maxSize) {
				++(*size);
				retval = UTE_BUFFER_TOO_SHORT; 
			}
			else {
				strcpy(date, str);
			}
		}
	}
	return retval;	
}
#if defined _UNICODE
int CUT_HTTPClient::GetModifiedDateFromHeader( LPWSTR date, size_t maxSize, size_t *size) {

	int retval;
	
	if(maxSize > 0) {
		char * dateA = new char [maxSize];
		
		if(dateA != NULL) {
			retval = GetModifiedDateFromHeader( dateA, maxSize, size);
			
			if(retval == UTE_SUCCESS) {
				CUT_Str::cvtcpy(date, maxSize, dateA);
			}
			delete [] dateA;
		}
		else {
			retval = UTE_OUT_OF_MEMORY;
		}
	}
	else {
		if(size == NULL) (retval = UTE_NULL_PARAM);
		else {
			LPCSTR lpStr = GetModifiedDateFromHeader();
			if(lpStr != NULL) {
				*size = strlen(lpStr)+1;
				retval = UTE_BUFFER_TOO_SHORT;
			}
			else {
				retval = UTE_INDEX_OUTOFRANGE;
			}
		}
	}
	return retval;
}
#endif

/*********************************************
GetLengthFromHeader
	Return the "Content-length:" header received from the server
PARAM:
    NONE
RETURN:
    LPCSTR the whole "Content-length:" header as string
    otherwise NULL

**********************************************/
LPCSTR CUT_HTTPClient::GetLengthFromHeader(){
    //mime tage: Content-length:
    
    int     count,loop;
    char    buf[64];

    count = GetHeaderLineCount();
    for(loop = 0; loop < count ; loop++){
        CUT_StrMethods::ParseString(GetHeaderLine(loop),": ",0,buf,sizeof(buf));
        if(_stricmp(buf,"Content-length") == 0 ){
            return GetHeaderLine(loop);
        }
    }

    return NULL;
}
/***********************************************
GetLengthFromHeader
	Return the "Content-length:" header received from the server
PARAM:
	length		- [out] buffer to receive proxy address
	maxSize		- [in]  length of buffer in chars
	size		- [out] actual length of string returned or required.
RETURN:
  RETURN				
  UTE_SUCCES			- ok - 
  UTE_NULL_PARAM		- headerText and/or size is a null pointer
  UTE_INDEX_OUTOFRANGE  - not found
  UTE_BUFFER_TOO_SHORT  - space in length buffer indicated by maxSize insufficient, realloc 
							based on size returned.
  UTE_OUT_OF_MEMORY		- possible in wide char overload

************************************************/
int CUT_HTTPClient::GetLengthFromHeader( LPSTR length, size_t maxSize, size_t *size) {
	
	int retval = UTE_SUCCESS;
	
	if(length == NULL || size == NULL) {
		retval = UTE_NULL_PARAM;
	}
	else {
		
		LPCSTR str = GetLengthFromHeader();
		
		if(str == NULL) {
			retval = UTE_INDEX_OUTOFRANGE;
		}
		else {
			*size = strlen(str);
			if(*size >= maxSize) {
				++(*size);
				retval = UTE_BUFFER_TOO_SHORT; 
			}
			else {
				strcpy(length, str);
			}
		}
	}
	return retval;	
}
#if defined _UNICODE
int CUT_HTTPClient::GetLengthFromHeader( LPWSTR length, size_t maxSize, size_t *size) {

	int retval;
	
	if(maxSize > 0) {
		char * lengthA = new char [maxSize];
		
		if(lengthA != NULL) {
			retval = GetLengthFromHeader( lengthA, maxSize, size);
			
			if(retval == UTE_SUCCESS) {
				CUT_Str::cvtcpy(length, maxSize, lengthA);
			}
			delete [] lengthA;
		}
		else {
			retval = UTE_OUT_OF_MEMORY;
		}
	}
	else {
		if(size == NULL) (retval = UTE_NULL_PARAM);
		else {
			LPCSTR lpStr = GetLengthFromHeader();
			if(lpStr != NULL) {
				*size = strlen(lpStr)+1;
				retval = UTE_BUFFER_TOO_SHORT;
			}
			else {
				retval = UTE_INDEX_OUTOFRANGE;
			}
		}
	}
	return retval;
}
#endif
/*********************************************
GetContentType:
Serach for the "Content-Type:" in thereceived headers 
    and retrurns it if found
PARAM:
    NONE
RETURN:
    LPCSTR  - the whole "Content-Type:...." header as string
    otherwise NULL

**********************************************/
LPCSTR CUT_HTTPClient::GetContentType(){
    //mime tage: Content-Type:
    
    int     count,loop;
    char    buf[64];

    count = GetHeaderLineCount();
    for(loop = 0; loop < count ; loop++){
        CUT_StrMethods::ParseString(GetHeaderLine(loop),": ",0,buf,sizeof(buf));
        if(_stricmp(buf,"Content-Type") == 0 ){
            return GetHeaderLine(loop);
        }
    }

    return NULL;
}
/***********************************************
GetContentType
	Retrieves the "Content-Type:...." header received from the server 
PARAM:
	contentType	- [out] buffer to receive proxy address
	maxSize		- [in]  length of buffer in chars
	size		- [out] actual length of string returned or required.
RETURN:
  RETURN				
  UTE_SUCCES			- ok - 
  UTE_NULL_PARAM		- headerText and/or size is a null pointer
  UTE_INDEX_OUTOFRANGE  - not found
  UTE_BUFFER_TOO_SHORT  - space in title buffer indicated by maxSize insufficient, realloc 
							based on size returned.
  UTE_OUT_OF_MEMORY		- possible in wide char overload

************************************************/
int CUT_HTTPClient::GetContentType( LPSTR contentType, size_t maxSize, size_t *size) {
	
	int retval = UTE_SUCCESS;
	
	if(contentType == NULL || size == NULL) {
		retval = UTE_NULL_PARAM;
	}
	else {
		
		LPCSTR str = GetContentType();
		
		if(str == NULL) {
			retval = UTE_INDEX_OUTOFRANGE;
		}
		else {
			*size = strlen(str);
			if(*size >= maxSize) {
				++(*size);
				retval = UTE_BUFFER_TOO_SHORT; 
			}
			else {
				strcpy(contentType, str);
			}
		}
	}
	return retval;	
}
#if defined _UNICODE
int CUT_HTTPClient::GetContentType( LPWSTR contentType, size_t maxSize, size_t *size) {

	int retval;
	
	if(maxSize > 0) {
		char * contentTypeA = new char [maxSize];
		
		if(contentTypeA != NULL) {
			retval = GetContentType( contentTypeA, maxSize, size);
			
			if(retval == UTE_SUCCESS) {
				CUT_Str::cvtcpy(contentType, maxSize, contentTypeA);
			}
			delete [] contentTypeA;
		}
		else {
			retval = UTE_OUT_OF_MEMORY;
		}
	}
	else {
		if(size == NULL) (retval = UTE_NULL_PARAM);
		else {
			LPCSTR lpStr = GetContentType();
			if(lpStr != NULL) {
				*size = strlen(lpStr)+1;
				retval = UTE_BUFFER_TOO_SHORT;
			}
			else {
				retval = UTE_INDEX_OUTOFRANGE;
			}
		}
	}
	return retval;
}
#endif

/*********************************************
    Sets communication that follow to be through 
    proxy
RET:
    VOID
******************************************/
void CUT_HTTPClient::UseProxyServer(BOOL flag){
    m_bUseProxy = flag;
}

/*************************************************
SetProxy
    Sets the proxy server address or name to be used
    when UseProxy is set to TRUE
Param:
    proxyIP     - new proxy address
Return:
    UTE_ERROR   - Empty string;
    UTE_SUCCESS - SUCESS
****************************************************/
#if defined _UNICODE
int CUT_HTTPClient::SetProxy( LPCWSTR proxyIP ){
	return SetProxy(AC(proxyIP));}
#endif
int CUT_HTTPClient::SetProxy( LPCSTR proxyIP ){
    
    if (proxyIP == NULL)
        return UTE_ERROR;

    strncpy(m_szProxyAddr, proxyIP, sizeof(m_szProxyAddr));
    return UTE_SUCCESS;
}

/*************************************************
GetProxy
    Gets the proxy server address or name to be used
    when UseProxy is set to TRUE
Param:
    none
Return:
    proxy address
****************************************************/
LPCSTR CUT_HTTPClient::GetProxy() const
{
    return m_szProxyAddr;
}

/***********************************************
GetProxy
	Get the proxy server previously assigned
PARAM:
	proxy		- [out] buffer to receive proxy address
	maxSize		- [in]  length of buffer in chars
	size		- [out] actual length of string returned or required.
RETURN:
  RETURN				
  UTE_SUCCES			- ok - 
  UTE_NULL_PARAM		- headerText and/or size is a null pointer
  UTE_INDEX_OUTOFRANGE  - not found
  UTE_BUFFER_TOO_SHORT  - space in title buffer indicated by maxSize insufficient, realloc 
							based on size returned.
  UTE_OUT_OF_MEMORY		- possible in wide char overload

************************************************/
int CUT_HTTPClient::GetProxy( LPSTR proxy, size_t maxSize, size_t *size) {
	
	int retval = UTE_SUCCESS;
	
	if(proxy == NULL || size == NULL) {
		retval = UTE_NULL_PARAM;
	}
	else {
		
		LPCSTR str = GetProxy();
		
		if(str == NULL) {
			retval = UTE_INDEX_OUTOFRANGE;
		}
		else {
			*size = strlen(str);
			if(*size >= maxSize) {
				++(*size);
				retval = UTE_BUFFER_TOO_SHORT; 
			}
			else {
				strcpy(proxy, str);
			}
		}
	}
	return retval;	
}
#if defined _UNICODE
int CUT_HTTPClient::GetProxy( LPWSTR proxy, size_t maxSize, size_t *size) {

	int retval;
	
	if(maxSize > 0) {
		char * proxyA = new char [maxSize];
		
		if(proxyA != NULL) {
			retval = GetProxy( proxyA, maxSize, size);
			
			if(retval == UTE_SUCCESS) {
				CUT_Str::cvtcpy(proxy, maxSize, proxyA);
			}
			delete [] proxyA;
		}
		else {
			retval = UTE_OUT_OF_MEMORY;
		}
	}
	else {
		if(size == NULL) (retval = UTE_NULL_PARAM);
		else {
			LPCSTR lpStr = GetProxy();
			if(lpStr != NULL) {
				*size = strlen(lpStr)+1;
				retval = UTE_BUFFER_TOO_SHORT;
			}
			else {
				retval = UTE_INDEX_OUTOFRANGE;
			}
		}
	}
	return retval;
}
#endif


/**************************************************
GET
    Sends a GET statement to the currently 
    connected server or proxy then retrieves the 
    results into the list or file.
  
 Route the Get command through a proxy

 Retrieves the results and seave it to a file if 
 destFile parameter set.

    
     The proxy may forward the request 
     on to another proxy or directly to the server specified
     In Order to avoid request loops, a proxy must be able to recognize all of its 
     server names, including any aliases, local variations 
     and numeric IP addreses
     SEE Section 5.1.2 RFC 1945

  "A proxy must interpret and, if necessary, rewrite a
 request message before forwarding it. Proxies are often 
 used as client-side portals through network firewalls 
 and as helper applications for handling requests via
 protocols not implemented by the user agent.
 "     See 1.2  (Terminology) RFC 1945.Berners-Lee et al

 Param:  
    url         - a pointer to the URL to be Requested
    [destFile]  - filename 
 Return:
    UTE_SUCCESS             - success
    UTE_CONNECT_FAILED      - unable to connect to server
    UTE_CONNECT_REJECTED    - connection rejected
    UTE_BAD_URL             - bad url
    UTE_CONNECT_TERMINATED  - connection terminated before the command
                                was completed   
    UTE_FILE_TYPE_ERROR     - invalid file type
    UTE_DS_OPEN_FAILED      - unable to open specified data source
    UTE_SOCK_TIMEOUT        - timeout
    UTE_SOCK_RECEIVE_ERROR  - receive socket error
    UTE_DS_WRITE_FAILED     - data source write error
    UTE_ABORTED             - aborted
**************************************************/
#if defined _UNICODE
int CUT_HTTPClient::GET(LPWSTR url, LPCTSTR destFile) {
	return GET(AC(url), destFile);}
#endif
int CUT_HTTPClient::GET(LPSTR url, LPCTSTR destFile) {
	int retval;

	if(destFile != NULL && _tcslen(destFile) > 0) 
	{
		CUT_FileDataSource ds(destFile);
		retval = GET(url,&ds);
	}
	else
	{	
		retval = GET(url, (CUT_FileDataSource*)NULL);
	}

    return retval;
}
/**************************************************
GET
    Sends a GET statement to the currently 
    connected server or proxy then retrieves the 
    results into the list or file.
  
 Route the Get command through a proxy

 Retrieves the results and seave it to a file if 
 destFile parameter set.

    
     The proxy may forward the request 
     on to another proxy or directly to the server specified
     In Order to avoid request loops, a proxy must be able to recognize all of its 
     server names, including any aliases, local variations 
     and numeric IP addreses
     SEE Section 5.1.2 RFC 1945

  "A proxy must interpret and, if necessary, rewrite a
 request message before forwarding it. Proxies are often 
 used as client-side portals through network firewalls 
 and as helper applications for handling requests via
 protocols not implemented by the user agent.
 "     See 1.2  (Terminology) RFC 1945.Berners-Lee et al

 Param:  
    url         - a pointer to the URL to be Requested
    [destFile]  - filename 
 Return:
    UTE_SUCCESS             - success
    UTE_CONNECT_FAILED      - unable to connect to server
    UTE_CONNECT_REJECTED    - connection rejected
    UTE_BAD_URL             - bad url
    UTE_CONNECT_TERMINATED  - connection terminated before the command
                                was completed   
    UTE_FILE_TYPE_ERROR     - invalid file type
    UTE_DS_OPEN_FAILED      - unable to open specified data source
    UTE_SOCK_TIMEOUT        - timeout
    UTE_SOCK_RECEIVE_ERROR  - receive socket error
    UTE_DS_WRITE_FAILED     - data source write error
    UTE_ABORTED             - aborted
**************************************************/
#if defined _UNICODE
int CUT_HTTPClient::GET(LPWSTR url, CUT_DataSource * dest) {
	return GET(AC(url), dest);}
#endif
int CUT_HTTPClient::GET(LPSTR url, CUT_DataSource * dest)
{
	int error = UTE_SUCCESS;

	if ((error = SendGetCommand(url)) != UTE_SUCCESS)
	{
		m_listSendHeader.ClearList();
		return OnError(error); //  for now 
	}
	
     //send the rest of the header info
		   //send the rest of the header info
	if ((error = SendRequestHeaders()) != UTE_SUCCESS)
	{
	   m_listSendHeader.ClearList();
       return OnError(error); //  for now 

	}


    Send("\r\n");
	// receive the response headers
	if ((error = ReceiveResponseHeaders()) == UTE_SUCCESS)
	{

		if (m_lLastStatusCode == 401)
		{
			char scheme[SCHEME_BUFFER_SIZE];
			char realm[REALM_BUFFER_SIZE];
			char password[PASSWORD_BUFFER_SIZE];
			char userName[USERR_NAME_BUFFER_SIZE];
			
			GetAuthenticationParams(scheme, realm);
			if (OnAccessDenied (realm,userName,password))
			{
				// no if the scheme is basic let call add basic Authorization
				if (_stricmp(scheme, "BASIC") == 0 )
				{
					CloseConnection();

					AddBasicAuthorizationHeader(userName, password);
					if ((error = SendGetCommand(url)) != UTE_SUCCESS)
					{
						m_listSendHeader.ClearList();
						return OnError(error); //  for now 
					}
					//send the rest of the header info
					if ((error = SendRequestHeaders()) != UTE_SUCCESS)
					{
						m_listSendHeader.ClearList();
						return OnError(error); //  for now 
					}
					
					Send("\r\n");
					// receive the response headers
					if(dest != NULL) 
					{
						error = Receive( *dest, UTM_OM_WRITING, GetReceiveTimeOut ()/1000);
					}
					else
					{
						// receive the response body
						error = ReceiveResponseBody();
					}
				}
			}
			
		}
		else if (
			m_lLastStatusCode ==  301  //Moved Permanently
			|| m_lLastStatusCode == 302 // Found
			|| m_lLastStatusCode == 303 //See Other
			|| m_lLastStatusCode ==  307 ) //Temporary Redirect
		{
			// get the redirection header
			//find the location header
			char newUrl[URL_RESOURCE_LENGTH];
			if (GetMovedLocation( newUrl ) )
			{
				if (OnRedirect(newUrl))
				{
					 CloseConnection();
					return GET (newUrl ,  dest);
				}	
				else if(dest != NULL)// Receive data in the file
				{
					error = Receive( *dest, UTM_OM_WRITING,GetReceiveTimeOut ()/1000);
				}
				else
				{
					// receive the response body
					error = ReceiveResponseBody();
				}
			}
			// pass it to the OnRedirect page
			// then see if we should go ahead and redirect.		

		}
		else if(dest != NULL)// Receive data in the file
		 
		{
			error = Receive( *dest, UTM_OM_WRITING,GetReceiveTimeOut ()/1000);
		}
		else
		{
			// receive the response body
			error = ReceiveResponseBody();
		}

	}
    CloseConnection();

    return OnError(error);
}
/*********************************************
HEADThroughProxy
    Sends a HEAD statement to the currently 
    connected server or to the proxy then 
    retrieves the results
Params
    url - URL to get the HEAD of
Return
    UTE_SUCCESS             - success
    UTE_CONNECT_FAILED      - unable to connect to server
    UTE_CONNECT_REJECTED    - connection rejected
    UTE_BAD_URL             - bad url
    UTE_CONNECT_TERMINATED  - connection terminated before the command
                                was completed   
    UTE_FILE_TYPE_ERROR     - invalid file type
    UTE_FILE_OPEN_ERROR     - unable to open or create file
    UTE_SOCK_TIMEOUT        - timeout
    UTE_SOCK_RECEIVE_ERROR  - receive socket error
    UTE_FILE_WRITE_ERROR    - file write error
    UTE_ABORTED             - aborted
**********************************************/
#if defined _UNICODE
int CUT_HTTPClient::HEAD(LPWSTR url) {
	return HEAD(AC(url));}
#endif
int CUT_HTTPClient::HEAD(LPSTR url) {

    int     error;
	
	if ((error = SendHeadCommand(url)) != UTE_SUCCESS)
	{
	   m_listSendHeader.ClearList();
       return OnError(error); //  for now 

	}
  //send the rest of the header info
	if ((error = SendRequestHeaders()) != UTE_SUCCESS)
	{
	   m_listSendHeader.ClearList();
       return OnError(error); //  for now 

	}
    Send("\r\n");
    //retrieve the header data
	// Get Response 
   	error = ReceiveResponseHeaders();
	if (m_lLastStatusCode == 401)
	{
			char scheme[SCHEME_BUFFER_SIZE];
			char realm[REALM_BUFFER_SIZE];
			char password[PASSWORD_BUFFER_SIZE];
			char userName[USERR_NAME_BUFFER_SIZE];
			
			GetAuthenticationParams(scheme, realm);
			if (OnAccessDenied (realm,userName,password))
			{
				// no if the scheme is basic let call add basic Authorization
				if (_stricmp(scheme, "BASIC") == 0 )
				{
					AddBasicAuthorizationHeader(userName, password);
					CloseConnection();

					if ((error = SendHeadCommand(url)) != UTE_SUCCESS)
					{
						m_listSendHeader.ClearList();
						return OnError(error); //  for now 
					}

					//send the rest of the header info
					if ((error = SendRequestHeaders()) != UTE_SUCCESS)
					{
						m_listSendHeader.ClearList();
						return OnError(error); //  for now 
					}
					Send("\r\n");
					error = ReceiveResponseHeaders();
				}
			}
	}
	ClearReceiveBuffer();
    CloseConnection();

    return OnError(error);
}
/*********************************************
CommandLine
    // issues a custom command through a currently 
    // connected server or proxy.
    // NOTE: ---->that the proxy may forward the request 
    // on to another proxy or directly to the server specified
    // In Order to avoid request loops, a proxy must be able to recognize all of its 
    // server names, including any aliases, local variations 
    // and numeric IP addreses
    // SEE Section 5.1.2 RFC 1945   
Params
    command - command to execute
    url     - URL to get the HEAD of
Return
    UTE_SUCCESS             - success
    UTE_CONNECT_FAILED      - unable to connect to server
    UTE_CONNECT_REJECTED    - connection rejected
    UTE_BAD_URL             - bad url
    UTE_CONNECT_TERMINATED  - connection terminated before the command
                                was completed   
    UTE_FILE_TYPE_ERROR     - invalid file type
    UTE_FILE_OPEN_ERROR     - unable to open or create file
    UTE_SOCK_TIMEOUT        - timeout
    UTE_SOCK_RECEIVE_ERROR  - receive socket error
    UTE_FILE_WRITE_ERROR    - file write error
    UTE_ABORTED             - aborted
********************************************/
#if defined _UNICODE
int CUT_HTTPClient::CommandLine(LPWSTR command,LPWSTR url, LPCWSTR data){
	return CommandLine(AC(command), AC(url), AC(data));}
#endif
int CUT_HTTPClient::CommandLine(LPSTR command,LPSTR url, LPCSTR data){
        
    char    buf[MAX_PATH * 2];
    char    file[MAX_PATH + 1];
    int     error;

    //if the url string is empty then return
    if (url == NULL)
        return OnError(UTE_BAD_URL);
    
    //clear any prev data
    ClearReceivedData();

    // if not using proxy
    if(!m_bUseProxy)
        //get the server Address and file to retrieve
        if(SplitURL(url, file, sizeof(file)) != UTE_SUCCESS)
            return OnError(UTE_BAD_URL);
    
     //connect
   if ((error = HTTPConnect()) !=  UTE_SUCCESS)
	    return OnError(error);

    
    // if using proxy
    if(m_bUseProxy) {
        // if the url includes http then it is already an absolute URI
        // so lets just format our command string
        if (_strnicmp (url,"http://", strlen("http://"))==0)
            _snprintf(buf,sizeof(buf)-1,"%s %s HTTP/1.0\r\n",command,url);
        else
            _snprintf(buf,sizeof(buf)-1,"%s http://%s HTTP/1.0\r\n",command,url);
        }
    else
        _snprintf(buf,sizeof(buf)-1,"%s %s HTTP/1.0\r\n", command, file);


    //send the command
    if(Send(buf) <= 0) {
        CloseConnection();
        return OnError(UTE_CONNECT_TERMINATED);
        }

    if(IsAborted()) {                       // Check if procedure is aborted
        CloseConnection();
        return OnError(UTE_ABORTED);        // Abort
    }

    //send the rest of the header info
	if ((error = SendRequestHeaders()) != UTE_SUCCESS)
	{
	   m_listSendHeader.ClearList();
       return OnError(error); //  for now 

	}	
     // now there is the blank line betwwen the data and the headers
    Send("\r\n");
    // send the data for the post function if any 
    if (data != NULL && strlen(data) > 0) {
        if (strlen(data))
        {
            Send(data);
            Send("\r\n");
        }
    }

    //retrieve the header data   
	// Get Response 
   	if ((error = ReceiveResponseHeaders()) == UTE_SUCCESS)
	{
    	// receive the response body
		error = ReceiveResponseBody();
	}


    CloseConnection();

    return OnError(UTE_SUCCESS);
}

/*********************************************
SetConnectTimeout
    Sets the time to wait for a connection 
    in seconds
    5 seconds is the default time
Params
    secs - seconds to wait
  Return
    UTE_SUCCESS - success
    UTE_ERROR   - invalid input value
**********************************************/
int CUT_HTTPClient::SetConnectTimeout(int secs){
    
    if(secs <= 0)
        return OnError(UTE_ERROR);

    m_nConnectTimeout = secs;

    return OnError(UTE_SUCCESS);
}
/*********************************************
GetConnectTimeout
    Gets the time to wait for a connection 
    in seconds
Params
    none
Return
    current time out value in seconds
**********************************************/
int CUT_HTTPClient::GetConnectTimeout() const
{
    return m_nConnectTimeout;
}

/***************************************************
PUT
    Create a resource at the target URL
    "
   The PUT method requests that the enclosed entity be stored under the
   supplied Request-URI. If the Request-URI refers to an already
   existing resource, the enclosed entity should be considered as a
   modified version of the one residing on the origin server. If the
   Request-URI does not point to an existing resource, and that URI is
   capable of being defined as a new resource by the requesting user
   agent, the origin server can create the resource with that URI.

   The fundamental difference between the POST and PUT requests is
   reflected in the different meaning of the Request-URI. The URI in a
   POST request identifies the resource that will handle the enclosed
   entity as data to be processed. That resource may be a data-accepting
   process, a gateway to some other protocol, or a separate entity that
   accepts annotations. In contrast, the URI in a PUT request identifies
   the entity enclosed with the request -- the user agent knows what URI
   is intended and the server should not apply the request to some other
   resource.
   "  - RFC 1945

PARAM
    LPSTR targetURL     -  the full name and path of the target file 
    LPCSTR sourceFile   -  full path of the source file
	BOOL	bPost		- if the command is post = TRUE or PUT =FALSE
Return
    UTE_SUCCESS             - success
    UTE_CONNECT_FAILED      - unable to connect to server
    UTE_CONNECT_REJECTED    - connection rejected
    UTE_BAD_URL             - bad url
    UTE_CONNECT_TERMINATED  - connection terminated before the command
                                was completed   
    UTE_FILE_TYPE_ERROR     - invalid file type
    UTE_FILE_OPEN_ERROR     - unable to open or create file
    UTE_SOCK_TIMEOUT        - timeout
    UTE_SOCK_RECEIVE_ERROR  - receive socket error
    UTE_FILE_WRITE_ERROR    - file write error
    UTE_ABORTED             - aborted
****************************************************/
#if defined _UNICODE
int CUT_HTTPClient::PUT(LPWSTR url, LPCTSTR sourceFile ,BOOL bPost ){
	return PUT(AC(url), sourceFile, bPost);}
#endif
int CUT_HTTPClient::PUT(LPSTR url, LPCTSTR sourceFile ,BOOL bPost ){
	CUT_FileDataSource ds(sourceFile);
    return  PUT(url,ds,bPost);
}

/***************************************************
PUT
    Create a resource at the target URL
    "
   The PUT method requests that the enclosed entity be stored under the
   supplied Request-URI. If the Request-URI refers to an already
   existing resource, the enclosed entity should be considered as a
   modified version of the one residing on the origin server. If the
   Request-URI does not point to an existing resource, and that URI is
   capable of being defined as a new resource by the requesting user
   agent, the origin server can create the resource with that URI.

   The fundamental difference between the POST and PUT requests is
   reflected in the different meaning of the Request-URI. The URI in a
   POST request identifies the resource that will handle the enclosed
   entity as data to be processed. That resource may be a data-accepting
   process, a gateway to some other protocol, or a separate entity that
   accepts annotations. In contrast, the URI in a PUT request identifies
   the entity enclosed with the request -- the user agent knows what URI
   is intended and the server should not apply the request to some other
   resource.
   "  - RFC 1945

PARAM
    LPSTR targetURL             -  the full name and path of the target file 
    CUT_DataSource sourceFile   -  the data source to be sent
Return
    UTE_SUCCESS                 - success
    UTE_CONNECT_FAILED          - unable to connect to server
    UTE_CONNECT_REJECTED        - connection rejected
    UTE_BAD_URL                 - bad url
    UTE_CONNECT_TERMINATED      - connection terminated before the command
                                was completed   
    UTE_FILE_TYPE_ERROR         - invalid file type
    UTE_FILE_OPEN_ERROR         - unable to open or create file
    UTE_SOCK_TIMEOUT            - timeout
    UTE_SOCK_RECEIVE_ERROR      - receive socket error
    UTE_FILE_WRITE_ERROR        - file write error
    UTE_ABORTED                 - aborted
****************************************************/
#if defined _UNICODE
int CUT_HTTPClient::PUT(LPWSTR targetURL, CUT_DataSource &sourceFile, BOOL bPost ){
	return PUT(AC(targetURL), sourceFile, bPost);}
#endif
int CUT_HTTPClient::PUT(LPSTR targetURL, CUT_DataSource &sourceFile, BOOL bPost )
{
    int      error = UTE_SUCCESS;

	if ((error = SendPutCommand(targetURL, sourceFile,  bPost)) != UTE_SUCCESS)
	{
	   m_listSendHeader.ClearList();
       return OnError(error); //  for now 

	}

	Send("\r\n");

	// Get Response 
   	if ((error = ReceiveResponseHeaders()) == UTE_SUCCESS)
	{
    	// receive the response body
		error = ReceiveResponseBody();
		if (m_lLastStatusCode == 401)
		{
			char scheme[SCHEME_BUFFER_SIZE];
			char realm[REALM_BUFFER_SIZE];
			char password[PASSWORD_BUFFER_SIZE];
			char userName[USERR_NAME_BUFFER_SIZE];
			
			GetAuthenticationParams(scheme, realm);
			if (OnAccessDenied (realm,userName,password))
			{
				// no if the scheme is basic let call add basic Authorization
				if (_stricmp(scheme, "BASIC") == 0 )
				{
					AddBasicAuthorizationHeader(userName, password);
					CloseConnection();
					if ((error = SendPutCommand(targetURL, sourceFile,  bPost)) != UTE_SUCCESS)
					{
						m_listSendHeader.ClearList();
						return OnError(error); //  for now 
					}
					
					Send("\r\n");
					// Get Response 
					error = ReceiveResponseHeaders();
				}
			}
		}
	}

    CloseConnection();
    m_listSendHeader.ClearList();

    return OnError(error);
}
/****************************************************
DeleteFile:
  The DELETE method requests that the origin server delete the resource
  identified by the Request-URI.
PARAM:
    LPSTR url   - The full URI of the resource to be deleted
RETURN:
    UTE_SUCCESS             - SUCCESS
    UTE_BAD_URL             - Bad domain name 
    UTE_CONNECT_TERMINATED  - Connection terminated prematurely
    UTE_ABORTED             - Operation aborted by user
****************************************************/
#if defined _UNICODE
int CUT_HTTPClient::DeleteFile(LPWSTR url){
	return DeleteFile(AC(url));}
#endif
int CUT_HTTPClient::DeleteFile(LPSTR url)
{
     int     error = UTE_SUCCESS;


	 if ((error = SendDeleteCommand(url)) != UTE_SUCCESS)
	{
		m_listSendHeader.ClearList();
		return OnError(error); //  for now 
	}

    //send the rest of the header info
	if ((error = SendRequestHeaders()) != UTE_SUCCESS)
	{
	   m_listSendHeader.ClearList();
       return OnError(error); //  for now 

	}

     // now there is the blank line between the data and the headers
    Send("\r\n");
  	// receive the response headers
	if ((error = ReceiveResponseHeaders()) == UTE_SUCCESS)
	{
    	// receive the response body
		error = ReceiveResponseBody();
		if (m_lLastStatusCode == 401)
		{
			char scheme[SCHEME_BUFFER_SIZE];
			char realm[REALM_BUFFER_SIZE];
			char password[PASSWORD_BUFFER_SIZE];
			char userName[USERR_NAME_BUFFER_SIZE];
			
			GetAuthenticationParams(scheme, realm);
			if (OnAccessDenied (realm,userName,password))
			{
				// no if the scheme is basic let call add basic Authorization
				if (_stricmp(scheme, "BASIC") == 0 )
				{
					AddBasicAuthorizationHeader(userName, password);
					CloseConnection();
					if ((error = SendDeleteCommand(url)) != UTE_SUCCESS)
					{
						m_listSendHeader.ClearList();
						return OnError(error); //  for now 
					}

					Send("\r\n");
					// Get Response 
					error = ReceiveResponseHeaders();
				}
			}
		}
	}

    CloseConnection();
    return OnError(error);
}
/************************************************************
	The POST method is used to request that the origin server accept the
	entity enclosed in the request as a new subordinate of the resource
	identified by the Request-URI in the Request-Line
PARAM
    LPSTR targetURL             -  the full name and path of the target file 
    CUT_DataSource sourceFile   -  the data source to be sent
Return
    UTE_SUCCESS                 - success
    UTE_CONNECT_FAILED          - unable to connect to server
    UTE_CONNECT_REJECTED        - connection rejected
    UTE_BAD_URL                 - bad url
    UTE_CONNECT_TERMINATED      - connection terminated before the command
                                was completed   
    UTE_FILE_TYPE_ERROR         - invalid file type
    UTE_FILE_OPEN_ERROR         - unable to open or create file
    UTE_SOCK_TIMEOUT            - timeout
    UTE_SOCK_RECEIVE_ERROR      - receive socket error
    UTE_FILE_WRITE_ERROR        - file write error
    UTE_ABORTED                 - aborted
************************************************************/
#if defined _UNICODE
int     CUT_HTTPClient::POST(LPWSTR url, CUT_DataSource &dest){
	return POST(AC(url), dest);}
#endif
int     CUT_HTTPClient::POST(LPSTR url, CUT_DataSource &dest)
{
	return PUT(url,dest, TRUE);
}
/************************************************************
	The POST method is used to request that the origin server accept the
	entity enclosed in the request as a new subordinate of the resource
	identified by the Request-URI in the Request-Line
 
PARAM
	LPSTR targetURL     -  the full name and path of the target file 
    LPCSTR sourceFile   -  full path of the source file
Return
    UTE_SUCCESS                 - success
    UTE_CONNECT_FAILED          - unable to connect to server
    UTE_CONNECT_REJECTED        - connection rejected
    UTE_BAD_URL                 - bad url
    UTE_CONNECT_TERMINATED      - connection terminated before the command
                                was completed   
    UTE_FILE_TYPE_ERROR         - invalid file type
    UTE_FILE_OPEN_ERROR         - unable to open or create file
    UTE_SOCK_TIMEOUT            - timeout
    UTE_SOCK_RECEIVE_ERROR      - receive socket error
    UTE_FILE_WRITE_ERROR        - file write error
    UTE_ABORTED                 - aborted
************************************************************/
#if defined _UNICODE
int   CUT_HTTPClient::POST( LPWSTR targetURL, LPCTSTR sourceFile){
	return POST(AC(targetURL), sourceFile);}
#endif
int   CUT_HTTPClient::POST( LPSTR targetURL, LPCTSTR sourceFile)
{
		return PUT(targetURL,sourceFile, TRUE);
}
/********************************************************
This function will Parses the server response 
to receive the status code as received from the server.

the status line is   
       Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
       
PARAM
	data	- The first line received from the server
RET
	the server response code.
                         
*********************************************************/
long	CUT_HTTPClient::ParseResponseCode(LPCSTR data)
{
	long code = 0;
	if (data != NULL)
	{

		// get the status code as number
		CUT_StrMethods::ParseString (data ," ",1,&code);
		// get the status reason
		// uncomment for debugging
		// char test[MAX_BUF];
		//CUT_StrMethods::ParseString (data ," ",1,test,MAX_PATH-1);	
		// assert(test);
	}
	return code;
}
/**********************************************************
This function will return the server response
the status line is   
       Status-Code    = "100"   ; Continue
                         | "101"   ; Switching Protocols
                         | "200"   ; OK
                         | "201"   ; Created
                         | "202"   ; Accepted
                         | "203"   ; Non-Authoritative Information
                         | "204"   ; No Content
                         | "205"   ; Reset Content
                         | "206"   ; Partial Content
                         | "300"   ; Multiple Choices
                         | "301"   ; Moved Permanently
                         | "302"   ; Moved Temporarily
                         | "303"   ; See Other
                         | "304"   ; Not Modified
                         | "305"   ; Use Proxy
                         | "400"   ; Bad Request
                         | "401"   ; Unauthorized
                         | "402"   ; Payment Required
                         | "403"   ; Forbidden
                         | "404"   ; Not Found
                         | "405"   ; Method Not Allowed
                         | "406"   ; Not Acceptable
                         | "407"   ; Proxy Authorization Required
                         | "408"   ; Request Time-out
                         | "409"   ; Conflict
                         | "410"   ; Gone
                         | "411"   ; Length Required
                         | "412"   ; Precondition Failed
                         | "413"   ; Request Entity Too Large
                         | "414"   ; Request-URI Too Large
                         | "415"   ; Unsupported Media Type
                         | "500"   ; Internal Server Error
                         | "501"   ; Not Implemented
                         | "502"   ; Bad Gateway
                         | "503"   ; Service Unavailable
                         | "504"   ; Gateway Time-out
                         | "505"   ; HTTP Version not supported
RET:
	long	- the status code as received from the server
**********************************************************/
long	CUT_HTTPClient::GetStatusCode()
{
	return m_lLastStatusCode;

}
/****************************************************
Receive the response headers

*****************************************************/
int CUT_HTTPClient::ReceiveResponseHeaders()
{

	char    buf[MAX_PATH * 2 + 1];
	bool once = true;
	int rt = 0;


    //retrieve the header data
	// v4.2 change to eliminate C4127: conditional expression is constant
	for(;;)
	{
        if(IsAborted())
		{                       // Check if procedure is aborted
            CloseConnection();
            m_listReceiveHeader.ClearList();
            return OnError(UTE_ABORTED);        // Abort
		}

        rt = ReceiveLine(buf,sizeof(buf),GetReceiveTimeOut ()/1000);
		if(rt <=0)
            break;
        if(rt <3)
            break;
        CUT_StrMethods::RemoveCRLF(buf);
		// lets just read the first line for the request status
		if (once )
		{
			m_lLastStatusCode = ParseResponseCode( buf);
			once = false;
		}
        m_listReceiveHeader.AddString(buf);
	}
	return UTE_SUCCESS;
}
/****************************************************
Receive the response body
*****************************************************/
int CUT_HTTPClient::ReceiveResponseBody()
{
	char    buf[MAX_PATH * 2 + 1];

	BOOL	bUppendToPrevious = FALSE;
	int rt = UTE_SUCCESS;


	//retrieve the body
	// v4.2 change to eliminate C4127: conditional expression is constant
	for(;;)
	{
		if(IsAborted())
		{                       // Check if procedure is aborted
			CloseConnection();
			m_listReceiveBody.ClearList();
			return OnError(UTE_ABORTED);        // Abort
		}

		rt = ReceiveLine(buf,sizeof(buf),GetReceiveTimeOut ()/1000);
		if(rt <=0)
			break;

		BOOL bNewFlag = CUT_StrMethods::IsWithCRLF(buf);
		CUT_StrMethods::RemoveCRLF(buf);
		if(bUppendToPrevious) 
		{
			// Add the string to the last string in the list
			unsigned int	nBufferSize;
			unsigned int    nLastItem = m_listReceiveBody.GetCount() - 1;
			char			*lpszBuffer;

			// Calculate the new string size
			nBufferSize = (int)strlen(buf);
			nBufferSize += (int)strlen(m_listReceiveBody.GetString(nLastItem)) + 10;

			// Allocate new buffer
			lpszBuffer = new char[nBufferSize];

			// Copy the data to the new string
			strcpy(lpszBuffer, m_listReceiveBody.GetString(nLastItem));
			strcat(lpszBuffer, buf);

			// Delete the last string in the list
			m_listReceiveBody.DeleteString(nLastItem);

			// Add new line (comined) to the list
			m_listReceiveBody.AddString(lpszBuffer);
		
			// Delete the buffer
			delete [] lpszBuffer;
		}
		else 
		{
			m_listReceiveBody.AddString(buf);
		}

		bUppendToPrevious = ! bNewFlag;
	}   
	return UTE_SUCCESS;
}
/**********************************************
Send the headers of the request to the server
PARAM:
	NONE
RET:
	UTE_CONNECT_TERMINATED
	UTE_SUCCESS
**********************************************/
int CUT_HTTPClient::SendRequestHeaders()
{
	 char buf[MAX_PATH * 2];

	BOOL hostIncluded = FALSE;


	// Send proxy authorization if any
	// notice we only send it if there is a proxy 
	// and it is not a tunneling process.
	char *ResultHeader = NULL;

	if (m_bUseProxy && !m_bEnableTunnelling) 
	// v4.2 - update 02 - fn was modified to take LPSTR* for parameter 3
	if (CreateProxyBasicAuthorizationHeader(m_szProxyUserName,m_szProxyPassword,&ResultHeader) == UTE_SUCCESS)
	{
		// now we send the proxy authorization 
		Send(ResultHeader);
		if (ResultHeader != NULL)
		delete ResultHeader;
	}

	int count = m_listSendHeader.GetCount();
    for(int loop =0;loop < count;loop++) 
	{
		// this send will return the number of bytes sent!!
        if(Send(m_listSendHeader.GetString(loop)) <= 0 )
		{
            CloseConnection();
            return OnError(UTE_CONNECT_TERMINATED);
		}
        if (strstr(m_listSendHeader.GetString(loop),"Host: "))
                hostIncluded = TRUE;
	}

     if (!hostIncluded || !m_bUseProxy) 
	 {
        // addede for the host command maybe we should leave it for the client to add the host header
        // add the host header 
        _snprintf(buf,sizeof(buf)-1,"Host: %s",m_szServerName);
        AddSendHeaderTag(buf);
        Send(buf);
        // note that we have sent a header string without the CRLF so lets send the CRLF
        Send("\r\n");
	 }

	 return UTE_SUCCESS;

}
/***************************************************
When an access denied response is received we will
 ask the user for password for the specified realm
 
   If the user wante to cancel then just return 0
REMARK
	maximum length of the userName will be 20, password is also 20
PARAM
	realm -  the realm the user name and password are for
	userName - The user name for the specified realm
	passWord - The password for the specified realm	
RET

	TRUE - the user has specified the user name and 
		password and would like us to continue
	FALSE - The user wishes to cancel the connection process
********************************************************/
BOOL CUT_HTTPClient::OnAccessDenied (LPCSTR /* realm */, LPSTR /* userName */, LPSTR /* password */)
{
	return FALSE;
}
// v4.2 this notification overload could be reviewed
BOOL CUT_HTTPClient::OnAccessDenied (LPCWSTR /* realm */, LPWSTR /* userName */, LPWSTR /* password */)
{
	return FALSE;
}
/**************************************************
Find the realm and Authorization mechanism

PARAM
	realm
		A string to be displayed to users so they know which username and
		password to use. This string should contain at least the name of
		the host performing the Authorization and might additionally
		indicate the collection of users who might have access.
	scheme	
		Encryption scheme used by the server to authenticate our request

RET
	UTE_SUCCESS
**************************************************/
int CUT_HTTPClient::GetAuthenticationParams(LPSTR scheme ,LPSTR	realm )
{
      
    int     count,loop;
    char    buf[64];	

    count = GetHeaderLineCount();
    for(loop = 0; loop < count ; loop++){
        CUT_StrMethods::ParseString(GetHeaderLine(loop),": ",0,buf,sizeof(buf));
        if(_stricmp(buf,"WWW-Authenticate") == 0 ){
			// get the schems
			CUT_StrMethods::ParseString(GetHeaderLine(loop)," ",1,scheme,SCHEME_BUFFER_SIZE-1);
			// get the realm
			CUT_StrMethods::ParseString(GetHeaderLine(loop),"=\"",1,realm,REALM_BUFFER_SIZE-1);            
        }
    }

    return UTE_SUCCESS;
}
/***************************************************
internal SendPutCommand
 Create a resource at the target URL
    "
   The PUT method requests that the enclosed entity be stored under the
   supplied Request-URI. If the Request-URI refers to an already
   existing resource, the enclosed entity should be considered as a
   modified version of the one residing on the origin server. If the
   Request-URI does not point to an existing resource, and that URI is
   capable of being defined as a new resource by the requesting user
   agent, the origin server can create the resource with that URI.

   The fundamental difference between the POST and PUT requests is
   reflected in the different meaning of the Request-URI. The URI in a
   POST request identifies the resource that will handle the enclosed
   entity as data to be processed. That resource may be a data-accepting
   process, a gateway to some other protocol, or a separate entity that
   accepts annotations. In contrast, the URI in a PUT request identifies
   the entity enclosed with the request -- the user agent knows what URI
   is intended and the server should not apply the request to some other
   resource.
   "  - RFC 1945

PARAM
	targetURL - Target URL as string
	sourceFile - Data source to be sent
	bPost		- should we use POST or PUT command

***************************************************/
int CUT_HTTPClient::SendPutCommand(LPSTR targetURL, CUT_DataSource &sourceFile, BOOL bPost){
   
	
	char    buf[MAX_PATH * 2 + 1];
    char    file[MAX_PATH + 1];
    int     rt, error;

    //if the url string is empty then return
    if (targetURL == NULL)
        return OnError(UTE_BAD_URL);
    
    //clear any prev data
    ClearReceivedData();

    // if not using proxy
    if(!m_bUseProxy)
        //get the server Address and file to retrieve
        if(SplitURL(targetURL, file, sizeof(file)) != UTE_SUCCESS)
            return OnError(UTE_BAD_URL);


    // before we attempt to connect 
    // lets make sure the file exists
    rt = sourceFile.Open (UTM_OM_READING);
    if (rt != UTE_SUCCESS)
         return OnError(UTE_DS_OPEN_FAILED);
    // now we will add the length of the bytes to be sent
    // from the file size
    _snprintf(buf,sizeof(buf)-1,"Content-Length: %d",sourceFile.Seek (0,SEEK_END));
    sourceFile.Close ();
    AddSendHeaderTag(buf);
	// if we are posting this header is required
	if (bPost)
		AddSendHeaderTag("Content-Type: application/x-www-form-urlencoded");
    //connect to proxy

   if ((error = HTTPConnect()) !=  UTE_SUCCESS)
		return OnError(error);

    // if using proxy
    if(m_bUseProxy) {
        // if the url includes http then it is already an absolute URI
        // so lets just format our command string
        if (_strnicmp (targetURL,"http://", strlen("http://"))==0)
			if (bPost)
				_snprintf(buf,sizeof(buf)-1,"POST %s HTTP/1.0\r\n",targetURL);
				else
            _snprintf(buf,sizeof(buf)-1,"PUT %s HTTP/1.0\r\n",targetURL);
        else
		{
			if (bPost)
				_snprintf(buf,sizeof(buf)-1,"POST http://%s HTTP/1.0\r\n",targetURL);
			else
            _snprintf(buf,sizeof(buf)-1,"PUT http://%s HTTP/1.0\r\n",targetURL);
		}
        }
    else
	{
		if (bPost)
			_snprintf(buf,sizeof(buf)-1, "POST %s HTTP/1.0\r\n",  file);
		else
			_snprintf(buf,sizeof(buf)-1,"PUT %s HTTP/1.0\r\n",  file);


	}


    //send the command
    if(Send(buf) <= 0) {
        CloseConnection();
        m_listSendHeader.ClearList();
        return OnError(UTE_CONNECT_TERMINATED);
        }

    if(IsAborted()) {                       // Check if procedure is aborted
        CloseConnection();
        m_listSendHeader.ClearList();
        return OnError(UTE_ABORTED);        // Abort
    }

	   //send the rest of the header info
	if ((rt = SendRequestHeaders()) != UTE_SUCCESS)
	{
	   m_listSendHeader.ClearList();
       return OnError(rt); //  for now 

	}

     // now there is the blank line betwwen the data and the headers
    Send("\r\n");
    
	// send the data for the post function if any 
    rt = Send(sourceFile);
    if ( rt != UTE_SUCCESS)
    {
        CloseConnection();
        m_listSendHeader.ClearList();
        return OnError(rt); //  for now 
    }
	return UTE_SUCCESS;

}
/***************************************************
	Sends a GET statement to the currently 
	connected server or proxy then retrieves the 
	results into the list or file.

	Route the Get command through a proxy

	Retrieves the results and seave it to a file if 
	destFile parameter set.


	 The proxy may forward the request 
	 on to another proxy or directly to the server specified
	 In Order to avoid request loops, a proxy must be able to recognize all of its 
	 server names, including any aliases, local variations 
	 and numeric IP addreses
	 SEE Section 5.1.2 RFC 1945

	"A proxy must interpret and, if necessary, rewrite a
	request message before forwarding it. Proxies are often 
	used as client-side portals through network firewalls 
	and as helper applications for handling requests via
	protocols not implemented by the user agent.
	"     See 1.2  (Terminology) RFC 1945

PARAM
	url - the usrl to retrieve
***************************************************/
int CUT_HTTPClient::SendGetCommand(LPSTR url)
{
    char    buf[MAX_PATH * 2 + 1];
    char    file[MAX_PATH+1];
    int     error = UTE_SUCCESS;

    //if the url string is empty then return
    if (url == NULL)
        return OnError(UTE_BAD_URL);

    //clear any prev data
    ClearReceivedData();

    // if not using proxy
    if(!m_bUseProxy || m_bEnableTunnelling)
        //get the server Address and file to retrieve
        if(SplitURL(url,file,sizeof(file)) != UTE_SUCCESS)
            return OnError(UTE_BAD_URL);


    //connect
	if ((error = HTTPConnect()) !=  UTE_SUCCESS)
			    return OnError(error);


    //prepare the GET command

    // if using proxy
    if(m_bUseProxy  && !m_bEnableTunnelling ) 
	{

        // NOTE:----> that when we add the proxy we don't add the slash after the 
        // GET command
        // if the url includes http then it is already an absolute URI
        // so lets just format our GET command string
        if (_strnicmp (url,"ftp://", strlen("ftp://"))==0)
            _snprintf(buf,sizeof(buf)-1,"GET %s HTTP/1.0\r\n",url);
        else if (_strnicmp (url,"ftp.", strlen("ftp."))==0)
            _snprintf(buf,sizeof(buf)-1,"GET ftp://%s HTTP/1.0\r\n",url);
        else if (_strnicmp (url,"http://", strlen("http://"))==0)
		{
            // does the target already contain http portion
            _snprintf(buf,sizeof(buf)-1,"GET %s HTTP/1.0\r\n",url);
		}
        else if (strncmp("//",url,2) == 0)
		{ // the user has input the whole url such as  
            //   { //user:passowrd@host:PortNumber/PathTarget }
            //    where the port number here is the port on the target not the proxy
            // then we will just send it to the proxy
            _snprintf(buf,sizeof(buf)-1,"GET %s HTTP/1.0\r\n",url);
		}
        else if (url[0] == '/')
		{
            // the user is targeting the Proxy as a server not a relay
            _snprintf(buf,sizeof(buf)-1,"GET http://%s:%d%s HTTP/1.0\r\n",m_szProxyAddr,m_nPort,url); 
		}   
        else // other wise prefix it with an http
            _snprintf(buf,sizeof(buf)-1,"GET http://%s HTTP/1.0\r\n",url); 
	}
    // if not using 
    else 
	{
        if (file[0] =='/' || (file[0] ==37))
            _snprintf(buf,sizeof(buf)-1,"GET %s HTTP/1.0\r\n",file);
        else
            _snprintf(buf,sizeof(buf)-1,"GET /%s HTTP/1.0\r\n",file);

    }

    //send the GET command
    if(Send(buf) <= 0)
	{
        CloseConnection();
        return OnError(UTE_CONNECT_TERMINATED);
	}

    if(IsAborted()) 
	{                       // Check if procedure is aborted
        CloseConnection();
        return OnError(UTE_ABORTED);        // Abort
	}
	return UTE_SUCCESS;



}
/***************************************************
	Sends a HEAD statement to the currently 
	connected server or to the proxy then 
	retrieves the results

	The head of the file will present the size date and other information of a resource
PARAM
	The resource to get the head for
***************************************************/
int		CUT_HTTPClient::SendHeadCommand(LPSTR url)
{
	char    buf[MAX_PATH * 2 + 1];
    char    file[MAX_PATH+1];
    int     error;
    
    //if the url string is empty then return
    if (url == NULL)
        return OnError(UTE_BAD_URL);

    //clear any prev data
    ClearReceivedData();

    // if not using proxy
    if(!m_bUseProxy)
        //get the server Address and file to retrieve
        if(SplitURL(url, file, sizeof(file)) != UTE_SUCCESS)
            return OnError(UTE_BAD_URL);

    //connect
   if ((error = HTTPConnect()) !=  UTE_SUCCESS)
	    return OnError(error);

    if(m_bUseProxy) {
        //send the HEAD command
        // NOTE:----> that when we add the proxy we don't add the slash after the 
        // HEAD command
        // if the url includes http then it is already an absolute URI
        // so lets just format our HEAD command string
        if (_strnicmp (url,"http://", strlen("http://"))==0)
            _snprintf(buf,sizeof(buf)-1,"HEAD %s HTTP/1.0\r\n",url);
        else // other wise prefix it with an http
            _snprintf(buf,sizeof(buf)-1,"HEAD http://%s HTTP/1.0\r\n", url);
        }
    else {
        if (file[0] =='/')
            _snprintf(buf,sizeof(buf)-1,"HEAD %s HTTP/1.0\r\n",file);
        else
            _snprintf(buf,sizeof(buf)-1,"HEAD /%s HTTP/1.0\r\n",file);
        }
    
    if(Send(buf) <= 0) {
        CloseConnection();
        return OnError(UTE_CONNECT_TERMINATED);
        }

    if(IsAborted()) {                       // Check if procedure is aborted
        CloseConnection();
        return OnError(UTE_ABORTED);        // Abort
        }
	return UTE_SUCCESS;

}
/***************************************************
  The DELETE method requests that the origin server delete the resource
  identified by the Request-URI.
PARAM:
    LPSTR url   - The full URI of the resource to be deleted
***************************************************/
int		CUT_HTTPClient::SendDeleteCommand(LPSTR url)
{
	char    buf[MAX_PATH * 2 + 1];
    char    file[MAX_PATH + 1];
    int     error;

    //if the url string is empty then return
    if (url == NULL)
        return OnError(UTE_BAD_URL);
    
    //clear any prev data
    ClearReceivedData();

    // if not using proxy
    if(!m_bUseProxy)
        //get the server Address and file to retrieve
        if(SplitURL(url, file, sizeof(file)) != UTE_SUCCESS)
            return OnError(UTE_BAD_URL);
    //connect to proxy
	if ((error = HTTPConnect()) !=  UTE_SUCCESS)
			return OnError(error);
    
    // if using proxy
    if(m_bUseProxy) {
        // if the url includes http then it is already an absolute URI
        // so lets just format our command string
        if (_strnicmp (url,"http://", strlen("http://"))==0)
            _snprintf(buf,sizeof(buf)-1,"DELETE %s HTTP/1.0\r\n",url);
        else
            _snprintf(buf,sizeof(buf)-1,"DELETE http://%s HTTP/1.0\r\n",url);
        }
    else
        _snprintf(buf,sizeof(buf)-1,"DELETE %s HTTP/1.0\r\n",  file);


    //send the command
    if(Send(buf) <= 0) {
        CloseConnection();
        return OnError(UTE_CONNECT_TERMINATED);
        }

    if(IsAborted()) {                       // Check if procedure is aborted
        CloseConnection();
        return OnError(UTE_ABORTED);        // Abort
    }
	return UTE_SUCCESS;

}
/**********************************************************

		The "basic" Authorization scheme is based on the model that the
		client must authenticate itself with a user-ID and a password for
		each realm.  The realm value should be considered an opaque string
		which can only be compared for equality with other realms on that
		server. The server will service the request only if it can validate
		the user-ID and password for the protection space of the Request-URI.
		There are no optional Authorization parameters

***********************************************************/
int	CUT_HTTPClient::AddBasicAuthorizationHeader(LPCWSTR userName, LPCWSTR password){
	return AddBasicAuthorizationHeader(AC(userName), AC(password));}
int	CUT_HTTPClient::AddBasicAuthorizationHeader(LPCSTR userName, LPCSTR password)
{
	if (userName == NULL || password == NULL)
	{
		return UTE_ERROR; // invalid parameters
	}
	int nNameLen = (int)strlen(userName);
	int nPassLen =  (int)strlen(password) ;

	if (  nNameLen <= 0  || nPassLen <= 0 )
		return UTE_ERROR; // invalid parameters
	
	char *pRawData = new char[nPassLen+nNameLen+2];
	_snprintf(pRawData,nPassLen+nNameLen+2, "%s:%s",userName,password);
	int nOutLen = (int)strlen(pRawData)*2;

	char *pResultData = new char[nOutLen];

	CBase64 base; 
	base.EncodeData ((BYTE*)pRawData,nPassLen+nNameLen+2,pResultData, nOutLen);
	delete pRawData;

	char *HeaderLine = new char [strlen(pResultData)+strlen("Authorization: Basic ")+2];

	_snprintf(HeaderLine,strlen(pResultData)+strlen("Authorization: Basic ")+2, "Authorization: Basic %s",pResultData);
	AddSendHeaderTag(HeaderLine);
	

	delete HeaderLine;
	delete pResultData;
	
	return 0;
	
}
/***********************************************************
		The "basic" Authorization scheme is based on the model that the
		client must authenticate itself with a user-ID and a password for
		each realm.  The realm value should be considered an opaque string
		which can only be compared for equality with other realms on that
		server. The server will service the request only if it can validate
		the user-ID and password for the protection space of the Request-URI.
		There are no optional Authorization parameters

REMARK:
	it is the responsibility of the caller to delete the resulting memory

***********************************************************/
// v4.2 - update 02 - changes Rob Caldecott - fix for parameter and buffer problems -
//        "The first bug is that the pointer passed actually needs to be the address 
//         of a pointer. The second bug means that the buffer allocated is one 
//		   byte too small (the NULL string terminator isn't taken into account)."
int	CUT_HTTPClient::CreateProxyBasicAuthorizationHeader(LPCSTR ProxyUserName, LPCSTR ProxyPassword, LPSTR* HeaderLine)
{
	if (ProxyUserName == NULL || ProxyPassword == NULL)	
	{		
		return UTE_ERROR; // invalid parameters	
	}	

	int nNameLen = (int)strlen(ProxyUserName);	
	int nPassLen =  (int)strlen(ProxyPassword) ;

	if (  nNameLen <= 0  || nPassLen <= 0 )		
		return UTE_ERROR; // invalid parameters	

	char *pRawData = new char[nPassLen+nNameLen+2];	
	_snprintf(pRawData,nPassLen+nNameLen+2,"%s:%s",ProxyUserName,ProxyPassword);

	int nOutLen = (int)strlen(pRawData)*2;	
	char *pResultData = new char[nOutLen];

	CBase64 base; 	
	base.EncodeData ((BYTE*)pRawData,nPassLen+nNameLen+2,pResultData, nOutLen);	
	delete pRawData;	

	// v4.2 - update 02 - mods RC
	int len = strlen(pResultData)+strlen("Proxy-Authorization: Basic ")+3;	

	*HeaderLine = new char [len];	
	_snprintf(*HeaderLine,len, "Proxy-Authorization: Basic %s\r\n",pResultData);
	// mods RC

	// the user will do call this line to add the authorization 	
	// AddSendHeaderTag(HeaderLine);			
	delete pResultData;

	return 0;		
}
/*****************************************************
Set tne port number for the Proxy
Note that the proxy port number may differ from the target server 
port number.

PARAM
  newPort -  The new port number value
*****************************************************/
void CUT_HTTPClient::SetProxyPortNumber(int newPort)
{
	m_nProxyPort = newPort;
}

/****************************************************
Enable Tunneling:
	This call will tel the client that prior to issueing 
	the request you must request that the  proxy 
	establishes a tunnel for our communication.

	The differnet between a tunneled connection and 
	non-tunneled connection is that the proxy will not 
	attempt to modify our request by any means.
PARAM
	flag -  TRUE Tunneled is enabled 
*****************************************************/
void CUT_HTTPClient::EnableTunneling(BOOL flag)
{
	m_bEnableTunnelling = flag;

}
/*********************************************************
I have removed the connection part to be in a function by itself
because they were common to all methods. and I want to handle the connection 
separatly based on usage of proxy or not.

  If Tunneling is enabled we will call Request Tunnel
  Otherwise we will just connect to the proxy or the client
PARAM
	See connection errors
**********************************************************/
int CUT_HTTPClient::HTTPConnect()
{
	int error =  UTE_SUCCESS;
	//connect
	if (!m_bEnableTunnelling)
	{
		if((error = Connect(m_nPort, (m_bUseProxy) ? m_szProxyAddr : m_szServerName, m_nConnectTimeout)) != UTE_SUCCESS)
			return OnError(error);
	}
	else
	{
		return RequestTunnel();
	}
	return UTE_SUCCESS;
}
/********************************************************
Requesting a Tunnel with CONNECT

	A CONNECT method requests that a proxy establish a tunnel connection
	on its behalf. The Request-URI portion of the Request-Line is always
	an 'authority' as defined by URI Generic Syntax [2], which is to say
	the host name and port number destination of the requested connection
	separated by a colon:

	  CONNECT server.example.com:80 HTTP/1.1
	  Host: server.example.com:80

	Other HTTP mechanisms can be used normally with the CONNECT method --
	except end-to-end protocol Upgrade requests, of course, since the
	tunnel must be established first.

	For example, proxy authentication might be used to establish the
	authority to create a tunnel:

	  CONNECT server.example.com:80 HTTP/1.1
	  Host: server.example.com:80
	  Proxy-Authorization: basic aGVsbG86d29ybGQ=

	Like any other pipelined HTTP/1.1 request, data to be tunneled may be
	sent immediately after the blank line. The usual caveats also apply:
	data may be discarded if the eventual response is negative, and the
	connection may be reset with no response if more than one TCP segment
	is outstanding.

	For more info see RFC  2817 
PARAM:
	NONE
RET:
	Connect error -
	UTE_ERROR - The server rejected the request for tunneling

********************************************************/
int CUT_HTTPClient::RequestTunnel()
{
	
	int error = UTE_SUCCESS;
	//  since we are going to go through a tunnel
	// we need to make sure that the hand shake is 
	// handled by the client and the remote server not by the client and the proxy

	// so how do we do that.
	// first we disable the security setting and keep track of it
#ifdef CUT_SECURE_SOCKET
	BOOL currentSecuritySetting = GetSecurityEnabled();	
	SetSecurityEnabled(FALSE);
#endif
	// this will stop our client from trying to preform the handshake as soon as we connect.


	if((error = Connect(m_nProxyPort,  m_szProxyAddr, m_nConnectTimeout)) != UTE_SUCCESS)
			return OnError(error);

	// now we construct a string of which host to instruct the proxy to connect to
	char tempBuffer[500];

	_snprintf(tempBuffer,sizeof(tempBuffer)-1,"CONNECT %s:%d HTTP/1.1\r\n", m_szServerName,m_nPort);
	tempBuffer[499] = NULL;

	Send(tempBuffer);

	_snprintf(tempBuffer,sizeof(tempBuffer)-1,"Host: %s:%d \r\n", m_szServerName,m_nPort);
	tempBuffer[499] = NULL;
	Send(tempBuffer);


	char *ResultHeader = NULL;
	
	// create the proxy authorization header.
	// v4.2 - update 02 - fn was modified to take LPSTR* for parameter 3
	if (CreateProxyBasicAuthorizationHeader(m_szProxyUserName,m_szProxyPassword,&ResultHeader) == UTE_SUCCESS)
	{
		// now we send the proxy authorization 
		Send(ResultHeader);
		delete ResultHeader;
	}


	Send("\r\n");

	CUT_StringList ProxyResponseHeaders;
	
	// now we receive the proxy server response
	do
	{
			ReceiveLine(tempBuffer,sizeof(tempBuffer)-1,m_nConnectTimeout);
			ProxyResponseHeaders.AddString (tempBuffer);
	}
	while (IsDataWaiting());

	// now right here check for the server 
	// response and make sure that the second peice is 200
	// The server response will be the first line we receive 
	long nServerResponse = 0;
	CUT_StrMethods::ParseString ( ProxyResponseHeaders.GetString ((long)0)," ",1,&nServerResponse);
	if (nServerResponse > 199 && nServerResponse < 300)
	{
		// call the base class to continue the hand shake
		// notice that we are sending the name of the server
		// not the proxy as this function has received
		// 
#ifdef CUT_SECURE_SOCKET
	// Set back the security setting to it's origional status
	SetSecurityEnabled(currentSecuritySetting);
#endif

			return CUT_WSClient::SocketOnConnected(GetSocket (),m_szServerName);
	}
	// notice that we are setting the error code to be passed as the server response
	// in the case of error
	// the m_lLastStatusCode is not  set to the proxy response if the 
	// operation succeded
	m_lLastStatusCode = nServerResponse;


#ifdef CUT_SECURE_SOCKET
	// Set back the security setting to it's origional status
	SetSecurityEnabled(currentSecuritySetting);
#endif

	// tunneling failed
	return  UTE_ERROR;
}

/*************************************************
SetProxyPassword
	Set the password to be used in occuring a proxy
	authorization 
PARAM
	szPass - The password to be used in occuring 
	a proxy authorization
REMARK
	If the string passed is NULL or empty, the	proxy
	password will be set To NULL
**************************************************/
#if defined _UNICODE
int CUT_HTTPClient::SetProxyPassword(LPCWSTR szPass){
	return SetProxyPassword(AC(szPass));}
#endif
int CUT_HTTPClient::SetProxyPassword(LPCSTR szPass)
{
	if (m_szProxyPassword != NULL)
	{
		// for security reasons we want to zero the memory used so it can't be seen
		memset (m_szProxyPassword,0, strlen(m_szProxyPassword));
		delete m_szProxyPassword;
		m_szProxyPassword = NULL;
	}
	// is the password passed to us empty
	if ( szPass == NULL || szPass[0] == 0)
		return 0;	

	m_szProxyPassword = new char [strlen(szPass)+1];
	strcpy(m_szProxyPassword,szPass);		

	return UTE_SUCCESS;
}
/**************************************************************
	Set the user name for the proxy
	Notice that so far we are using a basic authentication with base 64 encoding
	the basic authentication is not highly recomended.
	We have added this functionality as requested by our clients.
REMARK
	A call to this function will replace the exsiting user name 
	with a new one or with a null if any of the parameter is wrong
PARAM
	szUserName - The proxy user name
RET
	UTE_SUCCESS
***************************************************************/
#if defined _UNICODE
int CUT_HTTPClient::SetProxyUserName(LPCWSTR szUserName){
	return SetProxyUserName(AC(szUserName));}
#endif
int CUT_HTTPClient::SetProxyUserName(LPCSTR szUserName)
{
	if (m_szProxyUserName != NULL)
	{
		// for security reason we want to 
		// mutate the memory used so it can't be recovered
		memset (m_szProxyUserName,0, strlen(m_szProxyPassword));
		delete m_szProxyUserName;
		m_szProxyUserName = NULL;
	}
	// is the password passed to us empty
  if ( szUserName == NULL || szUserName[0] == 0)
	  return 0;	

	  m_szProxyUserName = new char [strlen(szUserName)+1];
	  strcpy(m_szProxyUserName,szUserName);		

	return UTE_SUCCESS;
}
/*******************************************************
OnRedirect
	Ass the user for permition to continue following the redirection
	Some page request may be answered with a 3xx status code from the server.
	This class of status code indicates that further action needs to be
	taken by the user agent in order to fulfill the request.  The action
	required MAY be carried out by the user agent without interaction
	with the user if and only if the method used in the second request is
	GET or HEAD.
	
REMARK:
	A client SHOULD detect infinite redirection loops, since
	such loops generate network traffic for each redirection.
	Note: previous versions of this specification recommended a
	maximum of five redirections. Content developers should be aware
	that there might be clients that implement such a fixed
	limitation.

	Users of the CUT_HTTPClient can also take advantage of this function 
	to set up any cookies or additional request headers for state management 
	proccess.

PARAM:
	szUrl - a string describing the new URL we are being redirected to
RET
	TRUE - User accept to be redirected
	FALSE - DONT'REDIRECT.	
*******************************************************/
// v4.2 this notification overload could be reviewed
BOOL CUT_HTTPClient::OnRedirect(LPCWSTR /* szUrl */){
	return FALSE;
}

BOOL CUT_HTTPClient::OnRedirect(LPCSTR /* szUrl */){
	return FALSE;
}
/********************************************************
INTERNAL 
GetMovedLocation()
Get the redirect URL from the server response
PARAM
	LPSTR newUrl -  the location of the new url
RET
	TRUE - location was found
	FALSE - No url was found
********************************************************/
BOOL CUT_HTTPClient::GetMovedLocation(LPSTR newUrl )
{
      
    int     count,loop;
    char    buf[URL_RESOURCE_LENGTH+ 10];	
	char    location[URL_RESOURCE_LENGTH+ 10];
	BOOL	bFound = FALSE; 

    count = GetHeaderLineCount();
    for(loop = 0; loop < count ; loop++){
        CUT_StrMethods::ParseString(GetHeaderLine(loop),":",0,buf,sizeof(buf));
        if(_stricmp(buf,"Location") == 0 ){
			// get the schems
			if (CUT_StrMethods::ParseString(GetHeaderLine(loop)," ",1,location,URL_RESOURCE_LENGTH-1) ==  UTE_SUCCESS)
			{
				bFound = TRUE;
				// if the first charecter is / then lets make sure we add it to origional serevr address 
				if (location[0] == '/')
				{
					strcpy(newUrl,m_szServerName);
					strcat(newUrl,location);
				}	
				else
					strcpy(newUrl,location);
			}

			break;
        }
    }

    return bFound;
}

#pragma warning ( pop )

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions