26

I'd like to write a small HTTP server application that receives HTTP GET requests, processes them and sends out a reply. Because of the history of the application I'd favor using Qt for this, but all I can find is the other (more common) direction: Send a request to a server and receive a reply using QNetworkAccessManager. What I need is something like a socket that, when a request comes in, produces an object where I can pick url etc. of this request, so I can send out an appropriate reply.

Am I just blind or is nothing like this in the Qt framework? If so, can you recommend alternatives?

grefab
  • 1,997
  • 2
  • 22
  • 32

8 Answers8

16

I found this https://github.com/vinipsmaker/tufao , Its a late answer .. not sure if it helps.

Anand Rathi
  • 790
  • 4
  • 11
15

QtWebApp is a HTTP server with support of GET and POST method, cookies, sessions and file uploads. Using this library is as simple as writing a Java Servlet.

The project website is in german, however the downloadable files are all in english, including the documentation.

blwy10
  • 4,862
  • 2
  • 24
  • 23
Stefan
  • 181
  • 1
  • 2
  • 3
    Nice one, using this for webservices: http://stackoverflow.com/questions/11558237/creating-simple-webservice-in-c-qt-acting-as-server-providing-json-data?lq=1 – Horst Walter Jul 21 '12 at 16:37
  • yep, very nice and easy to modify for own projects. – Zeks Sep 30 '14 at 19:31
14

I have just released the first version of QHttpEngine, which aims to fill the gap that you've described. The goal of the project is to provide an extremely simple set of classes that provide an HTTP server that integrates with Qt.

For example, to serve static files from resources in your application, all you would need to do is:

QFilesystemHandler handler(":/www");
QHttpServer server(&handler);

server.listen(QHostAddress::LocalHost, 8000);

You can also create a class derived from QObject that expose its slots as endpoints in an HTTP API. For example:

class ApiHandler : public QObjectHandler
{
    Q_OBJECT

private slots:

    QVariantMap doSomething(const QVariantMap &params) {
        // do something with the parameters and return a response
    }
};

Users can then send a POST request to /doSomething with the parameters encoded as JSON and receive the response that the slot generates.

The entire library is fully documented and comes with a rather exhaustive test suite. It is cross-platform and is officially tested and supported on Linux, Windows, and Mac OS X. There is at least one major open-source application using QHttpEngine, NitroShare.

Nathan Osman
  • 71,149
  • 71
  • 256
  • 361
10

Here is a very simple HTTP web server that will update the number of seconds, each second, since a connection was made on the web browser. It also displays the data sent by the web browser on the screen. The program is set to use port 8080 e.g 127.0.0.1:8080

#-------------- Project file webServer3.pro ------- 
QT       += core
QT       += network
QT       -= gui

TARGET = webServer3
CONFIG   += console
CONFIG   -= app_bundle

TEMPLATE = app


SOURCES += main.cpp

HEADERS += \
myhttpserver.h

/*------------------header file myhttpserver.h --------------*/ 
#ifndef MYHTTPSERVER
#define MYHTTPSERVER
#include <QCoreApplication>
#include <QNetworkInterface>
#include <iostream>
#include <QObject>
#include <QTcpSocket>
#include <QTcpServer>
#include <QDebug>

class myHTTPserver : public QObject
{
    Q_OBJECT
public:
    explicit myHTTPserver(QObject *parent = 0);
    ~myHTTPserver();
    QTcpSocket *socket ;
public slots:
    void myConnection();
private:
    qint64 bytesAvailable() const;
    QTcpServer *server;
signals:
};


/*------------------------main.cpp -------------------------*/
#include "myhttpserver.h"

using namespace std;
void delayms( int millisecondsToWait );

int main(int argc, char *argv[])
    {
    QCoreApplication a(argc, argv);
    myHTTPserver server;
    return a.exec();
}

myHTTPserver::myHTTPserver(QObject *parent) : QObject(parent)
    {
     server = new QTcpServer(this);
    // waiting for the web brower to make contact,this will emit signal
    connect(server, SIGNAL(newConnection()),this, SLOT(myConnection()));
    if(!server->listen(QHostAddress::Any,8080))cout<< "\nWeb server      could not start";
    else cout<<"\nWeb server is waiting for a connection on port 8080";
}

