Click here to Skip to main content
Email Password   helpLost your password?

Introduction

This article describes changes in ahttp library made from first release. I have decided to upload a new article because the server code was greatly modified and at present it is almost a production ready project.

The current server version can be easily used as an IIS replacement in ASP.NET applications development. Server supported wildcard ('.*') mapping with exclude exception list maintaining - this feature can be used to setup ASP.NET MVC application (see example in attached demo).

After first ahttp version sharing (about year ago), I have continued working on this project. The main goal of this development stayed unchanged - investigate and use latest features available in C++, apply different known design practices to create stable and extendable application architecture. This project is developed in my free time and is not related to my direct work - in office life mostly I work on web-applications (ASP.NET, JavaScript, jQuery, last time I participated in a project based on ASP.MVC).

Currently, the ahttp project contains three main parts:

The server still supports Windows and Linux platforms (tested on Ubuntu only).

To extend server features, a set of plugins was developed:

Using the Code

Server/Library Architecture

All HTTP server kernel code is located in the ahttp library to make possible embedding of the server into any existing architecture or use only necessary parts of server code, like HTTP requests parsing. Using this library provides a developer the ability to create customizable web-server to process specific HTTP requests - SOAP requests, files downloading and so on.

Complete standalone HTTP server application (ahttpserver) included in project sources has only about 15 KB of sources (except libraries code of course). Thus using of this library can greatly decrease developing/prototyping efforts at server-side project estimation. Even if it will be decided not to use this library as service base, one can use the provided source parts to include in their own project.

To get ahttp::HttpServer working, one need have filled HttpServerSettings instance - even for simple server, there are many settings that can be setup. As a result, the preferred place to store these settings is an XML file which can be updated by hand and loaded quickly.

Server Settings File

<?xml version="1.0" encoding="utf-8"?>
<settings>
    <server
	    version = "ahttp/0.17"
	    port="5555"
	    ip-address="0.0.0.0"
	    workers-count="50"
	    pooling-enabled="true"
	    worker-life-time="60"
	    command-port="5556"
	    root="root"

	    keep-alive-enabled = "true"
	    keep-alive-timeout = "10"
	    server-socket-timeout = "900"
	    command-socket-timeout = "30"

	    response-buffer-size = "8194304"
	    max-chunk-size = "512144"

	    directory-config-file = "directory.config"
	    messages-file = "messages.config"

	    uploads-dir = "c:\\temp\\ahttp"
	    locale=".1251"
	    >

	    <!-- log-level: "Debug", "Info", "Warning", "Error", "Critical" -
			if none of them - then debug -->
	    <log log-level="info" max-file-size="4194304">

		    <!-- {app-path} - path to directory where application
			is located (with trailing slash),
			     {timestamp} - generated timestamp -->
		    <path>{app-path}log\server_{timestamp}.log</path>
	    </log>

	    <mime-types file="{app-path}mime-types.config" />

	    <!-- All handlers must be registered there, concrete
		    assignments will be defined in <directory> elements -->
	    <handlers>
		    <register name="handler_python" default-ext=".py; .pyhtml">
			    <path>{app-path}handler_python-d.dll</path>
			    <!-- parameter name="uploads-dir">
				c:\temp\handler_python\</parameter -->
		    </register>
		    <register name="handler_php" default-ext=".php">
			    <path>{app-path}handler_isapi-d.dll</path>
			    <parameter name="engine">c:\PHP\php5isapi.dll</parameter>
			    <parameter name="update-path">c:\PHP\</parameter>
			    <parameter name="free-library">false</parameter>
			    <parameter name="check-file-exists">true</parameter>
		    </register>
		    <register name="handler_aspnet"
			default-ext=".aspx; .ashx; .asmx; .axd">
			    <path>{app-path}handler_aspnet-d.dll</path>
			    <parameter name="init-root">false</parameter>
			    <!-- parameter name="load-applications">mvc;
				books</parameter -->
		    </register>
	    </handlers>

        <!-- All modules must be registered there, concrete
        assignments will be defined in <directory> elements.
        'global' attribute defines that this module will be
	automatically applied to root directory.-->

        <modules>
            <register name="global_basic_auth" global="true">
	            <path>{app-path}module_authbasic-d.dll</path>
	            <parameter name="realm">Protected data</parameter>
	            <parameter name="provider">system</parameter>
	            <parameter name="default-domain">ES</parameter>
            </register>
        </modules>

    </server>

    <!-- virtual-path for root: "/"
			    'charset' - will be used when FS content is shown
			    default 'max-request-size': 2097152 bytes -->
    <directory name="root"
		    browsing-enabled="true"
		    charset="Windows-1251"
		    max-request-size="2097152"
		    enable-parent-path-access="true">

	    <path>d:\work\web\</path>

	    <default-documents>
		    <add>index.html</add>
		    <add>index.htm</add>
		    <add>main.html</add>
            <add>Default.aspx</add>
	    </default-documents>

	    <!-- ext="*" - will be applied to all requests -->
	    <!-- ext="." - will be applied to directory/file without extension -->
	    <handlers>
		    <add name="handler_python"/>
		    <add name="handler_php" />
		    <add name="handler_aspnet"/>
       </handlers>

	    <!-- Record attributes:
			    {name} - name of item,
			    {size} - size of item in kb,
			    {url} - url to open item
			    {time} - last modify dat/time of item,
			    {page-url} - url to current page
			    {parent-url} - url to parent directory
			    {files-count} - files count in current directory
			    {directories-count} - sub-directories count in
						current directory
			    {errors-count} - reading errors count
			    {tab} - will be replaced with '\t'
	    -->
	    	<header-template>
		<pre>{eol}
		<b>Directory: <i>{page-url}</i></b>{eol}{eol}
	</header-template>

	<parent-directory-template >
		<a href="{parent-url}">[parent directory]</a>{eol}{eol}
	</parent-directory-template>

	<directory-template>
		{time}{tab}{tab}directory{tab}{tab}<a href="{url}">{name}</a>{eol}
    </directory-template>

	<virtual-directory-template >
		{time}{tab}{tab}  virtual{tab}{tab}<a href="{url}">{name}</a>{eol}
    </virtual-directory-template>

	<file-template >
        {time}{tab}{size}{tab}{tab}<a href="{url}">{name}</a>{eol}
    </file-template>

	<footer-template>
        {eol}
		Files: {files-count}{eol}
		Directories: {directories-count}{eol}
		Reading errors: {errors-count}{eol}
		</pre>
	</footer-template>
    </directory>

    <directory name="server_data"
		    parent="root">
	    <virtual-path>server_data</virtual-path>
	    <path>{app-path}web</path>
    </directory>

    <directory name="mvc"
	       parent="root">
	    <handlers>
		    <add name="handler_aspnet" ext="*"/>
		    <remove name="handler_aspnet" ext=".gif; .js; .css; .jpg; .png"/>
	    </handlers>
	    <virtual-path>mvc</virtual-path>
	    <path>d:\work\Visual Studio 2008\Projects\
			OReilly-.NET3.5\MVCApplication\</path>
    </directory>
</settings>    

The first section of settings file - server defines HTTP server startup/runtime behavior: server's port (port attribute), IP address to bind on it (now only IPv4 is supported). Other parameters:

Virtual directory setup - directory element. Each virtual directory can be defined by absolute FS path ('path' attribute) or by relative path from parent's directory ('relative-path' attribute).

