Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

threaded with router and map my owner handler run crash when open url. #55

Open
kingctan opened this issue Nov 3, 2014 · 9 comments
Open

Comments

@kingctan
Copy link

kingctan commented Nov 3, 2014

code below, MainHandler just copy from your other example.

    TcpServer server;
//    MainHandler h;

    server.run(4, 8090, []() {
        QSharedPointer<Tufao::HttpServerRequestRouter> router;

        return [router](Tufao::HttpServerRequest &request,
                Tufao::HttpServerResponse &response) mutable {
            if (!router) {
                MainHandler h;
                router.reset(new Tufao::HttpServerRequestRouter);
                router->map({QRegularExpression{"^/$"},
                             Tufao::UrlRewriterHandler::handler(QUrl("/index.html"))});
                router->map({QRegularExpression{""}, h});
            }

            if (!router->handleRequest(request, response)) {
                response.writeHead(Tufao::HttpResponseStatus::NOT_FOUND);
                response.headers().insert("Content-Type", "text/plain");
                response.end("Not found\n");
            }

            return true;
        };
    });
@Kalileo
Copy link

Kalileo commented Nov 20, 2015

I can confirm this issue. I tried exactly the same, integrating the custom handler Mainhandler from the request-dumper example into the threads-with-router-example.
In other words, replacing the Tufao::HttpFileServer::handler("public") in router->map with this Mainhandler.
Same result as kingctan, crash. Interestingly most of the time not at the first browser request, but at the 2nd.

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    TcpServer server;

    server.run(4, 8080, []() {
        QSharedPointer<Tufao::HttpServerRequestRouter> router;
        MainHandler h;

        return [router](Tufao::HttpServerRequest &request,
                        Tufao::HttpServerResponse &response) mutable {
            if (!router) {
                router.reset(new Tufao::HttpServerRequestRouter);
                router->map({QRegularExpression{"^/([^/]+)"}, h});
            }

            if (!router->handleRequest(request, response)) {
                response.writeHead(Tufao::HttpResponseStatus::NOT_FOUND);
                response.headers().insert("Content-Type", "text/plain");
                response.end("404 Not found.\n");
            }

            return true;
        };
    });

    return a.exec();
}

Reducing to 1 worker thread ("server.run(1, 8080...") did not help.
The original example threads-with-router-example works fine, as well as all the other examples.

Unfortunately this is a showstopper.

Is there something wrong with this approach?
Or is there any other way to run multiple workers / threads and custom handlers?

@Kalileo
Copy link

Kalileo commented Nov 20, 2015

Qt 5.5.1 on Mac OS X (deployment will be on Linux though).

@Kalileo
Copy link

Kalileo commented Nov 21, 2015

Tested on linux, and the same problem, crashing as soon as a Url is requested which matches the QRegularExpression - unlike on Mac, where the first request still works.

There is some debug output on linux, when it crashes:

pure virtual method called
terminate called without an active exception
The program has unexpectedly finished.

Valgrind does not give more output than that.

In QtCreator, run in debug mode, this is where it stands after crashing:

inline AbstractHttpServerRequestHandler::operator
std::function<bool(HttpServerRequest&, HttpServerResponse&)>()
{
    return [this](HttpServerRequest &req, HttpServerResponse &res) {
        return this->handleRequest(req, res);
    };   <<=== here
}

I hope that gives enough info to fix it. Otherwise please ask.

@Kalileo
Copy link

Kalileo commented Nov 21, 2015

As a humble workaround, while waiting for the official fix, you can move the functionality of the lambda in main() at server.run(4, 8080, {...}) to the Worker class, eliminating all Factory() and setFactory() stuff in Worker and TcpServer, as well as the router. Then it works multithreaded.

Main changes below:

In main.cpp :

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

In worker.cpp call myHandler(*request, *response); instead of handler(*request, *response); :

bool Worker::myHandler(HttpServerRequest &request,
                       HttpServerResponse &response)
{
    const QString path(request.url().path());
    QRegularExpression re = QRegularExpression("^/([^/]+)......."); // change to what you need
    QRegularExpressionMatch match(re.match(path));

    if (request.method() == "GET" && match.hasMatch())
    {
        QStringList args{match.capturedTexts().mid(1)};
        QVariant backup{request.customData()};

        if (args.size()) {
            QVariantMap options{backup.toMap()};
            options["args"] = options["ags"].toStringList() + args;
            request.setCustomData(options);
        }

        // defined in worker.h:  MainHandler h;

        if (h.handleRequest(request, response))
            return true;

        if (args.size())
            request.setCustomData(backup);
    }

    response.writeHead(Tufao::HttpResponseStatus::NOT_FOUND);
    response.headers().insert("Content-Type", "text/plain");
    response.end("404 Not found.\n");

    return true;
}

It might be nice to get the router functionality back in, I skipped that here in favour of a simple workaround.

imho having the handler code in the worker instead of in main is not less efficient, with the lambda in main and the setFactory stuff it ends up there anyway.

@vinipsmaker
Copy link
Owner

Mainhandler from the request-dumper example into the threads-with-router-example.

It inherits QObject. You should not copy them, but you created them in the beginning of the block and copied it during the map call? Just a hint about what might be happening.

while waiting for the official fix

This is a malformed combination of two different examples. I don't claim an abstraction here being thread-safe when it's not. Examples are learning material to speedup your understanding. Not sure what to fix here.

@Kalileo
Copy link

Kalileo commented Dec 8, 2015

You should not copy them, but you created them in the beginning of the block and copied it during the map call?

Yes, see first code sample above.

a malformed combination of two different examples.

What would be a better example to combine the threads-with-router-example and handlers? I think such a combination is needed for any server doing more than just serving a few more or less static files or bytes of html. Especially also when handling file uploads.

Not sure what to fix here.

There might be nothing to fix in the server code, but just to show the correct way of doing it, an example for this not so uncommon use case.

Also I think that you laid the foundation to a beautiful server. I've played around with some handlers for our main use cases, and it's fun and easy.

@vinipsmaker
Copy link
Owner

There might be nothing to fix in the server code, but just to show the correct way of doing it, an example for this not so uncommon use case.

That's a starting point. Thanks.

@Kalileo
Copy link

Kalileo commented Jan 4, 2016

Just to make sure that the issue reported here is not misunderstood as a general problem with Tufao: a multithreaded server application with router and many handlers, based on the code as I posted it above, is currently in production test and so far no issues at all, rock solid, without a single change or issue in the Tufao code, and faaaast!
@vinipsmaker / Vinícius dos Santos Oliveira: Big thanks for Tufao!

@vinipsmaker
Copy link
Owner

Big thanks for Tufao!

You're welcome

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants