Move wcs as service module

This commit is contained in:
David Marteau 2017-01-17 00:09:24 +01:00
parent 56b2f08865
commit e17a7d4e21
35 changed files with 1026 additions and 886 deletions

View File

@ -84,11 +84,16 @@ IF(WITH_APIDOC)
${DOXYGEN_INPUT}
${CMAKE_SOURCE_DIR}/src/server/qgsserver.h
${CMAKE_SOURCE_DIR}/src/server/qgscapabilitiescache.h
${CMAKE_SOURCE_DIR}/src/server/qgsmapserviceexception.h
${CMAKE_SOURCE_DIR}/src/server/qgsserverexception.h
${CMAKE_SOURCE_DIR}/src/server/qgsrequesthandler.h
${CMAKE_SOURCE_DIR}/src/server/qgsserverfilter.h
${CMAKE_SOURCE_DIR}/src/server/qgsaccesscontrolfilter.h
${CMAKE_SOURCE_DIR}/src/server/qgsserverinterface.h
${CMAKE_SOURCE_DIR}/src/server/qgsserverrequest.h
${CMAKE_SOURCE_DIR}/src/server/qgsserverresponse.h
${CMAKE_SOURCE_DIR}/src/server/qgsserverrequest.h
${CMAKE_SOURCE_DIR}/src/server/qgsservice.h
${CMAKE_SOURCE_DIR}/src/server/qgsserviceregistry.h
)
ENDIF(WITH_SERVER_PLUGINS)

View File

@ -1898,6 +1898,13 @@ optional property map passing down layer level properties to the SLD encoders. I
- usedAttributes is now a const method and returns QSet<QString> instead of QStringList
QgsRequestHandler {#qgis_api_break_3_0_QgsRequestHandler}
-----------------
- Removed infoFormat and setInfoFormat methods: the format of the response is given and set with the "Content-Type" header.
- Removed setCoverageResponse
Processing {#qgis_api_break_3_0_Processing}
----------

View File

@ -29,9 +29,6 @@ class QgsRequestHandler /Abstract/
/** Allow plugins to return a QgsServerException*/
void setServiceException( const QgsServerException& ex );
//! @note not available in Python bindings
void setGetCoverageResponse( QByteArray* ba );
/** Set an HTTP header*/
void setHeader( const QString &name, const QString &value );
@ -50,9 +47,6 @@ class QgsRequestHandler /Abstract/
/** Append the bytestream to response body*/
void appendBody( const QByteArray &body );
/** Set the info format string such as "text/xml"*/
void setInfoFormat( const QString &format );
/** Send out HTTP headers and flush output buffer*/
void sendResponse();
@ -77,9 +71,6 @@ class QgsRequestHandler /Abstract/
/** Return the requested format string*/
QString format() const;
/** Return the mime type for the response*/
QString infoFormat() const;
/** Return true if the HTTP headers were already sent to the client*/
bool headersSent() const;
};

View File

@ -47,6 +47,7 @@ class QgsOgcServiceException
QString message() const;
QString code() const;
QString locator() const;
QString version() const;
virtual QByteArray formatResponse( QString& responseFormat / Out / ) const;
};

View File

@ -79,6 +79,21 @@ class QgsServerRequest
*/
QMap<QString, QString> parameters() const;
/**
* Set a parameter
*/
void setParameter( const QString& key, const QString& value );
/**
* Get a parameter value
*/
QString getParameter( const QString& key ) const;
/**
* Remove a parameter
*/
void removeParameter( const QString& key );
/**
* Return post/put data
* Check for QByteArray::isNull() to check if data

View File

@ -24,8 +24,6 @@ SET ( qgis_mapserv_SRCS
qgscapabilitiescache.cpp
qgsconfigcache.cpp
qgsrequesthandler.cpp
qgsowsserver.cpp
qgswcsserver.cpp
qgsserversettings.cpp
qgsserverexception.cpp
qgsmslayercache.cpp

View File

@ -1,66 +0,0 @@
/***************************************************************************
qgsowsserver.cpp
-------------------
begin : February 27, 2012
copyright : (C) 2012 by René-Luc D'Hont & Marco Hugentobler
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 "qgsowsserver.h"
#include "qgsmessagelog.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#ifdef HAVE_SERVER_PYTHON_PLUGINS
//! Apply filter from AccessControl
void QgsOWSServer::applyAccessControlLayerFilters( QgsMapLayer* mapLayer, QHash<QgsMapLayer*, QString>& originalLayerFilters ) const
{
if ( QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( mapLayer ) )
{
QString sql = mAccessControl->extraSubsetString( layer );
if ( !sql.isEmpty() )
{
if ( !originalLayerFilters.contains( layer ) )
{
originalLayerFilters.insert( layer, layer->subsetString() );
}
if ( !layer->subsetString().isEmpty() )
{
sql.prepend( " AND " );
sql.prepend( layer->subsetString() );
}
if ( !layer->setSubsetString( sql ) )
{
QgsMessageLog::logMessage( QStringLiteral( "Layer does not support Subset String" ) );
}
}
}
}
#endif
//! Restore layer filter as original
void QgsOWSServer::restoreLayerFilters( const QHash<QgsMapLayer*, QString>& filterMap )
{
QHash<QgsMapLayer*, QString>::const_iterator filterIt = filterMap.constBegin();
for ( ; filterIt != filterMap.constEnd(); ++filterIt )
{
QgsVectorLayer* filteredLayer = qobject_cast<QgsVectorLayer*>( filterIt.key() );
if ( filteredLayer )
{
QgsVectorDataProvider* dp = filteredLayer->dataProvider();
if ( dp )
{
dp->setSubsetString( filterIt.value() );
}
}
}
}

View File

@ -1,110 +0,0 @@
/***************************************************************************
qgsowsserver.h
--------------
begin : March 24, 2014
copyright : (C) 2006 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************/
/***************************************************************************
* *
* 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 QGSOWSSERVER_H
#define QGSOWSSERVER_H
#include "qgsconfig.h"
#include "qgsrequesthandler.h"
#include "qgsserversettings.h"
#ifdef HAVE_SERVER_PYTHON_PLUGINS
#include "qgsaccesscontrol.h"
#else
class QgsAccessControl;
#endif
#include <QHash>
class QgsMapLayer;
class QgsOWSServer
{
public:
QgsOWSServer(
const QString& configFilePath
, const QgsServerSettings& settings
, const QMap<QString, QString>& parameters
, QgsRequestHandler* rh
, QgsAccessControl* ac
)
: mSettings( settings )
, mParameters( parameters )
, mRequestHandler( rh )
, mConfigFilePath( configFilePath )
, mAccessControl( ac )
{}
virtual ~QgsOWSServer() = default;
virtual void executeRequest() = 0;
/** Restores the original layer filters
* @param filterMap the original layer filter
*/
static void restoreLayerFilters( const QHash < QgsMapLayer*, QString >& filterMap );
private:
QgsOWSServer() {}
protected:
QgsServerSettings mSettings;
QMap<QString, QString> mParameters;
QgsRequestHandler* mRequestHandler;
QString mConfigFilePath;
//! The access control helper
QgsAccessControl* mAccessControl;
#ifdef HAVE_SERVER_PYTHON_PLUGINS
/** Apply filter strings from the access control to the layers.
* @param layer the concerned layer
* @param originalLayerFilters the original layer filter
*
*/
void applyAccessControlLayerFilters( QgsMapLayer* layer, QHash<QgsMapLayer*, QString>& originalLayerFilters ) const;
#endif
};
/** RAII class to restore layer filters on destruction
*/
class QgsOWSServerFilterRestorer
{
public:
QgsOWSServerFilterRestorer() = default;
QgsOWSServerFilterRestorer( const QgsOWSServerFilterRestorer& rh ) = delete;
QgsOWSServerFilterRestorer& operator=( const QgsOWSServerFilterRestorer& rh ) = delete;
//! Destructor. When object is destroyed all original layer filters will be restored.
~QgsOWSServerFilterRestorer()
{
QgsOWSServer::restoreLayerFilters( mOriginalLayerFilters );
}
/** Returns a reference to the object's hash of layers to original subsetString filters.
* Original layer subsetString filters MUST be inserted into this hash before modifying them.
*/
QHash<QgsMapLayer*, QString>& originalFilters() { return mOriginalLayerFilters; }
private:
QHash<QgsMapLayer*, QString> mOriginalLayerFilters;
};
#endif // QGSOWSSERVER_H

View File

@ -53,20 +53,6 @@ QMap<QString, QString> QgsRequestHandler::parameterMap() const
return mRequest.parameters();
}
void QgsRequestHandler::setHttpResponse( const QByteArray& ba, const QString &format )
{
QgsMessageLog::logMessage( QStringLiteral( "Checking byte array is ok to set..." ) );
if ( ba.size() < 1 )
{
return;
}
QgsMessageLog::logMessage( QStringLiteral( "Byte array looks good, setting response..." ) );
appendBody( ba );
setInfoFormat( format );
}
bool QgsRequestHandler::exceptionRaised() const
{
return mExceptionRaised;
@ -107,55 +93,12 @@ void QgsRequestHandler::appendBody( const QByteArray &body )
mResponse.write( body );
}
void QgsRequestHandler::setInfoFormat( const QString &format )
{
mInfoFormat = format;
// Update header
QString fmt = mInfoFormat;
if ( mInfoFormat.startsWith( QLatin1String( "text/" ) ) || mInfoFormat.startsWith( QLatin1String( "application/vnd.ogc.gml" ) ) )
{
fmt.append( "; charset=utf-8" );
}
setHeader( QStringLiteral( "Content-Type" ), fmt );
}
void QgsRequestHandler::sendResponse()
{
// Send data to output
mResponse.flush();
}
QString QgsRequestHandler::formatToMimeType( const QString& format ) const
{
if ( format.compare( QLatin1String( "png" ), Qt::CaseInsensitive ) == 0 )
{
return QStringLiteral( "image/png" );
}
else if ( format.compare( QLatin1String( "jpg" ), Qt::CaseInsensitive ) == 0 )
{
return QStringLiteral( "image/jpeg" );
}
else if ( format.compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 )
{
return QStringLiteral( "image/svg+xml" );
}
else if ( format.compare( QLatin1String( "pdf" ), Qt::CaseInsensitive ) == 0 )
{
return QStringLiteral( "application/pdf" );
}
return format;
}
void QgsRequestHandler::setGetCapabilitiesResponse( const QDomDocument& doc )
{
QByteArray ba = doc.toByteArray();
setHttpResponse( ba, QStringLiteral( "text/xml" ) );
}
void QgsRequestHandler::setServiceException( const QgsServerException& ex )
{
// Safety measure to avoid potential leaks if called repeatedly
@ -163,14 +106,6 @@ void QgsRequestHandler::setServiceException( const QgsServerException& ex )
mResponse.write( ex );
}
void QgsRequestHandler::setGetCoverageResponse( QByteArray* ba )
{
if ( ba )
{
setHttpResponse( *ba, QStringLiteral( "image/tiff" ) );
}
}
void QgsRequestHandler::setupParameters()
{
const QgsServerRequest::Parameters parameters = mRequest.parameters();

View File

@ -54,15 +54,9 @@ class SERVER_EXPORT QgsRequestHandler
explicit QgsRequestHandler( QgsServerRequest& request, QgsServerResponse& response );
~QgsRequestHandler();
//! @note not available in Python bindings
void setGetCapabilitiesResponse( const QDomDocument& doc );
//! Allow plugins to return a QgsMapServiceException
void setServiceException( const QgsServerException &ex );
//! @note not available in Python bindings
void setGetCoverageResponse( QByteArray* ba );
/** Send out HTTP headers and flush output buffer
*
* This method is intended only for streaming
@ -88,9 +82,6 @@ class SERVER_EXPORT QgsRequestHandler
//! Set the info format string such as "text/xml"
void appendBody( const QByteArray &body );
//! Set the info format string such as "text/xml"
void setInfoFormat( const QString &format );
//! Pointer to last raised exception
bool exceptionRaised() const;
@ -117,19 +108,9 @@ class SERVER_EXPORT QgsRequestHandler
//! Return the requested format string
QString format() const { return mFormat; }
//! Return the mime type for the response
QString infoFormat() const { return mInfoFormat; }
//! Return true if the HTTP headers were already sent to the client
bool headersSent() const;
private:
void setHttpResponse( const QByteArray& ba, const QString &format );
/** Converts format to official mimetype (e.g. 'jpg' to 'image/jpeg')
@return mime string (or the entered string if not found)*/
QString formatToMimeType( const QString& format ) const;
private:
void setupParameters();
@ -138,7 +119,6 @@ class SERVER_EXPORT QgsRequestHandler
QString mFormat;
QString mFormatString; //format string as it is passed in the request (with base)
QString mService;
QString mInfoFormat;
bool mExceptionRaised;
QgsServerRequest& mRequest;

View File

@ -22,7 +22,6 @@
#include "qgsconfig.h"
#include "qgsserver.h"
#include "qgsmslayercache.h"
#include "qgsmapsettings.h"
#include "qgsauthmanager.h"
#include "qgscapabilitiescache.h"
@ -31,7 +30,6 @@
#include "qgsproject.h"
#include "qgsproviderregistry.h"
#include "qgslogger.h"
#include "qgswcsserver.h"
#include "qgsmapserviceexception.h"
#include "qgspallabeling.h"
#include "qgsnetworkaccessmanager.h"
@ -403,8 +401,6 @@ void QgsServer::handleRequest( QgsServerRequest& request, QgsServerResponse& res
QMap<QString, QString> parameterMap = request.parameters();
printRequestParameters( parameterMap, logLevel );
QgsAccessControl* accessControl = sServerInterface->accessControls();
//Config file path
QString configFilePath = configPath( *sConfigFilePath, parameterMap );
@ -438,31 +434,6 @@ void QgsServer::handleRequest( QgsServerRequest& request, QgsServerResponse& res
{
service->executeRequest( request, theResponse );
}
else if ( serviceString == QLatin1String( "WCS" ) )
{
QgsWCSProjectParser* p = QgsConfigCache::instance()->wcsConfiguration(
configFilePath
, accessControl
);
if ( !p )
{
theRequestHandler.setServiceException( QgsMapServiceException( QStringLiteral( "Project file error" ),
QStringLiteral( "Error reading the project file" ) ) );
}
else
{
QgsWCSServer wcsServer(
configFilePath
, sSettings
, parameterMap
, p
, &theRequestHandler
, accessControl
);
wcsServer.executeRequest();
}
}
else
{
throw QgsOgcServiceException( QStringLiteral( "Service configuration error" ),

View File

@ -27,10 +27,13 @@
/** \ingroup server
* \class QgsServerException
* \brief Exception base class for server exceptions.
*
* @note added in QGIS 3.0
*/
class SERVER_EXPORT QgsServerException : public QgsException
{
public:
//! Constructor
QgsServerException( const QString& message, int responseCode = 500 );
/**
@ -52,23 +55,34 @@ class SERVER_EXPORT QgsServerException : public QgsException
};
/** \ingroup server
* \class QgsOcgServiceException
* \class QgsOgcServiceException
* \brief Exception base class for service exceptions.
*
* Note that this exception is assaciated with a default return code 200 which may be
* Note that this exception is associated with a default return code 200 which may be
* not appropriate in some situations.
*
* @note added in QGIS 3.0
*/
class SERVER_EXPORT QgsOgcServiceException : public QgsServerException
{
public:
//! Construction
QgsOgcServiceException( const QString& code, const QString& message, const QString& locator = QString(),
int responseCode = 200, const QString& version = QStringLiteral( "1.3.0" ) );
//! @return message
QString message() const { return mMessage; }
//! @return code
QString code() const { return mCode; }
//! @return locator
QString locator() const { return mLocator; }
//!return exception version
QString version() const { return mVersion; }
//! Overrided from QgsServerException
virtual QByteArray formatResponse( QString& responseFormat ) const override;
private:
@ -76,8 +90,6 @@ class SERVER_EXPORT QgsOgcServiceException : public QgsServerException
QString mMessage;
QString mLocator;
QString mVersion;
};
#endif

View File

@ -27,6 +27,8 @@
* \ingroup server
* QgsServerRequest
* Class defining request interface passed to services QgsService::executeRequest() method
*
* @note added in QGIS 3.0
*/
// Note about design: this interface must be passed along to python and thus signatures methods must be
@ -38,6 +40,9 @@ class SERVER_EXPORT QgsServerRequest
typedef QMap<QString, QString> Parameters;
/**
* HTTP Method (or equivalent) used for the request
*/
enum Method
{
HeadMethod, PutMethod, GetMethod, PostMethod, DeleteMethod

View File

@ -30,6 +30,8 @@ class QgsServerException;
* \ingroup server
* QgsServerResponse
* Class defining response interface passed to services QgsService::executeRequest() method
*
* @note added in QGIS 3.0
*/
// Note:

View File

@ -35,6 +35,7 @@ class QgsProject;
* This class provides methods for executing server requests
* They are registered at runtime for a given service name.
*
* @note added in QGIS 3.0
*/
class SERVER_EXPORT QgsService
{

View File

@ -41,6 +41,7 @@ class QgsServerInterface;
* IMPORTANT: The registry hold ownership of registered services and
* will call 'delete' on cleanup
*
* @note added in QGIS 3.0
*/
class SERVER_EXPORT QgsServiceRegistry
{

View File

@ -1,493 +0,0 @@
/***************************************************************************
qgswcsserver.cpp
-------------------
begin : December 9, 2013
copyright : (C) 2013 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 "qgswcsserver.h"
#include "qgswcsprojectparser.h"
#include "qgsrasterdataprovider.h"
#include "qgsrasterlayer.h"
#include "qgsrasterpipe.h"
#include "qgsrasterprojector.h"
#include "qgsrasterfilewriter.h"
#include "qgslogger.h"
#include "qgsmapserviceexception.h"
#include "qgsaccesscontrol.h"
#include <QTemporaryFile>
#include <QUrl>
#ifndef Q_OS_WIN
#include <netinet/in.h>
#else
#include <winsock.h>
#endif
static const QString WCS_NAMESPACE = QStringLiteral( "http://www.opengis.net/wcs" );
static const QString GML_NAMESPACE = QStringLiteral( "http://www.opengis.net/gml" );
static const QString OGC_NAMESPACE = QStringLiteral( "http://www.opengis.net/ogc" );
QgsWCSServer::QgsWCSServer(
const QString& configFilePath
, const QgsServerSettings& settings
, QMap<QString, QString> &parameters
, QgsWCSProjectParser* pp
, QgsRequestHandler* rh
, QgsAccessControl* accessControl
)
: QgsOWSServer(
configFilePath
, settings
, parameters
, rh
, accessControl
)
, mConfigParser(
pp
)
{
}
QgsWCSServer::QgsWCSServer()
: QgsOWSServer(
QString()
, QgsServerSettings()
, QMap<QString, QString>()
, nullptr
, nullptr
)
, mConfigParser( nullptr )
{
}
void QgsWCSServer::executeRequest()
{
//request type
QString request = mParameters.value( QStringLiteral( "REQUEST" ) );
if ( request.isEmpty() )
{
//do some error handling
QgsDebugMsg( "unable to find 'REQUEST' parameter, exiting..." );
mRequestHandler->setServiceException( QgsMapServiceException( QStringLiteral( "OperationNotSupported" ), QStringLiteral( "Please check the value of the REQUEST parameter" ) ) );
return;
}
if ( request.compare( QLatin1String( "GetCapabilities" ), Qt::CaseInsensitive ) == 0 )
{
QDomDocument capabilitiesDocument;
try
{
capabilitiesDocument = getCapabilities();
}
catch ( QgsMapServiceException& ex )
{
mRequestHandler->setServiceException( ex );
return;
}
QgsDebugMsg( "seting GetCapabilities response" );
mRequestHandler->setGetCapabilitiesResponse( capabilitiesDocument );
return;
}
else if ( request.compare( QLatin1String( "DescribeCoverage" ), Qt::CaseInsensitive ) == 0 )
{
QDomDocument describeDocument;
try
{
describeDocument = describeCoverage();
}
catch ( QgsMapServiceException& ex )
{
mRequestHandler->setServiceException( ex );
return;
}
QgsDebugMsg( "seting GetCapabilities response" );
mRequestHandler->setGetCapabilitiesResponse( describeDocument );
return;
}
else if ( request.compare( QLatin1String( "GetCoverage" ), Qt::CaseInsensitive ) == 0 )
{
QByteArray* coverageOutput;
try
{
coverageOutput = getCoverage();
}
catch ( QgsMapServiceException& ex )
{
mRequestHandler->setServiceException( ex );
return;
}
if ( coverageOutput )
{
mRequestHandler->setGetCoverageResponse( coverageOutput );
}
return;
}
}
QDomDocument QgsWCSServer::getCapabilities()
{
QgsDebugMsg( "Entering." );
QDomDocument doc;
//wcs:WCS_Capabilities element
QDomElement wcsCapabilitiesElement = doc.createElement( QStringLiteral( "WCS_Capabilities" )/*wcs:WCS_Capabilities*/ );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns" ), WCS_NAMESPACE );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WCS_NAMESPACE + " http://schemas.opengis.net/wcs/1.0.0/wcsCapabilities.xsd" );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "updateSequence" ), QStringLiteral( "0" ) );
doc.appendChild( wcsCapabilitiesElement );
if ( mConfigParser )
{
mConfigParser->serviceCapabilities( wcsCapabilitiesElement, doc );
}
//INSERT Service
//wcs:Capability element
QDomElement capabilityElement = doc.createElement( QStringLiteral( "Capability" )/*wcs:Capability*/ );
wcsCapabilitiesElement.appendChild( capabilityElement );
//wcs:Request element
QDomElement requestElement = doc.createElement( QStringLiteral( "Request" )/*wcs:Request*/ );
capabilityElement.appendChild( requestElement );
//wcs:GetCapabilities
QDomElement getCapabilitiesElement = doc.createElement( QStringLiteral( "GetCapabilities" )/*wcs:GetCapabilities*/ );
requestElement.appendChild( getCapabilitiesElement );
QDomElement dcpTypeElement = doc.createElement( QStringLiteral( "DCPType" )/*wcs:DCPType*/ );
getCapabilitiesElement.appendChild( dcpTypeElement );
QDomElement httpElement = doc.createElement( QStringLiteral( "HTTP" )/*wcs:HTTP*/ );
dcpTypeElement.appendChild( httpElement );
//Prepare url
QString hrefString;
if ( mConfigParser )
{
hrefString = mConfigParser->wcsServiceUrl();
if ( hrefString.isEmpty() )
{
hrefString = mConfigParser->serviceUrl();
}
}
if ( hrefString.isEmpty() )
{
hrefString = serviceUrl();
}
QDomElement getElement = doc.createElement( QStringLiteral( "Get" )/*wcs:Get*/ );
httpElement.appendChild( getElement );
QDomElement onlineResourceElement = doc.createElement( QStringLiteral( "OnlineResource" )/*wcs:OnlineResource*/ );
onlineResourceElement.setAttribute( QStringLiteral( "xlink:type" ), QStringLiteral( "simple" ) );
onlineResourceElement.setAttribute( QStringLiteral( "xlink:href" ), hrefString );
getElement.appendChild( onlineResourceElement );
QDomElement getCapabilitiesDhcTypePostElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities'
getCapabilitiesDhcTypePostElement.firstChild().firstChild().toElement().setTagName( QStringLiteral( "Post" ) );
getCapabilitiesElement.appendChild( getCapabilitiesDhcTypePostElement );
QDomElement describeCoverageElement = getCapabilitiesElement.cloneNode().toElement();//this is the same as 'GetCapabilities'
describeCoverageElement.setTagName( QStringLiteral( "DescribeCoverage" ) );
requestElement.appendChild( describeCoverageElement );
QDomElement getCoverageElement = getCapabilitiesElement.cloneNode().toElement();//this is the same as 'GetCapabilities'
getCoverageElement.setTagName( QStringLiteral( "GetCoverage" ) );
requestElement.appendChild( getCoverageElement );
/*
* Adding layer list in ContentMetadata
*/
QDomElement contentMetadataElement = doc.createElement( QStringLiteral( "ContentMetadata" )/*wcs:ContentMetadata*/ );
wcsCapabilitiesElement.appendChild( contentMetadataElement );
/*
* Adding layer list in contentMetadataElement
*/
if ( mConfigParser )
{
mConfigParser->wcsContentMetadata( contentMetadataElement, doc );
}
return doc;
}
QDomDocument QgsWCSServer::describeCoverage()
{
QgsDebugMsg( "Entering." );
QDomDocument doc;
//wcs:WCS_Capabilities element
QDomElement coveDescElement = doc.createElement( QStringLiteral( "CoverageDescription" )/*wcs:CoverageDescription*/ );
coveDescElement.setAttribute( QStringLiteral( "xmlns" ), WCS_NAMESPACE );
coveDescElement.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
coveDescElement.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WCS_NAMESPACE + " http://schemas.opengis.net/wcs/1.0.0/describeCoverage.xsd" );
coveDescElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE );
coveDescElement.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
coveDescElement.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
coveDescElement.setAttribute( QStringLiteral( "updateSequence" ), QStringLiteral( "0" ) );
doc.appendChild( coveDescElement );
//defining coverage name
QString coveName = QLatin1String( "" );
//read COVERAGE
QMap<QString, QString>::const_iterator cove_name_it = mParameters.constFind( QStringLiteral( "COVERAGE" ) );
if ( cove_name_it != mParameters.constEnd() )
{
coveName = cove_name_it.value();
}
if ( coveName == QLatin1String( "" ) )
{
QMap<QString, QString>::const_iterator cove_name_it = mParameters.constFind( QStringLiteral( "IDENTIFIER" ) );
if ( cove_name_it != mParameters.constEnd() )
{
coveName = cove_name_it.value();
}
}
mConfigParser->describeCoverage( coveName, coveDescElement, doc );
return doc;
}
QByteArray* QgsWCSServer::getCoverage()
{
QStringList wcsLayersId = mConfigParser->wcsLayers();
QList<QgsMapLayer*> layerList;
QStringList mErrors = QStringList();
//defining coverage name
QString coveName = QLatin1String( "" );
//read COVERAGE
QMap<QString, QString>::const_iterator cove_name_it = mParameters.constFind( QStringLiteral( "COVERAGE" ) );
if ( cove_name_it != mParameters.constEnd() )
{
coveName = cove_name_it.value();
}
if ( coveName == QLatin1String( "" ) )
{
QMap<QString, QString>::const_iterator cove_name_it = mParameters.constFind( QStringLiteral( "IDENTIFIER" ) );
if ( cove_name_it != mParameters.constEnd() )
{
coveName = cove_name_it.value();
}
}
if ( coveName == QLatin1String( "" ) )
{
mErrors << QStringLiteral( "COVERAGE is mandatory" );
}
layerList = mConfigParser->mapLayerFromCoverage( coveName );
if ( layerList.size() < 1 )
{
mErrors << QStringLiteral( "The layer for the COVERAGE '%1' is not found" ).arg( coveName );
}
bool conversionSuccess;
// BBOX
bool bboxOk = false;
double minx = 0.0, miny = 0.0, maxx = 0.0, maxy = 0.0;
// WIDTh and HEIGHT
int width = 0, height = 0;
// CRS
QString crs = QLatin1String( "" );
// read BBOX
QMap<QString, QString>::const_iterator bbIt = mParameters.constFind( QStringLiteral( "BBOX" ) );
if ( bbIt == mParameters.constEnd() )
{
minx = 0;
miny = 0;
maxx = 0;
maxy = 0;
}
else
{
bboxOk = true;
QString bbString = bbIt.value();
minx = bbString.section( QStringLiteral( "," ), 0, 0 ).toDouble( &conversionSuccess );
if ( !conversionSuccess ) {bboxOk = false;}
miny = bbString.section( QStringLiteral( "," ), 1, 1 ).toDouble( &conversionSuccess );
if ( !conversionSuccess ) {bboxOk = false;}
maxx = bbString.section( QStringLiteral( "," ), 2, 2 ).toDouble( &conversionSuccess );
if ( !conversionSuccess ) {bboxOk = false;}
maxy = bbString.section( QStringLiteral( "," ), 3, 3 ).toDouble( &conversionSuccess );
if ( !conversionSuccess ) {bboxOk = false;}
}
if ( !bboxOk )
{
mErrors << QStringLiteral( "The BBOX is mandatory and has to be xx.xxx,yy.yyy,xx.xxx,yy.yyy" );
}
// read WIDTH
width = mParameters.value( QStringLiteral( "WIDTH" ), QStringLiteral( "0" ) ).toInt( &conversionSuccess );
if ( !conversionSuccess )
width = 0;
// read HEIGHT
height = mParameters.value( QStringLiteral( "HEIGHT" ), QStringLiteral( "0" ) ).toInt( &conversionSuccess );
if ( !conversionSuccess )
{
height = 0;
}
if ( width < 0 || height < 0 )
{
mErrors << QStringLiteral( "The WIDTH and HEIGHT are mandatory and have to be integer" );
}
crs = mParameters.value( QStringLiteral( "CRS" ), QLatin1String( "" ) );
if ( crs == QLatin1String( "" ) )
{
mErrors << QStringLiteral( "The CRS is mandatory" );
}
if ( mErrors.count() != 0 )
{
throw QgsMapServiceException( QStringLiteral( "RequestNotWellFormed" ), mErrors.join( QStringLiteral( ". " ) ) );
}
QgsCoordinateReferenceSystem requestCRS = QgsCoordinateReferenceSystem::fromOgcWmsCrs( crs );
if ( !requestCRS.isValid() )
{
mErrors << QStringLiteral( "Could not create request CRS" );
throw QgsMapServiceException( QStringLiteral( "RequestNotWellFormed" ), mErrors.join( QStringLiteral( ". " ) ) );
}
QgsRectangle rect( minx, miny, maxx, maxy );
QgsMapLayer* layer = layerList.at( 0 );
QgsRasterLayer* rLayer = qobject_cast<QgsRasterLayer*>( layer );
if ( rLayer && wcsLayersId.contains( rLayer->id() ) )
{
#ifdef HAVE_SERVER_PYTHON_PLUGINS
if ( !mAccessControl->layerReadPermission( rLayer ) )
{
throw QgsMapServiceException( QStringLiteral( "Security" ), QStringLiteral( "You are not allowed to access to this coverage" ) );
}
#endif
// RESPONSE_CRS
QgsCoordinateReferenceSystem responseCRS = rLayer->crs();
crs = mParameters.value( QStringLiteral( "RESPONSE_CRS" ), QLatin1String( "" ) );
if ( crs != QLatin1String( "" ) )
{
responseCRS = QgsCoordinateReferenceSystem::fromOgcWmsCrs( crs );
if ( !responseCRS.isValid() )
{
responseCRS = rLayer->crs();
}
}
// transform rect
if ( requestCRS != rLayer->crs() )
{
QgsCoordinateTransform t( requestCRS, rLayer->crs() );
rect = t.transformBoundingBox( rect );
}
QTemporaryFile tempFile;
tempFile.open();
QgsRasterFileWriter fileWriter( tempFile.fileName() );
// clone pipe/provider
QgsRasterPipe* pipe = new QgsRasterPipe();
if ( !pipe->set( rLayer->dataProvider()->clone() ) )
{
mErrors << QStringLiteral( "Cannot set pipe provider" );
throw QgsMapServiceException( QStringLiteral( "RequestNotWellFormed" ), mErrors.join( QStringLiteral( ". " ) ) );
}
// add projector if necessary
if ( responseCRS != rLayer->crs() )
{
QgsRasterProjector * projector = new QgsRasterProjector;
projector->setCrs( rLayer->crs(), responseCRS );
if ( !pipe->insert( 2, projector ) )
{
mErrors << QStringLiteral( "Cannot set pipe projector" );
throw QgsMapServiceException( QStringLiteral( "RequestNotWellFormed" ), mErrors.join( QStringLiteral( ". " ) ) );
}
}
QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe, width, height, rect, responseCRS );
if ( err != QgsRasterFileWriter::NoError )
{
mErrors << QStringLiteral( "Cannot write raster error code: %1" ).arg( err );
throw QgsMapServiceException( QStringLiteral( "RequestNotWellFormed" ), mErrors.join( QStringLiteral( ". " ) ) );
}
delete pipe;
QByteArray* ba = nullptr;
ba = new QByteArray();
*ba = tempFile.readAll();
return ba;
}
return nullptr;
}
QString QgsWCSServer::serviceUrl() const
{
QUrl mapUrl( getenv( "REQUEST_URI" ) );
mapUrl.setHost( getenv( "SERVER_NAME" ) );
//Add non-default ports to url
QString portString = getenv( "SERVER_PORT" );
if ( !portString.isEmpty() )
{
bool portOk;
int portNumber = portString.toInt( &portOk );
if ( portOk )
{
if ( portNumber != 80 )
{
mapUrl.setPort( portNumber );
}
}
}
if ( QString( getenv( "HTTPS" ) ).compare( QLatin1String( "on" ), Qt::CaseInsensitive ) == 0 )
{
mapUrl.setScheme( QStringLiteral( "https" ) );
}
else
{
mapUrl.setScheme( QStringLiteral( "http" ) );
}
QList<QPair<QString, QString> > queryItems = mapUrl.queryItems();
QList<QPair<QString, QString> >::const_iterator queryIt = queryItems.constBegin();
for ( ; queryIt != queryItems.constEnd(); ++queryIt )
{
if ( queryIt->first.compare( QLatin1String( "REQUEST" ), Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( QLatin1String( "VERSION" ), Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( QLatin1String( "SERVICE" ), Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( QLatin1String( "_DC" ), Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
}
return mapUrl.toString();
}

View File

@ -1,73 +0,0 @@
/***************************************************************************
qgswcsserver.h
-------------------
begin : December 9, 2013
copyright : (C) 2013 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 QGSWCSSERVER_H
#define QGSWCSSERVER_H
#include <QDomDocument>
#include <QMap>
#include <QString>
#include <map>
#include "qgis.h"
#include "qgsowsserver.h"
class QgsWCSProjectParser;
class QgsRequestHandler;
/** This class handles all the wcs server requests. The parameters and values have to be passed in the form of
a map<QString, QString>. This map is usually generated by a subclass of QgsWMSRequestHandler, which makes QgsWCSServer
independent from any server side technology*/
class QgsWCSServer: public QgsOWSServer
{
public:
//! Constructor. Takes parameter map and a pointer to a renderer object (does not take ownership)
QgsWCSServer(
const QString& configFilePath
, const QgsServerSettings& settings
, QMap<QString, QString>& parameters
, QgsWCSProjectParser* pp
, QgsRequestHandler* rh
, QgsAccessControl* accessControl
);
void executeRequest() override;
//! Returns an XML file with the capabilities description (as described in the WFS specs)
QDomDocument getCapabilities();
//! Returns an XML file with the describe Coverage (as described in the WCS specs)
QDomDocument describeCoverage();
//! Creates a file which is the result of the getCoverage request.
QByteArray* getCoverage();
//! Sets configuration parser for administration settings. Does not take ownership
void setAdminConfigParser( QgsWCSProjectParser* parser ) { mConfigParser = parser; }
private:
//! Don't use the default constructor
QgsWCSServer();
//! Get service address from REQUEST_URI if not specified in the configuration
QString serviceUrl() const;
QgsWCSProjectParser* mConfigParser;
};
#endif

View File

@ -9,4 +9,5 @@ SET (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/${QGIS_SERVER_MODUL
ADD_SUBDIRECTORY(DummyService)
ADD_SUBDIRECTORY(wms)
ADD_SUBDIRECTORY(wfs)
ADD_SUBDIRECTORY(wcs)

View File

@ -0,0 +1,59 @@
########################################################
# Files
SET (wcs_SRCS
qgswcs.cpp
qgswcsutils.cpp
qgswcsgetcapabilities.cpp
qgswcsdescribecoverage.cpp
qgswcsgetcoverage.cpp
)
########################################################
# Build
ADD_LIBRARY (wcs MODULE ${wcs_SRCS})
INCLUDE_DIRECTORIES(SYSTEM
${GDAL_INCLUDE_DIR}
${GEOS_INCLUDE_DIR}
${PROJ_INCLUDE_DIR}
${POSTGRES_INCLUDE_DIR}
)
INCLUDE_DIRECTORIES(
${CMAKE_BINARY_DIR}/src/core
${CMAKE_BINARY_DIR}/src/python
${CMAKE_BINARY_DIR}/src/analysis
${CMAKE_BINARY_DIR}/src/server
${CMAKE_CURRENT_BINARY_DIR}
../../../core
../../../core/dxf
../../../core/geometry
../../../core/raster
../../../core/symbology-ng
../../../core/composer
../../../core/layertree
../..
..
.
)
#endif
TARGET_LINK_LIBRARIES(wcs
qgis_core
qgis_server
)
########################################################
# Install
INSTALL(TARGETS wcs
RUNTIME DESTINATION ${QGIS_SERVER_MODULE_DIR}
LIBRARY DESTINATION ${QGIS_SERVER_MODULE_DIR}
)

View File

@ -0,0 +1,124 @@
/***************************************************************************
qgswcs.cpp
-------------------------
begin : January 16 , 2017
copyright : (C) 2013 by René-Luc D'Hont ( parts from qgswcsserver )
(C) 2017 by David Marteau
email : rldhont at 3liz dot com
david dot marteau 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 "qgsmodule.h"
#include "qgswcsutils.h"
#include "qgswcsgetcapabilities.h"
#include "qgswcsdescribecoverage.h"
#include "qgswcsgetcoverage.h"
#define QSTR_COMPARE( str, lit )\
(str.compare( QStringLiteral( lit ), Qt::CaseInsensitive ) == 0)
namespace QgsWcs
{
class Service: public QgsService
{
public:
// Constructor
Service( QgsServerInterface* serverIface )
: mServerIface( serverIface )
{}
QString name() const { return QStringLiteral( "WCS" ); }
QString version() const { return implementationVersion(); }
bool allowMethod( QgsServerRequest::Method method ) const
{
return method == QgsServerRequest::GetMethod || method == QgsServerRequest::PostMethod;
}
void executeRequest( const QgsServerRequest& request, QgsServerResponse& response,
QgsProject* project )
{
Q_UNUSED( project );
QgsServerRequest::Parameters params = request.parameters();
QString versionString = params.value( "VERSION" );
// Set the default version
if ( versionString.isEmpty() )
{
versionString = version();
}
// Get the request
QString req = params.value( QStringLiteral( "REQUEST" ) );
if ( req.isEmpty() )
{
throw QgsServiceException( QStringLiteral( "OperationNotSupported" ),
QStringLiteral( "Please check the value of the REQUEST parameter" ) );
}
if ( QSTR_COMPARE( req, "GetCapabilities" ) )
{
writeGetCapabilities( mServerIface, versionString, request, response );
}
else if ( QSTR_COMPARE( req, "DescribeCoverage" ) )
{
writeDescribeCoverage( mServerIface, versionString, request, response );
}
else if ( QSTR_COMPARE( req, "GetCoverage" ) )
{
writeGetCoverage( mServerIface, versionString, request, response );
}
else
{
// Operation not supported
throw QgsServiceException( QStringLiteral( "OperationNotSupported" ),
QStringLiteral( "Request %1 is not supported" ).arg( req ) );
}
}
private:
QgsServerInterface* mServerIface;
};
} // namespace QgsWfs
// Module
class QgsWcsModule: public QgsServiceModule
{
public:
void registerSelf( QgsServiceRegistry& registry, QgsServerInterface* serverIface )
{
QgsDebugMsg( "WCSModule::registerSelf called" );
registry.registerService( new QgsWcs::Service( serverIface ) );
}
};
// Entry points
QGISEXTERN QgsServiceModule* QGS_ServiceModule_Init()
{
static QgsWcsModule module;
return &module;
}
QGISEXTERN void QGS_ServiceModule_Exit( QgsServiceModule* )
{
// Nothing to do
}

View File

@ -0,0 +1,83 @@
/***************************************************************************
qgswcsdescribecoverage.cpp
-------------------------
begin : January 16 , 2017
copyright : (C) 2013 by René-Luc D'Hont ( parts from qgswcsserver )
(C) 2017 by David Marteau
email : rldhont at 3liz dot com
david dot marteau 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 "qgswcsutils.h"
#include "qgswcsdescribecoverage.h"
namespace QgsWcs
{
/**
* Output WCS DescribeCoverage response
*/
void writeDescribeCoverage( QgsServerInterface* serverIface, const QString& version,
const QgsServerRequest& request, QgsServerResponse& response )
{
QDomDocument doc = createDescribeCoverageDocument( serverIface, version, request );
response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
response.write( doc.toByteArray() );
}
QDomDocument createDescribeCoverageDocument( QgsServerInterface* serverIface, const QString& version,
const QgsServerRequest& request )
{
Q_UNUSED( version );
QDomDocument doc;
QgsServerRequest::Parameters parameters = request.parameters();
QgsWCSProjectParser* configParser = getConfigParser( serverIface );
//wcs:WCS_Capabilities element
QDomElement coveDescElement = doc.createElement( QStringLiteral( "CoverageDescription" )/*wcs:CoverageDescription*/ );
coveDescElement.setAttribute( QStringLiteral( "xmlns" ), WCS_NAMESPACE );
coveDescElement.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
coveDescElement.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WCS_NAMESPACE + " http://schemas.opengis.net/wcs/1.0.0/describeCoverage.xsd" );
coveDescElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE );
coveDescElement.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
coveDescElement.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) );
coveDescElement.setAttribute( QStringLiteral( "updateSequence" ), QStringLiteral( "0" ) );
doc.appendChild( coveDescElement );
//defining coverage name
QString coveName;
//read COVERAGE
QMap<QString, QString>::const_iterator cove_name_it = parameters.constFind( QStringLiteral( "COVERAGE" ) );
if ( cove_name_it != parameters.constEnd() )
{
coveName = cove_name_it.value();
}
if ( coveName.isEmpty() )
{
QMap<QString, QString>::const_iterator cove_name_it = parameters.constFind( QStringLiteral( "IDENTIFIER" ) );
if ( cove_name_it != parameters.constEnd() )
{
coveName = cove_name_it.value();
}
}
configParser->describeCoverage( coveName, coveDescElement, doc );
return doc;
}
} // namespace QgsWcs

View File

@ -0,0 +1,41 @@
/***************************************************************************
qgswcsdescribecoverage.h
-------------------------
begin : January 16 , 2017
copyright : (C) 2013 by René-Luc D'Hont ( parts from qgswcsserver )
(C) 2017 by David Marteau
email : rldhont at 3liz dot com
david dot marteau 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 QGSWCSDESCRIBECOVERAGE_H
#define QGSWCSDESCRIBECOVERAGE_H
#include <QDomDocument>
namespace QgsWcs
{
/**
* Create describe coverage document
*/
QDomDocument createDescribeCoverageDocument( QgsServerInterface* serverIface, const QString& version,
const QgsServerRequest& request );
/** Output WCS DescribeCoverage response
*/
void writeDescribeCoverage( QgsServerInterface* serverIface, const QString& version,
const QgsServerRequest& request, QgsServerResponse& response );
} // samespace QgsWcs
#endif

View File

@ -0,0 +1,121 @@
/***************************************************************************
qgswcsgecapabilities.cpp
-------------------------
begin : January 16 , 2017
copyright : (C) 2013 by René-Luc D'Hont ( parts from qgswcsserver )
(C) 2017 by David Marteau
email : rldhont at 3liz dot com
david dot marteau 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 "qgswcsutils.h"
#include "qgswcsgetcapabilities.h"
namespace QgsWcs
{
/**
* Output WCS GetCapabilities response
*/
void writeGetCapabilities( QgsServerInterface* serverIface, const QString& version,
const QgsServerRequest& request, QgsServerResponse& response )
{
QDomDocument doc = createGetCapabilitiesDocument( serverIface, version, request );
response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
response.write( doc.toByteArray() );
}
QDomDocument createGetCapabilitiesDocument( QgsServerInterface* serverIface, const QString& version,
const QgsServerRequest& request )
{
Q_UNUSED( version );
QDomDocument doc;
QgsWCSProjectParser* configParser = getConfigParser( serverIface );
//wcs:WCS_Capabilities element
QDomElement wcsCapabilitiesElement = doc.createElement( QStringLiteral( "WCS_Capabilities" )/*wcs:WCS_Capabilities*/ );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns" ), WCS_NAMESPACE );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WCS_NAMESPACE + " http://schemas.opengis.net/wcs/1.0.0/wcsCapabilities.xsd" );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "version" ), implementationVersion() );
wcsCapabilitiesElement.setAttribute( QStringLiteral( "updateSequence" ), QStringLiteral( "0" ) );
doc.appendChild( wcsCapabilitiesElement );
configParser->serviceCapabilities( wcsCapabilitiesElement, doc );
//INSERT Service
//wcs:Capability element
QDomElement capabilityElement = doc.createElement( QStringLiteral( "Capability" )/*wcs:Capability*/ );
wcsCapabilitiesElement.appendChild( capabilityElement );
//wcs:Request element
QDomElement requestElement = doc.createElement( QStringLiteral( "Request" )/*wcs:Request*/ );
capabilityElement.appendChild( requestElement );
//wcs:GetCapabilities
QDomElement getCapabilitiesElement = doc.createElement( QStringLiteral( "GetCapabilities" )/*wcs:GetCapabilities*/ );
requestElement.appendChild( getCapabilitiesElement );
QDomElement dcpTypeElement = doc.createElement( QStringLiteral( "DCPType" )/*wcs:DCPType*/ );
getCapabilitiesElement.appendChild( dcpTypeElement );
QDomElement httpElement = doc.createElement( QStringLiteral( "HTTP" )/*wcs:HTTP*/ );
dcpTypeElement.appendChild( httpElement );
//Prepare url
QString hrefString = serviceUrl( request, configParser );
QDomElement getElement = doc.createElement( QStringLiteral( "Get" )/*wcs:Get*/ );
httpElement.appendChild( getElement );
QDomElement onlineResourceElement = doc.createElement( QStringLiteral( "OnlineResource" )/*wcs:OnlineResource*/ );
onlineResourceElement.setAttribute( QStringLiteral( "xlink:type" ), QStringLiteral( "simple" ) );
onlineResourceElement.setAttribute( QStringLiteral( "xlink:href" ), hrefString );
getElement.appendChild( onlineResourceElement );
QDomElement getCapabilitiesDhcTypePostElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities'
getCapabilitiesDhcTypePostElement.firstChild().firstChild().toElement().setTagName( QStringLiteral( "Post" ) );
getCapabilitiesElement.appendChild( getCapabilitiesDhcTypePostElement );
QDomElement describeCoverageElement = getCapabilitiesElement.cloneNode().toElement();//this is the same as 'GetCapabilities'
describeCoverageElement.setTagName( QStringLiteral( "DescribeCoverage" ) );
requestElement.appendChild( describeCoverageElement );
QDomElement getCoverageElement = getCapabilitiesElement.cloneNode().toElement();//this is the same as 'GetCapabilities'
getCoverageElement.setTagName( QStringLiteral( "GetCoverage" ) );
requestElement.appendChild( getCoverageElement );
/*
* Adding layer list in ContentMetadata
*/
QDomElement contentMetadataElement = doc.createElement( QStringLiteral( "ContentMetadata" )/*wcs:ContentMetadata*/ );
wcsCapabilitiesElement.appendChild( contentMetadataElement );
/*
* Adding layer list in contentMetadataElement
*/
if ( configParser )
{
configParser->wcsContentMetadata( contentMetadataElement, doc );
}
return doc;
}
} // namespace QgsWcs

View File

@ -0,0 +1,41 @@
/***************************************************************************
qgswcsgecapabilities.h
-------------------------
begin : January 16 , 2017
copyright : (C) 2013 by René-Luc D'Hont ( parts from qgswcsserver )
(C) 2017 by David Marteau
email : rldhont at 3liz dot com
david dot marteau 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 QGSWCSGETCAPABILITIES_H
#define QGSWCSGETCAPABILITIES_H
#include <QDomDocument>
namespace QgsWcs
{
/**
* Create get capabilities document
*/
QDomDocument createGetCapabilitiesDocument( QgsServerInterface* serverIface, const QString& version,
const QgsServerRequest& request );
/** Output WCS GetCapabilities response
*/
void writeGetCapabilities( QgsServerInterface* serverIface, const QString& version,
const QgsServerRequest& request, QgsServerResponse& response );
} // samespace QgsWcs
#endif

View File

@ -0,0 +1,205 @@
/***************************************************************************
qgswcsgetcoverage.cpp
-------------------------
begin : January 16 , 2017
copyright : (C) 2013 by René-Luc D'Hont ( parts from qgswcsserver )
(C) 2017 by David Marteau
email : rldhont at 3liz dot com
david dot marteau 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 "qgswcsutils.h"
#include "qgsrasterlayer.h"
#include "qgsrasterdataprovider.h"
#include "qgsrasterpipe.h"
#include "qgsrasterprojector.h"
#include "qgsrasterfilewriter.h"
#include "qgswcsgetcoverage.h"
#include <QTemporaryFile>
namespace QgsWcs
{
/**
* Output WCS DescribeCoverage response
*/
void writeGetCoverage( QgsServerInterface* serverIface, const QString& version,
const QgsServerRequest& request, QgsServerResponse& response )
{
Q_UNUSED( version );
response.write( getCoverageData( serverIface, request ) );
response.setHeader( "Content-Type", "image/tiff" );
}
QByteArray getCoverageData( QgsServerInterface* serverIface, const QgsServerRequest& request )
{
QgsWCSProjectParser* configParser = getConfigParser( serverIface );
QgsAccessControl* accessControl = serverIface->accessControls();
QStringList wcsLayersId = configParser->wcsLayers();
QList<QgsMapLayer*> layerList;
QgsServerRequest::Parameters parameters = request.parameters();
//defining coverage name
QString coveName;
//read COVERAGE
QMap<QString, QString>::const_iterator cove_name_it = parameters.constFind( QStringLiteral( "COVERAGE" ) );
if ( cove_name_it != parameters.constEnd() )
{
coveName = cove_name_it.value();
}
if ( coveName.isEmpty() )
{
QMap<QString, QString>::const_iterator cove_name_it = parameters.constFind( QStringLiteral( "IDENTIFIER" ) );
if ( cove_name_it != parameters.constEnd() )
{
coveName = cove_name_it.value();
}
}
if ( coveName.isEmpty() )
{
throw QgsRequestNotWellFormedException( QStringLiteral( "COVERAGE is mandatory" ) );
}
layerList = configParser->mapLayerFromCoverage( coveName );
if ( layerList.size() < 1 )
{
throw QgsRequestNotWellFormedException( QStringLiteral( "The layer for the COVERAGE '%1' is not found" ).arg( coveName ) );
}
double minx = 0.0, miny = 0.0, maxx = 0.0, maxy = 0.0;
// WIDTh and HEIGHT
int width = 0, height = 0;
// CRS
QString crs;
// read BBOX
QgsRectangle bbox = parseBbox( parameters.value( QStringLiteral( "BBOX" ) ) );
if ( !bbox.isEmpty() )
{
minx = bbox.xMinimum();
miny = bbox.yMinimum();
maxx = bbox.xMaximum();
maxy = bbox.yMaximum();
}
else
{
throw QgsRequestNotWellFormedException( QStringLiteral( "The BBOX is mandatory and has to be xx.xxx,yy.yyy,xx.xxx,yy.yyy" ) );
}
// read WIDTH
bool conversionSuccess = false;
width = parameters.value( QStringLiteral( "WIDTH" ), QStringLiteral( "0" ) ).toInt( &conversionSuccess );
if ( !conversionSuccess )
{
width = 0;
}
// read HEIGHT
height = parameters.value( QStringLiteral( "HEIGHT" ), QStringLiteral( "0" ) ).toInt( &conversionSuccess );
if ( !conversionSuccess )
{
height = 0;
}
if ( width < 0 || height < 0 )
{
throw QgsRequestNotWellFormedException( QStringLiteral( "The WIDTH and HEIGHT are mandatory and have to be integer" ) );
}
crs = parameters.value( QStringLiteral( "CRS" ) );
if ( crs.isEmpty() )
{
throw QgsRequestNotWellFormedException( QStringLiteral( "The CRS is mandatory" ) );
}
QgsCoordinateReferenceSystem requestCRS = QgsCoordinateReferenceSystem::fromOgcWmsCrs( crs );
if ( !requestCRS.isValid() )
{
throw QgsRequestNotWellFormedException( QStringLiteral( "Invalid CRS" ) );
}
QgsRectangle rect( minx, miny, maxx, maxy );
QgsMapLayer* layer = layerList.at( 0 );
QgsRasterLayer* rLayer = qobject_cast<QgsRasterLayer*>( layer );
if ( rLayer && wcsLayersId.contains( rLayer->id() ) )
{
#ifdef HAVE_SERVER_PYTHON_PLUGINS
if ( !accessControl->layerReadPermission( rLayer ) )
{
throw QgsSecurityAccessException( QStringLiteral( "You are not allowed to access to this coverage" ) );
}
#endif
// RESPONSE_CRS
QgsCoordinateReferenceSystem responseCRS = rLayer->crs();
crs = parameters.value( QStringLiteral( "RESPONSE_CRS" ) );
if ( crs.isEmpty() )
{
responseCRS = QgsCoordinateReferenceSystem::fromOgcWmsCrs( crs );
if ( !responseCRS.isValid() )
{
responseCRS = rLayer->crs();
}
}
// transform rect
if ( requestCRS != rLayer->crs() )
{
QgsCoordinateTransform t( requestCRS, rLayer->crs() );
rect = t.transformBoundingBox( rect );
}
QTemporaryFile tempFile;
tempFile.open();
QgsRasterFileWriter fileWriter( tempFile.fileName() );
// clone pipe/provider
QgsRasterPipe pipe;
if ( !pipe.set( rLayer->dataProvider()->clone() ) )
{
throw QgsRequestNotWellFormedException( QStringLiteral( "Cannet set pipe provider" ) );
}
// add projector if necessary
if ( responseCRS != rLayer->crs() )
{
QgsRasterProjector * projector = new QgsRasterProjector;
projector->setCrs( rLayer->crs(), responseCRS );
if ( !pipe.insert( 2, projector ) )
{
throw QgsRequestNotWellFormedException( QStringLiteral( "Cannot set pipe projector" ) );
}
}
QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( &pipe, width, height, rect, responseCRS );
if ( err != QgsRasterFileWriter::NoError )
{
throw QgsRequestNotWellFormedException( QStringLiteral( "Cannot write raster error code: %1" ).arg( err ) );
}
return tempFile.readAll();
}
else
{
return QByteArray();
}
}
} // namespace QgsWcs

View File

@ -0,0 +1,40 @@
/***************************************************************************
qgswcsgetcoverage.h
-------------------------
begin : January 16 , 2017
copyright : (C) 2013 by René-Luc D'Hont ( parts from qgswcsserver )
(C) 2017 by David Marteau
email : rldhont at 3liz dot com
david dot marteau 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 QGSWCSGETCOVERAGE_H
#define QGSWCSGETCOVERAGE_H
#include <QByteArray>
namespace QgsWcs
{
/** Output WCS GetCoverage response
*/
void writeGetCoverage( QgsServerInterface* serverIface, const QString& version,
const QgsServerRequest& request, QgsServerResponse& response );
/**
* Compute coverage data
*/
QByteArray getCoverageData( QgsServerInterface* serverIface, const QgsServerRequest& request );
} // samespace QgsWcs
#endif

View File

@ -0,0 +1,80 @@
/***************************************************************************
qgswcsserviceexception.h
------------------------
begin : January 17, 2017
copyright : (C) 2017 by David Marteau
email : david dot marteau 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 QGSWCSSERVICEEXCEPTION_H
#define QGSWCSSERVICEEXCEPTION_H
#include <QString>
#include "qgsserverexception.h"
namespace QgsWcs
{
/** \ingroup server
* \class QgsserviceException
* \brief Exception class for WFS service exceptions.
*/
class QgsServiceException : public QgsOgcServiceException
{
public:
QgsServiceException( const QString& code, const QString& message,
int responseCode = 200 )
: QgsOgcServiceException( code, message, QString(), responseCode, QStringLiteral( "1.2.0" ) )
{}
QgsServiceException( const QString& code, const QString& message, const QString& locator,
int responseCode = 200 )
: QgsOgcServiceException( code, message, locator, responseCode, QStringLiteral( "1.2.0" ) )
{}
};
/** \ingroup server
* \class QgsSecurityAccessException
* \brief Exception thrown when data access violates access controls
*/
class QgsSecurityAccessException: public QgsServiceException
{
public:
QgsSecurityAccessException( const QString& message, const QString& locator = QString() )
: QgsServiceException( QStringLiteral( "Security" ), message, locator, 403 )
{}
};
/** \ingroup server
* \class QgsRequestNotWellFormedException
* \brief Exception thrown in case of malformed request
*/
class QgsRequestNotWellFormedException: public QgsServiceException
{
public:
QgsRequestNotWellFormedException( const QString& message, const QString& locator = QString() )
: QgsServiceException( QStringLiteral( "RequestNotWellFormed" ), message, locator, 400 )
{}
};
} // namespace QgsWcs
#endif

View File

@ -0,0 +1,94 @@
/***************************************************************************
qgswcsutils.cpp
-------------------------
begin : December 9, 2013
copyright : (C) 2013 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 "qgswcsutils.h"
#include "qgsconfigcache.h"
namespace QgsWcs
{
QString implementationVersion()
{
return QStringLiteral( "1.0.0" );
}
// Return the wms config parser (Transitional)
QgsWCSProjectParser* getConfigParser( QgsServerInterface* serverIface )
{
QString configFilePath = serverIface->configFilePath();
QgsWCSProjectParser* parser = QgsConfigCache::instance()->wcsConfiguration( configFilePath, serverIface->accessControls() );
if ( !parser )
{
throw QgsServiceException(
QStringLiteral( "WFS configuration error" ),
QStringLiteral( "There was an error reading the project file or the SLD configuration" ) );
}
return parser;
}
QString serviceUrl( const QgsServerRequest& request, QgsWCSProjectParser* parser )
{
QString href;
if ( parser )
{
href = parser->wcsServiceUrl();
if ( href.isEmpty() )
{
href = parser->serviceUrl();
}
}
// Build default url
if ( href.isEmpty() )
{
QUrl url = request.url();
QUrlQuery q( url );
q.removeAllQueryItems( QStringLiteral( "REQUEST" ) );
q.removeAllQueryItems( QStringLiteral( "VERSION" ) );
q.removeAllQueryItems( QStringLiteral( "SERVICE" ) );
q.removeAllQueryItems( QStringLiteral( "_DC" ) );
url.setQuery( q );
href = url.toString( QUrl::FullyDecoded );
}
return href;
}
QgsRectangle parseBbox( const QString& bboxStr )
{
QStringList lst = bboxStr.split( QStringLiteral( "," ) );
if ( lst.count() != 4 )
return QgsRectangle();
double d[4];
bool ok;
for ( int i = 0; i < 4; i++ )
{
lst[i].replace( QLatin1String( " " ), QLatin1String( "+" ) );
d[i] = lst[i].toDouble( &ok );
if ( !ok )
return QgsRectangle();
}
return QgsRectangle( d[0], d[1], d[2], d[3] );
}
} // namespace QgsWfs

View File

@ -0,0 +1,70 @@
/***************************************************************************
qgswcsutils.h
Define WCS service utility functions
------------------------------------
begin : January 16 , 2017
copyright : (C) 2013 by René-Luc D'Hont ( parts from qgswcsserver )
(C) 2017 by David Marteau
email : rldhont at 3liz dot com
david dot marteau 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 QGSWCSUTILS_H
#define QGSWCSUTILS_H
#include "qgsmodule.h"
#include "qgswcsprojectparser.h"
#include "qgswcsserviceexception.h"
/**
* \ingroup server
* WCS implementation
*/
//! WCS implementation
namespace QgsWcs
{
/**
* Return the highest version supported by this implementation
*/
QString implementationVersion();
/**
* Return the wms config parser (Transitional)
*
* XXX This is needed in the current implementation.
* This should disappear as soon we get rid of singleton.
*/
QgsWCSProjectParser* getConfigParser( QgsServerInterface* serverIface );
/**
* Service URL string
*/
QString serviceUrl( const QgsServerRequest& request, QgsWCSProjectParser* parser = nullptr );
/**
* Parse bounding box
*/
//XXX At some point, should be moved to common library
QgsRectangle parseBbox( const QString& bboxStr );
// Define namespaces used in WFS documents
const QString WCS_NAMESPACE = QStringLiteral( "http://www.opengis.net/wcs" );
const QString GML_NAMESPACE = QStringLiteral( "http://www.opengis.net/gml" );
const QString OGC_NAMESPACE = QStringLiteral( "http://www.opengis.net/ogc" );
} // namespace QgsWcs
#endif

View File

@ -26,7 +26,6 @@ INCLUDE_DIRECTORIES(SYSTEM
INCLUDE_DIRECTORIES(
${CMAKE_BINARY_DIR}/src/core
${CMAKE_BINARY_DIR}/src/gui
${CMAKE_BINARY_DIR}/src/python
${CMAKE_BINARY_DIR}/src/analysis
${CMAKE_BINARY_DIR}/src/server
@ -38,9 +37,6 @@ INCLUDE_DIRECTORIES(
../../../core/symbology-ng
../../../core/composer
../../../core/layertree
../../../gui
../../../gui/editorwidgets
../../../gui/editorwidgets/core
../..
..
.

View File

@ -25,6 +25,7 @@
namespace QgsWfs
{
/**
* Create get capabilities document
*/

View File

@ -25,6 +25,7 @@
namespace QgsWfs
{
/**
* Create get capabilities document
*/

View File

@ -35,6 +35,7 @@
//! WMS implementation
namespace QgsWfs
{
/** Return the highest version supported by this implementation
*/
QString implementationVersion();

View File

@ -88,13 +88,13 @@ namespace QgsWms
{
writeGetCapabilities( mServerIface, versionString, request, response, false );
}
else if( QSTR_COMPARE( req, "GetProjectSettings" ) )
else if ( QSTR_COMPARE( req, "GetProjectSettings" ) )
{
//getProjectSettings extends WMS 1.3.0 capabilities
versionString = QStringLiteral( "1.3.0" );
writeGetCapabilities( mServerIface, versionString, request, response, true );
}
else if( QSTR_COMPARE( req, "GetMap" ) )
else if ( QSTR_COMPARE( req, "GetMap" ) )
{
QString format = params.value( QStringLiteral( "FORMAT" ) );
if QSTR_COMPARE( format, "application/dxf" )
@ -106,35 +106,35 @@ namespace QgsWms
writeGetMap( mServerIface, versionString, request, response );
}
}
else if( QSTR_COMPARE( req, "GetFeatureInfo" ) )
else if ( QSTR_COMPARE( req, "GetFeatureInfo" ) )
{
writeGetFeatureInfo( mServerIface, versionString, request, response );
}
else if( QSTR_COMPARE( req, "GetContext" ) )
else if ( QSTR_COMPARE( req, "GetContext" ) )
{
writeGetContext( mServerIface, versionString, request, response );
}
else if( QSTR_COMPARE( req, "GetSchemaExtension" ) )
else if ( QSTR_COMPARE( req, "GetSchemaExtension" ) )
{
writeGetSchemaExtension( mServerIface, versionString, request, response );
}
else if( QSTR_COMPARE( req, "GetStyle" ) )
else if ( QSTR_COMPARE( req, "GetStyle" ) )
{
writeGetStyle( mServerIface, versionString, request, response );
}
else if( QSTR_COMPARE( req, "GetStyles" ) )
else if ( QSTR_COMPARE( req, "GetStyles" ) )
{
writeGetStyles( mServerIface, versionString, request, response );
}
else if( QSTR_COMPARE( req, "DescribeLayer" ) )
else if ( QSTR_COMPARE( req, "DescribeLayer" ) )
{
writeDescribeLayer( mServerIface, versionString, request, response );
}
else if( QSTR_COMPARE( req, "GetLegendGraphic" ) || QSTR_COMPARE( req, "GetLegendGraphics" ) )
else if ( QSTR_COMPARE( req, "GetLegendGraphic" ) || QSTR_COMPARE( req, "GetLegendGraphics" ) )
{
writeGetLegendGraphics( mServerIface, versionString, request, response );
}
else if( QSTR_COMPARE( req, "GetPrint" ) )
else if ( QSTR_COMPARE( req, "GetPrint" ) )
{
writeGetPrint( mServerIface, versionString, request, response );
}