QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgsserver.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsserver.cpp
3  A server application supporting WMS / WFS / WCS
4  -------------------
5  begin : July 04, 2006
6  copyright : (C) 2006 by Marco Hugentobler & Ionut Iosifescu Enescu
7  : (C) 2015 by Alessandro Pasotti
8  email : marco dot hugentobler at karto dot baug dot ethz dot ch
9  : elpaso at itopen dot it
10  ***************************************************************************/
11 
12 /***************************************************************************
13  * *
14  * This program is free software; you can redistribute it and/or modify *
15  * it under the terms of the GNU General Public License as published by *
16  * the Free Software Foundation; either version 2 of the License, or *
17  * (at your option) any later version. *
18  * *
19  ***************************************************************************/
20 
21 //for CMAKE_INSTALL_PREFIX
22 #include "qgsconfig.h"
23 #include "qgsversion.h"
24 #include "qgsserver.h"
25 #include "qgsauthmanager.h"
26 #include "qgscapabilitiescache.h"
27 #include "qgsfontutils.h"
28 #include "qgsrequesthandler.h"
29 #include "qgsproject.h"
30 #include "qgsproviderregistry.h"
31 #include "qgslogger.h"
32 #include "qgsmapserviceexception.h"
34 #include "qgsserverlogger.h"
35 #include "qgsserverrequest.h"
37 #include "qgsservice.h"
38 #include "qgsserverapi.h"
39 #include "qgsserverapicontext.h"
40 #include "qgsserverparameters.h"
41 #include "qgsapplication.h"
42 #include "qgsruntimeprofiler.h"
43 #include "qgscoordinatetransform.h"
44 
45 #include <QDomDocument>
46 #include <QNetworkDiskCache>
47 #include <QSettings>
48 #include <QElapsedTimer>
49 
50 // TODO: remove, it's only needed by a single debug message
51 #include <fcgi_stdio.h>
52 #include <cstdlib>
53 
54 
55 // Server status static initializers.
56 // Default values are for C++, SIP bindings will override their
57 // options in in init()
58 
59 QString *QgsServer::sConfigFilePath = nullptr;
60 QgsCapabilitiesCache *QgsServer::sCapabilitiesCache = nullptr;
61 QgsServerInterfaceImpl *QgsServer::sServerInterface = nullptr;
62 // Initialization must run once for all servers
63 bool QgsServer::sInitialized = false;
64 
65 QgsServiceRegistry *QgsServer::sServiceRegistry = nullptr;
66 
68 
70 {
71  // QgsApplication must exist
72  if ( qobject_cast<QgsApplication *>( qApp ) == nullptr )
73  {
74  qFatal( "A QgsApplication must exist before a QgsServer instance can be created." );
75  abort();
76  }
77  init();
78  mConfigCache = QgsConfigCache::instance();
79 }
80 
81 QFileInfo QgsServer::defaultAdminSLD()
82 {
83  return QFileInfo( QStringLiteral( "admin.sld" ) );
84 }
85 
86 void QgsServer::setupNetworkAccessManager()
87 {
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 );
98 }
99 
100 QFileInfo QgsServer::defaultProjectFile()
101 {
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++ )
109  {
110  QgsMessageLog::logMessage( projectFiles.at( x ).absoluteFilePath(), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
111  }
112  if ( projectFiles.isEmpty() )
113  {
114  return QFileInfo();
115  }
116  return projectFiles.at( 0 );
117 }
118 
119 void QgsServer::printRequestParameters( const QMap< QString, QString> &parameterMap, Qgis::MessageLevel logLevel )
120 {
121  if ( logLevel > Qgis::MessageLevel::Info )
122  {
123  return;
124  }
125 
126  QMap< QString, QString>::const_iterator pIt = parameterMap.constBegin();
127  for ( ; pIt != parameterMap.constEnd(); ++pIt )
128  {
129  QgsMessageLog::logMessage( pIt.key() + ":" + pIt.value(), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
130  }
131 }
132 
133 QString QgsServer::configPath( const QString &defaultConfigPath, const QString &configPath )
134 {
135  QString cfPath( defaultConfigPath );
136  const QString projectFile = sSettings()->projectFile();
137  if ( !projectFile.isEmpty() )
138  {
139  cfPath = projectFile;
140  QgsDebugMsg( QStringLiteral( "QGIS_PROJECT_FILE:%1" ).arg( cfPath ) );
141  }
142  else
143  {
144  if ( configPath.isEmpty() )
145  {
146  // Read it from the environment, because a rewrite rule may have rewritten it
147  if ( getenv( "QGIS_PROJECT_FILE" ) )
148  {
149  cfPath = getenv( "QGIS_PROJECT_FILE" );
150  QgsMessageLog::logMessage( QStringLiteral( "Using configuration file path from environment: %1" ).arg( cfPath ), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
151  }
152  else if ( ! defaultConfigPath.isEmpty() )
153  {
154  QgsMessageLog::logMessage( QStringLiteral( "Using default configuration file path: %1" ).arg( defaultConfigPath ), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
155  }
156  }
157  else
158  {
159  cfPath = configPath;
160  QgsDebugMsg( QStringLiteral( "MAP:%1" ).arg( cfPath ) );
161  }
162  }
163  return cfPath;
164 }
165 
166 void QgsServer::initLocale()
167 {
168  // System locale override
169  if ( ! sSettings()->overrideSystemLocale().isEmpty() )
170  {
171  QLocale::setDefault( QLocale( sSettings()->overrideSystemLocale() ) );
172  }
173  // Number group separator settings
174  QLocale currentLocale;
175  if ( sSettings()->showGroupSeparator() )
176  {
177  currentLocale.setNumberOptions( currentLocale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
178  }
179  else
180  {
181  currentLocale.setNumberOptions( currentLocale.numberOptions() |= QLocale::NumberOption::OmitGroupSeparator );
182  }
183  QLocale::setDefault( currentLocale );
184 }
185 
186 bool QgsServer::init()
187 {
188  if ( sInitialized )
189  {
190  return false;
191  }
192 
193  QCoreApplication::setOrganizationName( QgsApplication::QGIS_ORGANIZATION_NAME );
194  QCoreApplication::setOrganizationDomain( QgsApplication::QGIS_ORGANIZATION_DOMAIN );
195  QCoreApplication::setApplicationName( QgsApplication::QGIS_APPLICATION_NAME );
196 
197  // TODO: remove QGIS_OPTIONS_PATH from settings and rely on QgsApplication's env var QGIS_CUSTOM_CONFIG_PATH
198  // Note that QGIS_CUSTOM_CONFIG_PATH gives /tmp/qt_temp-rUpsId/profiles/default/QGIS/QGIS3.ini
199  // while QGIS_OPTIONS_PATH gives /tmp/qt_temp-rUpsId/QGIS/QGIS3.ini
200  QgsApplication::init( qgetenv( "QGIS_OPTIONS_PATH" ) );
201 
202 #if defined(SERVER_SKIP_ECW)
203  QgsMessageLog::logMessage( "Skipping GDAL ECW drivers in server.", "Server", Qgis::MessageLevel::Info );
205  QgsApplication::skipGdalDriver( "JP2ECW" );
206 #endif
207 
208  // reload settings to take into account QCoreApplication and QgsApplication
209  // configuration
210  sSettings()->load();
211 
212  // init and configure logger
214  QgsServerLogger::instance()->setLogLevel( sSettings()->logLevel() );
215  if ( ! sSettings()->logFile().isEmpty() )
216  {
217  QgsServerLogger::instance()->setLogFile( sSettings()->logFile() );
218  }
219  else if ( sSettings()->logStderr() )
220  {
222  }
223 
224  // Logging handlers for CRS grid issues
226  const QgsCoordinateReferenceSystem & destinationCrs,
227  const QgsDatumTransform::GridDetails & grid )
228  {
229  QgsServerLogger::instance()->logMessage( QStringLiteral( "Cannot use project transform between %1 and %2 - missing grid %3" )
232  grid.shortName ),
233  QStringLiteral( "QGIS Server" ), Qgis::MessageLevel::Warning );
234  } );
235 
236 
238  const QgsCoordinateReferenceSystem & destinationCrs,
239  const QgsDatumTransform::TransformDetails & details )
240  {
241  QString gridMessage;
242  for ( const QgsDatumTransform::GridDetails &grid : details.grids )
243  {
244  if ( !grid.isAvailable )
245  {
246  gridMessage.append( QStringLiteral( "This transformation requires the grid file '%1', which is not available for use on the system.\n" ).arg( grid.shortName ) );
247  }
248  }
249  QgsServerLogger::instance()->logMessage( QStringLiteral( "Cannot use project transform between %1 and %2 - %3.\n%4" )
252  details.name,
253  gridMessage ),
254  QStringLiteral( "QGIS Server" ), Qgis::MessageLevel::Warning );
255  } );
256 
257 
259  const QgsCoordinateReferenceSystem & destinationCrs,
260  const QgsDatumTransform::TransformDetails & preferredOperation,
261  const QgsDatumTransform::TransformDetails & availableOperation )
262  {
263 
264  QString gridMessage;
265  for ( const QgsDatumTransform::GridDetails &grid : preferredOperation.grids )
266  {
267  if ( !grid.isAvailable )
268  {
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() )
271  {
272  if ( !grid.packageName.isEmpty() )
273  {
274  gridMessage.append( QStringLiteral( "This grid is part of the '%1' package, available for download from %2.\n" ).arg( grid.packageName, grid.url ) );
275  }
276  else
277  {
278  gridMessage.append( QStringLiteral( "This grid is available for download from %1.\n" ).arg( grid.url ) );
279  }
280  }
281  }
282  }
283 
284  QString accuracyMessage;
285  if ( availableOperation.accuracy >= 0 && preferredOperation.accuracy >= 0 )
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 );
292 
293  const QString longMessage = QStringLiteral( "The preferred transform between '%1' and '%2' is not available for use on the system.\n" ).arg( sourceCrs.userFriendlyIdentifier(),
294  destinationCrs.userFriendlyIdentifier() )
295  + gridMessage + accuracyMessage;
296 
297  QgsServerLogger::instance()->logMessage( longMessage, QStringLiteral( "QGIS Server" ), Qgis::MessageLevel::Warning );
298 
299  } );
300 
302  {
303  const QString longMessage = QStringLiteral( "No transform is available between %1 and %2: %3" )
304  .arg( sourceCrs.userFriendlyIdentifier(), destinationCrs.userFriendlyIdentifier(), error );
305  QgsServerLogger::instance()->logMessage( longMessage, QStringLiteral( "QGIS Server" ), Qgis::MessageLevel::Warning );
306  } );
307 
308  // Configure locale
309  initLocale();
310 
311  QgsMessageLog::logMessage( QStringLiteral( "QGIS Server Starting : %1 (%2)" ).arg( _QGIS_VERSION, QGSVERSION ), "Server", Qgis::MessageLevel::Info );
312 
313  // log settings currently used
314  sSettings()->logSummary();
315 
316  setupNetworkAccessManager();
317  QDomImplementation::setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
318 
319  // Instantiate the plugin directory so that providers are loaded
321  QgsMessageLog::logMessage( "Prefix PATH: " + QgsApplication::prefixPath(), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
322  QgsMessageLog::logMessage( "Plugin PATH: " + QgsApplication::pluginPath(), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
323  QgsMessageLog::logMessage( "PkgData PATH: " + QgsApplication::pkgDataPath(), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
324  QgsMessageLog::logMessage( "User DB PATH: " + QgsApplication::qgisUserDatabaseFilePath(), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
325  QgsMessageLog::logMessage( "Auth DB PATH: " + QgsApplication::qgisAuthDatabaseFilePath(), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
326  QgsMessageLog::logMessage( "SVG PATHS: " + QgsApplication::svgPaths().join( QDir::listSeparator() ), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
327 
328  QgsApplication::createDatabase(); //init qgis.db (e.g. necessary for user crs)
329 
330  // Initialize the authentication system
331  // creates or uses qgis-auth.db in ~/.qgis3/ or directory defined by QGIS_AUTH_DB_DIR_PATH env variable
332  // set the master password as first line of file defined by QGIS_AUTH_PASSWORD_FILE env variable
333  // (QGIS_AUTH_PASSWORD_FILE variable removed from environment after accessing)
335 
336  QString defaultConfigFilePath;
337  const QFileInfo projectFileInfo = defaultProjectFile(); //try to find a .qgs/.qgz file in the server directory
338  if ( projectFileInfo.exists() )
339  {
340  defaultConfigFilePath = projectFileInfo.absoluteFilePath();
341  QgsMessageLog::logMessage( "Using default project file: " + defaultConfigFilePath, QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
342  }
343  else
344  {
345  const QFileInfo adminSLDFileInfo = defaultAdminSLD();
346  if ( adminSLDFileInfo.exists() )
347  {
348  defaultConfigFilePath = adminSLDFileInfo.absoluteFilePath();
349  }
350  }
351  // Store the config file path
352  sConfigFilePath = new QString( defaultConfigFilePath );
353 
354  //create cache for capabilities XML
355  sCapabilitiesCache = new QgsCapabilitiesCache();
356 
357  QgsFontUtils::loadStandardTestFonts( QStringList() << QStringLiteral( "Roman" ) << QStringLiteral( "Bold" ) );
358 
359  sServiceRegistry = new QgsServiceRegistry();
360 
361  sServerInterface = new QgsServerInterfaceImpl( sCapabilitiesCache, sServiceRegistry, sSettings() );
362 
363  // Load service module
364  const QString modulePath = QgsApplication::libexecPath() + "server";
365  // qDebug() << QStringLiteral( "Initializing server modules from: %1" ).arg( modulePath );
366  sServiceRegistry->init( modulePath, sServerInterface );
367 
368  sInitialized = true;
369  QgsMessageLog::logMessage( QStringLiteral( "Server initialized" ), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
370  return true;
371 }
372 
373 
374 
375 void QgsServer::putenv( const QString &var, const QString &val )
376 {
377  if ( val.isEmpty() )
378  {
379  qunsetenv( var.toUtf8().data() );
380  }
381  else
382  {
383  qputenv( var.toUtf8().data(), val.toUtf8() );
384  }
385  sSettings()->load( var );
386 }
387 
388 void QgsServer::handleRequest( QgsServerRequest &request, QgsServerResponse &response, const QgsProject *project )
389 {
391  {
392 
393  const QgsScopedRuntimeProfile profiler { QStringLiteral( "handleRequest" ), QStringLiteral( "server" ) };
394 
395  qApp->processEvents();
396 
397  response.clear();
398 
399  // Pass the filters to the requestHandler, this is needed for the following reasons:
400  // Allow server request to call sendResponse plugin hook if enabled
401  QgsFilterResponseDecorator responseDecorator( sServerInterface->filters(), response );
402 
403  //Request handler
404  QgsRequestHandler requestHandler( request, response );
405 
406  try
407  {
408  // TODO: split parse input into plain parse and processing from specific services
409  requestHandler.parseInput();
410  }
411  catch ( QgsMapServiceException &e )
412  {
413  QgsMessageLog::logMessage( "Parse input exception: " + e.message(), QStringLiteral( "Server" ), Qgis::MessageLevel::Critical );
414  requestHandler.setServiceException( e );
415  }
416 
417  // Set the request handler into the interface for plugins to manipulate it
418  sServerInterface->setRequestHandler( &requestHandler );
419 
420  // Initialize configfilepath so that is is available
421  // before calling plugin methods
422  // Note that plugins may still change that value using
423  // setConfigFilePath() interface method
424  if ( ! project )
425  {
426  const QString configFilePath = configPath( *sConfigFilePath, request.serverParameters().map() );
427  sServerInterface->setConfigFilePath( configFilePath );
428  }
429  else
430  {
431  sServerInterface->setConfigFilePath( project->fileName() );
432  }
433 
434  // Call requestReady() method (if enabled)
435  // This may also throw exceptions if there are errors in python plugins code
436  try
437  {
438  responseDecorator.start();
439  }
440  catch ( QgsException &ex )
441  {
442  // Internal server error
443  response.sendError( 500, QStringLiteral( "Internal Server Error" ) );
444  QgsMessageLog::logMessage( ex.what(), QStringLiteral( "Server" ), Qgis::MessageLevel::Critical );
445  }
446 
447  // Plugins may have set exceptions
448  if ( !requestHandler.exceptionRaised() )
449  {
450  try
451  {
452  const QgsServerParameters params = request.serverParameters();
453  printRequestParameters( params.toMap(), logLevel );
454 
455  // Setup project (config file path)
456  if ( ! project )
457  {
458  const QString configFilePath = configPath( *sConfigFilePath, params.map() );
459 
460  // load the project if needed and not empty
461  if ( ! configFilePath.isEmpty() )
462  {
463  project = mConfigCache->project( configFilePath, sServerInterface->serverSettings() );
464  }
465  }
466 
467  // Set the current project instance
468  QgsProject::setInstance( const_cast<QgsProject *>( project ) );
469 
470  if ( project )
471  {
472  sServerInterface->setConfigFilePath( project->fileName() );
473  }
474  else
475  {
476  sServerInterface->setConfigFilePath( QString() );
477  }
478 
479  // Note that at this point we still might not have set a valid project.
480  // There are APIs that work without a project (e.g. the landing page catalog API that
481  // lists the available projects metadata).
482 
483  // Dispatcher: if SERVICE is set, we assume a OWS service, if not, let's try an API
484  // TODO: QGIS 4 fix the OWS services and treat them as APIs
485  QgsServerApi *api = nullptr;
486  if ( params.service().isEmpty() && ( api = sServiceRegistry->apiForRequest( request ) ) )
487  {
488  const QgsServerApiContext context { api->rootPath(), &request, &responseDecorator, project, sServerInterface };
489  api->executeRequest( context );
490  }
491  else
492  {
493 
494  // Project is mandatory for OWS at this point
495  if ( ! project )
496  {
497  throw QgsServerException( QStringLiteral( "Project file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file" ) );
498  }
499 
500  if ( ! params.fileName().isEmpty() )
501  {
502  const QString value = QString( "attachment; filename=\"%1\"" ).arg( params.fileName() );
503  requestHandler.setResponseHeader( QStringLiteral( "Content-Disposition" ), value );
504  }
505 
506  // Lookup for service
507  QgsService *service = sServiceRegistry->getService( params.service(), params.version() );
508  if ( service )
509  {
510  service->executeRequest( request, responseDecorator, project );
511  }
512  else
513  {
514  throw QgsOgcServiceException( QStringLiteral( "Service configuration error" ),
515  QStringLiteral( "Service unknown or unsupported. Current supported services (case-sensitive): WMS WFS WCS WMTS SampleService, or use a WFS3 (OGC API Features) endpoint" ) );
516  }
517  }
518  }
519  catch ( QgsServerException &ex )
520  {
521  responseDecorator.write( ex );
522  QString format;
523  QgsMessageLog::logMessage( ex.formatResponse( format ), QStringLiteral( "Server" ), Qgis::MessageLevel::Warning );
524  }
525  catch ( QgsException &ex )
526  {
527  // Internal server error
528  response.sendError( 500, QStringLiteral( "Internal Server Error" ) );
529  QgsMessageLog::logMessage( ex.what(), QStringLiteral( "Server" ), Qgis::MessageLevel::Critical );
530  }
531  }
532 
533  // Terminate the response
534  // This may also throw exceptions if there are errors in python plugins code
535  try
536  {
537  responseDecorator.finish();
538  }
539  catch ( QgsException &ex )
540  {
541  // Internal server error
542  response.sendError( 500, QStringLiteral( "Internal Server Error" ) );
543  QgsMessageLog::logMessage( ex.what(), QStringLiteral( "Server" ), Qgis::MessageLevel::Critical );
544  }
545 
546  // We are done using requestHandler in plugins, make sure we don't access
547  // to a deleted request handler from Python bindings
548  sServerInterface->clearRequestHandler();
549  }
550 
551  if ( logLevel == Qgis::MessageLevel::Info )
552  {
553  QgsMessageLog::logMessage( "Request finished in " + QString::number( QgsApplication::profiler()->profileTime( QStringLiteral( "handleRequest" ), QStringLiteral( "server" ) ) * 1000.0 ) + " ms", QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
554  if ( sSettings->logProfile() )
555  {
556  std::function <void( const QModelIndex &, int )> profileFormatter;
557  profileFormatter = [ &profileFormatter ]( const QModelIndex & idx, int level )
558  {
559  QgsMessageLog::logMessage( QStringLiteral( "Profile: %1%2, %3 : %4 ms" )
560  .arg( level > 0 ? QString().fill( '-', level ) + ' ' : QString() )
561  .arg( QgsApplication::profiler()->data( idx, QgsRuntimeProfilerNode::Roles::Group ).toString() )
562  .arg( QgsApplication::profiler()->data( idx, QgsRuntimeProfilerNode::Roles::Name ).toString() )
563  .arg( QString::number( QgsApplication::profiler()->data( idx, QgsRuntimeProfilerNode::Roles::Elapsed ).toDouble() * 1000.0 ) ), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
564 
565  for ( int subRow = 0; subRow < QgsApplication::profiler()->rowCount( idx ); subRow++ )
566  {
567  const auto subIdx { QgsApplication::profiler()->index( subRow, 0, idx ) };
568  profileFormatter( subIdx, level + 1 );
569  }
570 
571  };
572 
573  for ( int row = 0; row < QgsApplication::profiler()->rowCount( ); row++ )
574  {
575  const auto idx { QgsApplication::profiler()->index( row, 0 ) };
576  profileFormatter( idx, 0 );
577  }
578  }
579  }
580 
581 
582  // Clear the profiler server section after each request
583  QgsApplication::profiler()->clear( QStringLiteral( "server" ) );
584 
585 }
586 
587 
588 #ifdef HAVE_SERVER_PYTHON_PLUGINS
589 void QgsServer::initPython()
590 {
591  // Init plugins
592  if ( ! QgsServerPlugins::initPlugins( sServerInterface ) )
593  {
594  QgsMessageLog::logMessage( QStringLiteral( "No server python plugins are available" ), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
595  }
596  else
597  {
598  QgsMessageLog::logMessage( QStringLiteral( "Server python plugins loaded" ), QStringLiteral( "Server" ), Qgis::MessageLevel::Info );
599  }
600 }
601 #endif
602 
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:107
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.
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.
static void setCustomMissingRequiredGridHandler(const std::function< void(const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, const QgsDatumTransform::GridDetails &grid)> &handler)
Sets a custom handler to use when a coordinate transform is created between sourceCrs and destination...
static void setCustomCoordinateOperationCreationErrorHandler(const std::function< void(const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, const QString &error)> &handler)
Sets a custom handler to use when a coordinate transform was required between sourceCrs and destinati...
static void setCustomMissingPreferredGridHandler(const std::function< void(const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, const QgsDatumTransform::TransformDetails &preferredOperation, const QgsDatumTransform::TransformDetails &availableOperation)> &handler)
Sets a custom handler to use when a coordinate transform is created between sourceCrs and destination...
static void setCustomMissingGridUsedByContextHandler(const std::function< void(const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, const QgsDatumTransform::TransformDetails &desiredOperation)> &handler)
Sets a custom handler to use when a coordinate operation was specified for use between sourceCrs and ...
Defines a QGIS exception class.
Definition: qgsexception.h:35
QString what() const
Definition: qgsexception.h:48
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,...
Definition: qgsproject.h:101
static void setInstance(QgsProject *project)
Set the current project singleton instance to project.
Definition: qgsproject.cpp:464
QString fileName
Definition: qgsproject.h:104
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.
Definition: qgsserverapi.h:81
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.
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.
Definition: qgsserver.cpp:69
void handleRequest(QgsServerRequest &request, QgsServerResponse &response, const QgsProject *project=nullptr)
Handles the request.
Definition: qgsserver.cpp:388
void putenv(const QString &var, const QString &val)
Set environment variable.
Definition: qgsserver.cpp:375
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.
Definition: qgsservice.h:40
virtual void executeRequest(const QgsServerRequest &request, QgsServerResponse &response, const QgsProject *project)=0
Execute the requests and set result in QgsServerRequest.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
Q_GLOBAL_STATIC(QgsServerSettings, sSettings)
Contains information about a projection transformation grid file.
QString shortName
Short name of transform grid.
Contains information about a coordinate transformation operation.
double accuracy
Transformation accuracy (in meters)
QString name
Display name of transform operation.
QList< QgsDatumTransform::GridDetails > grids
Contains a list of transform grids used by the operation.