2013-06-21 17:21:11 -05:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// pgAdmin 4 - PostgreSQL Tools
|
|
|
|
//
|
2018-01-05 04:42:49 -06:00
|
|
|
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
2013-06-21 17:21:11 -05:00
|
|
|
// This software is released under the PostgreSQL Licence
|
|
|
|
//
|
|
|
|
// Server.cpp - Thread in which the web server will run.
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include "pgAdmin4.h"
|
2018-09-14 08:41:52 -05:00
|
|
|
#include "Logger.h"
|
2013-06-21 17:21:11 -05:00
|
|
|
|
|
|
|
// Must be before QT
|
|
|
|
#include <Python.h>
|
|
|
|
|
|
|
|
// QT headers
|
2013-06-21 17:32:32 -05:00
|
|
|
#include <QDebug>
|
|
|
|
#include <QDir>
|
2018-03-21 06:27:59 -05:00
|
|
|
#include <QFile>
|
2013-06-21 17:21:11 -05:00
|
|
|
#include <QMessageBox>
|
|
|
|
|
|
|
|
// App headers
|
|
|
|
#include "Server.h"
|
|
|
|
|
2016-06-20 12:33:57 -05:00
|
|
|
static void add_to_path(QString &python_path, QString path, bool prepend=false)
|
2016-06-20 10:52:41 -05:00
|
|
|
{
|
|
|
|
if (!python_path.contains(path))
|
|
|
|
{
|
|
|
|
if (!prepend)
|
|
|
|
{
|
Resolved an issue finding the python interpreter on *nix systems, and
Windows 2008 R2 (32 bit), while running the pgAdmin 4 as runtime for
the PostgreSQL one click installers.
- Found a typo in runtime code, we were appending the path using ';' on
*nix systems too. We should have used ':', and that did not allow the
os.environ['PATH'] to identify the correct path of the python
interpreter under the 'venv' directory.
- On Windows 2008, it was not honouring the environment variables, set
under the Qt application (e.g. pgAdmin4.exe runtime), in the python
application. (e.g. pgAdmin4.py). We will need to assume that - the
python interpreter resides under the 'venv' directory outside the
'bin' directory.
- Also, on windows 2008, it was setting PYTHONHOME environment variable
to the full path of the pgAdmin4.exe, we need to reset it to 'venv'
directory, if we find the python interpreter under it.
Thanks Murtuza Zabuawala for tips, and help.
2017-03-10 09:46:13 -06:00
|
|
|
#if defined(Q_OS_WIN)
|
2016-06-20 10:52:41 -05:00
|
|
|
if (!python_path.isEmpty() && !python_path.endsWith(";"))
|
|
|
|
python_path.append(";");
|
Resolved an issue finding the python interpreter on *nix systems, and
Windows 2008 R2 (32 bit), while running the pgAdmin 4 as runtime for
the PostgreSQL one click installers.
- Found a typo in runtime code, we were appending the path using ';' on
*nix systems too. We should have used ':', and that did not allow the
os.environ['PATH'] to identify the correct path of the python
interpreter under the 'venv' directory.
- On Windows 2008, it was not honouring the environment variables, set
under the Qt application (e.g. pgAdmin4.exe runtime), in the python
application. (e.g. pgAdmin4.py). We will need to assume that - the
python interpreter resides under the 'venv' directory outside the
'bin' directory.
- Also, on windows 2008, it was setting PYTHONHOME environment variable
to the full path of the pgAdmin4.exe, we need to reset it to 'venv'
directory, if we find the python interpreter under it.
Thanks Murtuza Zabuawala for tips, and help.
2017-03-10 09:46:13 -06:00
|
|
|
#else
|
|
|
|
if (!python_path.isEmpty() && !python_path.endsWith(":"))
|
|
|
|
python_path.append(":");
|
|
|
|
#endif
|
2016-06-20 10:52:41 -05:00
|
|
|
|
|
|
|
python_path.append(path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Resolved an issue finding the python interpreter on *nix systems, and
Windows 2008 R2 (32 bit), while running the pgAdmin 4 as runtime for
the PostgreSQL one click installers.
- Found a typo in runtime code, we were appending the path using ';' on
*nix systems too. We should have used ':', and that did not allow the
os.environ['PATH'] to identify the correct path of the python
interpreter under the 'venv' directory.
- On Windows 2008, it was not honouring the environment variables, set
under the Qt application (e.g. pgAdmin4.exe runtime), in the python
application. (e.g. pgAdmin4.py). We will need to assume that - the
python interpreter resides under the 'venv' directory outside the
'bin' directory.
- Also, on windows 2008, it was setting PYTHONHOME environment variable
to the full path of the pgAdmin4.exe, we need to reset it to 'venv'
directory, if we find the python interpreter under it.
Thanks Murtuza Zabuawala for tips, and help.
2017-03-10 09:46:13 -06:00
|
|
|
#if defined(Q_OS_WIN)
|
2016-06-20 10:52:41 -05:00
|
|
|
if (!python_path.isEmpty() && !python_path.startsWith(";"))
|
|
|
|
python_path.prepend(";");
|
Resolved an issue finding the python interpreter on *nix systems, and
Windows 2008 R2 (32 bit), while running the pgAdmin 4 as runtime for
the PostgreSQL one click installers.
- Found a typo in runtime code, we were appending the path using ';' on
*nix systems too. We should have used ':', and that did not allow the
os.environ['PATH'] to identify the correct path of the python
interpreter under the 'venv' directory.
- On Windows 2008, it was not honouring the environment variables, set
under the Qt application (e.g. pgAdmin4.exe runtime), in the python
application. (e.g. pgAdmin4.py). We will need to assume that - the
python interpreter resides under the 'venv' directory outside the
'bin' directory.
- Also, on windows 2008, it was setting PYTHONHOME environment variable
to the full path of the pgAdmin4.exe, we need to reset it to 'venv'
directory, if we find the python interpreter under it.
Thanks Murtuza Zabuawala for tips, and help.
2017-03-10 09:46:13 -06:00
|
|
|
#else
|
|
|
|
if (!python_path.isEmpty() && !python_path.startsWith(":"))
|
|
|
|
python_path.prepend(":");
|
|
|
|
#endif
|
2016-06-20 10:52:41 -05:00
|
|
|
|
|
|
|
python_path.prepend(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-05 09:32:14 -06:00
|
|
|
Server::Server(quint16 port, QString key, QString logFileName)
|
2016-06-02 07:56:56 -05:00
|
|
|
{
|
2017-03-06 08:53:49 -06:00
|
|
|
// Appserver port etc
|
2013-10-04 11:12:10 -05:00
|
|
|
m_port = port;
|
2017-03-06 08:53:49 -06:00
|
|
|
m_key = key;
|
2018-02-05 09:32:14 -06:00
|
|
|
m_logFileName = logFileName;
|
2018-12-06 04:17:47 -06:00
|
|
|
m_wcAppName = nullptr;
|
|
|
|
m_wcPythonHome = nullptr;
|
2013-10-04 11:12:10 -05:00
|
|
|
|
2013-06-21 17:21:11 -05:00
|
|
|
// Initialise Python
|
2016-01-18 08:33:28 -06:00
|
|
|
Py_NoSiteFlag=1;
|
2017-06-11 08:34:49 -05:00
|
|
|
Py_NoUserSiteDirectory=1;
|
2016-06-16 05:30:23 -05:00
|
|
|
Py_DontWriteBytecodeFlag=1;
|
2016-01-18 08:33:28 -06:00
|
|
|
|
2017-03-28 07:26:16 -05:00
|
|
|
PGA_APP_NAME_UTF8 = PGA_APP_NAME.toUtf8();
|
|
|
|
|
2016-01-18 08:33:28 -06:00
|
|
|
// Python3 requires conversion of char * to wchar_t *, so...
|
|
|
|
#ifdef PYTHON2
|
2017-03-28 07:26:16 -05:00
|
|
|
Py_SetProgramName(PGA_APP_NAME_UTF8.data());
|
2016-01-18 08:33:28 -06:00
|
|
|
#else
|
2017-03-28 07:26:16 -05:00
|
|
|
char *appName = PGA_APP_NAME_UTF8.data();
|
2016-01-18 08:33:28 -06:00
|
|
|
const size_t cSize = strlen(appName)+1;
|
|
|
|
m_wcAppName = new wchar_t[cSize];
|
|
|
|
mbstowcs (m_wcAppName, appName, cSize);
|
|
|
|
Py_SetProgramName(m_wcAppName);
|
|
|
|
#endif
|
|
|
|
|
2014-12-16 06:53:09 -06:00
|
|
|
// Setup the search path
|
|
|
|
QSettings settings;
|
|
|
|
QString python_path = settings.value("PythonPath").toString();
|
|
|
|
|
2016-06-20 10:52:41 -05:00
|
|
|
// Get the application directory
|
2016-08-16 05:29:42 -05:00
|
|
|
QString app_dir = qApp->applicationDirPath(),
|
|
|
|
path_env = qgetenv("PATH"),
|
|
|
|
pythonHome;
|
2016-06-21 07:53:32 -05:00
|
|
|
QStringList path_list;
|
|
|
|
int i;
|
2016-06-20 10:52:41 -05:00
|
|
|
|
|
|
|
#ifdef Q_OS_MAC
|
2016-06-02 07:56:56 -05:00
|
|
|
// In the case we're running in a release appbundle, we need to ensure the
|
|
|
|
// bundled virtual env is included in the Python path. We include it at the
|
|
|
|
// end, so expert users can override the path, but we do not save it, because
|
|
|
|
// if users move the app bundle, we'll end up with dead entries
|
|
|
|
|
|
|
|
// Build (and canonicalise) the virtual environment path
|
2016-06-20 10:52:41 -05:00
|
|
|
QFileInfo venvBinPath(app_dir + "/../Resources/venv/bin");
|
|
|
|
QFileInfo venvLibPath(app_dir + "/../Resources/venv/lib/python");
|
|
|
|
QFileInfo venvDynLibPath(app_dir + "/../Resources/venv/lib/python/lib-dynload");
|
|
|
|
QFileInfo venvSitePackagesPath(app_dir + "/../Resources/venv/lib/python/site-packages");
|
2016-08-16 05:29:42 -05:00
|
|
|
QFileInfo venvPath(app_dir + "/../Resources/venv");
|
2016-06-02 07:56:56 -05:00
|
|
|
|
2016-06-20 10:52:41 -05:00
|
|
|
// Prepend the bin directory to the path
|
|
|
|
add_to_path(path_env, venvBinPath.canonicalFilePath(), true);
|
2016-06-02 07:56:56 -05:00
|
|
|
// Append the path, if it's not already there
|
2016-06-20 10:52:41 -05:00
|
|
|
add_to_path(python_path, venvLibPath.canonicalFilePath());
|
|
|
|
add_to_path(python_path, venvDynLibPath.canonicalFilePath());
|
|
|
|
add_to_path(python_path, venvSitePackagesPath.canonicalFilePath());
|
2016-08-16 05:29:42 -05:00
|
|
|
add_to_path(pythonHome, venvPath.canonicalFilePath());
|
2016-06-21 05:15:08 -05:00
|
|
|
#elif defined(Q_OS_WIN)
|
2016-06-16 07:07:35 -05:00
|
|
|
|
|
|
|
// In the case we're running in a release application, we need to ensure the
|
|
|
|
// bundled virtual env is included in the Python path. We include it at the
|
|
|
|
// end, so expert users can override the path, but we do not save it.
|
|
|
|
|
|
|
|
// Build (and canonicalise) the virtual environment path
|
2016-06-21 07:08:15 -05:00
|
|
|
QFileInfo venvBinPath(app_dir + "/../venv");
|
|
|
|
QFileInfo venvLibPath(app_dir + "/../venv/Lib");
|
|
|
|
QFileInfo venvDLLsPath(app_dir + "/../venv/DLLs");
|
|
|
|
QFileInfo venvSitePackagesPath(app_dir + "/../venv/Lib/site-packages");
|
2016-08-16 05:29:42 -05:00
|
|
|
QFileInfo venvPath(app_dir + "/../venv");
|
2016-06-16 07:07:35 -05:00
|
|
|
|
2016-06-20 10:52:41 -05:00
|
|
|
// Prepend the bin directory to the path
|
|
|
|
add_to_path(path_env, venvBinPath.canonicalFilePath(), true);
|
2016-06-16 10:21:55 -05:00
|
|
|
// Append paths, if they're not already there
|
2016-06-20 10:52:41 -05:00
|
|
|
add_to_path(python_path, venvLibPath.canonicalFilePath());
|
|
|
|
add_to_path(python_path, venvDLLsPath.canonicalFilePath());
|
|
|
|
add_to_path(python_path, venvSitePackagesPath.canonicalFilePath());
|
2016-08-16 05:29:42 -05:00
|
|
|
add_to_path(pythonHome, venvPath.canonicalFilePath());
|
2016-06-20 10:52:41 -05:00
|
|
|
#else
|
|
|
|
// Build (and canonicalise) the virtual environment path
|
|
|
|
QFileInfo venvBinPath(app_dir + "/../venv/bin");
|
|
|
|
QFileInfo venvLibPath(app_dir + "/../venv/lib/python");
|
|
|
|
QFileInfo venvDynLibPath(app_dir + "/../venv/lib/python/lib-dynload");
|
|
|
|
QFileInfo venvSitePackagesPath(app_dir + "/../venv/lib/python/site-packages");
|
2016-08-16 05:29:42 -05:00
|
|
|
QFileInfo venvPath(app_dir + "/../venv");
|
2016-06-16 10:21:55 -05:00
|
|
|
|
2016-06-20 10:52:41 -05:00
|
|
|
// Prepend the bin directory to the path
|
|
|
|
add_to_path(path_env, venvBinPath.canonicalFilePath(), true);
|
|
|
|
// Append the path, if it's not already there
|
|
|
|
add_to_path(python_path, venvLibPath.canonicalFilePath());
|
|
|
|
add_to_path(python_path, venvDynLibPath.canonicalFilePath());
|
|
|
|
add_to_path(python_path, venvSitePackagesPath.canonicalFilePath());
|
2016-08-16 05:29:42 -05:00
|
|
|
add_to_path(pythonHome, venvPath.canonicalFilePath());
|
2016-06-02 07:56:56 -05:00
|
|
|
#endif
|
|
|
|
|
2016-06-21 04:31:09 -05:00
|
|
|
qputenv("PATH", path_env.toUtf8().data());
|
2016-06-20 10:52:41 -05:00
|
|
|
|
2014-12-16 06:53:09 -06:00
|
|
|
if (python_path.length() > 0)
|
|
|
|
{
|
2016-01-12 07:50:49 -06:00
|
|
|
// Split the path setting into individual entries
|
2016-06-21 07:53:32 -05:00
|
|
|
path_list = python_path.split(";", QString::SkipEmptyParts);
|
2016-06-21 04:31:09 -05:00
|
|
|
python_path = QString();
|
2016-01-12 07:50:49 -06:00
|
|
|
|
|
|
|
// Add new additional path elements
|
2016-06-21 07:53:32 -05:00
|
|
|
for (i = path_list.size() - 1; i >= 0 ; --i)
|
2016-01-18 08:33:28 -06:00
|
|
|
{
|
2016-06-21 04:31:09 -05:00
|
|
|
python_path.append(path_list.at(i));
|
|
|
|
if (i > 0)
|
|
|
|
{
|
2016-06-21 05:15:08 -05:00
|
|
|
#if defined(Q_OS_WIN)
|
2016-06-21 04:31:09 -05:00
|
|
|
python_path.append(";");
|
2016-01-18 08:33:28 -06:00
|
|
|
#else
|
2016-06-21 04:31:09 -05:00
|
|
|
python_path.append(":");
|
2016-01-18 08:33:28 -06:00
|
|
|
#endif
|
2016-06-21 04:31:09 -05:00
|
|
|
}
|
2016-01-18 08:33:28 -06:00
|
|
|
}
|
2016-06-21 04:31:09 -05:00
|
|
|
qputenv("PYTHONPATH", python_path.toUtf8().data());
|
2014-12-16 06:53:09 -06:00
|
|
|
}
|
2016-06-16 10:21:55 -05:00
|
|
|
|
2016-08-16 05:29:42 -05:00
|
|
|
qDebug() << "Python path: " << python_path
|
|
|
|
<< "\nPython Home: " << pythonHome;
|
2018-09-14 08:41:52 -05:00
|
|
|
|
|
|
|
Logger::GetLogger()->Log(QString("Python Path: %1").arg(python_path));
|
|
|
|
Logger::GetLogger()->Log(QString("Python Home: %1").arg(pythonHome));
|
|
|
|
|
2016-08-16 05:29:42 -05:00
|
|
|
if (!pythonHome.isEmpty())
|
|
|
|
{
|
2017-03-28 07:26:16 -05:00
|
|
|
pythonHome_utf8 = pythonHome.toUtf8();
|
2016-08-16 05:29:42 -05:00
|
|
|
#ifdef PYTHON2
|
2017-03-28 07:26:16 -05:00
|
|
|
Py_SetPythonHome(pythonHome_utf8.data());
|
2016-08-16 05:29:42 -05:00
|
|
|
#else
|
2017-03-28 07:26:16 -05:00
|
|
|
char *python_home = pythonHome_utf8.data();
|
2016-08-16 05:29:42 -05:00
|
|
|
const size_t cSize = strlen(python_home) + 1;
|
2017-03-28 07:26:16 -05:00
|
|
|
m_wcPythonHome = new wchar_t[cSize];
|
2017-03-28 07:55:38 -05:00
|
|
|
mbstowcs (m_wcPythonHome, python_home, cSize);
|
2016-06-16 10:21:55 -05:00
|
|
|
|
2017-03-28 07:26:16 -05:00
|
|
|
Py_SetPythonHome(m_wcPythonHome);
|
2016-08-16 05:29:42 -05:00
|
|
|
#endif
|
|
|
|
}
|
2016-06-21 04:31:09 -05:00
|
|
|
|
2018-09-14 08:41:52 -05:00
|
|
|
Logger::GetLogger()->Log("Initializing Python...");
|
2016-06-21 04:31:09 -05:00
|
|
|
Py_Initialize();
|
2018-09-14 08:41:52 -05:00
|
|
|
Logger::GetLogger()->Log("Python initialized.");
|
2016-06-21 07:53:32 -05:00
|
|
|
|
|
|
|
// Get the current path
|
2018-12-06 04:36:57 -06:00
|
|
|
PyObject* sysPath = PySys_GetObject(const_cast<char *>("path"));
|
2018-12-06 04:17:47 -06:00
|
|
|
if (sysPath != nullptr)
|
2016-06-21 07:53:32 -05:00
|
|
|
{
|
2018-09-17 04:46:48 -05:00
|
|
|
// Add new additional path elements
|
|
|
|
Logger::GetLogger()->Log("Adding new additional path elements");
|
|
|
|
for (i = path_list.size() - 1; i >= 0 ; --i)
|
|
|
|
{
|
2016-06-21 07:53:32 -05:00
|
|
|
#ifdef PYTHON2
|
2018-09-17 04:46:48 -05:00
|
|
|
PyList_Append(sysPath, PyString_FromString(path_list.at(i).toUtf8().data()));
|
2016-06-21 07:53:32 -05:00
|
|
|
#else
|
|
|
|
#if PY_MINOR_VERSION > 2
|
2018-09-17 04:46:48 -05:00
|
|
|
PyList_Append(sysPath, PyUnicode_DecodeFSDefault(path_list.at(i).toUtf8().data()));
|
2016-06-21 07:53:32 -05:00
|
|
|
#else
|
2018-09-17 04:46:48 -05:00
|
|
|
PyList_Append(sysPath, PyBytes_FromString(path_list.at(i).toUtf8().data()));
|
2016-06-21 07:53:32 -05:00
|
|
|
#endif
|
|
|
|
#endif
|
2018-09-17 04:46:48 -05:00
|
|
|
}
|
2016-06-21 07:53:32 -05:00
|
|
|
}
|
2018-09-17 04:46:48 -05:00
|
|
|
else
|
|
|
|
Logger::GetLogger()->Log("Unable to get the current path.");
|
2018-02-05 09:32:14 -06:00
|
|
|
|
|
|
|
// Redirect stderr
|
2018-09-14 08:41:52 -05:00
|
|
|
Logger::GetLogger()->Log("Redirecting stderr...");
|
2018-02-05 09:32:14 -06:00
|
|
|
PyObject *sys = PyImport_ImportModule("sys");
|
2018-12-06 04:17:47 -06:00
|
|
|
if (sys != nullptr)
|
2018-09-17 04:46:48 -05:00
|
|
|
{
|
2018-12-06 04:17:47 -06:00
|
|
|
PyObject *err = nullptr;
|
2018-02-19 11:06:01 -06:00
|
|
|
#ifdef PYTHON2
|
2018-09-17 04:46:48 -05:00
|
|
|
err = PyFile_FromString(m_logFileName.toUtf8().data(), (char *)"w");
|
2018-02-19 11:06:01 -06:00
|
|
|
#else
|
2018-12-06 04:17:47 -06:00
|
|
|
FILE *log = nullptr;
|
2018-09-18 09:08:31 -05:00
|
|
|
|
|
|
|
#if defined(Q_OS_WIN)
|
|
|
|
char *logFile = m_logFileName.toUtf8().data();
|
|
|
|
size_t fileSize = strlen(logFile) + 1;
|
|
|
|
wchar_t * wcLogFileName = new wchar_t[fileSize];
|
|
|
|
mbstowcs (wcLogFileName, logFile, fileSize);
|
|
|
|
|
|
|
|
log = _wfopen(wcLogFileName, (wchar_t *)"w");
|
|
|
|
#else
|
2018-12-06 04:36:57 -06:00
|
|
|
log = fopen(m_logFileName.toUtf8().data(), const_cast<char *>("w"));
|
2018-09-18 09:08:31 -05:00
|
|
|
#endif
|
2018-12-06 04:17:47 -06:00
|
|
|
if (log != nullptr)
|
2018-09-17 04:46:48 -05:00
|
|
|
{
|
|
|
|
int fd = fileno(log);
|
2018-12-06 04:36:57 -06:00
|
|
|
err = PyFile_FromFd(fd, nullptr, const_cast<char *>("w"), -1, nullptr, nullptr, nullptr, 0);
|
2018-09-17 04:46:48 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
Logger::GetLogger()->Log(QString("Failed to open log file: %1").arg(m_logFileName));
|
2018-09-18 09:08:31 -05:00
|
|
|
|
|
|
|
#if defined(Q_OS_WIN)
|
|
|
|
if (wcLogFileName != NULL)
|
|
|
|
{
|
|
|
|
delete wcLogFileName;
|
|
|
|
wcLogFileName = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2018-02-19 10:30:43 -06:00
|
|
|
#endif
|
2018-09-17 04:46:48 -05:00
|
|
|
QFile(m_logFileName).setPermissions(QFile::ReadOwner|QFile::WriteOwner);
|
2018-12-06 04:17:47 -06:00
|
|
|
if (err != nullptr)
|
2018-09-17 04:46:48 -05:00
|
|
|
{
|
|
|
|
PyObject_SetAttrString(sys, "stderr", err);
|
|
|
|
Logger::GetLogger()->Log("stderr redirected successfully.");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Logger::GetLogger()->Log(QString("Failed to get the file pointer of: %1 ").arg(m_logFileName));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Logger::GetLogger()->Log("Failed to import 'sys' module.");
|
2013-06-21 17:21:11 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Server::~Server()
|
|
|
|
{
|
2016-01-18 08:33:28 -06:00
|
|
|
if (m_wcAppName)
|
|
|
|
delete m_wcAppName;
|
|
|
|
|
2017-03-28 07:26:16 -05:00
|
|
|
if (m_wcPythonHome)
|
|
|
|
delete m_wcPythonHome;
|
|
|
|
|
2013-06-21 17:21:11 -05:00
|
|
|
// Shutdown Python
|
|
|
|
Py_Finalize();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Server::Init()
|
|
|
|
{
|
2016-01-19 04:26:01 -06:00
|
|
|
QSettings settings;
|
|
|
|
|
2013-06-21 17:21:11 -05:00
|
|
|
// Find the webapp
|
|
|
|
QStringList paths;
|
2016-02-02 07:16:01 -06:00
|
|
|
paths.append("../web/"); // Linux source tree
|
|
|
|
paths.append("../../web/"); // Windows source tree
|
2016-05-10 10:38:28 -05:00
|
|
|
paths.append("../../../../web/"); // Mac source tree (in a dev env)
|
2016-06-21 07:08:15 -05:00
|
|
|
#ifdef Q_OS_MAC
|
2016-05-10 10:38:28 -05:00
|
|
|
paths.append("../Resources/web/"); // Mac source tree (in a release app bundle)
|
2016-06-02 07:56:56 -05:00
|
|
|
#endif
|
2016-01-19 04:26:01 -06:00
|
|
|
paths.append(settings.value("ApplicationPath").toString()); // System configured value
|
2013-06-21 17:21:11 -05:00
|
|
|
paths.append(""); // Should be last!
|
|
|
|
|
|
|
|
for (int i = 0; i < paths.size(); ++i)
|
|
|
|
{
|
2016-12-01 20:10:08 -06:00
|
|
|
QDir dir;
|
|
|
|
|
|
|
|
if (paths[i].startsWith('/'))
|
|
|
|
dir = paths[i];
|
|
|
|
else
|
|
|
|
dir = QCoreApplication::applicationDirPath() + "/" + paths[i];
|
|
|
|
|
2013-06-21 17:21:11 -05:00
|
|
|
m_appfile = dir.canonicalPath() + "/pgAdmin4.py";
|
|
|
|
|
|
|
|
if (QFile::exists(m_appfile))
|
|
|
|
{
|
|
|
|
qDebug() << "Webapp path: " << m_appfile;
|
2018-09-14 08:41:52 -05:00
|
|
|
Logger::GetLogger()->Log(QString("Webapp Path: %1").arg(m_appfile));
|
2013-06-21 17:21:11 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!QFile::exists(m_appfile))
|
|
|
|
{
|
2018-09-14 08:41:52 -05:00
|
|
|
Logger::GetLogger()->Log("Failed to locate pgAdmin4.py, terminating server thread.");
|
2013-10-04 12:16:31 -05:00
|
|
|
setError(tr("Failed to locate pgAdmin4.py, terminating server thread."));
|
2013-06-21 17:21:11 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Server::run()
|
|
|
|
{
|
|
|
|
// Open the application code and run it.
|
2018-09-14 08:41:52 -05:00
|
|
|
Logger::GetLogger()->Log("Open the application code and run it.");
|
2013-06-21 17:21:11 -05:00
|
|
|
FILE *cp = fopen(m_appfile.toUtf8().data(), "r");
|
|
|
|
if (!cp)
|
|
|
|
{
|
2018-09-14 08:41:52 -05:00
|
|
|
Logger::GetLogger()->Log(QString(tr("Failed to open the application file: %1, server thread exiting.")).arg(m_appfile));
|
2013-10-04 12:16:31 -05:00
|
|
|
setError(QString(tr("Failed to open the application file: %1, server thread exiting.")).arg(m_appfile));
|
2013-06-21 17:21:11 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-25 04:54:28 -05:00
|
|
|
// Set the port number and key, and force SERVER_MODE off.
|
2018-09-17 04:46:48 -05:00
|
|
|
Logger::GetLogger()->Log("Set the port number, key and force SERVER_MODE off");
|
2013-10-04 11:12:10 -05:00
|
|
|
PyRun_SimpleString(QString("PGADMIN_PORT = %1").arg(m_port).toLatin1());
|
2017-03-06 08:53:49 -06:00
|
|
|
PyRun_SimpleString(QString("PGADMIN_KEY = '%1'").arg(m_key).toLatin1());
|
2017-08-25 04:54:28 -05:00
|
|
|
PyRun_SimpleString(QString("SERVER_MODE = False").toLatin1());
|
2013-10-04 11:12:10 -05:00
|
|
|
|
2016-06-02 07:56:56 -05:00
|
|
|
// Run the app!
|
2017-03-28 07:26:16 -05:00
|
|
|
QByteArray m_appfile_utf8 = m_appfile.toUtf8();
|
2016-02-02 07:16:01 -06:00
|
|
|
#ifdef PYTHON2
|
2016-08-16 05:29:42 -05:00
|
|
|
/*
|
|
|
|
* Untrusted search path vulnerability in the PySys_SetArgv API function in Python 2.6 and earlier, and possibly later
|
|
|
|
* versions, prepends an empty string to sys.path when the argv[0] argument does not contain a path separator,
|
|
|
|
* which might allow local users to execute arbitrary code via a Trojan horse Python file in the current working directory.
|
|
|
|
* Here we have to set arguments explicitly to python interpreter. Check more details in 'PySys_SetArgv' documentation.
|
|
|
|
*/
|
2017-03-28 07:26:16 -05:00
|
|
|
char* n_argv[] = { m_appfile_utf8.data() };
|
2016-08-16 05:29:42 -05:00
|
|
|
PySys_SetArgv(1, n_argv);
|
|
|
|
|
2018-09-17 04:46:48 -05:00
|
|
|
Logger::GetLogger()->Log("PyRun_SimpleFile launching application server...");
|
2017-03-28 07:26:16 -05:00
|
|
|
PyObject* PyFileObject = PyFile_FromString(m_appfile_utf8.data(), (char *)"r");
|
|
|
|
int ret = PyRun_SimpleFile(PyFile_AsFile(PyFileObject), m_appfile_utf8.data());
|
2016-08-16 05:29:42 -05:00
|
|
|
if (ret != 0)
|
2018-09-14 08:41:52 -05:00
|
|
|
{
|
|
|
|
Logger::GetLogger()->Log("Failed to launch the application server, server thread exiting.");
|
2016-02-02 07:16:01 -06:00
|
|
|
setError(tr("Failed to launch the application server, server thread exiting."));
|
2018-09-14 08:41:52 -05:00
|
|
|
}
|
2016-02-02 07:16:01 -06:00
|
|
|
#else
|
2016-08-16 05:29:42 -05:00
|
|
|
/*
|
|
|
|
* Untrusted search path vulnerability in the PySys_SetArgv API function in Python 2.6 and earlier, and possibly later
|
|
|
|
* versions, prepends an empty string to sys.path when the argv[0] argument does not contain a path separator,
|
|
|
|
* which might allow local users to execute arbitrary code via a Trojan horse Python file in the current working directory.
|
|
|
|
* Here we have to set arguments explicitly to python interpreter. Check more details in 'PySys_SetArgv' documentation.
|
|
|
|
*/
|
2017-03-28 07:26:16 -05:00
|
|
|
char *appName = m_appfile_utf8.data();
|
2016-08-16 05:29:42 -05:00
|
|
|
const size_t cSize = strlen(appName)+1;
|
|
|
|
wchar_t* wcAppName = new wchar_t[cSize];
|
|
|
|
mbstowcs (wcAppName, appName, cSize);
|
|
|
|
wchar_t* n_argv[] = { wcAppName };
|
|
|
|
PySys_SetArgv(1, n_argv);
|
|
|
|
|
2018-09-17 04:46:48 -05:00
|
|
|
Logger::GetLogger()->Log("PyRun_SimpleFile launching application server...");
|
2018-05-31 09:07:08 -05:00
|
|
|
if (PyRun_SimpleFile(cp, m_appfile_utf8.data()) != 0)
|
2018-09-14 08:41:52 -05:00
|
|
|
{
|
|
|
|
Logger::GetLogger()->Log("Failed to launch the application server, server thread exiting.");
|
2013-10-04 12:16:31 -05:00
|
|
|
setError(tr("Failed to launch the application server, server thread exiting."));
|
2018-09-14 08:41:52 -05:00
|
|
|
}
|
2016-02-02 07:16:01 -06:00
|
|
|
#endif
|
2013-06-21 17:21:11 -05:00
|
|
|
|
|
|
|
fclose(cp);
|
|
|
|
}
|
2018-02-05 09:32:14 -06:00
|
|
|
|
2018-03-15 02:56:24 -05:00
|
|
|
void Server::shutdown(QUrl url)
|
|
|
|
{
|
|
|
|
bool shotdown = shutdownServer(url);
|
|
|
|
if (!shotdown)
|
2018-06-08 02:45:02 -05:00
|
|
|
setError(tr("Failed to shut down application server thread."));
|
2018-03-15 02:56:24 -05:00
|
|
|
|
|
|
|
QThread::quit();
|
|
|
|
QThread::wait();
|
|
|
|
while(!this->isFinished()){}
|
|
|
|
}
|
|
|
|
|