Skip to content

Commit

Permalink
[SERVER] QgsRequestHandler now returns a QPair
Browse files Browse the repository at this point in the history
Much simpler GUI with a single method for all
cases. handleRequest now returns both headers and
body in a QPair.
Python binding returns a tuple of QByteArray.
  • Loading branch information
elpaso committed Sep 5, 2015
1 parent 8611543 commit a9f2acc
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 104 deletions.
55 changes: 44 additions & 11 deletions python/server/qgsserver.sip
Expand Up @@ -17,6 +17,48 @@
***************************************************************************/


%MappedType QPair<QByteArray, QByteArray>
{
%TypeHeaderCode
#include <QPair>
#include <QByteArray>
%End


%TypeCode
// Convenience function for converting a QByteArray to a Python str object. (from QtCore/qbytearray.sip)
static PyObject *QByteArrayToPyStr(QByteArray *ba)
{
char *data = ba->data();

if (data)
// QByteArrays may have embedded '\0's so set the size explicitly.
return SIPBytes_FromStringAndSize(data, ba->size());
return SIPBytes_FromString("");
}
%End


%ConvertFromTypeCode
// Create the tuple.
return Py_BuildValue((char *)"OO", QByteArrayToPyStr( &sipCpp->first ), QByteArrayToPyStr( &sipCpp->second ) );
%End

%ConvertToTypeCode
// Check the type if that is all that is required.
if (sipIsErr == NULL)
return (PyTuple_Size(sipPy) == 2);

QPair<QByteArray, QByteArray> *qp = new QPair<QByteArray, QByteArray>;

qp->first = SIPLong_AsLong(PyTuple_GET_ITEM(sipPy, 0));
qp->second = SIPLong_AsLong(PyTuple_GET_ITEM(sipPy, 1));

*sipCppPtr = qp;

return sipGetState(sipTransferObj);
%End
};

class QgsServer
{
Expand All @@ -31,21 +73,12 @@ class QgsServer
//void init( int argc, char* argv[] );
// init for python bindings:
void init( );
QByteArray handleRequest( const QString queryString = QString( ) );
// TODO: if HAVE_SERVER_PYTHON
QByteArray handleRequest( const QString queryString,
const bool returnHeaders,
const bool returnBody );
QByteArray handleRequestGetBody( const QString queryString = QString( ) );
QByteArray handleRequestGetHeaders( const QString queryString = QString( ) );
//QgsServerContext& serverContext ( ) /KeepReference/;
QPair<QByteArray, QByteArray> handleRequest( const QString queryString = QString( ) );
%If (HAVE_SERVER_PYTHON_PLUGINS)
QgsServerInterface* serverInterface( );
// Needs %MethodCode
//QMultiMap<int, QgsServerFilter*> pluginFilters( );
%End

// The following is needed because otherwise SIP fails trying to create copy
// The following is needed because otherwise SIP fails trying to create copy
// ctor
private:
QgsServer( const QgsServer& );
Expand Down
17 changes: 3 additions & 14 deletions src/server/qgshttprequesthandler.cpp
Expand Up @@ -218,21 +218,10 @@ void QgsHttpRequestHandler::sendResponse()
clearBody();
}

QByteArray QgsHttpRequestHandler::getResponse( const bool returnHeaders,
const bool returnBody )
QPair<QByteArray, QByteArray> QgsHttpRequestHandler::getResponse()
{
if ( ! returnHeaders )
{
return mResponseBody;
}
else if ( ! returnBody )
{
return mResponseHeader;
}
else
{
return mResponseHeader.append( mResponseBody );
}
QPair<QByteArray, QByteArray> response( mResponseHeader, mResponseBody );
return response;
}

