Skip to content

Commit a9f2acc

Browse files
committed
[SERVER] QgsRequestHandler now returns a QPair
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.
1 parent 8611543 commit a9f2acc

File tree

7 files changed

+67
-104
lines changed

7 files changed

+67
-104
lines changed

python/server/qgsserver.sip

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,48 @@
1717
***************************************************************************/
1818

1919

20+
%MappedType QPair<QByteArray, QByteArray>
21+
{
22+
%TypeHeaderCode
23+
#include <QPair>
24+
#include <QByteArray>
25+
%End
26+
27+
28+
%TypeCode
29+
// Convenience function for converting a QByteArray to a Python str object. (from QtCore/qbytearray.sip)
30+
static PyObject *QByteArrayToPyStr(QByteArray *ba)
31+
{
32+
char *data = ba->data();
33+
34+
if (data)
35+
// QByteArrays may have embedded '\0's so set the size explicitly.
36+
return SIPBytes_FromStringAndSize(data, ba->size());
37+
return SIPBytes_FromString("");
38+
}
39+
%End
40+
41+
42+
%ConvertFromTypeCode
43+
// Create the tuple.
44+
return Py_BuildValue((char *)"OO", QByteArrayToPyStr( &sipCpp->first ), QByteArrayToPyStr( &sipCpp->second ) );
45+
%End
46+
47+
%ConvertToTypeCode
48+
// Check the type if that is all that is required.
49+
if (sipIsErr == NULL)
50+
return (PyTuple_Size(sipPy) == 2);
51+
52+
QPair<QByteArray, QByteArray> *qp = new QPair<QByteArray, QByteArray>;
53+
54+
qp->first = SIPLong_AsLong(PyTuple_GET_ITEM(sipPy, 0));
55+
qp->second = SIPLong_AsLong(PyTuple_GET_ITEM(sipPy, 1));
56+
57+
*sipCppPtr = qp;
58+
59+
return sipGetState(sipTransferObj);
60+
%End
61+
};
2062

2163
class QgsServer
2264
{
@@ -31,21 +73,12 @@ class QgsServer
3173
//void init( int argc, char* argv[] );
3274
// init for python bindings:
3375
void init( );
34-
QByteArray handleRequest( const QString queryString = QString( ) );
35-
// TODO: if HAVE_SERVER_PYTHON
36-
QByteArray handleRequest( const QString queryString,
37-
const bool returnHeaders,
38-
const bool returnBody );
39-
QByteArray handleRequestGetBody( const QString queryString = QString( ) );
40-
QByteArray handleRequestGetHeaders( const QString queryString = QString( ) );
41-
//QgsServerContext& serverContext ( ) /KeepReference/;
76+
QPair<QByteArray, QByteArray> handleRequest( const QString queryString = QString( ) );
4277
%If (HAVE_SERVER_PYTHON_PLUGINS)
4378
QgsServerInterface* serverInterface( );
44-
// Needs %MethodCode
45-
//QMultiMap<int, QgsServerFilter*> pluginFilters( );
4679
%End
4780

48-
// The following is needed because otherwise SIP fails trying to create copy
81+
// The following is needed because otherwise SIP fails trying to create copy
4982
// ctor
5083
private:
5184
QgsServer( const QgsServer& );

src/server/qgshttprequesthandler.cpp

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -218,21 +218,10 @@ void QgsHttpRequestHandler::sendResponse()
218218
clearBody();
219219
}
220220

221-
QByteArray QgsHttpRequestHandler::getResponse( const bool returnHeaders,
222-
const bool returnBody )
221+
QPair<QByteArray, QByteArray> QgsHttpRequestHandler::getResponse()
223222
{
224-
if ( ! returnHeaders )
225-
{
226-
return mResponseBody;
227-
}
228-
else if ( ! returnBody )
229-
{
230-
return mResponseHeader;
231-
}
232-
else
233-
{
234-
return mResponseHeader.append( mResponseBody );
235-
}
223+
QPair<QByteArray, QByteArray> response( mResponseHeader, mResponseBody );
224+
return response;
236225
}
237226

238227
QString QgsHttpRequestHandler::formatToMimeType( const QString& format ) const

src/server/qgshttprequesthandler.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,8 @@ class QgsHttpRequestHandler: public QgsRequestHandler
6363
#ifdef HAVE_SERVER_PYTHON_PLUGINS
6464
virtual void setPluginFilters( QgsServerFiltersMap pluginFilters ) override;
6565
#endif
66-
// TODO: if HAVE_SERVER_PYTHON
67-
QByteArray getResponseHeader( ) override { return mResponseHeader; }
68-
QByteArray getResponseBody( ) override { return mResponseBody; }
6966
/** Return the response if capture output is activated */
70-
QByteArray getResponse( const bool returnHeaders = TRUE,
71-
const bool returnBody = TRUE ) override;
67+
QPair<QByteArray, QByteArray> getResponse( ) override;
7268

7369
protected:
7470
virtual void sendHeaders( ) override;

src/server/qgsrequesthandler.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <QMap>
2929
#include <QString>
3030
#include <QStringList>
31+
#include <QPair>
3132

3233
#ifdef HAVE_SERVER_PYTHON_PLUGINS
3334
#include "qgsserverfilter.h"
@@ -113,11 +114,7 @@ class QgsRequestHandler
113114
*/
114115
virtual void setPluginFilters( QgsServerFiltersMap pluginFilters ) = 0;
115116
#endif
116-
// TODO: if HAVE_SERVER_PYTHON
117-
virtual QByteArray getResponseHeader( ) = 0;
118-
virtual QByteArray getResponseBody( ) = 0;
119-
virtual QByteArray getResponse( const bool returnHeaders = TRUE,
120-
const bool returnBody = TRUE ) = 0;
117+
virtual QPair<QByteArray, QByteArray> getResponse( ) = 0;
121118