Complete Sample Code of a Very Simple Server

    // globals
    namespace Global
    {
	    aconnect::string settingsFilePath;
             ahttp::HttpServerSettings globalSettings;

	    aconnect::BackgroundFileLogger logger;
	    aconnect::Server httpServer;
    }

    void processException (aconnect::string_constptr message, int exitCode) {
	    std::cerr << "Unrecorable error caught: " << message << std::endl;
	    exit (exitCode);
    }

    int main (int argc, char* args[])
    {
        using namespace aconnect;
	    namespace fs = boost::filesystem;

        if (argc < 2) {
            std::cerr << "Usage: " << args[0] <<  " " << std::endl;
        }

        Global::settingsFilePath = args[1];
	    string appPath = aconnect::util::getAppLocation (args[0]);

        try
	    {
		    Global::globalSettings.setAppLocaton ( fs::path
		       (Global::appPath).remove_leaf().directory_string().c_str() );
		    Global::globalSettings.load ( Global::settingsFilePath.c_str() );

	    } catch (std::exception &ex) {
		    processException (ex.what(), 1);
	    } catch (...) {
		    processException
			("Unknown exception caught at settings loading", 1);
	    }

	    try
	    {
		    // create global logger
		    string logFileTemplate = Global::globalSettings.logFileTemplate();
		    Global::globalSettings.updateAppLocationInPath (logFileTemplate);
		    fs::path logFilesDir = fs::path
				(logFileTemplate, fs::native).branch_path();
		    if (!fs::exists (logFilesDir))
			    fs::create_directories(logFilesDir);

		    Global::logger.init (Global::globalSettings.logLevel(),
			logFileTemplate.c_str(),
			Global::globalSettings.maxLogFileSize());

	    } catch (std::exception &ex) {
		    processException (ex.what(), 2);
	    } catch (...) {
		    processException
			("Unknown exception caught at logger creation", 2);
	    }

	    Global::globalSettings.setLogger ( &Global::logger);
	    // init ahttp library
        ahttp::HttpServer::init ( &Global::globalSettings);

	    try
	    {
		    Global::globalSettings.initPlugins(ahttp::PluginModule);
		    Global::globalSettings.initPlugins(ahttp::PluginHandler);

		    Global::httpServer.setLog ( &Global::logger);
		    Global::httpServer.init (Global::globalSettings.port(),
			    ahttp::HttpServer::processConnection,
			    Global::globalSettings.serverSettings());

		    Global::httpServer.start (true);

	    } catch (std::exception &ex) {
		    processException (ex.what(), 3);
	    } catch (...) {
		    processException
			("Unknown exception caught at server startup", 3);
	    }

        return 0;
    }    

See more details in library code - I tried my best to write all simple code.

Points of Interest

While working on this project, I realized that C++ is still the best variant for high-load server-side services. The strongly typed language provides the ability to write short but fast and powerful constructions like this...

    template 
    class ScopedMemberPointerGuard {
    public:
        ScopedMemberPointerGuard (T* obj, F T::* member, F initialValue ) :
            _obj (obj), _member (member) {
                _obj->*_member = initialValue;
        }

        ~ScopedMemberPointerGuard () {
            _obj->*_member = 0;
        }

    private:
        T* _obj;
        F T::* _member;
    };    

... cannot be forgotten by developers. Working on this project, I have got great experience in ISAPI extensions internal architecture, ASP.NET HTTP runtime programming in native environment - all these skills are not trivial programming tasks and can be effectively used in professional work.

Planned Improvements

aconnect library:

ahttp library and plugins:

Known Compatibility Issues

  1. Using of c:\PHP\php5isapi.dll through ISAPI handler (tested with PHP 5.2.5 and PHP 4.3.10) can be the cause of "Access violation" exception at server stopping (::FreeLibrary call)
  2. ASP.NET handler tested only with .NET Framework v2.0.50727 (Microsoft .NET Framework 3.5 SP1 installed)

Version History

Ver. 0.15

Ver. 0.16

Ver. 0.17

Ver. 0.18

Ver. 0.19

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralProject page created on CodePlex
Artem Kustikov
5:26 12 Aug '09  
Official project page created at http://ahttpserver.codeplex.com/[^]
QuestionCoInitializeEx fails in handler_isapi.cpp
tompaolo
1:36 12 May '09  
Building with Visual Studio 2005:

::CoInitializeEx(0, COINIT_MULTITHREADED) fails with error 0x80010106. Why? Any idea?
AnswerRe: CoInitializeEx fails in handler_isapi.cpp
Artem Kustikov
2:45 12 May '09  
Try to apply skipping of this error as described in http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/e1bc9fe4-d985-473a-88f7-ef2ed47f77b3/[^].

I have not seen this error before - I have tested ahttp only under Windows XP.

Also you can disable ISAPI handler loading in server.config (handler_isapi.dll).
GeneralWeb services
Niemand25
0:31 10 Feb '09  
Maybe it's a stupid question. Does it support web services?
GeneralRe: Web services
Artem Kustikov
1:45 10 Feb '09  
Of course, handler_aspnet already setup to process .asmx extensions (see sample in sources archive).
Generalembedded market
Leblanc Meneses
17:59 9 Feb '09  
interesting project you have here.

I think the windows and linux world is closed already... but the embedded world is still wide open..

here are the competitors...

http://acme.com/software/thttpd/[^]

http://www.goahead.com/[^]

http://gladesoft.com/products/seminole/[^]


I've only used goahead .. seminole looks familiar to iis concepts.

- lm
http://www.codeplex.com/npeg
looking for help implementing c/c++ versions .. a lot of work for 1 person.
GeneralInteresting
Werson Kremlor
5:49 8 Feb '09  
Interesting little project, btw have you considered using ASIO instead of rolling out your own n/w stuff?
GeneralRe: Interesting
Artem Kustikov
0:21 9 Feb '09  
Hello,
Firstly I have used boost 1.34.1 when I have started this project - and that release did not contain ASIO library (it was introduced in 1.35.0 release), and secondly - one of this project targets for me was investigation of TCP network programming concepts. Thus I have implemented my own sockets working functionality to get some programming experience with it.
GeneralClassic ASP support?
Volleyknaller
22:08 7 Feb '09  
Is it planned to support classic ASP(Vbscript style)???

best regards
Christian
GeneralRe: Classic ASP support?
Artem Kustikov
8:01 8 Feb '09  
I have tried to load ASP 3.0 ISAPI extension by means handler_isapi but it relies on IIS metabase file (maybe other undocumented features of IIS) and cannot be loaded.

Generally any ASP page can be easy ported to ASP.NET thus I propose to avoid using classic ASP and transfer your projects to ASP.NET.
GeneralRe: Classic ASP support?
Volleyknaller
13:28 14 Feb '09  
What version of ASP ISAPI extension have you tested?
Gave you the new IIS7 ISAPI extension a try?

regards
Christian
GeneralWow
Jerry Evans
8:13 6 Feb '09  
Nice work here Artem. One question: why the reliance on Boost? Is this specifically used for parsing or what?

Thanks for sharing this.

Jerry
GeneralLI XIao Long
Haozes
22:06 5 Feb '09  
KongFu Big Grin

welcome to my blog:http://solo.cnblogs.com

Generalat last
mascix
20:14 5 Feb '09  
sometime IIS can be freaken crazy. it was time to see something else around. nice job.


GeneralGreat side project
GriffonRL
10:41 5 Feb '09  
Hi,

I would love to work on such side project too.
I have 2 questions:
- do you have some performance metrics ? Does it scale ?
- Django would be great and even more if you can offer good performance for Python. Not really a question.

Regards,

R. LOPES
Just programmer.
Http://sili.co.nz/blog

GeneralRe: Great side project
Artem Kustikov
22:08 5 Feb '09  
Hello, I have created VS2008 web-test project and compared ahttpserver performance to IIS on simple ASP.NET application. Page loading timings were almost the same but IIS produces mush more server-side errors (timeouts, incorrect response).

One problem - after several restarts web-tests functionality in my VS2008 crashed and now it does not work at all. I am planning to create set of unit tests (AHttp.Test) to check different server features and performance.
GeneralRe: Great side project
GriffonRL
23:02 5 Feb '09  
Hi,

Sounds good to me. We long for an alternative to IIS.
And some openness to alternatives like Python is definitive plus.
Keep us updated.

Regards,

R. LOPES
Just programmer.
Http://sili.co.nz/blog


Last Updated 5 Feb 2009 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010