QString QgsHttpRequestHandler::formatToMimeType( const QString& format ) const
Expand Down
6 changes: 1 addition & 5 deletions src/server/qgshttprequesthandler.h
Expand Up @@ -63,12 +63,8 @@ class QgsHttpRequestHandler: public QgsRequestHandler
#ifdef HAVE_SERVER_PYTHON_PLUGINS
virtual void setPluginFilters( QgsServerFiltersMap pluginFilters ) override;
#endif
// TODO: if HAVE_SERVER_PYTHON
QByteArray getResponseHeader( ) override { return mResponseHeader; }
QByteArray getResponseBody( ) override { return mResponseBody; }
/** Return the response if capture output is activated */
QByteArray getResponse( const bool returnHeaders = TRUE,
const bool returnBody = TRUE ) override;
QPair<QByteArray, QByteArray> getResponse( ) override;

protected:
virtual void sendHeaders( ) override;
Expand Down
7 changes: 2 additions & 5 deletions src/server/qgsrequesthandler.h
Expand Up @@ -28,6 +28,7 @@
#include <QMap>
#include <QString>
#include <QStringList>
#include <QPair>

#ifdef HAVE_SERVER_PYTHON_PLUGINS
#include "qgsserverfilter.h"
Expand Down Expand Up @@ -113,11 +114,7 @@ class QgsRequestHandler
*/
virtual void setPluginFilters( QgsServerFiltersMap pluginFilters ) = 0;
#endif
// TODO: if HAVE_SERVER_PYTHON
virtual QByteArray getResponseHeader( ) = 0;
virtual QByteArray getResponseBody( ) = 0;
virtual QByteArray getResponse( const bool returnHeaders = TRUE,
const bool returnBody = TRUE ) = 0;
virtual QPair<QByteArray, QByteArray> getResponse( ) = 0;

protected:
virtual void sendHeaders( ) = 0;
Expand Down
40 changes: 4 additions & 36 deletions src/server/qgsserver.cpp
Expand Up @@ -403,47 +403,14 @@ bool QgsServer::init( int & argc, char ** argv )
}


/**
* Handles the request
*/
QByteArray QgsServer::handleRequest( const QString queryString /*= QString( )*/ )
{
return handleRequest( queryString, TRUE, TRUE );
}

/**
* @brief Handles the request, returning only the body
* @param queryString
* @return response body if mCaptureOutput is set, empty QByteArray if not
*/
QByteArray QgsServer::handleRequestGetBody( const QString queryString /*= QString( )*/ )
{
return handleRequest( queryString, FALSE, TRUE );
}

/**
* @brief Handles the request, returning only the headers
* @param queryString
* @return response headers if mCaptureOutput is set, empty QByteArray if not
*/
QByteArray QgsServer::handleRequestGetHeaders( const QString queryString /*= QString( )*/ )
{
return handleRequest( queryString, TRUE, FALSE );
}

/**
* @brief Handles the request
* @param queryString
* @param returnBody
* @param returnHeaders
* @return response body and headers if mCaptureOutput is set and the
* flags are set, empty QByteArray if not
* @return response body and headers
*/
QByteArray QgsServer::handleRequest( const QString queryString ,
bool returnHeaders,
bool returnBody )
QPair<QByteArray, QByteArray> QgsServer::handleRequest( const QString queryString /*= QString( )*/ )
{

// Run init if handleRequest was called without previously initialising
// the server
if ( ! mInitialised )
Expand Down Expand Up @@ -603,6 +570,7 @@ QByteArray QgsServer::handleRequest( const QString queryString ,
}
// TODO: if HAVE_SERVER_PYTHON
// Returns the response bytestream
return theRequestHandler->getResponse( returnHeaders , returnBody );
return theRequestHandler->getResponse( );

}

27 changes: 3 additions & 24 deletions src/server/qgsserver.h
Expand Up @@ -61,36 +61,15 @@ class SERVER_EXPORT QgsServer
/** Handles the request. The output is normally printed trough FCGI printf
* by the request handler or, in case the server has been invoked from python
* bindings, a flag is set that captures all the output headers and body, instead
* of printing it returns the output as a QByteArray.
* When calling handleRequest() from python bindings an additional argument
* specify if we only want the headers or the body back, this is mainly useful
* for testing purposes.
* of printing it returns the output as a QPair of QByteArray.
* The query string is normally read from environment
* but can be also passed in args and in this case overrides the environment
* variable
*
* @param queryString optional QString containing the query string
* @return the response QByteArray if called from python bindings, empty otherwise
* @return the response headers and body QPair of QByteArray if called from python bindings, empty otherwise
*/
QByteArray handleRequest( const QString queryString = QString( ) );
QByteArray handleRequest( const QString queryString,
const bool returnHeaders,
const bool returnBody );
/**
* Handles the request and returns only the body
*
* @param queryString optional QString containing the query string
* @return the response body QByteArray if called from python bindings, empty otherwise
*/
QByteArray handleRequestGetBody( const QString queryString = QString( ) );

