Skip to content

Commit 2330b7f

Browse files
committedMay 23, 2018
[WFS provider] Handle buggy servers that require plural form TYPENAMES for DescribeFeatureType (fixes #18882, refs #17872)
Some servers like http://geoportal.samregion.ru/wfs12 return an error when issuing a REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=... query, which is the conformant way They expect the plural form TYPENAMES to be passed As they return an exception when being provided with the singular form, we can automate the retry with TYPENAMES.
1 parent 7511d1f commit 2330b7f

File tree

4 files changed

+102
-17
lines changed

4 files changed

+102
-17
lines changed
 

‎src/providers/wfs/qgswfsdescribefeaturetype.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ QgsWFSDescribeFeatureType::QgsWFSDescribeFeatureType( QgsWFSDataSourceURI &uri )
2121
}
2222

2323
bool QgsWFSDescribeFeatureType::requestFeatureType( const QString &WFSVersion,
24-
const QString &typeName )
24+
const QString &typeName, bool bUsePlural )
2525
{
2626
QUrl url( mUri.requestUrl( QStringLiteral( "DescribeFeatureType" ) ) );
2727
url.addQueryItem( QStringLiteral( "VERSION" ), WFSVersion );
28-
url.addQueryItem( QStringLiteral( "TYPENAME" ), typeName );
28+
url.addQueryItem( bUsePlural ?
29+
QStringLiteral( "TYPENAMES" ) : QStringLiteral( "TYPENAME" ), typeName );
2930

3031
return sendGET( url, true, false );
3132
}

‎src/providers/wfs/qgswfsdescribefeaturetype.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class QgsWFSDescribeFeatureType : public QgsWfsRequest
2525
explicit QgsWFSDescribeFeatureType( QgsWFSDataSourceURI &uri );
2626

2727
//! Issue the request
28-
bool requestFeatureType( const QString &WFSVersion, const QString &typeName );
28+
bool requestFeatureType( const QString &WFSVersion, const QString &typeName, bool bUsePlural );
2929

3030
protected:
3131
QString errorMessageWithReason( const QString &reason ) override;

‎src/providers/wfs/qgswfsprovider.cpp

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -420,15 +420,31 @@ bool QgsWFSProvider::processSQL( const QString &sqlString, QString &errorMsg, QS
420420
}
421421

422422
QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI );
423-
if ( !describeFeatureType.requestFeatureType( mShared->mWFSVersion,
424-
concatenatedTypenames ) )
423+
bool bUsePlural = false;
424+
QByteArray response;
425+
for ( int i = 0; i < 2; i++ )
425426
{
426-
errorMsg = tr( "DescribeFeatureType failed for url %1: %2" ).
427-
arg( dataSourceUri(), describeFeatureType.errorMessage() );
428-
return false;
429-
}
427+
if ( !describeFeatureType.requestFeatureType( mShared->mWFSVersion,
428+
concatenatedTypenames, bUsePlural ) )
429+
{
430+
errorMsg = tr( "DescribeFeatureType failed for url %1: %2" ).
431+
arg( dataSourceUri(), describeFeatureType.errorMessage() );
432+
return false;
433+
}
430434

431-
const QByteArray &response = describeFeatureType.response();
435+
response = describeFeatureType.response();
436+
// "http://geoportal.samregion.ru/wfs12?SERVICE=WFS&REQUEST=DescribeFeatureType&TYPENAME=EC_1_132&VERSION=2.0.0"
437+
// returns a <ExceptionText><![CDATA[Missing typeNames parameter]]></ExceptionText>
438+
if ( i == 0 && response.indexOf( "<![CDATA[Missing typeNames parameter]]>" ) >= 0 )
439+
{
440+
QgsDebugMsg( "Server does not accept TYPENAME parameter for DescribeFeatureType. Re-trying with TYPENAMES" );
441+
bUsePlural = true;
442+
}
443+
else
444+
{
445+
break;
446+
}
447+
}
432448

