mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-03 21:20:31 -05:00 
			
		
		
		
	Found with:
ASAN_OPTIONS="detect_odr_violation=1,strip_path_prefix=$(pwd)/" build/sdrangel
Fixes:
Direct leak of 8 byte(s) in 1 object(s) allocated from:
    #0 0x7efeb72f46b8 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:95
    #1 0x7efe83515718 in WebServer::addSubstitution(QString, QString, QString) sdrangel/plugins/feature/map/webserver.cpp:84
    #2 0x7efe83559c9e in MapGUI::applyMap3DSettings(bool) sdrangel/plugins/feature/map/mapgui.cpp:1789
    #3 0x7efe8355e483 in MapGUI::displaySettings() sdrangel/plugins/feature/map/mapgui.cpp:1964
    #4 0x7efe834be0f6 in MapGUI::MapGUI(PluginAPI*, FeatureUISet*, Feature*, QWidget*) sdrangel/plugins/feature/map/mapgui.cpp:376
    #5 0x7efe835372f4 in MapGUI::create(PluginAPI*, FeatureUISet*, Feature*) sdrangel/plugins/feature/map/mapgui.cpp:66
    #6 0x7efe834b5471 in MapPlugin::createFeatureGUI(FeatureUISet*, Feature*) const sdrangel/plugins/feature/map/mapplugin.cpp:72
    #7 0x7efeb6b416c2 in FeatureUISet::loadFeatureSetSettings(FeatureSetPreset const*, PluginAPI*, WebAPIAdapterInterface*, QList<Workspace*>*, Workspace*) sdrangel/sdrgui/feature/featureuiset.cpp:185
    #8 0x7efeb67e9b41 in MainWindow::loadConfiguration(Configuration const*, bool) sdrangel/sdrgui/mainwindow.cpp:1503
    #9 0x7efeb6730e3e in MainWindow::MainWindow(qtwebapp::LoggerWithFile*, MainParser const&, QWidget*) sdrangel/sdrgui/mainwindow.cpp:257
    #10 0x557281218bad in runQtApplication sdrangel/app/main.cpp:196
    #11 0x5572812194a3 in main sdrangel/app/main.cpp:248
    #12 0x7efeb10456c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
		
	
			
		
			
				
	
	
		
			230 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			230 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
///////////////////////////////////////////////////////////////////////////////////
 | 
						|
// Copyright (C) 2022-2023 Jon Beniston, M7RCE <jon@beniston.com>                //
 | 
						|
//                                                                               //
 | 
						|
// This program is free software; you can redistribute it and/or modify          //
 | 
						|
// it under the terms of the GNU General Public License as published by          //
 | 
						|
// the Free Software Foundation as version 3 of the License, or                  //
 | 
						|
// (at your option) any later version.                                           //
 | 
						|
//                                                                               //
 | 
						|
// This program 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 General Public License V3 for more details.                               //
 | 
						|
//                                                                               //
 | 
						|
// You should have received a copy of the GNU General Public License             //
 | 
						|
// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | 
						|
///////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
#include <QtAlgorithms>
 | 
						|
#include <QResource>
 | 
						|
#include <QFile>
 | 
						|
#include <QRegularExpression>
 | 
						|
#include <QDebug>
 | 
						|
 | 
						|
#include "webserver.h"
 | 
						|
 | 
						|
// port - port to listen on / is listening on. Use 0 for any free port.
 | 
						|
WebServer::WebServer(quint16 &port, QObject* parent) :
 | 
						|
    QTcpServer(parent),
 | 
						|
    m_defaultMimeType("application/octet-stream")
 | 
						|
{
 | 
						|
    listen(QHostAddress::Any, port);
 | 
						|
    port = serverPort();
 | 
						|
    qDebug() << "WebServer on port " << port;
 | 
						|
 | 
						|
    m_mimeTypes.insert(".html", new MimeType("text/html; charset=\"utf-8\"", false));
 | 
						|
    m_mimeTypes.insert(".png", new MimeType("image/png"));
 | 
						|
    m_mimeTypes.insert(".glb", new MimeType("model/gltf-binary"));
 | 
						|
    m_mimeTypes.insert(".glbe", new MimeType("model/gltf-binary"));
 | 
						|
    m_mimeTypes.insert(".js", new MimeType("text/javascript"));
 | 
						|
    m_mimeTypes.insert(".css", new MimeType("text/css"));
 | 
						|
    m_mimeTypes.insert(".json", new MimeType("application/json"));
 | 
						|
    m_mimeTypes.insert(".geojson", new MimeType("application/geo+json"));
 | 
						|
}
 | 
						|
 | 
						|
