mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[Server][Feature][needs-docs] Server Cache can be manage by plugins
First commit to add a way to manage the QGIS Server cache with plugins. In this commit only GetCapabilities document can be cached by plugins.
This commit is contained in:
parent
b39ee5a40c
commit
9bd23b5ac3
@ -83,6 +83,19 @@ Register an access control filter
|
||||
virtual QgsAccessControl *accessControls() const = 0;
|
||||
%Docstring
|
||||
Gets the registered access control filters
|
||||
%End
|
||||
|
||||
virtual void registerServerCache( QgsServerCacheFilter *serverCache /Transfer/, int priority = 0 ) = 0;
|
||||
%Docstring
|
||||
Register a server cache filter
|
||||
|
||||
:param serverCache: the server cache to register
|
||||
:param priority: the priority used to order them
|
||||
%End
|
||||
|
||||
virtual QgsServerCacheManager *cacheManager() const = 0;
|
||||
%Docstring
|
||||
Gets the registered server cache filters
|
||||
%End
|
||||
|
||||
virtual QString getEnv( const QString &name ) const = 0;
|
||||
|
@ -29,3 +29,9 @@
|
||||
%If ( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
%Include auto_generated/qgsaccesscontrol.sip
|
||||
%End
|
||||
%If ( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
%Include auto_generated/qgsservercachefilter.sip
|
||||
%End
|
||||
%If ( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
%Include auto_generated/qgsservercachemanager.sip
|
||||
%End
|
||||
|
@ -73,6 +73,8 @@ IF (WITH_SERVER_PLUGINS)
|
||||
qgsserverfilter.cpp
|
||||
qgsaccesscontrolfilter.cpp
|
||||
qgsaccesscontrol.cpp
|
||||
qgsservercachefilter.cpp
|
||||
qgsservercachemanager.cpp
|
||||
)
|
||||
ENDIF (WITH_SERVER_PLUGINS)
|
||||
|
||||
|
56
src/server/qgsservercachefilter.cpp
Normal file
56
src/server/qgsservercachefilter.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
qgsservercachefilter.cpp
|
||||
------------------------
|
||||
Cache interface for Qgis Server plugins
|
||||
|
||||
begin : 2018-07-05
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz dot 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; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsservercachefilter.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
|
||||
//! Constructor
|
||||
QgsServerCacheFilter::QgsServerCacheFilter( const QgsServerInterface *serverInterface ):
|
||||
mServerInterface( serverInterface )
|
||||
{
|
||||
}
|
||||
|
||||
//! Returns cached document
|
||||
QByteArray QgsServerCacheFilter::getCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
Q_UNUSED( project );
|
||||
Q_UNUSED( request );
|
||||
Q_UNUSED( key );
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
//! Updates or inserts the document in cache
|
||||
bool QgsServerCacheFilter::setCachedDocument( const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
Q_UNUSED( doc );
|
||||
Q_UNUSED( project );
|
||||
Q_UNUSED( request );
|
||||
Q_UNUSED( key );
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Deletes the cached document
|
||||
bool QgsServerCacheFilter::deleteCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
Q_UNUSED( project );
|
||||
Q_UNUSED( request );
|
||||
Q_UNUSED( key );
|
||||
return false;
|
||||
}
|
93
src/server/qgsservercachefilter.h
Normal file
93
src/server/qgsservercachefilter.h
Normal file
@ -0,0 +1,93 @@
|
||||
/***************************************************************************
|
||||
qgsservercachefilter.h
|
||||
------------------------
|
||||
Cache interface for Qgis Server plugins
|
||||
|
||||
begin : 2018-07-05
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz dot 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; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSSERVERCACHEPLUGIN_H
|
||||
#define QGSSERVERCACHEPLUGIN_H
|
||||
|
||||
#include <QMultiMap>
|
||||
#include <QDomDocument>
|
||||
#include <QObject>
|
||||
#include "qgsproject.h"
|
||||
#include "qgsserverrequest.h"
|
||||
#include "qgis_server.h"
|
||||
#include "qgis_sip.h"
|
||||
|
||||
SIP_IF_MODULE( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
|
||||
class QgsServerInterface;
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsServerCacheFilter
|
||||
* \brief Class defining cache interface for QGIS Server plugins.
|
||||
*/
|
||||
class SERVER_EXPORT QgsServerCacheFilter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* QgsServerInterface passed to plugins constructors
|
||||
* and must be passed to QgsServerCacheFilter instances.
|
||||
*/
|
||||
QgsServerCacheFilter( const QgsServerInterface *serverInterface );
|
||||
|
||||
virtual ~QgsServerCacheFilter() = default;
|
||||
|
||||
/**
|
||||
* Returns cached document (or 0 if document not in cache) like capabilities
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param key the key provided by the access control to identify differents documents for the same request
|
||||
* \returns QByteArray of the cached document or an empty one if no corresponding document found
|
||||
*/
|
||||
virtual QByteArray getCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Updates or inserts the document in cache like capabilities
|
||||
* \param doc the document to cache
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param key the key provided by the access control to identify differents documents for the same request
|
||||
* \returns true if the document has been cached
|
||||
*/
|
||||
virtual bool setCachedDocument( const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Deletes the cached document
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param key the key provided by the access control to identify differents documents for the same request
|
||||
* \returns true if the document has been deleted
|
||||
*/
|
||||
virtual bool deleteCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
private:
|
||||
|
||||
//! The server interface
|
||||
const QgsServerInterface *mServerInterface = nullptr;
|
||||
|
||||
};
|
||||
|
||||
//! The registry definition
|
||||
typedef QMultiMap<int, QgsServerCacheFilter *> QgsServerCacheFilterMap;
|
||||
|
||||
#endif // QGSSERVERSECURITY_H
|
72
src/server/qgsservercachemanager.cpp
Normal file
72
src/server/qgsservercachemanager.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/***************************************************************************
|
||||
qgsservercachemanager.cpp
|
||||
-------------------------
|
||||
|
||||
begin : 2018-07-05
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz dot 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; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsservercachemanager.h"
|
||||
|
||||
//! Returns cached document (or 0 if document not in cache) like capabilities
|
||||
const QDomDocument *QgsServerCacheManager::getCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
QByteArray content = scIterator.value()->getCachedDocument( project, request, key );
|
||||
if ( !content.isEmpty() )
|
||||
{
|
||||
QDomDocument doc;
|
||||
if ( doc.setContent( content ) )
|
||||
{
|
||||
return &doc;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//! Updates or inserts the document in cache like capabilities
|
||||
bool QgsServerCacheManager::setCachedDocument( const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
if ( scIterator.value()->setCachedDocument( doc, project, request, key ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Deletes the cached document
|
||||
bool QgsServerCacheManager::deleteCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
if ( scIterator.value()->deleteCachedDocument( project, request, key ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Register a new access control filter
|
||||
void QgsServerCacheManager::registerServerCache( QgsServerCacheFilter *serverCache, int priority )
|
||||
{
|
||||
mPluginsServerCaches->insert( priority, serverCache );
|
||||
}
|
111
src/server/qgsservercachemanager.h
Normal file
111
src/server/qgsservercachemanager.h
Normal file
@ -0,0 +1,111 @@
|
||||
/***************************************************************************
|
||||
qgsservercachemanager.h
|
||||
-----------------------
|
||||
|
||||
begin : 2018-07-05
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz dot 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; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSSERVERCACHEMANAGER_H
|
||||
#define QGSSERVERCACHEMANAGER_H
|
||||
|
||||
#include "qgsservercachefilter.h"
|
||||
#include "qgsserverrequest.h"
|
||||
|
||||
#include <QMultiMap>
|
||||
#include <QDomDocument>
|
||||
#include "qgsproject.h"
|
||||
#include "qgis_server.h"
|
||||
#include "qgis_sip.h"
|
||||
|
||||
SIP_IF_MODULE( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
|
||||
class QgsServerCachePlugin;
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsServerCacheManager
|
||||
* \brief A helper class that centralizes caches accesses given by all the server cache filter plugins.
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class SERVER_EXPORT QgsServerCacheManager
|
||||
{
|
||||
#ifdef SIP_RUN
|
||||
#include "qgsservercachefilter.h"
|
||||
#endif
|
||||
|
||||
public:
|
||||
//! Constructor
|
||||
QgsServerCacheManager()
|
||||
{
|
||||
mPluginsServerCaches = new QgsServerCacheFilterMap();
|
||||
mResolved = false;
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QgsServerCacheManager( const QgsServerCacheManager © )
|
||||
{
|
||||
mPluginsServerCaches = new QgsServerCacheFilterMap( *copy.mPluginsServerCaches );
|
||||
mResolved = copy.mResolved;
|
||||
}
|
||||
|
||||
|
||||
~QgsServerCacheManager()
|
||||
{
|
||||
delete mPluginsServerCaches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns cached document (or 0 if document not in cache) like capabilities
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param key the key provided by the access control to identify differents documents for the same request
|
||||
* \returns the cached document or 0 if no corresponding document found
|
||||
*/
|
||||
const QDomDocument *getCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Updates or inserts the document in cache like capabilities
|
||||
* \param doc the document to cache
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param key the key provided by the access control to identify differents documents for the same request
|
||||
* \returns true if the document has been cached
|
||||
*/
|
||||
bool setCachedDocument( const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Deletes the cached document
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param key the key provided by the access control to identify differents documents for the same request
|
||||
* \returns true if the document has been deleted
|
||||
*/
|
||||
bool deleteCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Register a server cache filter
|
||||
* \param serverCache the server cache to add
|
||||
* \param priority the priority used to define the order
|
||||
*/
|
||||
void registerServerCache( QgsServerCacheFilter *serverCache, int priority = 0 );
|
||||
|
||||
private:
|
||||
//! The ServerCache plugins registry
|
||||
QgsServerCacheFilterMap *mPluginsServerCaches = nullptr;
|
||||
|
||||
bool mResolved;
|
||||
};
|
||||
|
||||
#endif
|
@ -30,9 +30,13 @@
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
#include "qgsaccesscontrolfilter.h"
|
||||
#include "qgsaccesscontrol.h"
|
||||
#include "qgsservercachefilter.h"
|
||||
#include "qgsservercachemanager.h"
|
||||
#else
|
||||
class QgsAccessControl;
|
||||
class QgsAccessControlFilter;
|
||||
class QgsServerCacheManager;
|
||||
class QgsServerCacheFilter;
|
||||
#endif
|
||||
#include "qgsserviceregistry.h"
|
||||
#include "qgis_server.h"
|
||||
@ -118,6 +122,16 @@ class SERVER_EXPORT QgsServerInterface
|
||||
//! Gets the registered access control filters
|
||||
virtual QgsAccessControl *accessControls() const = 0;
|
||||
|
||||
/**
|
||||
* Register a server cache filter
|
||||
* \param serverCache the server cache to register
|
||||
* \param priority the priority used to order them
|
||||
*/
|
||||
virtual void registerServerCache( QgsServerCacheFilter *serverCache SIP_TRANSFER, int priority = 0 ) = 0;
|
||||
|
||||
//! Gets the registered server cache filters
|
||||
virtual QgsServerCacheManager *cacheManager() const = 0;
|
||||
|
||||
//! Returns an enrironment variable, used to pass environment variables to Python
|
||||
virtual QString getEnv( const QString &name ) const = 0;
|
||||
|
||||
|
@ -29,8 +29,10 @@ QgsServerInterfaceImpl::QgsServerInterfaceImpl( QgsCapabilitiesCache *capCache,
|
||||
mRequestHandler = nullptr;
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
mAccessControls = new QgsAccessControl();
|
||||
mCacheManager = new QgsServerCacheManager();
|
||||
#else
|
||||
mAccessControls = nullptr;
|
||||
mCacheManager = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -84,6 +86,17 @@ void QgsServerInterfaceImpl::registerAccessControl( QgsAccessControlFilter *acce
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Register a new access control filter
|
||||
void QgsServerInterfaceImpl::registerServerCache( QgsServerCacheFilter *serverCache, int priority )
|
||||
{
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
mCacheManager->registerServerCache( serverCache, priority );
|
||||
#else
|
||||
Q_UNUSED( serverCache );
|
||||
Q_UNUSED( priority );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void QgsServerInterfaceImpl::removeConfigCacheEntry( const QString &path )
|
||||
{
|
||||
|
@ -50,8 +50,8 @@ class QgsServerInterfaceImpl : public QgsServerInterface
|
||||
QgsRequestHandler *requestHandler() override { return mRequestHandler; }
|
||||
void registerFilter( QgsServerFilter *filter, int priority = 0 ) override;
|
||||
QgsServerFiltersMap filters() override { return mFilters; }
|
||||
|
||||
//! Register an access control filter
|
||||
//
|
||||
void registerAccessControl( QgsAccessControlFilter *accessControl, int priority = 0 ) override;
|
||||
|
||||
/**
|
||||
@ -59,6 +59,16 @@ class QgsServerInterfaceImpl : public QgsServerInterface
|
||||
* \returns the access control helper
|
||||
*/
|
||||
QgsAccessControl *accessControls() const override { return mAccessControls; }
|
||||
|
||||
//! Register a server cache filter
|
||||
void registerServerCache( QgsServerCacheFilter *serverCache, int priority = 0 ) override;
|
||||
|
||||
/**
|
||||
* Gets the helper over all the registered server cache filters
|
||||
* \returns the server cache helper
|
||||
*/
|
||||
QgsServerCacheManager *cacheManager() const override { return mCacheManager; }
|
||||
|
||||
QString getEnv( const QString &name ) const override;
|
||||
QString configFilePath() override { return mConfigFilePath; }
|
||||
void setConfigFilePath( const QString &configFilePath ) override;
|
||||
@ -74,6 +84,7 @@ class QgsServerInterfaceImpl : public QgsServerInterface
|
||||
QString mConfigFilePath;
|
||||
QgsServerFiltersMap mFilters;
|
||||
QgsAccessControl *mAccessControls = nullptr;
|
||||
QgsServerCacheManager *mCacheManager = nullptr;
|
||||
QgsCapabilitiesCache *mCapabilitiesCache = nullptr;
|
||||
QgsRequestHandler *mRequestHandler = nullptr;
|
||||
QgsServiceRegistry *mServiceRegistry = nullptr;
|
||||
|
@ -37,10 +37,43 @@ namespace QgsWcs
|
||||
void writeGetCapabilities( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
|
||||
const QgsServerRequest &request, QgsServerResponse &response )
|
||||
{
|
||||
QDomDocument doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
QStringList cacheKeyList;
|
||||
bool cache = true;
|
||||
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
if ( accessControl )
|
||||
cache = accessControl->fillCacheKey( cacheKeyList );
|
||||
|
||||
QDomDocument doc;
|
||||
QString cacheKey = cacheKeyList.join( QStringLiteral( "-" ) );
|
||||
const QDomDocument *capabilitiesDocument;
|
||||
|
||||
QgsServerCacheManager *cacheManager = serverIface->cacheManager();
|
||||
if ( cacheManager && cache )
|
||||
{
|
||||
capabilitiesDocument = cacheManager->getCachedDocument( project, request, cacheKey );
|
||||
}
|
||||
|
||||
if ( !capabilitiesDocument ) //capabilities xml not in cache. Create a new one
|
||||
{
|
||||
doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
|
||||
if ( cache && cacheManager )
|
||||
{
|
||||
if ( cacheManager->setCachedDocument( &doc, project, request, cacheKey ) )
|
||||
{
|
||||
capabilitiesDocument = cacheManager->getCachedDocument( project, request, cacheKey );
|
||||
}
|
||||
}
|
||||
if ( !capabilitiesDocument )
|
||||
{
|
||||
doc = doc.cloneNode().toDocument();
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
}
|
||||
|
||||
response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
|
||||
response.write( doc.toByteArray() );
|
||||
response.write( capabilitiesDocument->toByteArray() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,10 +41,43 @@ namespace QgsWfs
|
||||
void writeGetCapabilities( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
|
||||
const QgsServerRequest &request, QgsServerResponse &response )
|
||||
{
|
||||
QDomDocument doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
QStringList cacheKeyList;
|
||||
bool cache = true;
|
||||
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
if ( accessControl )
|
||||
cache = accessControl->fillCacheKey( cacheKeyList );
|
||||
|
||||
QDomDocument doc;
|
||||
QString cacheKey = cacheKeyList.join( QStringLiteral( "-" ) );
|
||||
const QDomDocument *capabilitiesDocument;
|
||||
|
||||
QgsServerCacheManager *cacheManager = serverIface->cacheManager();
|
||||
if ( cacheManager && cache )
|
||||
{
|
||||
capabilitiesDocument = cacheManager->getCachedDocument( project, request, cacheKey );
|
||||
}
|
||||
|
||||
if ( !capabilitiesDocument ) //capabilities xml not in cache. Create a new one
|
||||
{
|
||||
doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
|
||||
if ( cache && cacheManager )
|
||||
{
|
||||
if ( cacheManager->setCachedDocument( &doc, project, request, cacheKey ) )
|
||||
{
|
||||
capabilitiesDocument = cacheManager->getCachedDocument( project, request, cacheKey );
|
||||
}
|
||||
}
|
||||
if ( !capabilitiesDocument )
|
||||
{
|
||||
doc = doc.cloneNode().toDocument();
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
}
|
||||
|
||||
response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
|
||||
response.write( doc.toByteArray() );
|
||||
response.write( capabilitiesDocument->toByteArray() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -43,10 +43,43 @@ namespace QgsWfs
|
||||
void writeGetCapabilities( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
|
||||
const QgsServerRequest &request, QgsServerResponse &response )
|
||||
{
|
||||
QDomDocument doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
QStringList cacheKeyList;
|
||||
bool cache = true;
|
||||
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
if ( accessControl )
|
||||
cache = accessControl->fillCacheKey( cacheKeyList );
|
||||
|
||||
QDomDocument doc;
|
||||
QString cacheKey = cacheKeyList.join( QStringLiteral( "-" ) );
|
||||
const QDomDocument *capabilitiesDocument;
|
||||
|
||||
QgsServerCacheManager *cacheManager = serverIface->cacheManager();
|
||||
if ( cacheManager && cache )
|
||||
{
|
||||
capabilitiesDocument = cacheManager->getCachedDocument( project, request, cacheKey );
|
||||
}
|
||||
|
||||
if ( !capabilitiesDocument ) //capabilities xml not in cache. Create a new one
|
||||
{
|
||||
doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
|
||||
if ( cache && cacheManager )
|
||||
{
|
||||
if ( cacheManager->setCachedDocument( &doc, project, request, cacheKey ) )
|
||||
{
|
||||
capabilitiesDocument = cacheManager->getCachedDocument( project, request, cacheKey );
|
||||
}
|
||||
}
|
||||
if ( !capabilitiesDocument )
|
||||
{
|
||||
doc = doc.cloneNode().toDocument();
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
}
|
||||
|
||||
response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
|
||||
response.write( doc.toByteArray() );
|
||||
response.write( capabilitiesDocument->toByteArray() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,15 +100,26 @@ namespace QgsWms
|
||||
cacheKeyList << request.url().host();
|
||||
bool cache = true;
|
||||
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
if ( accessControl )
|
||||
cache = accessControl->fillCacheKey( cacheKeyList );
|
||||
#endif
|
||||
|
||||
|
||||
QDomDocument doc;
|
||||
QString cacheKey = cacheKeyList.join( QStringLiteral( "-" ) );
|
||||
const QDomDocument *capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey );
|
||||
const QDomDocument *capabilitiesDocument;
|
||||
|
||||
QgsServerCacheManager *cacheManager = serverIface->cacheManager();
|
||||
if ( cacheManager && cache )
|
||||
{
|
||||
if ( cacheKeyList.count() == 2 )
|
||||
capabilitiesDocument = cacheManager->getCachedDocument( project, request, QStringLiteral( "" ) );
|
||||
else if ( cacheKeyList.count() > 2 )
|
||||
capabilitiesDocument = cacheManager->getCachedDocument( project, request, cacheKeyList.at( 3 ) );
|
||||
}
|
||||
|
||||
if ( !capabilitiesDocument ) //capabilities xml not in cache plugins
|
||||
capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey );
|
||||
if ( !capabilitiesDocument ) //capabilities xml not in cache. Create a new one
|
||||
{
|
||||
QgsMessageLog::logMessage( QStringLiteral( "Capabilities document not found in cache" ) );
|
||||
@ -117,10 +128,26 @@ namespace QgsWms
|
||||
|
||||
if ( cache )
|
||||
{
|
||||
capabilitiesCache->insertCapabilitiesDocument( configFilePath, cacheKey, &doc );
|
||||
capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey );
|
||||
if ( cacheManager )
|
||||
{
|
||||
if ( cacheKeyList.count() == 2 &&
|
||||
cacheManager->setCachedDocument( &doc, project, request, QStringLiteral( "" ) ) )
|
||||
{
|
||||
capabilitiesDocument = cacheManager->getCachedDocument( project, request, QStringLiteral( "" ) );
|
||||
}
|
||||
else if ( cacheKeyList.count() > 2 &&
|
||||
cacheManager->setCachedDocument( &doc, project, request, cacheKeyList.at( 3 ) ) )
|
||||
{
|
||||
capabilitiesDocument = cacheManager->getCachedDocument( project, request, cacheKeyList.at( 3 ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
capabilitiesCache->insertCapabilitiesDocument( configFilePath, cacheKey, &doc );
|
||||
capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey );
|
||||
}
|
||||
}
|
||||
else
|
||||
if ( !capabilitiesDocument )
|
||||
{
|
||||
doc = doc.cloneNode().toDocument();
|
||||
capabilitiesDocument = &doc;
|
||||
|
@ -268,6 +268,7 @@ IF (WITH_SERVER)
|
||||
ADD_PYTHON_TEST(PyQgsServerAccessControlWFS test_qgsserver_accesscontrol_wfs.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerAccessControlWCS test_qgsserver_accesscontrol_wcs.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerAccessControlWFSTransactional test_qgsserver_accesscontrol_wfs_transactional.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerCacheManager test_qgsserver_cachemanager.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerWFS test_qgsserver_wfs.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerWFST test_qgsserver_wfst.py)
|
||||
ADD_PYTHON_TEST(PyQgsOfflineEditingWFS test_offline_editing_wfs.py)
|
||||
|
154
tests/src/python/test_qgsserver_cachemanager.py
Normal file
154
tests/src/python/test_qgsserver_cachemanager.py
Normal file
@ -0,0 +1,154 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""QGIS Unit tests for QgsServer.
|
||||
|
||||
.. note:: 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; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
"""
|
||||
__author__ = 'René-Luc DHONT'
|
||||
__date__ = '19/07/2018'
|
||||
__copyright__ = 'Copyright 2015, The QGIS Project'
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
print('CTEST_FULL_OUTPUT')
|
||||
|
||||
import qgis # NOQA
|
||||
|
||||
import os
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
import urllib.error
|
||||
import tempfile
|
||||
import hashlib
|
||||
|
||||
from qgis.testing import unittest
|
||||
from utilities import unitTestDataPath
|
||||
from qgis.server import QgsServer, QgsServerCacheFilter, QgsServerRequest, QgsBufferServerRequest, QgsBufferServerResponse
|
||||
from qgis.core import QgsApplication, QgsFontUtils
|
||||
from qgis.PyQt.QtCore import QFile, QByteArray
|
||||
from qgis.PyQt.QtXml import QDomDocument
|
||||
|
||||
|
||||
class PyServerCache(QgsServerCacheFilter):
|
||||
|
||||
""" Used to have restriction access """
|
||||
|
||||
# Be able to deactivate the access control to have a reference point
|
||||
_active = False
|
||||
|
||||
def __init__(self, server_iface):
|
||||
super(QgsServerCacheFilter, self).__init__(server_iface)
|
||||
self._cache_dir = os.path.join(tempfile.gettempdir(), "qgs_server_cache")
|
||||
if not os.path.exists(self._cache_dir):
|
||||
os.mkdir(self._cache_dir)
|
||||
|
||||
def getCachedDocument(self, project, request, key):
|
||||
m = hashlib.md5()
|
||||
paramMap = request.parameters()
|
||||
urlParam = "&".join(["%s=%s" % (k, paramMap[k]) for k in paramMap.keys()])
|
||||
m.update(urlParam.encode('utf8'))
|
||||
|
||||
if not os.path.exists(os.path.join(self._cache_dir, m.hexdigest() + ".xml")):
|
||||
return QByteArray()
|
||||
|
||||
doc = QDomDocument(m.hexdigest() + ".xml")
|
||||
with open(os.path.join(self._cache_dir, m.hexdigest() + ".xml"), "r") as f:
|
||||
statusOK, errorStr, errorLine, errorColumn = doc.setContent(f.read(), True)
|
||||
if not statusOK:
|
||||
print("Could not read or find the contents document. Error at line %d, column %d:\n%s" % (errorLine, errorColumn, errorStr))
|
||||
return QByteArray()
|
||||
|
||||
return doc.toByteArray()
|
||||
|
||||
def setCachedDocument(self, doc, project, request, key):
|
||||
m = hashlib.md5()
|
||||
paramMap = request.parameters()
|
||||
urlParam = "&".join(["%s=%s" % (k, paramMap[k]) for k in paramMap.keys()])
|
||||
m.update(urlParam.encode('utf8'))
|
||||
with open(os.path.join(self._cache_dir, m.hexdigest() + ".xml"), "w") as f:
|
||||
f.write(doc.toString())
|
||||
return os.path.exists(os.path.join(self._cache_dir, m.hexdigest() + ".xml"))
|
||||
|
||||
|
||||
class TestQgsServerCacheManager(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def _handle_request(cls, qs, requestMethod=QgsServerRequest.GetMethod, data=None):
|
||||
if data is not None:
|
||||
data = data.encode('utf-8')
|
||||
request = QgsBufferServerRequest(qs, requestMethod, {}, data)
|
||||
response = QgsBufferServerResponse()
|
||||
cls._server.handleRequest(request, response)
|
||||
headers = []
|
||||
rh = response.headers()
|
||||
rk = sorted(rh.keys())
|
||||
for k in rk:
|
||||
headers.append(("%s: %s" % (k, rh[k])).encode('utf-8'))
|
||||
return b"\n".join(headers) + b"\n\n", bytes(response.body())
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
"""Run before all tests"""
|
||||
cls._app = QgsApplication([], False)
|
||||
cls._server = QgsServer()
|
||||
cls._handle_request("")
|
||||
cls._server_iface = cls._server.serverInterface()
|
||||
cls._servercache = PyServerCache(cls._server_iface)
|
||||
cls._server_iface.registerServerCache(cls._servercache, 100)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
"""Run after all tests"""
|
||||
filelist = [f for f in os.listdir(cls._servercache._cache_dir) if f.endswith(".xml")]
|
||||
for f in filelist:
|
||||
os.remove(os.path.join(cls._servercache._cache_dir, f))
|
||||
del cls._server
|
||||
cls._app.exitQgis
|
||||
|
||||
def _result(self, data):
|
||||
headers = {}
|
||||
for line in data[0].decode('UTF-8').split("\n"):
|
||||
if line != "":
|
||||
header = line.split(":")
|
||||
self.assertEqual(len(header), 2, line)
|
||||
headers[str(header[0])] = str(header[1]).strip()
|
||||
|
||||
return data[1], headers
|
||||
|
||||
def _execute_request(self, qs, requestMethod=QgsServerRequest.GetMethod, data=None):
|
||||
request = QgsBufferServerRequest(qs, requestMethod, {}, data)
|
||||
response = QgsBufferServerResponse()
|
||||
self._server.handleRequest(request, response)
|
||||
headers = []
|
||||
rh = response.headers()
|
||||
rk = sorted(rh.keys())
|
||||
for k in rk:
|
||||
headers.append(("%s: %s" % (k, rh[k])).encode('utf-8'))
|
||||
return b"\n".join(headers) + b"\n\n", bytes(response.body())
|
||||
|
||||
def setUp(self):
|
||||
"""Create the server instance"""
|
||||
self.fontFamily = QgsFontUtils.standardTestFontFamily()
|
||||
QgsFontUtils.loadStandardTestFonts(['All'])
|
||||
|
||||
d = unitTestDataPath('qgis_server_accesscontrol') + '/'
|
||||
self._project_path = os.path.join(d, "project.qgs")
|
||||
|
||||
def test_getcapabilities(self):
|
||||
project = self._project_path
|
||||
assert os.path.exists(project), "Project file not found: " + project
|
||||
|
||||
query_string = '?MAP=%s&SERVICE=WMS&VERSION=1.3.0&REQUEST=%s' % (urllib.parse.quote(project), 'GetCapabilities')
|
||||
header, body = self._execute_request(query_string)
|
||||
|
||||
query_string = '?MAP=%s&SERVICE=WFS&VERSION=1.1.0&REQUEST=%s' % (urllib.parse.quote(project), 'GetCapabilities')
|
||||
header, body = self._execute_request(query_string)
|
||||
|
||||
query_string = '?MAP=%s&SERVICE=WCS&VERSION=1.0.0&REQUEST=%s' % (urllib.parse.quote(project), 'GetCapabilities')
|
||||
header, body = self._execute_request(query_string)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user