Skip to content
Permalink
Browse files

Revisit server exceptions

    - Add server exception base class
    - Enable per service exception definition
    - Handle QgsException gracefully (error 500)
    - Handle OGC exception versioning
  • Loading branch information
dmarteau committed Jan 14, 2017
1 parent c128d13 commit 8b0526d678b5381936e3e894fdd87620213a3b6e
Showing with 552 additions and 410 deletions.
  1. +3 −42 python/server/qgsrequesthandler.sip
  2. +56 −0 python/server/qgsserverexception.sip
  3. +5 −0 python/server/qgsserverresponse.sip
  4. +1 −0 python/server/server.sip
  5. +1 −1 src/server/CMakeLists.txt
  6. +5 −5 src/server/qgsfcgiserverresponse.cpp
  7. +4 −4 src/server/qgsfcgiserverresponse.h
  8. +8 −9 src/server/qgsmapserviceexception.h
  9. +6 −24 src/server/qgsrequesthandler.cpp
  10. +3 −3 src/server/qgsrequesthandler.h
  11. +89 −76 src/server/qgsserver.cpp
  12. +77 −0 src/server/qgsserverexception.cpp
  13. +84 −0 src/server/qgsserverexception.h
  14. +19 −1 src/server/qgsserverresponse.cpp
  15. +7 −0 src/server/qgsserverresponse.h
  16. +4 −6 src/server/services/wms/qgswms.cpp
  17. +9 −15 src/server/services/wms/qgswmsdescribelayer.cpp
  18. +8 −14 src/server/services/wms/qgswmsgetcapabilities.cpp
  19. +11 −16 src/server/services/wms/qgswmsgetcontext.cpp
  20. +5 −13 src/server/services/wms/qgswmsgetfeatureinfo.cpp
  21. +13 −16 src/server/services/wms/qgswmsgetlegendgraphics.cpp
  22. +8 −14 src/server/services/wms/qgswmsgetmap.cpp
  23. +34 −39 src/server/services/wms/qgswmsgetprint.cpp
  24. +9 −15 src/server/services/wms/qgswmsgetschemaextension.cpp
  25. +10 −16 src/server/services/wms/qgswmsgetstyle.cpp
  26. +4 −10 src/server/services/wms/qgswmsgetstyles.cpp
  27. +33 −33 src/server/services/wms/qgswmsservertransitional.cpp
  28. +32 −7 src/server/{qgsmapserviceexception.cpp → services/wms/qgswmsserviceexception.h}
  29. +3 −26 src/server/services/wms/qgswmsutils.cpp
  30. +1 −5 src/server/services/wms/qgswmsutils.h
@@ -20,45 +20,14 @@
class QgsRequestHandler /Abstract/
{
%TypeHeaderCode
#include "qgsmapserviceexception.h"
#include "qgsserverexception.h"
#include "qgsrequesthandler.h"
%End

public:

/** Parses the input and creates a request neutral Parameter/Value map
* @note not available in Python bindings
*/
// virtual void parseInput() = 0;

/** Sends the map image back to the client
* @note not available in Python bindings
*/
// virtual void setGetMapResponse( const QString& service, QImage* img, int imageQuality ) = 0;

//! @note not available in Python bindings
// virtual void setGetCapabilitiesResponse( const QDomDocument& doc ) = 0;

//! @note not available in Python bindings
// virtual void setGetFeatureInfoResponse( const QDomDocument& infoDoc, const QString& infoFormat ) = 0;

/** Allow plugins to return a QgsMapServiceException*/
void setServiceException( const QgsMapServiceException& ex /Transfer/ );

//! @note not available in Python bindings
// virtual void setXmlResponse( const QDomDocument& doc ) = 0;

//! @note not available in Python bindings
// virtual void setXmlResponse( const QDomDocument& doc, const QString& mimeType ) = 0;

//! @note not available in Python bindings
// virtual void setGetPrintResponse( QByteArray* b ) = 0;

//! @note not available in Python bindings
// virtual bool startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) = 0;

//! @note not available in Python bindings
// virtual void setGetFeatureResponse( QByteArray* ba ) = 0;
/** Allow plugins to return a QgsServerException*/
void setServiceException( const QgsServerException& ex );

//! @note not available in Python bindings
void endGetFeatureResponse( QByteArray* ba );
@@ -116,12 +85,4 @@ class QgsRequestHandler /Abstract/

/** Return true if the HTTP headers were already sent to the client*/
bool headersSent() const;


//! @note not available in Python bindings
// virtual QPair<QByteArray, QByteArray> getResponse() = 0;

private:
/** Parses the input and creates a request neutral Parameter/Value map*/
void parseInput();
};
@@ -0,0 +1,56 @@
/***************************************************************************
qgsserverexception.sip
------------------------
begin : January 11 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. *
* *
***************************************************************************/


