23#include "qgsversion.h"
45#include <QDomDocument>
46#include <QNetworkDiskCache>
48#include <QElapsedTimer>
51#include <fcgi_stdio.h>
59QString *QgsServer::sConfigFilePath =
nullptr;
63bool QgsServer::sInitialized =
false;
72 if ( qobject_cast<QgsApplication *>( qApp ) ==
nullptr )
74 qFatal(
"A QgsApplication must exist before a QgsServer instance can be created." );
81QFileInfo QgsServer::defaultAdminSLD()
83 return QFileInfo( QStringLiteral(
"admin.sld" ) );
86void QgsServer::setupNetworkAccessManager()
88 const QSettings settings;
90 QNetworkDiskCache *cache =
new QNetworkDiskCache(
nullptr );
91 const qint64 cacheSize = sSettings()->cacheSize();
92 const QString cacheDirectory = sSettings()->cacheDirectory();
93 cache->setCacheDirectory( cacheDirectory );
94 cache->setMaximumCacheSize( cacheSize );
95 QgsMessageLog::logMessage( QStringLiteral(
"cacheDirectory: %1" ).arg( cache->cacheDirectory() ), QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
96 QgsMessageLog::logMessage( QStringLiteral(
"maximumCacheSize: %1" ).arg( cache->maximumCacheSize() ), QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
97 nam->setCache( cache );
100QFileInfo QgsServer::defaultProjectFile()
102 const QDir currentDir;
103 fprintf( FCGI_stderr,
"current directory: %s\n", currentDir.absolutePath().toUtf8().constData() );
104 QStringList nameFilterList;
105 nameFilterList << QStringLiteral(
"*.qgs" )
106 << QStringLiteral(
"*.qgz" );
107 const QFileInfoList projectFiles = currentDir.entryInfoList( nameFilterList, QDir::Files, QDir::Name );
108 for (
int x = 0; x < projectFiles.size(); x++ )
110 QgsMessageLog::logMessage( projectFiles.at( x ).absoluteFilePath(), QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
112 if ( projectFiles.isEmpty() )
116 return projectFiles.at( 0 );
119void QgsServer::printRequestParameters(
const QMap< QString, QString> ¶meterMap,
Qgis::MessageLevel logLevel )
121 if ( logLevel > Qgis::MessageLevel::Info )
126 QMap< QString, QString>::const_iterator pIt = parameterMap.constBegin();
127 for ( ; pIt != parameterMap.constEnd(); ++pIt )
133QString QgsServer::configPath(
const QString &defaultConfigPath,
const QString &configPath )
135 QString cfPath( defaultConfigPath );
136 const QString projectFile = sSettings()->projectFile();
137 if ( !projectFile.isEmpty() )
139 cfPath = projectFile;
140 QgsDebugMsgLevel( QStringLiteral(
"QGIS_PROJECT_FILE:%1" ).arg( cfPath ), 2 );
144 if ( configPath.isEmpty() )
147 if ( getenv(
"QGIS_PROJECT_FILE" ) )
149 cfPath = getenv(
"QGIS_PROJECT_FILE" );
150 QgsMessageLog::logMessage( QStringLiteral(
"Using configuration file path from environment: %1" ).arg( cfPath ), QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
152 else if ( ! defaultConfigPath.isEmpty() )
154 QgsMessageLog::logMessage( QStringLiteral(
"Using default configuration file path: %1" ).arg( defaultConfigPath ), QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
166void QgsServer::initLocale()
169 if ( ! sSettings()->overrideSystemLocale().isEmpty() )
171 QLocale::setDefault( QLocale( sSettings()->overrideSystemLocale() ) );
174 QLocale currentLocale;
175 if ( sSettings()->showGroupSeparator() )
177 currentLocale.setNumberOptions( currentLocale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
181 currentLocale.setNumberOptions( currentLocale.numberOptions() |= QLocale::NumberOption::OmitGroupSeparator );
183 QLocale::setDefault( currentLocale );
186bool QgsServer::init()
202#if defined(SERVER_SKIP_ECW)
215 if ( ! sSettings()->logFile().isEmpty() )
219 else if ( sSettings()->logStderr() )
233 QStringLiteral(
"QGIS Server" ), Qgis::MessageLevel::Warning );
244 if ( !grid.isAvailable )
246 gridMessage.append( QStringLiteral(
"This transformation requires the grid file '%1', which is not available for use on the system.\n" ).arg( grid.shortName ) );
254 QStringLiteral(
"QGIS Server" ), Qgis::MessageLevel::Warning );
267 if ( !grid.isAvailable )
269 gridMessage.append( QStringLiteral(
"This transformation requires the grid file '%1', which is not available for use on the system.\n" ).arg( grid.shortName ) );
270 if ( !grid.url.isEmpty() )
272 if ( !grid.packageName.isEmpty() )
274 gridMessage.append( QStringLiteral(
"This grid is part of the '%1' package, available for download from %2.\n" ).arg( grid.packageName, grid.url ) );
278 gridMessage.append( QStringLiteral(
"This grid is available for download from %1.\n" ).arg( grid.url ) );
284 QString accuracyMessage;
286 accuracyMessage = QStringLiteral(
"Current transform '%1' has an accuracy of %2 meters, while the preferred transformation '%3' has accuracy %4 meters.\n" ).arg( availableOperation.
name )
287 .arg( availableOperation.
accuracy ).arg( preferredOperation.
name ).arg( preferredOperation.
accuracy );
288 else if ( preferredOperation.
accuracy >= 0 )
289 accuracyMessage = QStringLiteral(
"Current transform '%1' has an unknown accuracy, while the preferred transformation '%2' has accuracy %3 meters.\n" )
290 .arg( availableOperation.
name, preferredOperation.
name )
291 .arg( preferredOperation.
accuracy );
293 const QString longMessage = QStringLiteral(
"The preferred transform between '%1' and '%2' is not available for use on the system.\n" ).arg( sourceCrs.
userFriendlyIdentifier(),
295 + gridMessage + accuracyMessage;
303 const QString longMessage = QStringLiteral(
"No transform is available between %1 and %2: %3" )
311 QgsMessageLog::logMessage( QStringLiteral(
"QGIS Server Starting : %1 (%2)" ).arg( _QGIS_VERSION, QGSVERSION ),
"Server", Qgis::MessageLevel::Info );
314 sSettings()->logSummary();
316 setupNetworkAccessManager();
317 QDomImplementation::setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
336 QString defaultConfigFilePath;
337 const QFileInfo projectFileInfo = defaultProjectFile();
338 if ( projectFileInfo.exists() )
340 defaultConfigFilePath = projectFileInfo.absoluteFilePath();
341 QgsMessageLog::logMessage(
"Using default project file: " + defaultConfigFilePath, QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
345 const QFileInfo adminSLDFileInfo = defaultAdminSLD();
346 if ( adminSLDFileInfo.exists() )
348 defaultConfigFilePath = adminSLDFileInfo.absoluteFilePath();
352 sConfigFilePath =
new QString( defaultConfigFilePath );
366 sServiceRegistry->init( modulePath, sServerInterface );
372 QgsMessageLog::logMessage( QStringLiteral(
"Server initialized" ), QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
382 qunsetenv( var.toUtf8().data() );
386 qputenv( var.toUtf8().data(), val.toUtf8() );
388 sSettings()->load( var );
398 qApp->processEvents();
404#ifdef HAVE_SERVER_PYTHON_PLUGINS
406 if ( accessControls )
439 const QString configFilePath = configPath( *sConfigFilePath, request.
serverParameters().
map() );
451 responseDecorator.
start();
456 response.
sendError( 500, QStringLiteral(
"Internal Server Error" ) );
466 printRequestParameters( params.
toMap(), logLevel );
471 const QString configFilePath = configPath( *sConfigFilePath, params.
map() );
474 if ( ! configFilePath.isEmpty() )
511 throw QgsServerException( QStringLiteral(
"Project file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file" ) );
514 if ( ! params.
fileName().isEmpty() )
516 const QString value = QString(
"attachment; filename=\"%1\"" ).arg( params.
fileName() );
517 requestHandler.
setResponseHeader( QStringLiteral(
"Content-Disposition" ), value );
529 QStringLiteral(
"Service unknown or unsupported. Current supported services (case-sensitive): WMS WFS WCS WMTS SampleService, or use a WFS3 (OGC API Features) endpoint" ) );
535 responseDecorator.
write( ex );
542 response.
sendError( 500, QStringLiteral(
"Internal Server Error" ) );
551 responseDecorator.
finish();
556 response.
sendError( 500, QStringLiteral(
"Internal Server Error" ) );
565 if ( logLevel == Qgis::MessageLevel::Info )
567 QgsMessageLog::logMessage(
"Request finished in " + QString::number(
QgsApplication::profiler()->profileTime( QStringLiteral(
"handleRequest" ), QStringLiteral(
"server" ) ) * 1000.0 ) +
" ms", QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
568 if ( sSettings->logProfile() )
570 std::function <void(
const QModelIndex &,
int )> profileFormatter;
571 profileFormatter = [ &profileFormatter ](
const QModelIndex & idx,
int level )
574 .arg( level > 0 ? QString().fill(
'-', level ) +
' ' : QString() )
577 .arg( QString::number(
QgsApplication::profiler()->data( idx, QgsRuntimeProfilerNode::Roles::Elapsed ).toDouble() * 1000.0 ) ), QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
582 profileFormatter( subIdx, level + 1 );
590 profileFormatter( idx, 0 );
602#ifdef HAVE_SERVER_PYTHON_PLUGINS
603void QgsServer::initPython()
608 QgsMessageLog::logMessage( QStringLiteral(
"No server python plugins are available" ), QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
612 QgsMessageLog::logMessage( QStringLiteral(
"Server python plugins loaded" ), QStringLiteral(
"Server" ), Qgis::MessageLevel::Info );
MessageLevel
Level for messages This will be used both for message log and message bar in application.
A helper class that centralizes restrictions given by all the access control filter plugins.
void unresolveFilterFeatures()
Clear expression's cache computed from resolveFilterFeatures
static void skipGdalDriver(const QString &driver)
Sets the GDAL_SKIP environment variable to include the specified driver and then calls GDALDriverMana...
static QString pluginPath()
Returns the path to the application plugin directory.
static bool createDatabase(QString *errorMessage=nullptr)
initialize qgis.db
static void init(QString profileFolder=QString())
This method initializes paths etc for QGIS.
static QString pkgDataPath()
Returns the common root path of all application data directories.
static QString libexecPath()
Returns the path with utility executables (help viewer, crssync, ...)
static QStringList svgPaths()
Returns the paths to svg directories.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
static const char * QGIS_APPLICATION_NAME
static const char * QGIS_ORGANIZATION_DOMAIN
static QString prefixPath()
Returns the path to the application prefix directory.
static const char * QGIS_ORGANIZATION_NAME
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static QString qgisAuthDatabaseFilePath()
Returns the path to the user authentication database file: qgis-auth.db.
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
bool init(const QString &pluginPath=QString(), const QString &authDatabasePath=QString())
init initialize QCA, prioritize qca-ossl plugin and optionally set up the authentication database
A cache for capabilities xml documents (by configuration file path)
static QgsConfigCache * instance()
Returns the current instance.
static void initialize(QgsServerSettings *settings)
Initialize from settings.
const QgsProject * project(const QString &path, const QgsServerSettings *settings=nullptr)
If the project is not cached yet, then the project is read from the path.
This class represents a coordinate reference system (CRS).
@ ShortString
A heavily abbreviated string, for use when a compact representation is required.
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
Defines a QGIS exception class.
Class defining decorator for calling filter's hooks.
void finish() override
Finish the response, ending the transaction.
void start() SIP_THROW(QgsServerException)
Call filters requestReady() method.
static bool loadStandardTestFonts(const QStringList &loadstyles)
Loads standard test fonts from filesystem or qrc resource.
Exception class for WMS service exceptions (for compatibility only).
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
network access manager for QGIS
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
Exception base class for service exceptions.
QString message() const
Returns the exception message.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
static void setInstance(QgsProject *project)
Set the current project singleton instance to project.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
This class is an interface hiding the details of reading input and writing output from/to a wms reque...
bool exceptionRaised() const
Pointer to last raised exception.
void parseInput()
Parses the input and creates a request neutral Parameter/Value map.
void setServiceException(const QgsServerException &ex)
Allow plugins to return a QgsMapServiceException.
void setResponseHeader(const QString &name, const QString &value)
Sets an HTTP response header.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void clear(const QString &group="startup")
clear Clear all profile data.
Scoped object for logging of the runtime for a single operation or group of operations.
The QgsServerApiContext class encapsulates the resources for a particular client request: the request...
Server generic API endpoint abstract base class.
virtual void executeRequest(const QgsServerApiContext &context) const =0
Executes a request by passing the given context to the API handlers.
virtual const QString rootPath() const =0
Returns the root path for the API.
Exception base class for server exceptions.
virtual QByteArray formatResponse(QString &responseFormat) const
Formats the exception for sending to client.
Interfaces exposed by QGIS Server and made available to plugins.
QgsServerSettings * serverSettings() override
Returns the server settings.
void setRequestHandler(QgsRequestHandler *requestHandler) override
Set the request handler.
void clearRequestHandler() override
Clear the request handler.
QgsServerFiltersMap filters() override
Returns the list of current QgsServerFilter.
void setConfigFilePath(const QString &configFilePath) override
Set the configuration file path.
QgsAccessControl * accessControls() const override
Gets the helper over all the registered access control filters.
static QgsServerLogger * instance()
Gets the singleton instance.
Qgis::MessageLevel logLevel() const
Gets the current log level.
void setLogLevel(Qgis::MessageLevel level)
Set the current log level.
void setLogFile(const QString &filename=QString())
Set the current log file.
void setLogStderr()
Activates logging to stderr.
void logMessage(const QString &message, const QString &tag, Qgis::MessageLevel level) override
Log a message from the server context.
QgsServerParameters provides an interface to retrieve and manipulate global parameters received from ...
QMap< QString, QString > toMap() const
Returns all parameters in a map.
QString map() const
Returns MAP parameter as a string or an empty string if not defined.
QString service() const
Returns SERVICE parameter as a string or an empty string if not defined.
QString fileName() const
Returns FILE_NAME parameter as a string or an empty string if not defined.
virtual QString version() const
Returns VERSION parameter as a string or an empty string if not defined.
static bool initPlugins(QgsServerInterface *interface)
Initializes the Python plugins.
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
QgsServerParameters serverParameters() const
Returns parameters.
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device.
virtual void clear()=0
Reset all headers and content for this response.
virtual void sendError(int code, const QString &message)=0
Send error This method delegates error handling at the server level.
Provides a way to retrieve settings by prioritizing according to environment variables,...
QgsServer()
Creates the server instance.
void handleRequest(QgsServerRequest &request, QgsServerResponse &response, const QgsProject *project=nullptr)
Handles the request.
void putenv(const QString &var, const QString &val)
Set environment variable.
QgsServiceRegistry Class defining the registry manager for QGIS server services.
QgsServerApi * apiForRequest(const QgsServerRequest &request) const
Searches the API register for an API matching the request and returns a (possibly NULL) pointer to it...
QgsService * getService(const QString &name, const QString &version=QString())
Retrieve a service from its name.
QgsService Class defining interfaces for QGIS server services.
virtual void executeRequest(const QgsServerRequest &request, QgsServerResponse &response, const QgsProject *project)=0
Execute the requests and set result in QgsServerRequest.
#define QgsDebugMsgLevel(str, level)
Q_GLOBAL_STATIC(QgsServerSettings, sSettings)