/**
* Handles the request and returns only the headers
*
* @param queryString optional QString containing the query string
* @return the response headers QByteArray if called from python bindings, empty otherwise
*/
QByteArray handleRequestGetHeaders( const QString queryString = QString( ) );
QPair<QByteArray, QByteArray> handleRequest( const QString queryString = QString( ) );

/** Returns a pointer to the server interface */
#ifdef HAVE_SERVER_PYTHON_PLUGINS
Expand Down
19 changes: 10 additions & 9 deletions tests/src/python/test_qgsserver.py
Expand Up @@ -53,17 +53,15 @@ def test_api(self):
"""Using an empty query string (returns an XML exception)
we are going to test if headers and body are returned correctly"""
# Test as a whole
response = str(self.server.handleRequest())
header, body = [str(_v) for _v in self.server.handleRequest()]
response = header + body
expected = 'Content-Length: 206\nContent-Type: text/xml; charset=utf-8\n\n<ServiceExceptionReport version="1.3.0" xmlns="http://www.opengis.net/ogc">\n <ServiceException code="Service configuration error">Service unknown or unsupported</ServiceException>\n</ServiceExceptionReport>\n'
self.assertEqual(response, expected)
# Test header
response = str(self.server.handleRequestGetHeaders())
expected = 'Content-Length: 206\nContent-Type: text/xml; charset=utf-8\n\n'
self.assertEqual(response, expected)
self.assertEqual(header, expected)
# Test body
response = str(self.server.handleRequestGetBody())
expected = '<ServiceExceptionReport version="1.3.0" xmlns="http://www.opengis.net/ogc">\n <ServiceException code="Service configuration error">Service unknown or unsupported</ServiceException>\n</ServiceExceptionReport>\n'
self.assertEqual(response, expected)
self.assertEqual(body, expected)

def test_pluginfilters(self):
"""Test python plugins filters"""
Expand Down Expand Up @@ -122,7 +120,8 @@ def responseComplete(self):
self.assertTrue(filter2 in serverIface.filters()[100])
self.assertEqual(filter1, serverIface.filters()[101][0])
self.assertEqual(filter2, serverIface.filters()[200][0])
response = str(self.server.handleRequest('service=simple'))
header, body = [str(_v) for _v in self.server.handleRequest('service=simple')]
response = header + body
expected = 'Content-type: text/plain\n\nHello from SimpleServer!Hello from Filter1!Hello from Filter2!'
self.assertEqual(response, expected)

Expand All @@ -133,7 +132,8 @@ def responseComplete(self):
self.assertTrue(filter2 in serverIface.filters()[100])
self.assertEqual(filter1, serverIface.filters()[101][0])
self.assertEqual(filter2, serverIface.filters()[200][0])
response = str(self.server.handleRequest('service=simple'))
header, body = [str(_v) for _v in self.server.handleRequest('service=simple')]
response = header + body
expected = 'Content-type: text/plain\n\nHello from SimpleServer!Hello from Filter1!Hello from Filter2!'
self.assertEqual(response, expected)

Expand All @@ -143,7 +143,8 @@ def wms_request_compare(self, request):
assert os.path.exists(project), "Project file not found: " + project

query_string = 'MAP=%s&SERVICE=WMS&VERSION=1.3&REQUEST=%s' % (urllib.quote(project), request)
response = str(self.server.handleRequest(query_string))
header, body = [str(_v) for _v in self.server.handleRequest(query_string)]
response = header + body
f = open(self.testdata_path + request.lower() + '.txt')
expected = f.read()
f.close()
Expand Down

0 comments on commit a9f2acc

Please sign in to comment.