Skip to content

Commit 5221937

Browse files
committedMay 21, 2019
Check width/height values in context
1 parent fe856d6 commit 5221937

File tree

4 files changed

+127
-104
lines changed

4 files changed

+127
-104
lines changed
 

‎src/server/services/wms/qgswmsrendercontext.cpp

Lines changed: 105 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -538,25 +538,111 @@ QMap<QString, QList<QgsMapLayer *> > QgsWmsRenderContext::layerGroups() const
538538
return mLayerGroups;
539539
}
540540

541-
QSize QgsWmsRenderContext::mapSize( const bool aspectRatio ) const
541+
int QgsWmsRenderContext::width() const
542542
{
543543
int width = mParameters.widthAsInt();
544+
545+
// May use SRCWIDTH to define image map size
546+
if ( ( mFlags & UseSrcWidthHeight ) && mParameters.srcWidthAsInt() > 0 )
547+
{
548+
width = mParameters.srcWidthAsInt();
549+
}
550+
551+
return width;
552+
}
553+
554+
int QgsWmsRenderContext::height() const
555+
{
544556
int height = mParameters.heightAsInt();
545557

546-
// May use SRCWIDTH and SRCHEIGHT to define image map size
547-
if ( mFlags & UseSrcWidthHeight )
558+
// May use SRCHEIGHT to define image map size
559+
if ( ( mFlags & UseSrcWidthHeight ) && mParameters.srcHeightAsInt() > 0 )
548560
{
549-
if ( mParameters.srcWidthAsInt() > 0 )
550-
{
551-
width = mParameters.srcWidthAsInt();
552-
}
561+
height = mParameters.srcHeightAsInt();
562+
}
553563

554-
if ( mParameters.srcHeightAsInt() > 0 )
555-
{
556-
height = mParameters.srcHeightAsInt();
557-
}
564+
return height;
565+
}
566+
567+
bool QgsWmsRenderContext::isValidWidthHeight() const
568+
{
569+
//test if maxWidth / maxHeight are set in the project or as an env variable
570+
//and WIDTH / HEIGHT parameter is in the range allowed range
571+
//WIDTH
572+
const int wmsMaxWidthProj = QgsServerProjectUtils::wmsMaxWidth( *mProject );
573+
const int wmsMaxWidthEnv = settings().wmsMaxWidth();
574+
int wmsMaxWidth;
575+
if ( wmsMaxWidthEnv != -1 && wmsMaxWidthProj != -1 )
576+
{
577+
// both are set, so we take the more conservative one
578+
wmsMaxWidth = std::min( wmsMaxWidthProj, wmsMaxWidthEnv );
579+
}
580+
else
581+
{
582+
// none or one are set, so we take the bigger one which is the one set or -1
583+
wmsMaxWidth = std::max( wmsMaxWidthProj, wmsMaxWidthEnv );
584+
}
585+
586+
if ( wmsMaxWidth != -1 && width() > wmsMaxWidth )
587+
{
588+
return false;
558589
}
559590

591+
//HEIGHT
592+
const int wmsMaxHeightProj = QgsServerProjectUtils::wmsMaxHeight( *mProject );
593+
const int wmsMaxHeightEnv = settings().wmsMaxHeight();
594+
int wmsMaxHeight;
595+
if ( wmsMaxHeightEnv != -1 && wmsMaxHeightProj != -1 )
596+
{
597+
// both are set, so we take the more conservative one
598+
wmsMaxHeight = std::min( wmsMaxHeightProj, wmsMaxHeightEnv );
599+
}
600+
else
601+
{
602+
// none or one are set, so we take the bigger one which is the one set or -1
603+
wmsMaxHeight = std::max( wmsMaxHeightProj, wmsMaxHeightEnv );
604+
}
605+
606+
if ( wmsMaxHeight != -1 && height() > wmsMaxHeight )
607+
{
608+
return false;
609+
}
610+
611+
// Sanity check from internal QImage checks (see qimage.cpp)
612+
// this is to report a meaningful error message in case of
613+
// image creation failure and to differentiate it from out
614+
// of memory conditions.
615+
616+
// depth for now it cannot be anything other than 32, but I don't like
617+
// to hardcode it: I hope we will support other depths in the future.
618+
uint depth = 32;
619+
switch ( mParameters.format() )
620+
{
621+
case QgsWmsParameters::Format::JPG:
622+
case QgsWmsParameters::Format::PNG:
623+
default:
624+
depth = 32;
625+
}
626+
627+
const int bytes_per_line = ( ( width() * depth + 31 ) >> 5 ) << 2; // bytes per scanline (must be multiple of 4)
628+
629+
if ( std::numeric_limits<int>::max() / depth < static_cast<uint>( width() )
630+
|| bytes_per_line <= 0
631+
|| height() <= 0
632+
|| std::numeric_limits<int>::max() / static_cast<uint>( bytes_per_line ) < static_cast<uint>( height() )
633+
|| std::numeric_limits<int>::max() / sizeof( uchar * ) < static_cast<uint>( height() ) )
634+
{
635+
return false;
636+
}
637+
638+
return true;
639+
}
640+
641+
QSize QgsWmsRenderContext::mapSize( const bool aspectRatio ) const
642+
{
643+
int mapWidth = width();
644+
int mapHeight = height();
645+
560646
// Adapt width / height if the aspect ratio does not correspond with the BBOX.
561647
// Required by WMS spec. 1.3.
562648
if ( aspectRatio
@@ -582,32 +668,32 @@ QSize QgsWmsRenderContext::mapSize( const bool aspectRatio ) const
582668
extent.invert();
583669
}
584670

585-
if ( !extent.isEmpty() && height > 0 && width > 0 )
671+
if ( !extent.isEmpty() && mapHeight > 0 && mapWidth > 0 )
586672
{
587673
const double mapRatio = extent.width() / extent.height();
588-
const double imageRatio = static_cast<double>( width ) / static_cast<double>( height );
674+
const double imageRatio = static_cast<double>( mapWidth ) / static_cast<double>( mapHeight );
589675
if ( !qgsDoubleNear( mapRatio, imageRatio, 0.0001 ) )
590676
{
591677
// inspired by MapServer, mapdraw.c L115
592-
const double cellsize = ( extent.width() / static_cast<double>( width ) ) * 0.5 + ( extent.height() / static_cast<double>( height ) ) * 0.5;
593-
width = extent.width() / cellsize;
594-
height = extent.height() / cellsize;
678+
const double cellsize = ( extent.width() / static_cast<double>( mapWidth ) ) * 0.5 + ( extent.height() / static_cast<double>( mapHeight ) ) * 0.5;
679+
mapWidth = extent.width() / cellsize;
680+
mapHeight = extent.height() / cellsize;
595681
}
596682
}
597683
}
598684

599-
if ( width <= 0 )
685+
if ( mapWidth <= 0 )
600686
{
601687
throw QgsBadRequestException( QgsServiceException::QGIS_InvalidParameterValue,
602688
mParameters[QgsWmsParameter::WIDTH] );
603689
}
604-
else if ( height <= 0 )
690+
else if ( mapHeight <= 0 )
605691
{
606692
throw QgsBadRequestException( QgsServiceException::QGIS_InvalidParameterValue,
607693
mParameters[QgsWmsParameter::HEIGHT] );
608694
}
609695

610-
return QSize( width, height );
696+
return QSize( mapWidth, mapHeight );
611697
}
612698

613699
void QgsWmsRenderContext::removeUnwantedLayers()

‎src/server/services/wms/qgswmsrendercontext.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,18 @@ namespace QgsWms
207207
*/
208208
QSize mapSize( bool aspectRatio = true ) const;
209209

210+
bool isValidWidthHeight() const;
211+
212+
/**
213+
* Returns WIDTH or SRCWIDTH according to \a UseSrcWidthHeight flag.
214+
*/
215+
int width() const;
216+
217+
/**
218+
* Returns HEIGHT or SRCHEIGHT according to \a UseSrcWidthHeight flag.
219+
*/
220+
int height() const;
221+
210222
private:
211223
void initNicknameLayers();
212224
void initRestrictedLayers();

‎src/server/services/wms/qgswmsrenderer.cpp

Lines changed: 10 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,11 @@ namespace QgsWms
257257
QgsRenderer::HitTest QgsRenderer::symbols()
258258
{
259259
// check size
260-
checkMaximumWidthHeight();
260+
if ( ! mContext.isValidWidthHeight() )
261+
{
262+
throw QgsBadRequestException( QgsServiceException::QGIS_InvalidParameterValue,
263+
QStringLiteral( "The requested map size is too large" ) );
264+
}
261265

262266
// init layer restorer before doing anything
263267
std::unique_ptr<QgsLayerRestorer> restorer;
@@ -763,7 +767,11 @@ namespace QgsWms
763767
QImage *QgsRenderer::getMap()
764768
{
765769
// check size
766-
checkMaximumWidthHeight();
770+
if ( ! mContext.isValidWidthHeight() )
771+
{
772+
throw QgsBadRequestException( QgsServiceException::QGIS_InvalidParameterValue,
773+
QStringLiteral( "The requested map size is too large" ) );
774+
}
767775

768776
// init layer restorer before doing anything
769777
std::unique_ptr<QgsLayerRestorer> restorer;
@@ -1824,84 +1832,6 @@ namespace QgsWms
18241832
}
18251833
}
18261834