433449
QDomDocument describeFeatureDocument;
434450
errorMsg.clear();
@@ -1165,15 +1181,31 @@ bool QgsWFSProvider::describeFeatureType( QString &geometryAttribute, QgsFields
11651181
fields.clear();
11661182

11671183
QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI );
1168-
if ( !describeFeatureType.requestFeatureType( mShared->mWFSVersion,
1169-
mShared->mURI.typeName() ) )
1184+
bool bUsePlural = false;
1185+
QByteArray response;
1186+
for ( int i = 0; i < 2; i++ )
11701187
{
1171-
QgsMessageLog::logMessage( tr( "DescribeFeatureType network request failed for url %1: %2" ).
1172-
arg( dataSourceUri(), describeFeatureType.errorMessage() ), tr( "WFS" ) );
1173-
return false;
1174-
}
1188+
if ( !describeFeatureType.requestFeatureType( mShared->mWFSVersion,
1189+
mShared->mURI.typeName(), bUsePlural ) )
1190+
{
1191+
QgsMessageLog::logMessage( tr( "DescribeFeatureType network request failed for url %1: %2" ).
1192+
arg( dataSourceUri(), describeFeatureType.errorMessage() ), tr( "WFS" ) );
1193+
return false;
1194+
}
11751195

1176-
const QByteArray &response = describeFeatureType.response();
1196+
response = describeFeatureType.response();
1197+
// "http://geoportal.samregion.ru/wfs12?SERVICE=WFS&REQUEST=DescribeFeatureType&TYPENAME=EC_1_132&VERSION=2.0.0"
1198+
// returns a <ExceptionText><![CDATA[Missing typeNames parameter]]></ExceptionText>
1199+
if ( i == 0 && response.indexOf( "<![CDATA[Missing typeNames parameter]]>" ) >= 0 )
1200+
{
1201+
QgsDebugMsg( "Server does not accept TYPENAME parameter for DescribeFeatureType. Re-trying with TYPENAMES" );
1202+
bUsePlural = true;
1203+
}
1204+
else
1205+
{
1206+
break;
1207+
}
1208+
}
11771209

11781210
QDomDocument describeFeatureDocument;
11791211
QString errorMsg;

‎tests/src/python/test_provider_wfs.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3221,6 +3221,58 @@ def testWfs20SamServer(self):
32213221
geom_string = re.sub(r'\.\d+', '', geom_string)[:100]
32223222
self.assertEqual(geom_string, "LineString (9540051 5997366, 9539934 5997127, 9539822 5996862, 9539504 5996097, 9539529 5996093, 953")
32233223

3224+
def testWfs20DescribeFeatureTypePluralForm(self):
3225+
"""Specs are inconsistent and some 2.0 servers use the TYPENAMES plural form"""
3226+
3227+
endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_describe_typenames'
3228+
3229+
with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), 'wb') as f:
3230+
f.write("""
3231+
<wfs:WFS_Capabilities version="2.0.0" xmlns="http://www.opengis.net/wfs/2.0" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:gml="http://schemas.opengis.net/gml/3.2" xmlns:fes="http://www.opengis.net/fes/2.0">
3232+
<FeatureTypeList>
3233+
<FeatureType>
3234+
<Name>my:typename</Name>
3235+
<DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
3236+
</FeatureType>
3237+
</FeatureTypeList>
3238+
</wfs:WFS_Capabilities>""".encode('UTF-8'))
3239+
3240+
with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename'), 'wb') as f:
3241+
f.write("""
3242+
<?xml version="1.0"?>
3243+
<ExceptionReport
3244+
version="2.0.0"
3245+
xmlns="http://www.opengis.net/ows/1.1"
3246+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3247+
xsi:schemaLocation="http://www.opengis.net/ows/1.1
3248+
http://schemas.opengis.net/ows/1.1.0/owsAll.xsd">
3249+
<Exception exceptionCode="MissingParameterValue" locator="">
3250+
<ExceptionText><![CDATA[Missing typeNames parameter]]></ExceptionText>
3251+
</Exception>
3252+
</ExceptionReport
3253+
""".encode('UTF-8'))
3254+
3255+
with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename'), 'wb') as f:
3256+
f.write("""
3257+
<xsd:schema xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
3258+
<xsd:import namespace="http://www.opengis.net/gml/3.2"/>
3259+
<xsd:complexType name="typenameType">
3260+
<xsd:complexContent>
3261+
<xsd:extension base="gml:AbstractFeatureType">
3262+
<xsd:sequence>
3263+
<xsd:element maxOccurs="1" minOccurs="0" name="geometryProperty" nillable="true" type="gml:PointPropertyType"/>
3264+
</xsd:sequence>
3265+
</xsd:extension>
3266+
</xsd:complexContent>
3267+
</xsd:complexType>
3268+
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
3269+
</xsd:schema>
3270+
""".encode('UTF-8'))
3271+
3272+
# Create test layer
3273+
vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename'", 'test', 'WFS')
3274+
self.assertTrue(vl.isValid())
3275+
32243276

32253277
if __name__ == '__main__':
32263278
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.