WebServer::~WebServer()
 | 
						|
{
 | 
						|
    qDeleteAll(m_substitutions);
 | 
						|
    qDeleteAll(m_mimeTypes);
 | 
						|
}
 | 
						|
 | 
						|
void WebServer::incomingConnection(qintptr socket)
 | 
						|
{
 | 
						|
    QTcpSocket* s = new QTcpSocket(this);
 | 
						|
    connect(s, SIGNAL(readyRead()), this, SLOT(readClient()));
 | 
						|
    connect(s, SIGNAL(disconnected()), this, SLOT(discardClient()));
 | 
						|
    s->setSocketDescriptor(socket);
 | 
						|
    //addPendingConnection(socket);
 | 
						|
}
 | 
						|
 | 
						|
// Don't include leading or trailing / in from
 | 
						|
void WebServer::addPathSubstitution(const QString &from, const QString &to)
 | 
						|
{
 | 
						|
    //qDebug() << "Mapping " << from << " to " << to;
 | 
						|
    m_pathSubstitutions.insert(from, to);
 | 
						|
}
 | 
						|
 | 
						|
void WebServer::addSubstitution(QString path, QString from, QString to)
 | 
						|
{
 | 
						|
    Substitution *s = new Substitution(from, to);
 | 
						|
    if (m_substitutions.contains(path))
 | 
						|
    {
 | 
						|
        QList<Substitution *> *list = m_substitutions.value(path);
 | 
						|
        QMutableListIterator<Substitution *> i(*list);
 | 
						|
        while (i.hasNext()) {
 | 
						|
            Substitution *sub = i.next();
 | 
						|
            if (sub->m_from == from) {
 | 
						|
                i.remove();
 | 
						|
                delete sub;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        list->append(s);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        QList<Substitution *> *list = new QList<Substitution *>();
 | 
						|
        list->append(s);
 | 
						|
        m_substitutions.insert(path, list);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
QString WebServer::substitute(QString path, QString html)
 | 
						|
{
 | 
						|
    QList<Substitution *> *list = m_substitutions.value(path);
 | 
						|
    for (const auto s : *list) {
 | 
						|
        html = html.replace(s->m_from, s->m_to);
 | 
						|
    }
 | 
						|
    return html;
 | 
						|
}
 | 
						|
 | 
						|
void WebServer::addFile(const QString &path, const QByteArray &data)
 | 
						|
{
 | 
						|
    m_files.insert(path, data);
 | 
						|
}
 | 
						|
 | 
						|
void WebServer::sendFile(QTcpSocket* socket, const QByteArray &data, MimeType *mimeType, const QString &path)
 | 
						|
{
 | 
						|
    QString header = QString("HTTP/1.0 200 Ok\r\nContent-Type: %1\r\nAccess-Control-Allow-Headers: *\r\nAccess-Control-Allow-Methods: *\r\nAccess-Control-Allow-Origin: *\r\n\r\n").arg(mimeType->m_type);
 | 
						|
    if (mimeType->m_binary)
 | 
						|
    {
 | 
						|
        // Send file as binary
 | 
						|
        QByteArray headerUtf8 = header.toUtf8();
 | 
						|
        socket->write(headerUtf8);
 | 
						|
        socket->write(data);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        // Send file as text
 | 
						|
        QString html = QString(data);
 | 
						|
        // Make any substitutions in the content of the file
 | 
						|
        if (m_substitutions.contains(path)) {
 | 
						|
            html = substitute(path, html);
 | 
						|
        }
 | 
						|
        QTextStream os(socket);
 | 
						|
        os.setAutoDetectUnicode(true);
 | 
						|
        os << header << html;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void WebServer::readClient()
 | 
						|
{
 | 
						|
    QTcpSocket* socket = (QTcpSocket*)sender();
 | 
						|
    if (socket->canReadLine())
 | 
						|
    {
 | 
						|
        QString line = socket->readLine();
 | 
						|
        //qDebug() << "WebServer HTTP Request: " << line;
 | 
						|
 | 
						|
        QStringList tokens = QString(line).split(QRegularExpression("[ \r\n][ \r\n]*"));
 | 
						|
        if (tokens[0] == "GET")
 | 
						|
        {
 | 
						|
            // Get file type from extension
 | 
						|
            QString path = tokens[1];
 | 
						|
            MimeType *mimeType = &m_defaultMimeType;
 | 
						|
            int extensionIdx = path.lastIndexOf(".");
 | 
						|
            if (extensionIdx != -1) {
 | 
						|
                QString extension = path.mid(extensionIdx);
 | 
						|
                if (m_mimeTypes.contains(extension)) {
 | 
						|
                     mimeType = m_mimeTypes[extension];
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            // Try mapping path
 | 
						|
            QStringList dirs = path.split('/');
 | 
						|
            if ((dirs.length() >= 2) && m_pathSubstitutions.contains(dirs[1]))
 | 
						|
            {
 | 
						|
                dirs[1] = m_pathSubstitutions.value(dirs[1]);
 | 
						|
                dirs.removeFirst();
 | 
						|
                QString newPath = dirs.join('/');
 | 
						|
                //qDebug() << "Mapping " << path << " to " << newPath;
 | 
						|
                path = newPath;
 | 
						|
            }
 | 
						|
 | 
						|
            // See if we can find the file in our resources
 | 
						|
            QResource res(path);
 | 
						|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
 | 
						|
            if (res.isValid() && (res.uncompressedSize() > 0))
 | 
						|
            {
 | 
						|
                QByteArray data = res.uncompressedData();
 | 
						|
                sendFile(socket, data, mimeType, path);
 | 
						|
            }
 | 
						|
#else
 | 
						|
            if (res.isValid() && (res.size() > 0))
 | 
						|
            {
 | 
						|
                QByteArray data = QByteArray::fromRawData((const char *)res.data(), res.size());
 | 
						|
                if (res.isCompressed()) {
 | 
						|
                    data = qUncompress(data);
 | 
						|
                }
 | 
						|
                sendFile(socket, data, mimeType, path);
 | 
						|
            }
 | 
						|
#endif
 | 
						|
            else if (m_files.contains(path))
 | 
						|
            {
 | 
						|
                // Path is a file held in memory
 | 
						|
                sendFile(socket, m_files.value(path).data(), mimeType, path);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                // See if we can find a file on disk
 | 
						|
                QFile file(path);
 | 
						|
                if (file.open(QIODevice::ReadOnly))
 | 
						|
                {
 | 
						|
                    QByteArray data = file.readAll();
 | 
						|
                    if (path.endsWith(".glbe")) {
 | 
						|
                        for (int i = 0; i < data.size(); i++) {
 | 
						|
                            data[i] = data[i] ^ 0x55;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    sendFile(socket, data, mimeType, path);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    qDebug() << "WebServer " << path << " not found";
 | 
						|
                    // File not found
 | 
						|
                    QTextStream os(socket);
 | 
						|
                    os.setAutoDetectUnicode(true);
 | 
						|
                    os << "HTTP/1.0 404 Not Found\r\n"
 | 
						|
                        "Content-Type: text/html; charset=\"utf-8\"\r\n"
 | 
						|
                        "\r\n"
 | 
						|
                        "<html>\n"
 | 
						|
                        "<body>\n"
 | 
						|
                        "<h1>404 Not Found</h1>\n"
 | 
						|
                        "</body>\n"
 | 
						|
                        "</html>\n";
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            socket->close();
 | 
						|
 | 
						|
            if (socket->state() == QTcpSocket::UnconnectedState) {
 | 
						|
                delete socket;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void WebServer::discardClient()
 | 
						|
{
 | 
						|
    QTcpSocket* socket = (QTcpSocket*)sender();
 | 
						|
    socket->deleteLater();
 | 
						|
}
 |