1827-
void QgsRenderer::checkMaximumWidthHeight() const
1828-
{
1829-
//test if maxWidth / maxHeight are set in the project or as an env variable
1830-
//and WIDTH / HEIGHT parameter is in the range allowed range
1831-
//WIDTH
1832-
int wmsMaxWidthProj = QgsServerProjectUtils::wmsMaxWidth( *mProject );
1833-
int wmsMaxWidthEnv = mContext.settings().wmsMaxWidth();
1834-
int wmsMaxWidth;
1835-
if ( wmsMaxWidthEnv != -1 && wmsMaxWidthProj != -1 )
1836-
{
1837-
// both are set, so we take the more conservative one
1838-
wmsMaxWidth = std::min( wmsMaxWidthProj, wmsMaxWidthEnv );
1839-
}
1840-
else
1841-
{
1842-
// none or one are set, so we take the bigger one which is the one set or -1
1843-
wmsMaxWidth = std::max( wmsMaxWidthProj, wmsMaxWidthEnv );
1844-
}
1845-
1846-
int width = this->width();
1847-
if ( wmsMaxWidth != -1 && width > wmsMaxWidth )
1848-
{
1849-
throw QgsBadRequestException( QgsServiceException::QGIS_InvalidParameterValue,
1850-
QStringLiteral( "The requested map width is too large" ) );
1851-
}
1852-
1853-
//HEIGHT
1854-
int wmsMaxHeightProj = QgsServerProjectUtils::wmsMaxHeight( *mProject );
1855-
int wmsMaxHeightEnv = mContext.settings().wmsMaxHeight();
1856-
int wmsMaxHeight;
1857-
if ( wmsMaxHeightEnv != -1 && wmsMaxHeightProj != -1 )
1858-
{
1859-
// both are set, so we take the more conservative one
1860-
wmsMaxHeight = std::min( wmsMaxHeightProj, wmsMaxHeightEnv );
1861-
}
1862-
else
1863-
{
1864-
// none or one are set, so we take the bigger one which is the one set or -1
1865-
wmsMaxHeight = std::max( wmsMaxHeightProj, wmsMaxHeightEnv );
1866-
}
1867-
1868-
int height = this->height();
1869-
if ( wmsMaxHeight != -1 && height > wmsMaxHeight )
1870-
{
1871-
throw QgsBadRequestException( QgsServiceException::QGIS_InvalidParameterValue,
1872-
QStringLiteral( "The requested map height is too large" ) );
1873-
}
1874-
1875-
1876-
// Sanity check from internal QImage checks (see qimage.cpp)
1877-
// this is to report a meaningful error message in case of
1878-
// image creation failure and to differentiate it from out
1879-
// of memory conditions.
1880-
1881-
// depth for now it cannot be anything other than 32, but I don't like
1882-
// to hardcode it: I hope we will support other depths in the future.
1883-
uint depth = 32;
1884-
switch ( mWmsParameters.format() )
1885-
{
1886-
case QgsWmsParameters::Format::JPG:
1887-
case QgsWmsParameters::Format::PNG:
1888-
default:
1889-
depth = 32;
1890-
}
1891-
1892-
const int bytes_per_line = ( ( width * depth + 31 ) >> 5 ) << 2; // bytes per scanline (must be multiple of 4)
1893-
1894-
if ( std::numeric_limits<int>::max() / depth < static_cast<uint>( width )
1895-
|| bytes_per_line <= 0
1896-
|| height <= 0
1897-
|| std::numeric_limits<int>::max() / static_cast<uint>( bytes_per_line ) < static_cast<uint>( height )
1898-
|| std::numeric_limits<int>::max() / sizeof( uchar * ) < static_cast<uint>( height ) )
1899-
{
1900-
throw QgsBadRequestException( QgsServiceException::QGIS_InvalidParameterValue,
1901-
QStringLiteral( "The requested map size is too large" ) );
1902-
}
1903-
}
1904-
19051835
void QgsRenderer::convertFeatureInfoToSia2045( QDomDocument &doc ) const
19061836
{
19071837
QDomDocument SIAInfoDoc;

‎src/server/services/wms/qgswmsrenderer.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,6 @@ namespace QgsWms
228228
//! Helper function for filter safety test. Groups stringlist to merge entries starting/ending with quotes
229229
static void groupStringList( QStringList &list, const QString &groupString );
230230

231-
/**
232-
* Checks WIDTH/HEIGHT values against MaxWidth and MaxHeight
233-
\returns true if width/height values are okay*/
234-
void checkMaximumWidthHeight() const;
235-
236231
//! Converts a feature info xml document to SIA2045 norm
237232
void convertFeatureInfoToSia2045( QDomDocument &doc ) const;
238233

0 commit comments

Comments
 (0)
Please sign in to comment.