/** \ingroup server
* \class QgsServerException
* \brief server Exception base class.
*/

class QgsServerException
{
%TypeHeaderCode
#include <qgsserverexception.h>
%End
public:
QgsServerException( const QString& message, int responseCode = 500 );

int responseCode() const;

virtual QByteArray formatResponse( QString& responseFormat ) const;
};


class QgsOgcServiceException
{
%TypeHeaderCode
#include <qgsserverexception.h>
%End
public:
QgsOgcServiceException( const QString& code, const QString& message, const QString& locator = QString(),
int responseCode = 200, const QString& version = "1.3.0" );

QString message() const;
QString code() const;
QString locator() const;

virtual QByteArray formatResponse( QString& responseFormat / Out / ) const;
};




@@ -92,6 +92,11 @@ class QgsServerResponse
*/
virtual qint64 write( const QByteArray& byteArray );

/**
* Write server exception
*/
virtual void write( const QgsServerException& ex );

/**
* Return the underlying QIODevice
*/
@@ -32,6 +32,7 @@

%Include qgsserverrequest.sip
%Include qgsserverresponse.sip
%Include qgsserverexception.sip
%Include qgsservice.sip
%Include qgsservicemodule.sip
%Include qgsserviceregistry.sip
@@ -28,7 +28,7 @@ SET ( qgis_mapserv_SRCS
qgswfsserver.cpp
qgswcsserver.cpp
qgsserversettings.cpp
qgsmapserviceexception.cpp
qgsserverexception.cpp
qgsmslayercache.cpp
qgsmslayerbuilder.cpp
qgshostedvdsbuilder.cpp
@@ -30,16 +30,14 @@
//

QgsFcgiServerResponse::QgsFcgiServerResponse( QgsServerRequest::Method method )
: mMethod( method )
{
mBuffer.open( QIODevice::ReadWrite );
mHeadersSent = false;
mFinished = false;
mMethod = method;
setDefaultHeaders();
}

QgsFcgiServerResponse::~QgsFcgiServerResponse()
{

}

void QgsFcgiServerResponse::clearHeader( const QString& key )
@@ -82,7 +80,6 @@ void QgsFcgiServerResponse::sendError( int code, const QString& message )
}

clear();
setDefaultHeaders();
setReturnCode( code );
setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/html;charset=utf-8" ) );
write( QStringLiteral( "<html><body>%1</body></html>" ).arg( message ) );
@@ -157,6 +154,9 @@ void QgsFcgiServerResponse::clear()
mHeaders.clear();
mBuffer.seek( 0 );
mBuffer.buffer().clear();

// Restore default headers
setDefaultHeaders();
}

void QgsFcgiServerResponse::setDefaultHeaders()
@@ -61,13 +61,13 @@ class QgsFcgiServerResponse: public QgsServerResponse
/**
* Set the default headers
*/
virtual void setDefaultHeaders();
void setDefaultHeaders();

private:
QMap<QString, QString> mHeaders;
QBuffer mBuffer;
bool mFinished;
bool mHeadersSent;
QBuffer mBuffer;
bool mFinished = false;
bool mHeadersSent = false;
QgsServerRequest::Method mMethod;
};

@@ -20,12 +20,14 @@

#include <QString>

#include "qgsexception.h"
#include "qgsserverexception.h"
#include "qgis_server.h"

/** \ingroup server
* \class QgsMapServiceException
* \brief Exception class for WMS service exceptions.
* \brief Exception class for WMS service exceptions (for compatibility only).
*
* \deprecated Use QsgServerException
*
* The most important codes are:
* * "InvalidFormat"
@@ -34,15 +36,12 @@
* * "OperationNotSupported"
*/

class SERVER_EXPORT QgsMapServiceException : public QgsException
class SERVER_EXPORT QgsMapServiceException : public QgsOgcServiceException
{
public:
QgsMapServiceException( const QString& code, const QString& message );
QString code() const {return mCode;}
QString message() const {return mMessage;}
private:
QString mCode;
QString mMessage;
QgsMapServiceException( const QString& code, const QString& message )
: QgsOgcServiceException( code, message )
{}
};

#endif
@@ -24,7 +24,7 @@
#include "qgshttptransaction.h"
#endif
#include "qgsmessagelog.h"
#include "qgsmapserviceexception.h"
#include "qgsserverexception.h"
#include "qgsserverrequest.h"
#include "qgsserverresponse.h"
#include <QBuffer>
@@ -38,15 +38,14 @@
#include <QUrlQuery>

QgsRequestHandler::QgsRequestHandler( QgsServerRequest& request, QgsServerResponse& response )
: mException( nullptr )
: mExceptionRaised( false )
, mRequest( request )
, mResponse( response )
{
}

QgsRequestHandler::~QgsRequestHandler()
{
delete mException;
}

QMap<QString, QString> QgsRequestHandler::parameterMap() const
@@ -70,7 +69,7 @@ void QgsRequestHandler::setHttpResponse( const QByteArray& ba, const QString &fo

bool QgsRequestHandler::exceptionRaised() const
{
return mException;
return mExceptionRaised;
}

void QgsRequestHandler::setHeader( const QString &name, const QString &value )
@@ -169,28 +168,11 @@ void QgsRequestHandler::setXmlResponse( const QDomDocument& doc, const QString&
setHttpResponse( ba, mimeType );
}

void QgsRequestHandler::setServiceException( const QgsMapServiceException& ex )
void QgsRequestHandler::setServiceException( const QgsServerException& ex )
{
// Safety measure to avoid potential leaks if called repeatedly
delete mException;
mException = new QgsMapServiceException( ex );
//create Exception DOM document
QDomDocument exceptionDoc;
QDomElement serviceExceptionReportElem = exceptionDoc.createElement( QStringLiteral( "ServiceExceptionReport" ) );
serviceExceptionReportElem.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.3.0" ) );
serviceExceptionReportElem.setAttribute( QStringLiteral( "xmlns" ), QStringLiteral( "http://www.opengis.net/ogc" ) );
exceptionDoc.appendChild( serviceExceptionReportElem );
QDomElement serviceExceptionElem = exceptionDoc.createElement( QStringLiteral( "ServiceException" ) );
serviceExceptionElem.setAttribute( QStringLiteral( "code" ), ex.code() );
QDomText messageText = exceptionDoc.createTextNode( ex.message() );
serviceExceptionElem.appendChild( messageText );
serviceExceptionReportElem.appendChild( serviceExceptionElem );

QByteArray ba = exceptionDoc.toByteArray();
// Clear response headers and body and set new exception
// TODO: check for headersSent()
clear();
setHttpResponse( ba, QStringLiteral( "text/xml" ) );
mExceptionRaised = true;
mResponse.write( ex );
}

bool QgsRequestHandler::startGetFeatureResponse( QByteArray* ba, const QString& infoFormat )
@@ -31,7 +31,7 @@

class QDomDocument;
class QImage;
class QgsMapServiceException;
class QgsServerException;
class QgsServerRequest;
class QgsServerResponse;

@@ -58,7 +58,7 @@ class SERVER_EXPORT QgsRequestHandler
void setGetCapabilitiesResponse( const QDomDocument& doc );

//! Allow plugins to return a QgsMapServiceException
void setServiceException( const QgsMapServiceException &ex );
void setServiceException( const QgsServerException &ex );

//! @note not available in Python bindings
void setXmlResponse( const QDomDocument& doc );
@@ -154,7 +154,7 @@ class SERVER_EXPORT QgsRequestHandler
QString mFormatString; //format string as it is passed in the request (with base)
QString mService;
QString mInfoFormat;
QgsMapServiceException* mException; // Stores the exception
bool mExceptionRaised;

QgsServerRequest& mRequest;
QgsServerResponse& mResponse;

0 comments on commit 8b0526d

Please sign in to comment.
You can’t perform that action at this time.