Skip to content
Permalink
Browse files

Merge pull request #2200 from mhugent/server_content_disposition

Server content disposition
  • Loading branch information
mhugent committed Jul 8, 2015
2 parents c74754e + f0835ec commit 736f1c4fa0a1ea7689c012837a72f3808c464e35
@@ -30,6 +30,7 @@ class QgsRequestHandler

/**Allow plugins to return a QgsMapServiceException*/
virtual void setServiceException( QgsMapServiceException ex /Transfer/ ) = 0;
virtual void setDefaultHeaders();
/**Set an HTTP header*/
virtual void setHeader( const QString &name, const QString &value ) = 0;
/**Remove an HTTP header*/
@@ -72,6 +72,24 @@ bool QgsHttpRequestHandler::exceptionRaised() const
return mException != NULL;
}

void QgsHttpRequestHandler::setDefaultHeaders()
{
//format
QString format = mInfoFormat;
if ( mInfoFormat.startsWith( "text/" ) )
{
format.append( "; charset=utf-8" );
}
setHeader( "Content-Type", format );

//length
int contentLength = mBody.size();
if ( contentLength > 0 ) // size is not known when streaming
{
setHeader( "Content-Length", QString::number( contentLength ) );
}
}

void QgsHttpRequestHandler::setHeader( const QString &name, const QString &value )
{
mHeaders.insert( name, value );
@@ -133,29 +151,16 @@ void QgsHttpRequestHandler::sendHeaders()
// Send default headers if they've not been set in a previous stage
if ( mHeaders.empty() )
{
QgsDebugMsg( QString( "Content size: %1" ).arg( mBody.size() ) );
QgsDebugMsg( QString( "Content format: %1" ).arg( mInfoFormat ) );
addToResponseHeader( "Content-Type: " );
addToResponseHeader( mInfoFormat.toUtf8() );
if ( mInfoFormat.startsWith( "text/" ) )
addToResponseHeader( "; charset=utf-8" );
addToResponseHeader( "\n" );
// size is not known when streaming
if ( mBody.size() > 0 )
{
addToResponseHeader( QString( "Content-Length: %1\n" ).arg( mBody.size() ).toUtf8( ) );
}
setDefaultHeaders();
}
else

QMap<QString, QString>::const_iterator it;
for ( it = mHeaders.constBegin(); it != mHeaders.constEnd(); ++it )
{
QMap<QString, QString>::const_iterator it;
for ( it = mHeaders.constBegin(); it != mHeaders.constEnd(); ++it )
{
addToResponseHeader( it.key().toUtf8() );
addToResponseHeader( ": " );
addToResponseHeader( it.value().toUtf8() );
addToResponseHeader( "\n" );
}
addToResponseHeader( it.key().toUtf8() );
addToResponseHeader( ": " );
addToResponseHeader( it.value().toUtf8() );
addToResponseHeader( "\n" );
}
addToResponseHeader( "\n" );
mHeaders.clear();
@@ -48,6 +48,7 @@ class QgsHttpRequestHandler: public QgsRequestHandler
virtual void setGetCoverageResponse( QByteArray* ba ) override;
/** Send out HTTP headers and flush output buffer*/
virtual void sendResponse() override;
virtual void setDefaultHeaders() override;
virtual void setHeader( const QString &name, const QString &value ) override;
virtual int removeHeader( const QString &name ) override;
virtual void clearHeaders( ) override;
@@ -37,7 +37,7 @@ class QDomDocument;
class QImage;
class QgsMapServiceException;

/**This class is an interface hiding the details of reading input and writing output from/to a wms request mechanism.
/** This class is an interface hiding the details of reading input and writing output from/to a wms request mechanism.
Examples of possible mechanisms are cgi Get, cgi Post, SOAP or the usage as a standalone command line executable*/
class QgsRequestHandler
{
@@ -49,13 +49,13 @@ class QgsRequestHandler
, mException( 0 )
{}
virtual ~QgsRequestHandler( ) {}
/**Parses the input and creates a request neutral Parameter/Value map*/
/** Parses the input and creates a request neutral Parameter/Value map*/
virtual void parseInput() = 0;
/**Sends the map image back to the client*/
/** Sends the map image back to the client*/
virtual void setGetMapResponse( const QString& service, QImage* img, int imageQuality ) = 0;
virtual void setGetCapabilitiesResponse( const QDomDocument& doc ) = 0;
virtual void setGetFeatureInfoResponse( const QDomDocument& infoDoc, const QString& infoFormat ) = 0;
/**Allow plugins to return a QgsMapServiceException*/
/** Allow plugins to return a QgsMapServiceException*/
virtual void setServiceException( QgsMapServiceException ex ) = 0;
virtual void setXmlResponse( const QDomDocument& doc ) = 0;
virtual void setXmlResponse( const QDomDocument& doc, const QString& mimeType ) = 0;
@@ -64,45 +64,46 @@ class QgsRequestHandler
virtual void setGetFeatureResponse( QByteArray* ba ) = 0;
virtual void endGetFeatureResponse( QByteArray* ba ) = 0;
virtual void setGetCoverageResponse( QByteArray* ba ) = 0;
/**Set an HTTP header*/
virtual void setDefaultHeaders() {}
/** Set an HTTP header*/
virtual void setHeader( const QString &name, const QString &value ) = 0;
/**Remove an HTTP header*/
/** Remove an HTTP header*/
virtual int removeHeader( const QString &name ) = 0;
/**Delete all HTTP headers*/
/** Delete all HTTP headers*/
virtual void clearHeaders( ) = 0;
/**Append the bytestream to response body*/
/** Append the bytestream to response body*/
virtual void appendBody( const QByteArray &body ) = 0;
/**Clears the response body*/
/** Clears the response body*/
virtual void clearBody( ) = 0;
/**Return the response body*/
/** Return the response body*/
virtual QByteArray body() { return mBody; }
/**Set the info format string such as "text/xml"*/
/** Set the info format string such as "text/xml"*/
virtual void setInfoFormat( const QString &format ) = 0;
/**Check whether there is any header set or the body is not empty*/
/** Check whether there is any header set or the body is not empty*/
virtual bool responseReady() const = 0;
/**Send out HTTP headers and flush output buffer*/
/** Send out HTTP headers and flush output buffer*/
virtual void sendResponse( ) = 0;
/**Pointer to last raised exception*/
/** Pointer to last raised exception*/
virtual bool exceptionRaised() const = 0;
/**Return a copy of the parsed parameters as a key-value pair, to modify
/** Return a copy of the parsed parameters as a key-value pair, to modify
* a parameter setParameter( const QString &key, const QString &value)
* and removeParameter(const QString &key) must be used
*/
QMap<QString, QString> parameterMap() { return mParameterMap; }
/**Set a request parameter*/
/** Set a request parameter*/
virtual void setParameter( const QString &key, const QString &value ) = 0;
/**Remove a request parameter*/
/** Remove a request parameter*/
virtual int removeParameter( const QString &key ) = 0;
/**Return a request parameter*/
/** Return a request parameter*/
virtual QString parameter( const QString &key ) const = 0;
/**Return the requested format string*/
/** Return the requested format string*/
QString format() const { return mFormat; }
/**Return the mime type for the response*/
/** Return the mime type for the response*/
QString infoFormat() const { return mInfoFormat; }
/**Return true if the HTTP headers were already sent to the client*/
/** Return true if the HTTP headers were already sent to the client*/
bool headersSent() { return mHeadersSent; }
#ifdef HAVE_SERVER_PYTHON_PLUGINS
/**Allow core services to call plugin hooks through sendResponse() */
/** Allow core services to call plugin hooks through sendResponse() */
virtual void setPluginFilters( QgsServerFiltersMap pluginFilters ) = 0;
#endif
// TODO: if HAVE_SERVER_PYTHON
@@ -118,7 +119,7 @@ class QgsRequestHandler
QgsServerFiltersMap mPluginFilters;
#endif
QByteArray mBody; // The response payload
/**This is set by the parseInput methods of the subclasses (parameter FORMAT, e.g. 'FORMAT=PNG')*/
/** This is set by the parseInput methods of the subclasses (parameter FORMAT, e.g. 'FORMAT=PNG')*/
QString mFormat;
QString mFormatString; //format string as it is passed in the request (with base)
bool mHeadersSent;
@@ -583,6 +583,15 @@ QByteArray QgsServer::handleRequest( const QString queryString ,
filtersIterator.value()->responseComplete();
}
#endif

//possibility for client to suggest a download filename
QString outputFileName = theRequestHandler->parameter( "FILE_NAME" );
if ( !outputFileName.isEmpty() )
{
theRequestHandler->setDefaultHeaders();
theRequestHandler->setHeader( "Content-Disposition", "attachment; filename=\"" + outputFileName + "\"" );
}

theRequestHandler->sendResponse();

if ( logLevel < 1 )
@@ -56,11 +56,11 @@ def test_api(self):
we are going to test if headers and body are returned correctly"""
# Test as a whole
response = str(self.server.handleRequest())
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'
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-Type: text/xml; charset=utf-8\nContent-Length: 206\n\n'
expected = 'Content-Length: 206\nContent-Type: text/xml; charset=utf-8\n\n'
self.assertEqual(response, expected)
# Test body
response = str(self.server.handleRequestGetBody())
@@ -1,5 +1,5 @@
Content-Type: text/xml; charset=utf-8
Content-Length: 5250
Content-Type: text/xml; charset=utf-8

<?xml version="1.0" encoding="utf-8"?>
<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">
@@ -1,5 +1,5 @@
Content-Type: text/xml; charset=utf-8
Content-Length: 6268
Content-Type: text/xml; charset=utf-8

<?xml version="1.0" encoding="utf-8"?>
<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 comments on commit 736f1c4

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