26.1.2015

foto Petr Bravenec

Petr Bravenec
Twitter: @BravenecPetr
+420 777 566 384
petr.bravenec@hobrasoft.cz

Thanks

Our http server is based on Stefan Fings's work:
http://stefanfrings.de/qtwebapp/index-en.html.
I'd like to thank Stefan for his work.

You can find overview of http server here: Our work - Http Server for C++ and Qt

Why another server?

For one of our projects I looked for some web server. At first I wanted to use QtWebapp. I have good experience with it from another project: Fotobot. But using it in the Fotobot I found some drawbacks: parameters are passed as references, not pointers, server is multi-threaded and the number of threads is preset in configuration file. Sometime the fixed number of connections is problematic in the fotobot project and in our next project we expected much worse situation.

We tried another web servers but we were limited with the multi-threaded environment, too.

I have nothing against the multi-threaded application. But the Qt is oriented to event driven programming and if whole application is event driven, multi-threaded web server is a useless complication (need for locking).

People are copying ideas. Apache shows the road once. If the Apache is so successful, one can not make a mistake to design its own web server with similar architecture. So we did not find usable single-threaded embedded WWW server.

Fortunately servers like Nginx, Lighttpd and HobrasoftHttpd exist.

Request to server

Embedded

Number of our application run in small ARM computer BeableBone. It is nonsense to write C++ application for bit juggling and then use Apache and PHP to present data. Of course, the Apache runs in BeagleBone but we want to have whole environment as simple as possible, including installation. Ideal installation looks like this:

apt-get install fotobot

I do not want to write long manuals "You have to configure apache: 1. apt-get.. 2. cd /etc/apache/vhosts/... 3. vi default_vhost.conf... 99. /etc/init.d/apache restart".

Windows

It is possible to write detailed installation manual for Linux admins or for my own employee. But I cannot imagine to make product with http server for Windows without embedded http server. Windows applications are installed clicking "Next... Next... Next..." Definitely.

Unlimited number of connections

Applications we make in last time open for every page a few connections and do not release them. All connections are opened while the page is shown in browser. It is insufficient to use ten threads. (Of course, I will leave the idea of unlimited number or connections once someone crash my server ;-)

Single thread

I want to use single-thread WWW server in single-thread application. Other number of threads than one leads to locking, the application becomes complex and predisposed to errors. One missing mutext can crash the application or worst damage your data.

Event driver

The Qt library is event driven. Even the writing of multi-threaded application is easy, writing of single-threaded application is easier.

How to use the server

If you want to serve only static content, the use of http server is very simple:

#include 
#include "httpd.h"
using namespace HobrasoftHttpd;
int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);
    new HttpServer(0); // Server can serve static file from current directory 
    return app.exec();
}

Configuration is implemented in one class loaded from default QSettings Qt's class. If you want to use other configuration file, you can make it like this:

    QSettings qsettings("/etc/http.conf", QSettings::IniFormat);
    HttpSettings settings(&qsettings, 0);
    new HttpServer(&settings,0);

When you need to server dynamic content, you have to extend HttpServer class and reimplement HttpServer::requestHandler() method. The method has to return new instance of your own request mapper:

#include "httpserver.h"
#include "httprequesthandler.h"
#include "myclass.h"

using namespace HobrasoftHttpd;

class RequestMapper : public HttpRequestHandler {
    Q_OBJECT
  public:
    RequestMapper(HttpConnection *parent);
    void service(HttpRequest *request, HttpResponse *response) {
        if (request->path().startsWith("/my-function")) {
            HttpRequestHandler controller = new MyClass(connection());
            controller->service(request, response);
            return;
            }
        // call default handler - static html pages, shtml pages, images, javascript, styles...
        HttpRequestHandler::service(request, response);
        }
};

class MyHttpd : public HttpServer {
    Q_OBJECT
  public:
    Httpd(QObject *parent) : QObject(parent) { }
    // The method returns pointer to new instance of your own request mapper
    // The request mapper maps requests like "/my-function" to call your own classes
    HttpRequestHandler *requestHandler(HttpConnection *connection) {
        return new RequestMapper(connection);
        }
};

See documentation: http://www.hobrasoft.cz/en/httpserver/doc/

Part of the package is an documented example. I recommend you to study class AbstractController and its usage. That class implements simple API for common problem:

  • load list of object of a group (list of room for example)
  • load concrete object of the group (room)
  • create, change or delete the object
  • report changes in the object or the group

The class communicates using JSON, changes are reported using HTML event streams.

Hobrasoft s.r.o. | Contact