Skip to content

Commit 736f1c4

Browse files
committed
Merge pull request #2200 from mhugent/server_content_disposition
Server content disposition
2 parents c74754e + f0835ec commit 736f1c4

File tree

8 files changed

+65
-48
lines changed

8 files changed

+65
-48
lines changed

python/server/qgsrequesthandler.sip

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class QgsRequestHandler
3030

3131
/**Allow plugins to return a QgsMapServiceException*/
3232
virtual void setServiceException( QgsMapServiceException ex /Transfer/ ) = 0;
33+
virtual void setDefaultHeaders();
3334
/**Set an HTTP header*/
3435
virtual void setHeader( const QString &name, const QString &value ) = 0;
3536
/**Remove an HTTP header*/

src/server/qgshttprequesthandler.cpp

+26-21
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,24 @@ bool QgsHttpRequestHandler::exceptionRaised() const
7272
return mException != NULL;
7373
}
7474

75+
void QgsHttpRequestHandler::setDefaultHeaders()
76+
{
77+
//format
78+
QString format = mInfoFormat;
79+
if ( mInfoFormat.startsWith( "text/" ) )
80+
{
81+
format.append( "; charset=utf-8" );
82+
}
83+
setHeader( "Content-Type", format );
84+
85+
//length
86+
int contentLength = mBody.size();
87+
if ( contentLength > 0 ) // size is not known when streaming
88+
{
89+
setHeader( "Content-Length", QString::number( contentLength ) );
90+
}
91+
}
92+
7593
void QgsHttpRequestHandler::setHeader( const QString &name, const QString &value )
7694
{
7795
mHeaders.insert( name, value );
@@ -133,29 +151,16 @@ void QgsHttpRequestHandler::sendHeaders()
133151
// Send default headers if they've not been set in a previous stage
134152
if ( mHeaders.empty() )
135153
{
136-
QgsDebugMsg( QString( "Content size: %1" ).arg( mBody.size() ) );
137-
QgsDebugMsg( QString( "Content format: %1" ).arg( mInfoFormat ) );
138-
addToResponseHeader( "Content-Type: " );
139-
addToResponseHeader( mInfoFormat.toUtf8() );
140-
if ( mInfoFormat.startsWith( "text/" ) )
141-
addToResponseHeader( "; charset=utf-8" );
142-
addToResponseHeader( "\n" );
143-
// size is not known when streaming
144-
if ( mBody.size() > 0 )
145-
{
146-
addToResponseHeader( QString( "Content-Length: %1\n" ).arg( mBody.size() ).toUtf8( ) );
147-
}
154+
setDefaultHeaders();
148155
}
149-
else
156+
157+
QMap<QString, QString>::const_iterator it;
158+
for ( it = mHeaders.constBegin(); it != mHeaders.constEnd(); ++it )
150159
{
151-
QMap<QString, QString>::const_iterator it;
152-
for ( it = mHeaders.constBegin(); it != mHeaders.constEnd(); ++it )
153-
{
154-
addToResponseHeader( it.key().toUtf8() );
155-
addToResponseHeader( ": " );
156-
addToResponseHeader( it.value().toUtf8() );
157-
addToResponseHeader( "\n" );
158-
}
160+
addToResponseHeader( it.key().toUtf8() );
161+
addToResponseHeader( ": " );
162+
addToResponseHeader( it.value().toUtf8() );
163+
addToResponseHeader( "\n" );
159164
}
160165
addToResponseHeader( "\n" );
161166
mHeaders.clear();

src/server/qgshttprequesthandler.h

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class QgsHttpRequestHandler: public QgsRequestHandler
4848
virtual void setGetCoverageResponse( QByteArray* ba ) override;
4949
/** Send out HTTP headers and flush output buffer*/
5050
virtual void sendResponse() override;
51+
virtual void setDefaultHeaders() override;
5152
virtual void setHeader( const QString &name, const QString &value ) override;
5253
virtual int removeHeader( const QString &name ) override;
5354
virtual void clearHeaders( ) override;

src/server/qgsrequesthandler.h

+24-23
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class QDomDocument;
3737
class QImage;
3838
class QgsMapServiceException;
3939

40-
/**This class is an interface hiding the details of reading input and writing output from/to a wms request mechanism.
40+
/** This class is an interface hiding the details of reading input and writing output from/to a wms request mechanism.
4141
Examples of possible mechanisms are cgi Get, cgi Post, SOAP or the usage as a standalone command line executable*/
4242
class QgsRequestHandler
4343
{
@@ -49,13 +49,13 @@ class QgsRequestHandler
4949
, mException( 0 )
5050
{}
5151
virtual ~QgsRequestHandler( ) {}
52-
/**Parses the input and creates a request neutral Parameter/Value map*/
52+
/** Parses the input and creates a request neutral Parameter/Value map*/
5353
virtual void parseInput() = 0;
54-
/**Sends the map image back to the client*/
54+
/** Sends the map image back to the client*/
5555
virtual void setGetMapResponse( const QString& service, QImage* img, int imageQuality ) = 0;
5656
virtual void setGetCapabilitiesResponse( const QDomDocument& doc ) = 0;
5757
virtual void setGetFeatureInfoResponse( const QDomDocument& infoDoc, const QString& infoFormat ) = 0;
58-
/**Allow plugins to return a QgsMapServiceException*/
58+
/** Allow plugins to return a QgsMapServiceException*/
5959
virtual void setServiceException( QgsMapServiceException ex ) = 0;
6060
virtual void setXmlResponse( const QDomDocument& doc ) = 0;
6161
virtual void setXmlResponse( const QDomDocument& doc, const QString& mimeType ) = 0;
@@ -64,45 +64,46 @@ class QgsRequestHandler
6464
virtual void setGetFeatureResponse( QByteArray* ba ) = 0;
6565
virtual void endGetFeatureResponse( QByteArray* ba ) = 0;
6666
virtual void setGetCoverageResponse( QByteArray* ba ) = 0;
67-
/**Set an HTTP header*/
67+
virtual void setDefaultHeaders() {}
68+
/** Set an HTTP header*/
6869
virtual void setHeader( const QString &name, const QString &value ) = 0;
69-
/**Remove an HTTP header*/
70+
/** Remove an HTTP header*/
7071
virtual int removeHeader( const QString &name ) = 0;
71-
/**Delete all HTTP headers*/
72+
/** Delete all HTTP headers*/
7273
virtual void clearHeaders( ) = 0;
73-
/**Append the bytestream to response body*/
74+
/** Append the bytestream to response body*/
7475
virtual void appendBody( const QByteArray &body ) = 0;
75-
/**Clears the response body*/
76+
/** Clears the response body*/
7677
virtual void clearBody( ) = 0;
77-
/**Return the response body*/
78+
/** Return the response body*/
7879
virtual QByteArray body() { return mBody; }
79-
/**Set the info format string such as "text/xml"*/
80+
/** Set the info format string such as "text/xml"*/
8081
virtual void setInfoFormat( const QString &format ) = 0;
81-
/**Check whether there is any header set or the body is not empty*/
82+
/** Check whether there is any header set or the body is not empty*/
8283
virtual bool responseReady() const = 0;
83-
/**Send out HTTP headers and flush output buffer*/
84+
/** Send out HTTP headers and flush output buffer*/
8485
virtual void sendResponse( ) = 0;
85-
/**Pointer to last raised exception*/
86+
/** Pointer to last raised exception*/
8687
virtual bool exceptionRaised() const = 0;
87-
/**Return a copy of the parsed parameters as a key-value pair, to modify
88+
/** Return a copy of the parsed parameters as a key-value pair, to modify
8889
* a parameter setParameter( const QString &key, const QString &value)
8990
* and removeParameter(const QString &key) must be used
9091
*/
9192
QMap<QString, QString> parameterMap() { return mParameterMap; }
92-
/**Set a request parameter*/
93+
/** Set a request parameter*/
9394
virtual void setParameter( const QString &key, const QString &value ) = 0;
94-
/**Remove a request parameter*/
95+
/** Remove a request parameter*/
9596
virtual int removeParameter( const QString &key ) = 0;
96-
/**Return a request parameter*/
97+
/** Return a request parameter*/
9798
virtual QString parameter( const QString &key ) const = 0;
98-
/**Return the requested format string*/
99+
/** Return the requested format string*/
99100
QString format() const { return mFormat; }
100-
/**Return the mime type for the response*/
101+
/** Return the mime type for the response*/
101102
QString infoFormat() const { return mInfoFormat; }
102-
/**Return true if the HTTP headers were already sent to the client*/
103+
/** Return true if the HTTP headers were already sent to the client*/
103104
bool headersSent() { return mHeadersSent; }
104105
#ifdef HAVE_SERVER_PYTHON_PLUGINS
105-
/**Allow core services to call plugin hooks through sendResponse() */
106+
/** Allow core services to call plugin hooks through sendResponse() */
106107
virtual void setPluginFilters( QgsServerFiltersMap pluginFilters ) = 0;
107108
#endif
108109
// TODO: if HAVE_SERVER_PYTHON
@@ -118,7 +119,7 @@ class QgsRequestHandler
118119
QgsServerFiltersMap mPluginFilters;
119120
#endif
120121
QByteArray mBody; // The response payload
121-
/**This is set by the parseInput methods of the subclasses (parameter FORMAT, e.g. 'FORMAT=PNG')*/
122+
/** This is set by the parseInput methods of the subclasses (parameter FORMAT, e.g. 'FORMAT=PNG')*/
122123
QString mFormat;
123124
QString mFormatString; //format string as it is passed in the request (with base)
124125
bool mHeadersSent;

src/server/qgsserver.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,15 @@ QByteArray QgsServer::handleRequest( const QString queryString ,
583583
filtersIterator.value()->responseComplete();
584584
}
585585
#endif
586+
587+
//possibility for client to suggest a download filename
588+
QString outputFileName = theRequestHandler->parameter( "FILE_NAME" );
589+
if ( !outputFileName.isEmpty() )
590+
{
591+
theRequestHandler->setDefaultHeaders();
592+
theRequestHandler->setHeader( "Content-Disposition", "attachment; filename=\"" + outputFileName + "\"" );
593+
}
594+
586595
theRequestHandler->sendResponse();
587596

588597
if ( logLevel < 1 )

tests/src/python/test_qgsserver.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ def test_api(self):
5656
we are going to test if headers and body are returned correctly"""
5757
# Test as a whole
5858
response = str(self.server.handleRequest())
59-
expected = 'Content-Type: text/xml; charset=utf-8\nContent-Length: 206\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'
59+
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'
6060
self.assertEqual(response, expected)
6161
# Test header
6262
response = str(self.server.handleRequestGetHeaders())
63-
expected = 'Content-Type: text/xml; charset=utf-8\nContent-Length: 206\n\n'
63+
expected = 'Content-Length: 206\nContent-Type: text/xml; charset=utf-8\n\n'
6464
self.assertEqual(response, expected)
6565
# Test body
6666
response = str(self.server.handleRequestGetBody())

tests/testdata/qgis_server/getcapabilities.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Content-Type: text/xml; charset=utf-8
21
Content-Length: 5250
2+
Content-Type: text/xml; charset=utf-8
33

44
<?xml version="1.0" encoding="utf-8"?>
55
<WMS_Capabilities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.3" xmlns="http://www.opengis.net/wms" xsi:schemaLocation="http://www.opengis.net/wms http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd http://www.qgis.org/wms http:?MAP=/home/ale/dev/QGIS/tests/testdata/qgis_server/testproject.qgs&amp;SERVICE=WMS&amp;REQUEST=GetSchemaExtension" xmlns:sld="http://www.opengis.net/sld" xmlns:qgs="http://www.qgis.org/wms">

tests/testdata/qgis_server/getprojectsettings.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Content-Type: text/xml; charset=utf-8
21
Content-Length: 6268
2+
Content-Type: text/xml; charset=utf-8
33

44
<?xml version="1.0" encoding="utf-8"?>
55
<WMS_Capabilities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.3.0" xmlns="http://www.opengis.net/wms" xsi:schemaLocation="http://www.opengis.net/wms http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd http://www.qgis.org/wms http:?MAP=/home/ale/dev/QGIS/tests/testdata/qgis_server/testproject.qgs&amp;SERVICE=WMS&amp;REQUEST=GetSchemaExtension" xmlns:sld="http://www.opengis.net/sld" xmlns:qgs="http://www.qgis.org/wms">

0 commit comments

Comments
 (0)