Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

STL WebServer

, 8 May 2000
A set of classes written in STL that implement a web server
#include "stdafx.h"

#include "HttpServerInfo.h"



HttpServerInfo::HttpServerInfo ( long port ) :

	HttpServerStats(),

	_strTitleBase(""),
	_strRoot(""),
	_strServer(),
	_timeStarted(),
	_port(port),
	_server(0),
	_bListIcon(false),
	_bAllowListing(true)

{}



HttpServerInfo::~HttpServerInfo ()
{
	release();
}


bool HttpServerInfo::create ( string & server, string & directory )
{
	// reset stats
	reset();

	// show logging
	setLogging( true );

	// assign default values
	_strServer = server;

	// get the default root path
	_strRoot = directory;

	// ensure no final separator character
	if ( _strRoot[_strRoot.size()-1] == SEPCHAR )
		_strRoot.erase( _strRoot.size() -  1 );

	// make into a full path string
	char buffer[MAX_PATH+1];
	GetFullPathName( _strRoot.c_str(), MAX_PATH, buffer, NULL);
	_strRoot = buffer;

	return true;
}

void HttpServerInfo::release ()
{
	// release stats
	HttpServerStats::release();

	// release objects
	_strTitleBase.erase();
	_strRoot.erase();
	_strServer.erase();

}


bool HttpServerInfo::urlToPath ( string & strFile )
{
	bool bLegal = false;

	// remove leading indicators
	StringUtil::trimLeft( strFile, "/" );


	// start with the root, append the abs path
	string & strRoot = getRoot();
	string strTemp   = strRoot + SEPCHAR + strFile;

	// now canonicalize it
	char buffer[MAX_PATH+1];

	DWORD dwSize = 
	GetFullPathName( strTemp.c_str(), MAX_PATH, buffer, NULL );
	strFile = buffer;

	// get the full path okay?
	if ( dwSize )
	{
		int cchRoot = strRoot.size();
		int cchFile = strFile.size();

		// must be the same or longer than the root
		if ( cchRoot == cchFile )
		{
			// must be exactly the same
			if ( strRoot.compare( strFile ) == 0 )
				bLegal = true;
		}
		else if ( cchRoot < cchFile )
		{
			// must have the root as the base
			if ( strRoot.compare( StringUtil::left(strFile,cchRoot) ) == 0 &&
				 strFile[cchRoot] == SEPCHAR )
				bLegal = true;
		}
	}

	return bLegal;
}

bool HttpServerInfo::pathToUrl ( string & strFile )
{
	int index;

	// a local reference to the root
	string & strRoot = getRoot();

	// change all SEPCHARs to forward slashes
	while ( (index=strFile.find( SEPCHAR )) != -1 )
		strFile = StringUtil::left( strFile,index ) + '/' + StringUtil::mid(strFile,index+1);

	// now add the prefix and server, and cut the root
	string strPort;
	UINT uPort = getPort();
	if ( uPort != PORT_HTTP )
		StringUtil::formatString(strPort, ":%d", uPort );

	
	strFile = string("http://")
		+ getServer()
		+ strPort
		+ StringUtil::mid(strFile,strRoot.size());
	

	return true;
}

string HttpServerInfo::stripLast ( string & strPath )
{
	string strExtra;
	if ( !strPath.empty() )
	{
		int index = strPath.rfind( SEPCHAR );
		if ( index < 0 )
			index = 0;

		strExtra = StringUtil::mid(strPath,index);
		strPath  = StringUtil::left( strPath, index );
	}
	return strExtra;
}