122119
protected:
123120
virtual void sendHeaders( ) = 0;

src/server/qgsserver.cpp

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -403,47 +403,14 @@ bool QgsServer::init( int & argc, char ** argv )
403403
}
404404

405405

406-
/**
407-
* Handles the request
408-
*/
409-
QByteArray QgsServer::handleRequest( const QString queryString /*= QString( )*/ )
410-
{
411-
return handleRequest( queryString, TRUE, TRUE );
412-
}
413-
414-
/**
415-
* @brief Handles the request, returning only the body
416-
* @param queryString
417-
* @return response body if mCaptureOutput is set, empty QByteArray if not
418-
*/
419-
QByteArray QgsServer::handleRequestGetBody( const QString queryString /*= QString( )*/ )
420-
{
421-
return handleRequest( queryString, FALSE, TRUE );
422-
}
423-
424-
/**
425-
* @brief Handles the request, returning only the headers
426-
* @param queryString
427-
* @return response headers if mCaptureOutput is set, empty QByteArray if not
428-
*/
429-
QByteArray QgsServer::handleRequestGetHeaders( const QString queryString /*= QString( )*/ )
430-
{
431-
return handleRequest( queryString, TRUE, FALSE );
432-
}
433406

434407
/**
435408
* @brief Handles the request
436409
* @param queryString
437-
* @param returnBody
438-
* @param returnHeaders
439-
* @return response body and headers if mCaptureOutput is set and the
440-
* flags are set, empty QByteArray if not
410+
* @return response body and headers
441411
*/
442-
QByteArray QgsServer::handleRequest( const QString queryString ,
443-
bool returnHeaders,
444-
bool returnBody )
412+
QPair<QByteArray, QByteArray> QgsServer::handleRequest( const QString queryString /*= QString( )*/ )
445413
{
446-
447414
// Run init if handleRequest was called without previously initialising
448415
// the server
449416
if ( ! mInitialised )
@@ -603,6 +570,7 @@ QByteArray QgsServer::handleRequest( const QString queryString ,
603570
}
604571
// TODO: if HAVE_SERVER_PYTHON
605572
// Returns the response bytestream
606-
return theRequestHandler->getResponse( returnHeaders , returnBody );
573+
return theRequestHandler->getResponse( );
574+
607575
}
608576

src/server/qgsserver.h

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -61,36 +61,15 @@ class SERVER_EXPORT QgsServer
6161
/** Handles the request. The output is normally printed trough FCGI printf
6262
* by the request handler or, in case the server has been invoked from python
6363
* bindings, a flag is set that captures all the output headers and body, instead
64-
* of printing it returns the output as a QByteArray.
65-
* When calling handleRequest() from python bindings an additional argument
66-
* specify if we only want the headers or the body back, this is mainly useful
67-
* for testing purposes.
64+
* of printing it returns the output as a QPair of QByteArray.
6865
* The query string is normally read from environment
6966
* but can be also passed in args and in this case overrides the environment
7067
* variable
7168
*
7269
* @param queryString optional QString containing the query string
73-
* @return the response QByteArray if called from python bindings, empty otherwise
70+
* @return the response headers and body QPair of QByteArray if called from python bindings, empty otherwise
7471
*/
75-
QByteArray handleRequest( const QString queryString = QString( ) );
76-
QByteArray handleRequest( const QString queryString,
77-
const bool returnHeaders,
78-
const bool returnBody );
79-
/**
80-
* Handles the request and returns only the body
81-
*
82-
* @param queryString optional QString containing the query string
83-
* @return the response body QByteArray if called from python bindings, empty otherwise
84-
*/
85-
QByteArray handleRequestGetBody( const QString queryString = QString( ) );
86-
87-
/**
88-
* Handles the request and returns only the headers
89-
*
90-
* @param queryString optional QString containing the query string
91-
* @return the response headers QByteArray if called from python bindings, empty otherwise
92-
*/
93-
QByteArray handleRequestGetHeaders( const QString queryString = QString( ) );
72+
QPair<QByteArray, QByteArray> handleRequest( const QString queryString = QString( ) );
9473

9574
/** Returns a pointer to the server interface */
9675
#ifdef HAVE_SERVER_PYTHON_PLUGINS

tests/src/python/test_qgsserver.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,15 @@ def test_api(self):
5353
"""Using an empty query string (returns an XML exception)
5454
we are going to test if headers and body are returned correctly"""
5555
# Test as a whole
56-
response = str(self.server.handleRequest())
56+
header, body = [str(_v) for _v in self.server.handleRequest()]
57+
response = header + body
5758
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'
5859
self.assertEqual(response, expected)
59-
# Test header
60-
response = str(self.server.handleRequestGetHeaders())
6160
expected = 'Content-Length: 206\nContent-Type: text/xml; charset=utf-8\n\n'
62-
self.assertEqual(response, expected)
61+
self.assertEqual(header, expected)
6362
# Test body
64-
response = str(self.server.handleRequestGetBody())
6563
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'
66-
self.assertEqual(response, expected)
64+
self.assertEqual(body, expected)
6765

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

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

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

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

0 commit comments

Comments
 (0)