45#include "qgsversion.h"
47#include <QDomDocument>
48#include <QElapsedTimer>
49#include <QNetworkDiskCache>
53using namespace Qt::StringLiterals;
56#include <fcgi_stdio.h>
64QString *QgsServer::sConfigFilePath =
nullptr;
68bool QgsServer::sInitialized =
false;
77 if ( !qobject_cast<QgsApplication *>( qApp ) )
79 qFatal(
"A QgsApplication must exist before a QgsServer instance can be created." );
86QFileInfo QgsServer::defaultAdminSLD()
88 return QFileInfo( u
"admin.sld"_s );
91void QgsServer::setupNetworkAccessManager()
96 if ( QgsNetworkDiskCache *cache =
dynamic_cast<QgsNetworkDiskCache *
>( nam->cache() ) )
98 const QString cacheDirectory = sSettings()->cacheDirectory();
99 if ( cacheDirectory.isEmpty() )
105 cache->setCacheDirectory( cacheDirectory );
107 const qint64 cacheSize = sSettings()->cacheSize();
108 cache->setMaximumCacheSize( cacheSize );
118QFileInfo QgsServer::defaultProjectFile()
120 const QDir currentDir;
121 fprintf( FCGI_stderr,
"current directory: %s\n", currentDir.absolutePath().toUtf8().constData() );
122 QStringList nameFilterList;
123 nameFilterList << u
"*.qgs"_s << u
"*.qgz"_s;
124 const QFileInfoList projectFiles = currentDir.entryInfoList( nameFilterList, QDir::Files, QDir::Name );
125 for (
int x = 0; x < projectFiles.size(); x++ )
129 if ( projectFiles.isEmpty() )
133 return projectFiles.at( 0 );
136void QgsServer::printRequestParameters(
const QMap<QString, QString> ¶meterMap,
Qgis::MessageLevel logLevel )
143 QMap<QString, QString>::const_iterator pIt = parameterMap.constBegin();
144 for ( ; pIt != parameterMap.constEnd(); ++pIt )
150QString QgsServer::configPath(
const QString &defaultConfigPath,
const QString &configPath )
152 QString cfPath( defaultConfigPath );
153 const QString projectFile = sSettings()->projectFile();
154 if ( !projectFile.isEmpty() )
156 cfPath = projectFile;
161 if ( configPath.isEmpty() )
164 if ( getenv(
"QGIS_PROJECT_FILE" ) )
166 cfPath = getenv(
"QGIS_PROJECT_FILE" );
169 else if ( !defaultConfigPath.isEmpty() )
183void QgsServer::initLocale()
186 if ( !sSettings()->overrideSystemLocale().isEmpty() )
188 QLocale::setDefault( QLocale( sSettings()->overrideSystemLocale() ) );
191 QLocale currentLocale;
192 if ( sSettings()->showGroupSeparator() )
194 currentLocale.setNumberOptions( currentLocale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
198 currentLocale.setNumberOptions( currentLocale.numberOptions() |= QLocale::NumberOption::OmitGroupSeparator );
200 QLocale::setDefault( currentLocale );
203bool QgsServer::init()
219#if defined( SERVER_SKIP_ECW )
232 if ( !sSettings()->logFile().isEmpty() )
236 else if ( sSettings()->logStderr() )
243 [](
const QgsCoordinateReferenceSystem &sourceCrs,
const QgsCoordinateReferenceSystem &destinationCrs,
const QgsDatumTransform::GridDetails &grid ) {
245 u
"Cannot use project transform between %1 and %2 - missing grid %3"_s
255 [](
const QgsCoordinateReferenceSystem &sourceCrs,
const QgsCoordinateReferenceSystem &destinationCrs,
const QgsDatumTransform::TransformDetails &details ) {
257 for (
const QgsDatumTransform::GridDetails &grid : details.
grids )
261 gridMessage.append( u
"This transformation requires the grid file '%1', which is not available for use on the system.\n"_s.arg( grid.
shortName ) );
265 u
"Cannot use project transform between %1 and %2 - %3.\n%4"_s
275 [](
const QgsCoordinateReferenceSystem &sourceCrs,
const QgsCoordinateReferenceSystem &destinationCrs,
const QgsDatumTransform::TransformDetails &preferredOperation,
const QgsDatumTransform::TransformDetails &availableOperation ) {
277 for (
const QgsDatumTransform::GridDetails &grid : preferredOperation.
grids )
281 gridMessage.append( u
"This transformation requires the grid file '%1', which is not available for use on the system.\n"_s.arg( grid.
shortName ) );
282 if ( !grid.
url.isEmpty() )
286 gridMessage.append( u
"This grid is part of the '%1' package, available for download from %2.\n"_s.arg( grid.
packageName, grid.
url ) );
290 gridMessage.append( u
"This grid is available for download from %1.\n"_s.arg( grid.
url ) );
296 QString accuracyMessage;
298 accuracyMessage = u
"Current transform '%1' has an accuracy of %2 meters, while the preferred transformation '%3' has accuracy %4 meters.\n"_s.arg( availableOperation.
name )
300 .arg( preferredOperation.
name )
301 .arg( preferredOperation.
accuracy );
302 else if ( preferredOperation.
accuracy >= 0 )
303 accuracyMessage = u
"Current transform '%1' has an unknown accuracy, while the preferred transformation '%2' has accuracy %3 meters.\n"_s.arg( availableOperation.
name, preferredOperation.
name )
304 .arg( preferredOperation.
accuracy );
306 const QString longMessage
326 sSettings()->logSummary();
328 setupNetworkAccessManager();
329 QDomImplementation::setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
349 QString defaultConfigFilePath;
350 const QFileInfo projectFileInfo = defaultProjectFile();
351 if ( projectFileInfo.exists() )
353 defaultConfigFilePath = projectFileInfo.absoluteFilePath();
358 const QFileInfo adminSLDFileInfo = defaultAdminSLD();
359 if ( adminSLDFileInfo.exists() )
361 defaultConfigFilePath = adminSLDFileInfo.absoluteFilePath();
365 sConfigFilePath =
new QString( defaultConfigFilePath );
368 sCapabilitiesCache =
new QgsCapabilitiesCache( sSettings()->capabilitiesCacheSize() );
372 sServiceRegistry =
new QgsServiceRegistry();
374 sServerInterface =
new QgsServerInterfaceImpl( sCapabilitiesCache, sServiceRegistry, sSettings() );
379 sServiceRegistry->init( modulePath, sServerInterface );
396 qunsetenv( var.toUtf8().data() );
400 qputenv( var.toUtf8().data(), val.toUtf8() );
402 sSettings()->load( var );
411 qApp->processEvents();
417#ifdef HAVE_SERVER_PYTHON_PLUGINS
419 if ( accessControls )
447 sServerInterface->setRequestHandler( &requestHandler );
455 const QString configFilePath = configPath( *sConfigFilePath, request.
serverParameters().
map() );
456 sServerInterface->setConfigFilePath( configFilePath );
460 sServerInterface->setConfigFilePath( project->
fileName() );
467 responseDecorator.
start();
472 response.
sendError( 500, u
"Internal Server Error"_s );
482 printRequestParameters( params.
toMap(), logLevel );
487 const QString configFilePath = configPath( *sConfigFilePath, params.
map() );
490 if ( !configFilePath.isEmpty() )
493 project = mConfigCache->project( configFilePath, sServerInterface->serverSettings() );
502 sServerInterface->setConfigFilePath( project->
fileName() );
506 sServerInterface->setConfigFilePath( QString() );
511 responseDecorator.
ready();
521 if ( params.
service().isEmpty() )
523 QgsServerApi *api = sServiceRegistry->apiForRequest( request );
532 u
"Service configuration error"_s,
534 "Service unknown or unsupported. Current supported services "
535 "(case-sensitive): WMS WFS WCS WMTS SampleService, or use a WFS3 "
536 "(OGC API Features) endpoint"
547 "Project file error. For OWS services: please provide a SERVICE "
548 "and a MAP parameter pointing to a valid QGIS project file"
554 const QString value = QString(
"attachment; filename=\"%1\"" ).arg( params.
fileName() );
567 u
"Service configuration error"_s,
569 "Service unknown or unsupported. Current supported services "
570 "(case-sensitive): WMS WFS WCS WMTS SampleService, or use a WFS3 "
571 "(OGC API Features) endpoint"
580 responseDecorator.
write( ex );
587 response.
sendError( 500, u
"Internal Server Error"_s );
596 responseDecorator.
finish();
601 response.
sendError( 500, u
"Internal Server Error"_s );
607 sServerInterface->clearRequestHandler();
613 if ( sSettings->logProfile() )
615 std::function<void(
const QModelIndex &,
int )> profileFormatter;
616 profileFormatter = [&profileFormatter](
const QModelIndex &idx,
int level ) {
618 u
"Profile: %1%2, %3 : %4 ms"_s.arg( level > 0 ? QString().fill(
'-', level ) +
' ' : QString() )
629 profileFormatter( subIdx, level + 1 );
636 profileFormatter( idx, 0 );
650#ifdef HAVE_SERVER_PYTHON_PLUGINS
651void QgsServer::initPython()
@ ShortString
A heavily abbreviated string, for use when a compact representation is required.
MessageLevel
Level for messages This will be used both for message log and message bar in application.
@ Warning
Warning message.
@ Critical
Critical/error message.
@ Info
Information message.
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 QString qgisAuthDatabaseUri()
Returns the URI to the user authentication database.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
void setup(const QString &pluginPath=QString(), const QString &authDatabasePath=QString())
Sets up the authentication manager configuration.
A cache for capabilities xml documents (by configuration file path).
void removeCapabilitiesDocument(const QString &path)
Removes capabilities document.
static QgsConfigCache * instance()
Returns the current instance.
static void initialize(QgsServerSettings *settings)
Initialize from settings.
void projectRemovedFromCache(const QString &path)
Emitted whenever a project is removed from the cache.
QString userFriendlyIdentifier(Qgis::CrsIdentifierType type=Qgis::CrsIdentifierType::MediumString) const
Returns a user friendly identifier for the CRS.
Defines a QGIS exception class.
bool isCanceled() const
Tells whether the operation has been canceled already.
A decorator for calling filter's hooks.
void start()
Call filters requestReady() method.
void finish() override
Finish the response, ending the transaction.
void ready()
Call filters projectReady() 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, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
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.
An interface hiding the details of reading input and writing output from/to a wms request mechanism.
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.
@ Elapsed
Node elapsed time.
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.
Encapsulates the resources for a particular client 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.
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
Provides an interface to retrieve and manipulate global parameters received from the client.
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.
Defines requests passed to QgsService classes.
QgsServerParameters serverParameters() const
Returns parameters.
Defines the response interface passed to QgsService.
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device.
virtual QgsFeedback * feedback() const
Returns the socket feedback if any.
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.
A registry manager for QGIS server services.
Defines interfaces for QGIS server services.
virtual void executeRequest(const QgsServerRequest &request, QgsServerResponse &response, const QgsProject *project)=0
Executes the requests and sets result in QgsServerRequest.
#define QgsDebugMsgLevel(str, level)
Q_GLOBAL_STATIC(QgsServerSettings, sSettings)