bool HttpServerInfo::find ( HttpRequest & request, 
						    string & strFile )
{
	bool found = false;

	// get url
	strFile = request.getUrl();

	// remove leading indicators
	StringUtil::trimLeft( strFile, "/" );


	// change from URL to local file system path
	if ( urlToPath( strFile ) )
	{
		string strExtra; // extra path info

		request.setAttributes( GetFileAttributes( strFile.c_str() ) );

		if ( request.getAttributes() != -1 )
			found = true;
		else
		{
			// rip off the last portion
			strExtra = stripLast( strFile );

			while( !strFile.empty() )
			{
				// anything there?
				request.setAttributes( GetFileAttributes( strFile.c_str() ) );

				if ( request.getAttributes() != -1 )
				{
					// found something; better not be a folder
					if( ( request.getAttributes() & FILE_ATTRIBUTE_DIRECTORY ) == 0 )
						found = true;
					break;
				}

				// rip off the next portion
				strExtra = stripLast( strFile ) + strExtra;
			}
		}
	

		
		// #DGH
		// come back to later
		// this code exists in above if statement

		
		if ( found )
		{
			// strip any trailing SEPCHAR
			if ( strFile[strFile.size()-1] == SEPCHAR )
				request.setFullPath( StringUtil::left( strFile, strFile.size()-1 ) );
			else
				request.setFullPath( strFile );

			// see if we need to set the extra path info
			if ( !strExtra.empty() )
			{
				request.setPathInfo( strExtra );

				if ( urlToPath( strExtra ) )
					request.setPathTranslated( strExtra );
			}

			// if it's a folder, see if we can redirect to
			// one of the default docs or apps
			if ( request.getAttributes() & FILE_ATTRIBUTE_DIRECTORY )
			{
				// check for existence of a default doc or app
				if ( !checkDefault( request, IDS_DEFAULTDOC, false ) )
					checkDefault( request, IDS_DEFAULTAPP, true );
			}
			else if ( request.getExecute() && !isSeverApp(request) )
			{
				request.addError( idHttpBadRequest );
			}
		}
		else
		{
			request.addError( idHttpNotFound );
		}
	}
	else
	{
		request.addError( idHttpBadRequest );
	}

	
	return found;
}


bool HttpServerInfo::checkDefault ( HttpRequest & request, 
								    LPTSTR uList, 
									bool bExecute )
{
	bool found = false;
	DWORD dwAttr;
	string strDefault;

	// get default list
	string strDefList;
	StringUtil::loadString( strDefList,  uList );

	// test list
	while ( !strDefList.empty() )
	{
		// get path
		int index;
		strDefault = request.getFullPath();

		index = strDefList.find('\n');
		if ( index == -1 )
		{
			HttpUtil::addFile( strDefault, strDefList );
			strDefList.erase();
		}
		else
		{
			HttpUtil::addFile( strDefault, StringUtil::left( strDefList, index) );
			strDefList = StringUtil::mid( strDefList,  index+1 );
		}

		if ( (dwAttr=GetFileAttributes(strDefault.c_str())) != -1 &&
			 (dwAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 )
		{
			found = true;
			break;
		}
	}

	if ( found )
	{
		// redirect to the default file
		pathToUrl( strDefault );
		if ( bExecute )
			strDefault += '?';

		request.addStatus( idHttpMovedTemp );
		request.addHeader( "Location", strDefault );
		request.addString( CRLF );
		
	}
	return found;
}

bool HttpServerInfo::isSeverApp ( HttpRequest & request )
{
	bool ok = false;

	// find ext terminator
	int index = request.getFullPath().rfind( '.' );

	// if found
	if ( index != -1 )
	{
		// get extension
		string strExt = StringUtil::mid( request.getFullPath(), index+1 );
		string strAvail;

		// check if CGI app
		StringUtil::loadString( strAvail, IDS_APP_CGI );

		ok = checkExt( request, strExt, strAvail, idAppCgi );
		if ( !ok )
		{
			StringUtil::loadString( strAvail, IDS_APP_ISAPI );
			ok = checkExt( request, strExt, strAvail, idAppIsapi );
		}
	}

	return ok;
}


bool HttpServerInfo::checkExt ( HttpRequest & request,
							    const string & strExt, 
								string & strAvail, 
								DWORD dwType )
{
	// show match not found
	bool match = false;

	// stores test extension
	string strPossible;

	// loop through all possible exts
	while( !strAvail.empty() )
	{
		int index = strAvail.rfind('\n');
		if ( index == -1 )
		{
			strPossible = strAvail;
			strAvail.erase();
		}
		else
		{
			strPossible = StringUtil::mid( strAvail, index+1 );
			strAvail    = StringUtil::left( strAvail,  index );
		}

		// compare extension
		if ( StringUtil::compareNoCase( strExt, strPossible ) == 0 )
		{
			request.setExecute( dwType );
			match = true;

			break;
		}
	}

	return match;
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

David Hubbard

United States United States
No Biography provided

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.1411023.1 | Last Updated 9 May 2000
Article Copyright 2000 by David Hubbard
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid