<commit_before>/*
 * Copyright (C) 2013-2015 <NAME> <<EMAIL>>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "engineuwsgi.h"

#include "bodyuwsgi.h"
#include "bodybuffereduwsgi.h"

#include <QSocketNotifier>

#include <Cutelyst/common.h>
#include <Cutelyst/application.h>
#include <Cutelyst/context.h>
#include <Cutelyst/response.h>
#include <Cutelyst/request_p.h>

Q_LOGGING_CATEGORY(CUTELYST_UWSGI, "cutelyst.uwsgi")

using namespace Cutelyst;

typedef struct {
    QFile *bodyFile;
    BodyUWSGI *bodyUWSGI;
    BodyBufferedUWSGI *bodyBufferedUWSGI;
    RequestPrivate *priv;
    Request *request;
} CachedRequest;

uWSGI::uWSGI(const QVariantHash &opts, Application *app, QObject *parent) : Engine(opts, parent)
  , m_app(app)
{
    connect(this, &uWSGI::postFork,
            this, &uWSGI::forked);
}

uWSGI::~uWSGI()
{
}

void uWSGI::setThread(QThread *thread)
{
    moveToThread(thread);
    connect(thread, &QThread::started,
            this, &uWSGI::forked, Qt::DirectConnection);
}

qint64 uWSGI::doWrite(Context *c, const char *data, qint64 len, void *engineData)
{
    struct wsgi_request *wsgi_req = static_cast<wsgi_request*>(engineData);
    char *block = strdup(data);
    if (uwsgi_response_write_body_do(wsgi_req, block, len) != UWSGI_OK) {
        qCWarning(CUTELYST_UWSGI) << "Failed to write body";
        return -1;
    }
    free(block);
    return len;
}

void uWSGI::readRequestUWSGI(wsgi_request *wsgi_req)
{
    for(;;) {
        int ret = uwsgi_wait_read_req(wsgi_req);
        if (ret <= 0) {
            uwsgi_log("Failed wait read\n");
            goto end;
        }

        int status = wsgi_req->socket->proto(wsgi_req);
        if (status < 0) {
            uwsgi_log("Failed broken socket\n");
            goto end;
        } else if (status == 0) {
            break;
        }
    }

    // empty request ?
    if (!wsgi_req->uh->pktsize) {
        qCDebug(CUTELYST_UWSGI) << "Empty request. skip.";
        uwsgi_log("Failed empty request\n");
        goto end;
    }

    // get uwsgi variables
    if (uwsgi_parse_vars(wsgi_req)) {
        uwsgi_log("Invalid request. skip.\n");
        qCDebug(CUTELYST_UWSGI) << "Invalid request. skip.";
        goto end;
    }

    processRequest(wsgi_req);

end:
    uwsgi_close_request(wsgi_req);
}

void uWSGI::processRequest(wsgi_request *req)
{
    CachedRequest *cache = static_cast<CachedRequest *>(req->async_environ);

    RequestPrivate *priv = cache->priv;
    priv->reset();

    priv->startOfRequest = req->start_of_request;
    priv->https = req->https_len;
    // wsgi_req->uri containg the whole URI it /foo/bar?query=null
    // so we use path_info, maybe it would be better to just build our
    // Request->uri() from it, but we need to run a performance test
    priv->path = QString::fromLatin1(req->path_info + 1, req->path_info_len - 1);

    priv->serverAddress = QString::fromLatin1(req->host, req->host_len);
    priv->query = QByteArray::fromRawData(req->query_string, req->query_string_len);

    priv->method = QString::fromLatin1(req->method, req->method_len);
    priv->protocol = QString::fromLatin1(req->protocol, req->protocol_len);
    priv->remoteAddress = QHostAddress(QString::fromLatin1(req->remote_addr, req->remote_addr_len));
    priv->remoteUser = QString::fromLatin1(req->remote_user, req->remote_user_len);

    uint16_t remote_port_len;
    char *remote_port = uwsgi_get_var(req, (char *) "REMOTE_PORT", 11, &remote_port_len);
    priv->remotePort = QByteArray::fromRawData(remote_port, remote_port_len).toUInt();

    Headers headers;<commit_msg>Avoid crashing is wsgi_request->path_info_len is zero<commit_after>/*
 * Copyright (C) 2013-2015 <NAME> <<EMAIL>>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "engineuwsgi.h"

#include "bodyuwsgi.h"
#include "bodybuffereduwsgi.h"

#include <QSocketNotifier>

#include <Cutelyst/common.h>
#include <Cutelyst/application.h>
#include <Cutelyst/context.h>
#include <Cutelyst/response.h>
#include <Cutelyst/request_p.h>

Q_LOGGING_CATEGORY(CUTELYST_UWSGI, "cutelyst.uwsgi")

using namespace Cutelyst;

typedef struct {
    QFile *bodyFile;
    BodyUWSGI *bodyUWSGI;
    BodyBufferedUWSGI *bodyBufferedUWSGI;
    RequestPrivate *priv;
    Request *request;
} CachedRequest;

uWSGI::uWSGI(const QVariantHash &opts, Application *app, QObject *parent) : Engine(opts, parent)
  , m_app(app)
{
    connect(this, &uWSGI::postFork,
            this, &uWSGI::forked);
}

uWSGI::~uWSGI()
{
}

void uWSGI::setThread(QThread *thread)
{
    moveToThread(thread);
    connect(thread, &QThread::started,
            this, &uWSGI::forked, Qt::DirectConnection);
}

qint64 uWSGI::doWrite(Context *c, const char *data, qint64 len, void *engineData)
{
    struct wsgi_request *wsgi_req = static_cast<wsgi_request*>(engineData);
    char *block = strdup(data);
    if (uwsgi_response_write_body_do(wsgi_req, block, len) != UWSGI_OK) {
        qCWarning(CUTELYST_UWSGI) << "Failed to write body";
        return -1;
    }
    free(block);
    return len;
}

void uWSGI::readRequestUWSGI(wsgi_request *wsgi_req)
{
    for(;;) {
        int ret = uwsgi_wait_read_req(wsgi_req);
        if (ret <= 0) {
            uwsgi_log("Failed wait read\n");
            goto end;
        }

        int status = wsgi_req->socket->proto(wsgi_req);
        if (status < 0) {
            uwsgi_log("Failed broken socket\n");
            goto end;
        } else if (status == 0) {
            break;
        }
    }

    // empty request ?
    if (!wsgi_req->uh->pktsize) {
        qCDebug(CUTELYST_UWSGI) << "Empty request. skip.";
        uwsgi_log("Failed empty request\n");
        goto end;
    }

    // get uwsgi variables
    if (uwsgi_parse_vars(wsgi_req)) {
        uwsgi_log("Invalid request. skip.\n");
        qCDebug(CUTELYST_UWSGI) << "Invalid request. skip.";
        goto end;
    }

    processRequest(wsgi_req);

end:
    uwsgi_close_request(wsgi_req);
}

void uWSGI::processRequest(wsgi_request *req)
{
    CachedRequest *cache = static_cast<CachedRequest *>(req->async_environ);

    RequestPrivate *priv = cache->priv;
    priv->reset();

    priv->startOfRequest = req->start_of_request;
    priv->https = req->https_len;
    // wsgi_req->uri containg the whole URI it /foo/bar?query=null
    // so we use path_info, maybe it would be better to just build our
    // Request->uri() from it, but we need to run a performance test
    if (req->path_info_len) {
        priv->path = QString::fromLatin1(req->path_info + 1, req->path_info_len - 1);
    } else {
        priv->path = QString();
    }

    priv->serverAddress = QString::fromLatin1(req->host, req->host_len);
    priv->query = QByteArray::fromRawData(req->query_string, req->query_string_len);

    priv->method = QString::fromLatin1(req->method, req->method_len);
    priv->protocol = QString::fromLatin1(req->protocol, req->protocol_len);
    priv->remoteAddress = QHostAddress(QString::fromLatin1(req->remote_addr, req->remote_addr_len));
    priv->remoteUser = QString::fromLatin1(req->remote_user, req->remote_user_len);

    uint16_t remote_port_len;
    char *remote_port = uwsgi_get_var(req, (char *) "REMOTE_PORT", 11, &remote_port_len);
    priv->remotePort = QByteArray::fromRawData(remote_port, remote_port_len).toUInt();

    Headers headers;
{'fraction_non_alphanumeric': 0.121302113078241, 'fraction_numerical': 0.009137635636778984, 'mean_word_length': 3.525064599483204, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 98, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4411901', 'n_tokens_mistral': 3059, 'n_tokens_neox': 2923, 'n_words': 733}