René Nyffenegger's collection of things on the web
René Nyffenegger on Oracle - Most wanted - Feedback
 

A Simple Webserver in C++ for Windows

This Webserver makes use of this Socket classes. The programm is far from being finished... I welcome anyone to help me.
The webserver's constructor is basically waiting for new connection request on the port passed as argument to the constructor. As soon as a request is detected, a new thread is created (_beginthreadex) which starts in the static method Request. This method fills the http_request structure and passes it to the supplied http handler function
Request then reads the first line from the socket ReceiveLine to determine the Request method.
If you install the webserver and run it, you can connect to it with http://localhost:8080/.

Downloading

Download the web server including its sources as a zip file that contains the following files:

Compiling

I was able to compile the webserver with mingw using the supplied makefile.
Cybrax Cyberspace points out that VS 2008 doesn't compile the code with a error C2065: 'EAGAIN': undeclared identifier error unless a
#include <errno.h>
is added in the source. Many thanks for the feedback!

Some extracts from the code

the webserver::http_request struct

The following struct is arguably on of the most important structures for the webserver. For each HTTP request, path_ is filled with the request's path. params_ contains name values pairs if the GET request passes some form variables. After filling these fields, this structure is passed to the request handler function who is responsible of filling answer_.
struct http_request {

  http_request() : authentication_given_(false) {}

  Socket*                            s_;
  std::string                        method_;
  std::string                        path_;
  std::map<std::string, std::string> params_;

  std::string                        accept_;
  std::string                        accept_language_;
  std::string                        accept_encoding_;
  std::string                        user_agent_;

  /* status_: used to transmit server's error status, such as
     o  202 OK
     o  404 Not Found 
     and so on */
  std::string                        status_;

  /* auth_realm_: allows to set the basic realm for an authentication,
     no need to additionally set status_ if set */
  std::string                        auth_realm_;

  std::string                        answer_;

  /*   authentication_given_ is true when the user has entered a username and password.
       These can then be read from username_ and password_ */
  bool authentication_given_;
  std::string username_;
  std::string password_;
};

main.cpp

The following code is
#include "webserver.h"
#include "Socket.h"

void Request_Handler(webserver::http_request* r) {
  Socket s = *(r->s_);

  std::string title;
  std::string body;
  std::string bgcolor="#ffffff";
  std::string links =
      "<p><a href='/red'>red</a> "
      "<br><a href='/blue'>blue</a> "
      "<br><a href='/form'>form</a> "
      "<br><a href='/auth'>authentication example</a> [use <b>adp</b> as username and <b>gmbh</b> as password"
      "<br><a href='/header'>show some HTTP header details</a> "
      ;

  if(r->path_ == "/") {
    title = "Web Server Example";
    body  = "<h1>Welcome to Rene's Web Server</h1>"
            "I wonder what you're going to click"  + links;
  }
  else if (r->path_ == "/red") {
    bgcolor = "#ff4444";
    title   = "You chose red";
    body    = "<h1>Red</h1>" + links;
  }
  else if (r->path_ == "/blue") {
    bgcolor = "#4444ff";
    title   = "You chose blue";
    body    = "<h1>Blue</h1>" + links;
  }
  else if (r->path_ == "/form") {
    title   = "Fill a form";

    body    = "<h1>Fill a form</h1>";
    body   += "<form action='/form'>"
              "<table>"
              "<tr><td>Field 1</td><td><input name=field_1></td></tr>"
              "<tr><td>Field 2</td><td><input name=field_2></td></tr>"
              "<tr><td>Field 3</td><td><input name=field_3></td></tr>"
              "</table>"
              "<input type=submit></form>";


    for (std::map<std::string, std::string>::const_iterator i = r->params_.begin();
         i != r->params_.end();
         i++) {

      body += "<br>" + i->first + " = " + i->second;
    }


    body += "<hr>" + links;

  }
  else if (r->path_ == "/auth") {
    if (r->authentication_given_) {
      if (r->username_ == "adp" && r->password_ == "gmbh") {
         body = "<h1>Successfully authenticated</h1>" + links;
      }
      else {
         body = "<h1>Wrong username or password</h1>" + links;
         r->auth_realm_ = "Private Stuff";
      }
    }
    else {
      r->auth_realm_ = "Private Stuff";
    }
  }
  else if (r->path_ == "/header") {
    title   = "some HTTP header details";
    body    = std::string ("<table>")                                   +
              "<tr><td>Accept:</td><td>"          + r->accept_          + "</td></tr>" +
              "<tr><td>Accept-Encoding:</td><td>" + r->accept_encoding_ + "</td></tr>" +
              "<tr><td>Accept-Language:</td><td>" + r->accept_language_ + "</td></tr>" +
              "<tr><td>User-Agent:</td><td>"      + r->user_agent_      + "</td></tr>" +
              "</table>"                                                +
              links;
  }
  else {
    r->status_ = "404 Not Found";
    title      = "Wrong URL";
    body       = "<h1>Wrong URL</h1>";
    body      += "Path is : &gt;" + r->path_ + "&lt;"; 
  }

  r->answer_  = "<html><head><title>";
  r->answer_ += title;
  r->answer_ += "</title></head><body bgcolor='" + bgcolor + "'>";
  r->answer_ += body;
  r->answer_ += "</body></html>";
}

int main() {
  webserver(8080, Request_Handler);
}

Visual Studio Project

Kaarlo Räihä has created a Visual Studio 6 project for the webserver which can be downloaded here.

Thanks

Thanks to Tom Lynn and Frank M. Hoffmann who each pointed out an error in webserver.cpp.