void myHTTPserver::myConnection()
    {
    static qint16 count;  //count number to be displayed on web browser
    socket = server->nextPendingConnection();
    while(!(socket->waitForReadyRead(100)));  //waiting for data to be read from web browser

    char webBrowerRXData[1000];
    int sv=socket->read(webBrowerRXData,1000);
    cout<<"\nreading web browser data=\n";
    for(int i=0;i<sv;i++)cout<<webBrowerRXData[i];
    cout<<"\n";

    socket->write("HTTP/1.1 200 OK\r\n");       // \r needs to be before \n
    socket->write("Content-Type: text/html\r\n");
    socket->write("Connection: close\r\n");
    socket->write("Refresh: 1\r\n\r\n");     //refreshes web browser     every second. Require two \r\n.

    socket->write("<!DOCTYPE html>\r\n");
    socket->write("<html><body>Number of seconds since connected.. ");
    QByteArray str;
    str.setNum(count++);   //convert int to string
    socket->write(str);
    socket->write(" </body>\n</html>\n");

    socket->flush();
    connect(socket, SIGNAL(disconnected()),socket, SLOT(deleteLater()));
    socket->disconnectFromHost();
}

myHTTPserver::~myHTTPserver()
    {
    socket->close();
}
vk3who
  • 349
  • 2
  • 7
7

QttpServer = Qt + libuv + REST = your API server

For an Qt API server that need to handle a large number of concurrent connections, request, and what-have-you... we have the libuv library.

Though libuv is built for NodeJS, we fans in Qt-land can still benefit from epolls and kqueues instead of the default select method.

See more on github https://github.com/supamii/QttpServer

Son-Huy Pham
  • 1,899
  • 18
  • 19
  • That's the best answer here... after investigating a number of solutions. This solution is simple, based on the right tech's + got clean and simple examples. Going to test it now... – rubmz Jan 16 '17 at 10:15
3

QhttpServer seems to do exactly what you need. unfortunately it does not seem to be very active.

Pierre Rust
  • 2,474
  • 18
  • 15
2

Here is simple Qt server that can be used from QML, pure-JS HTTP processing: https://github.com/ncp1402/ql-server

user2053898
  • 479
  • 1
  • 5
  • 8
2

The above simple server had issues running on MSwindows operating systems as it would lockup after a while. This was due to waitForReadyRead() operating in a random fashion on MS systems. The program below waitForReadyRead() was replaced with an event loop using readyRead() signal.

# Project file
QT       += core
QT       += network
QT       -= gui
TARGET = webServer
CONFIG   += console
CONFIG   -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
HEADERS += myhttpserver.h

//-----------myhttpserver.h--------------   
#ifndef MYHTTPSERVER
#define MYHTTPSERVER
#include <QCoreApplication>
#include <iostream>
#include <QObject>
#include <QTcpSocket>
#include <QTcpServer>
#include <QIODevice>

class myHTTPserver : public QObject
{
    Q_OBJECT
public:
    explicit myHTTPserver(QObject *parent = 0);
    ~myHTTPserver();
    QTcpSocket *socket ;
public slots:
    void myConnection();
    void txRx();
    void closingClient();
private:
    qint64 bytesAvailable() const;
    QTcpServer *server;
};
#endif // MYHTTPSERVER

//------------------------ main.cpp ----------------------  
#include "myhttpserver.h"

using namespace std;

int main(int argc, char *argv[])
    {
    QCoreApplication a(argc, argv);
    myHTTPserver server;
    return a.exec();
}

myHTTPserver::myHTTPserver(QObject *parent) : QObject(parent)
    {
    server = new QTcpServer(this);
    connect(server, SIGNAL(newConnection()),this, SLOT(myConnection()));
    if(!server->listen(QHostAddress::Any,8080))cout<< "\nWeb server     could not start";
    else cout<<"\nWeb server is waiting for a connection on port 8080";
}

void myHTTPserver::myConnection()
    {
    socket = server->nextPendingConnection();
    connect(socket, SIGNAL(readyRead()), this, SLOT(txRx()));
    connect(socket, SIGNAL(disconnected()), this, SLOT(closingClient()));
}
void myHTTPserver::txRx()
    {
    char webBrowerRXData[1000];
    int sv=socket->read(webBrowerRXData,1000);
    cout<<"\nreading web browser data\n";
    for(int i=0;i<sv;i++)cout<<webBrowerRXData[i];
    cout<<"\n";

    socket->write("HTTP/1.1 200 OK\r\n");       // \r needs to be before \n
    socket->write("Content-Type: text/html\r\n");
    socket->write("Connection: close\r\n");
    socket->write("Refresh: 1\r\n");     //refreshes web browser every second. Require two \r\n.
    socket->write("Pragma: no-cache\r\n");
    socket->write("\r\n");
    socket->write("<!DOCTYPE html>\r\n");
    socket->write("<html><body>Number of seconds since connected.. ");
    QByteArray str;
    static qint16 count;  //count number to be displayed on web browser
    str.setNum(count++);   //convert int to string
    socket->write(str);
    socket->disconnectFromHost();
}

void myHTTPserver::closingClient()
    {
        socket->deleteLater();
}

myHTTPserver::~myHTTPserver()
    {
    cout<<"\nclosing socket\n";
    socket->close();
}
vk3who
  • 349
  • 2
  • 7