Skip to content

Commit f1b5987

Browse files
committed
[bugfix] Support Distributed Computing Platform (DCP) for WFS
Implement the possibility to specify different endpoints for different WFS operations. With tests. Fixes #18099 WFS Capabilities handling problem
1 parent 42908eb commit f1b5987

14 files changed

+542
-190
lines changed

src/providers/wfs/qgswfscapabilities.cpp

+24-3
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@
2828
#include <QStringList>
2929

3030
QgsWfsCapabilities::QgsWfsCapabilities( const QString &uri )
31-
: QgsWfsRequest( uri )
31+
: QgsWfsRequest( QgsWFSDataSourceURI( uri ) )
3232
{
3333
connect( this, &QgsWfsRequest::downloadFinished, this, &QgsWfsCapabilities::capabilitiesReplyFinished );
3434
}
3535

3636
bool QgsWfsCapabilities::requestCapabilities( bool synchronous, bool forceRefresh )
3737
{
38-
QUrl url( baseURL() );
38+
QUrl url( mUri.baseURL( ) );
3939
url.addQueryItem( QStringLiteral( "REQUEST" ), QStringLiteral( "GetCapabilities" ) );
4040

4141
const QString &version = mUri.version();
@@ -249,7 +249,28 @@ void QgsWfsCapabilities::capabilitiesReplyFinished()
249249
for ( int i = 0; i < operationList.size(); ++i )
250250
{
251251
QDomElement operation = operationList.at( i ).toElement();
252-
if ( operation.attribute( QStringLiteral( "name" ) ) == QLatin1String( "GetFeature" ) )
252+
QString name = operation.attribute( QStringLiteral( "name" ) );
253+
254+
// Search for DCP/HTTP
255+
QDomNodeList operationHttpList = operation.elementsByTagName( QStringLiteral( "HTTP" ) );
256+
for ( int j = 0; j < operationHttpList.size(); ++j )
257+
{
258+
QDomElement value = operationHttpList.at( j ).toElement();
259+
QDomNodeList httpGetMethodList = value.elementsByTagName( QStringLiteral( "Get" ) );
260+
QDomNodeList httpPostMethodList = value.elementsByTagName( QStringLiteral( "Post" ) );
261+
if ( httpGetMethodList.size() > 0 )
262+
{
263+
mCaps.operationGetEndpoints[name] = httpGetMethodList.at( 0 ).toElement().attribute( QStringLiteral( "href" ) );
264+
QgsDebugMsgLevel( QStringLiteral( "Adding DCP Get %1 %2" ).arg( name, mCaps.operationGetEndpoints[name] ), 3 );
265+
}
266+
if ( httpPostMethodList.size() > 0 )
267+
{
268+
mCaps.operationPostEndpoints[name] = httpPostMethodList.at( 0 ).toElement().attribute( QStringLiteral( "href" ) );
269+
QgsDebugMsgLevel( QStringLiteral( "Adding DCP Post %1 %2" ).arg( name, mCaps.operationPostEndpoints[name] ), 3 );
270+
}
271+
}
272+
273+
if ( name == QLatin1String( "GetFeature" ) )
253274
{
254275
QDomNodeList operationContraintList = operation.elementsByTagName( QStringLiteral( "Constraint" ) );
255276
for ( int j = 0; j < operationContraintList.size(); ++j )

src/providers/wfs/qgswfscapabilities.h

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ class QgsWfsCapabilities : public QgsWfsRequest
9898
QList<Function> functionList;
9999
bool useEPSGColumnFormat; // whether to use EPSG:XXXX srsname
100100
QList< QString > outputFormats;
101+
QgsStringMap operationGetEndpoints;
102+
QgsStringMap operationPostEndpoints;
101103

102104
QSet< QString > setAllTypenames;
103105
QMap< QString, QString> mapUnprefixedTypenameToPrefixedTypename;

src/providers/wfs/qgswfsdatasourceuri.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,28 @@ QUrl QgsWFSDataSourceURI::baseURL( bool bIncludeServiceWFS ) const
165165
return url;
166166
}
167167

168+
QUrl QgsWFSDataSourceURI::requestUrl( const QString &request, const Method &method ) const
169+
{
170+
QString endpoint;
171+
switch ( method )
172+
{
173+
case Post:
174+
endpoint = mPostEndpoints.contains( request ) ?
175+
mPostEndpoints[ request ] : mURI.param( QgsWFSConstants::URI_PARAM_URL );
176+
break;
177+
default:
178+
case Get:
179+
endpoint = mGetEndpoints.contains( request ) ?
180+
mGetEndpoints[ request ] : mURI.param( QgsWFSConstants::URI_PARAM_URL );
181+
break;
182+
}
183+
QUrl url( endpoint );
184+
url.addQueryItem( QStringLiteral( "SERVICE" ), QStringLiteral( "WFS" ) );
185+
if ( ! request.isEmpty() )
186+
url.addQueryItem( QStringLiteral( "REQUEST" ), request );
187+
return url;
188+
}
189+
168190
QString QgsWFSDataSourceURI::version() const
169191
{
170192
if ( !mURI.hasParam( QgsWFSConstants::URI_PARAM_VERSION ) )
@@ -298,3 +320,13 @@ QString QgsWFSDataSourceURI::build( const QString &baseUri,
298320
uri.mURI.setParam( QgsWFSConstants::URI_PARAM_RESTRICT_TO_REQUEST_BBOX, QStringLiteral( "1" ) );
299321
return uri.uri();
300322
}
323+
324+
void QgsWFSDataSourceURI::setGetEndpoints( const QgsStringMap &map )
325+
{
326+
mGetEndpoints = map;
327+
}
328+
329+
void QgsWFSDataSourceURI::setPostEndpoints( const QgsStringMap &map )
330+
{
331+
mPostEndpoints = map;
332+
}

src/providers/wfs/qgswfsdatasourceuri.h

+18
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ class QgsWFSDataSourceURI
7575
{
7676
public:
7777

78+
//! Http method for DCP URIs
79+
enum Method
80+
{
81+
Get,
82+
Post
83+
};
84+
7885
explicit QgsWFSDataSourceURI( const QString &uri );
7986

8087
//! Return the URI, avoiding expansion of authentication configuration, which is handled during network access
@@ -83,6 +90,9 @@ class QgsWFSDataSourceURI
8390
//! Return base URL (with SERVICE=WFS parameter if bIncludeServiceWFS=true)
8491
QUrl baseURL( bool bIncludeServiceWFS = true ) const;
8592

93+
//! Return request URL with SERVICE=WFS parameter)
94+
QUrl requestUrl( const QString &request, const Method &method = Method::Get ) const;
95+
8696
//! Get WFS version. Can be auto, 1.0.0, 1.1.0 or 2.0.0.
8797
QString version() const;
8898

@@ -150,9 +160,17 @@ class QgsWFSDataSourceURI
150160
const QString &sql = QString(),
151161
bool restrictToCurrentViewExtent = false );
152162

163+
//! Set Get DCP endpoints
164+
void setGetEndpoints( const QgsStringMap &map );
165+
166+
//! Set Post DCP endpoints
167+
void setPostEndpoints( const QgsStringMap &map );
168+
153169
private:
154170
QgsDataSourceUri mURI;
155171
QgsWFSAuthorization mAuth;
172+
QgsStringMap mGetEndpoints;
173+
QgsStringMap mPostEndpoints;
156174
};
157175

158176

src/providers/wfs/qgswfsdescribefeaturetype.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,15 @@
1616
#include "qgswfsdescribefeaturetype.h"
1717
#include "qgswfsutils.h"
1818

19-
QgsWFSDescribeFeatureType::QgsWFSDescribeFeatureType( const QString &uri )
19+
QgsWFSDescribeFeatureType::QgsWFSDescribeFeatureType( QgsWFSDataSourceURI &uri )
2020
: QgsWfsRequest( uri )
2121
{
2222
}
2323

2424
bool QgsWFSDescribeFeatureType::requestFeatureType( const QString &WFSVersion,
2525
const QString &typeName, bool forceSingularTypeName )
2626
{
27-
QUrl url( baseURL() );
28-
url.addQueryItem( QStringLiteral( "REQUEST" ), QStringLiteral( "DescribeFeatureType" ) );
27+
QUrl url( mUri.requestUrl( QStringLiteral( "DescribeFeatureType" ) ) );
2928
url.addQueryItem( QStringLiteral( "VERSION" ), WFSVersion );
3029
// The specs are not consistent: is it singular in 1.0.x and plural in 2.0.0?
3130
// see http://docs.opengeospatial.org/is/09-025r2/09-025r2.html#147

src/providers/wfs/qgswfsdescribefeaturetype.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class QgsWFSDescribeFeatureType : public QgsWfsRequest
2222
{
2323
Q_OBJECT
2424
public:
25-
explicit QgsWFSDescribeFeatureType( const QString &uri );
25+
explicit QgsWFSDescribeFeatureType( QgsWFSDataSourceURI &uri );
2626

2727
//! Issue the request
2828
bool requestFeatureType( const QString &WFSVersion, const QString &typeName,

src/providers/wfs/qgswfsfeatureiterator.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
#include <QStyle>
3636

3737
QgsWFSFeatureHitsAsyncRequest::QgsWFSFeatureHitsAsyncRequest( QgsWFSDataSourceURI &uri )
38-
: QgsWfsRequest( uri.uri() )
38+
: QgsWfsRequest( uri )
3939
, mNumberMatched( -1 )
4040
{
4141
connect( this, &QgsWfsRequest::downloadFinished, this, &QgsWFSFeatureHitsAsyncRequest::hitsReplyFinished );
@@ -77,7 +77,7 @@ QString QgsWFSFeatureHitsAsyncRequest::errorMessageWithReason( const QString &re
7777
// -------------------------
7878

7979
QgsWFSFeatureDownloader::QgsWFSFeatureDownloader( QgsWFSSharedData *shared )
80-
: QgsWfsRequest( shared->mURI.uri() )
80+
: QgsWfsRequest( shared->mURI )
8181
, mShared( shared )
8282
, mStop( false )
8383
, mProgressDialogShowImmediately( false )
@@ -187,8 +187,7 @@ QString QgsWFSFeatureDownloader::sanitizeFilter( QString filter )
187187

188188
QUrl QgsWFSFeatureDownloader::buildURL( int startIndex, int maxFeatures, bool forHits )
189189
{
190-
QUrl getFeatureUrl( mShared->mURI.baseURL() );
191-
getFeatureUrl.addQueryItem( QStringLiteral( "REQUEST" ), QStringLiteral( "GetFeature" ) );
190+
QUrl getFeatureUrl( mShared->mURI.requestUrl( QStringLiteral( "GetFeature" ) ) );
192191
getFeatureUrl.addQueryItem( QStringLiteral( "VERSION" ), mShared->mWFSVersion );
193192

194193
QString typenames;
@@ -375,6 +374,8 @@ QUrl QgsWFSFeatureDownloader::buildURL( int startIndex, int maxFeatures, bool fo
375374
namespaces );
376375
}
377376

377+
QgsDebugMsgLevel( QStringLiteral( "WFS GetFeature URL: %1" ).arg( getFeatureUrl.toDisplayString( ) ), 2 );
378+
378379
return getFeatureUrl;
379380
}
380381

src/providers/wfs/qgswfsprovider.cpp

+10-6
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ bool QgsWFSProvider::processSQL( const QString &sqlString, QString &errorMsg, QS
419419
concatenatedTypenames += typeName;
420420
}
421421

422-
QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI.uri() );
422+
QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI );
423423
if ( !describeFeatureType.requestFeatureType( mShared->mWFSVersion,
424424
concatenatedTypenames ) )
425425
{
@@ -1168,7 +1168,7 @@ bool QgsWFSProvider::describeFeatureType( QString &geometryAttribute,
11681168
{
11691169
fields.clear();
11701170

1171-
QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI.uri() );
1171+
QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI );
11721172
if ( !describeFeatureType.requestFeatureType( mShared->mWFSVersion,
11731173
mShared->mURI.typeName(), forceSingularTypeNames ) )
11741174
{
@@ -1450,7 +1450,7 @@ bool QgsWFSProvider::sendTransactionDocument( const QDomDocument &doc, QDomDocum
14501450
return false;
14511451
}
14521452

1453-
QgsWFSTransactionRequest request( mShared->mURI.uri() );
1453+
QgsWFSTransactionRequest request( mShared->mURI );
14541454
return request.send( doc, serverResponse );
14551455
}
14561456

@@ -1464,11 +1464,13 @@ QDomElement QgsWFSProvider::createTransactionElement( QDomDocument &doc ) const
14641464
transactionElem.setAttribute( QStringLiteral( "service" ), QStringLiteral( "WFS" ) );
14651465
transactionElem.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
14661466

1467-
QUrl describeFeatureTypeURL( mShared->mURI.baseURL() );
1467+
QUrl describeFeatureTypeURL = mShared->mURI.requestUrl( QStringLiteral( "DescribeFeatureType" ) );
14681468
// For tests (since the URL contains part of random data, we need to replace it with a fixed content)
1469-
if ( mShared->mURI.baseURL().toString().contains( QLatin1String( "fake_qgis_http_endpoint" ) ) )
1469+
if ( describeFeatureTypeURL.toString().contains( QLatin1String( "fake_qgis_http_endpoint" ) ) )
1470+
{
14701471
describeFeatureTypeURL = QUrl( QStringLiteral( "http://fake_qgis_http_endpoint" ) );
1471-
describeFeatureTypeURL.addQueryItem( QStringLiteral( "REQUEST" ), QStringLiteral( "DescribeFeatureType" ) );
1472+
describeFeatureTypeURL.addQueryItem( QStringLiteral( "REQUEST" ), QStringLiteral( "DescribeFeatureType" ) );
1473+
}
14721474
describeFeatureTypeURL.addQueryItem( QStringLiteral( "VERSION" ), QStringLiteral( "1.0.0" ) );
14731475
//TODO: proper support of 2.0.0, for now hardcoded
14741476
describeFeatureTypeURL.addQueryItem( QgsWFSUtils::typeNameParameterForVersion( WfsVersion ).toUpper(), mShared->mURI.typeName() );
@@ -1562,6 +1564,8 @@ bool QgsWFSProvider::getCapabilities()
15621564

15631565
const QgsWfsCapabilities::Capabilities caps = getCapabilities.capabilities();
15641566
mShared->mCaps = caps;
1567+
mShared->mURI.setGetEndpoints( caps.operationGetEndpoints );
1568+
mShared->mURI.setPostEndpoints( caps.operationPostEndpoints );
15651569
}
15661570

15671571
mShared->mWFSVersion = mShared->mCaps.version;

src/providers/wfs/qgswfsrequest.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@
2525
#include <QNetworkCacheMetaData>
2626
#include <QCryptographicHash> // just for testin file:// fake_qgis_http_endpoint hack
2727

28-
QgsWfsRequest::QgsWfsRequest( const QString &uri )
28+
QgsWfsRequest::QgsWfsRequest( const QgsWFSDataSourceURI &uri )
2929
: mUri( uri )
3030
, mErrorCode( QgsWfsRequest::NoError )
3131
, mIsAborted( false )
3232
, mForceRefresh( false )
3333
, mTimedout( false )
3434
, mGotNonEmptyResponse( false )
3535
{
36-
QgsDebugMsg( "theUri = " + uri );
36+
QgsDebugMsg( "theUri = " + uri.uri( ) );
3737
connect( QgsNetworkAccessManager::instance(), &QgsNetworkAccessManager::requestTimedOut, this, &QgsWfsRequest::requestTimedOut );
3838
}
3939

@@ -48,6 +48,11 @@ void QgsWfsRequest::requestTimedOut( QNetworkReply *reply )
4848
mTimedout = true;
4949
}
5050

51+
QUrl QgsWfsRequest::requestUrl( const QString &request ) const
52+
{
53+
return mUri.requestUrl( request );
54+
}
55+
5156
bool QgsWfsRequest::sendGET( const QUrl &url, bool synchronous, bool forceRefresh, bool cache )
5257
{
5358
abort(); // cancel previous
@@ -61,6 +66,8 @@ bool QgsWfsRequest::sendGET( const QUrl &url, bool synchronous, bool forceRefres
6166
mResponse.clear();
6267

6368
QUrl modifiedUrl( url );
69+
70+
// Specific code for testing
6471
if ( modifiedUrl.toString().contains( QLatin1String( "fake_qgis_http_endpoint" ) ) )
6572
{
6673
// Just for testing with local files instead of http:// resources

src/providers/wfs/qgswfsrequest.h

+6-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class QgsWfsRequest : public QObject
2727
{
2828
Q_OBJECT
2929
public:
30-
explicit QgsWfsRequest( const QString &uri );
30+
explicit QgsWfsRequest( const QgsWFSDataSourceURI &uri );
3131

3232
~QgsWfsRequest() override;
3333

@@ -54,6 +54,9 @@ class QgsWfsRequest : public QObject
5454
//! \brief Return server response (after download/post)
5555
QByteArray response() const { return mResponse; }
5656

57+
//! Return the url for a WFS request
58+
QUrl requestUrl( const QString &request ) const;
59+
5760
public slots:
5861
//! Abort network request immediately
5962
void abort();
@@ -100,12 +103,10 @@ class QgsWfsRequest : public QObject
100103

101104
protected:
102105

103-
//! base service URL
104-
QUrl baseURL() const { return mUri.baseURL(); }
105-
106106
/**
107107
* Return (translated) error message, composed with a
108-
(possibly translated, but sometimes coming from server) reason */
108+
* (possibly translated, but sometimes coming from server) reason
109+
*/
109110
virtual QString errorMessageWithReason( const QString &reason ) = 0;
110111

111112
//! Return experiation delay in second

src/providers/wfs/qgswfsshareddata.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -1170,15 +1170,14 @@ QgsGmlStreamingParser *QgsWFSSharedData::createParser()
11701170

11711171

11721172
QgsWFSFeatureHitsRequest::QgsWFSFeatureHitsRequest( QgsWFSDataSourceURI &uri )
1173-
: QgsWfsRequest( uri.uri() )
1173+
: QgsWfsRequest( uri )
11741174
{
11751175
}
11761176

11771177
int QgsWFSFeatureHitsRequest::getFeatureCount( const QString &WFSVersion,
11781178
const QString &filter )
11791179
{
1180-
QUrl getFeatureUrl( mUri.baseURL() );
1181-
getFeatureUrl.addQueryItem( QStringLiteral( "REQUEST" ), QStringLiteral( "GetFeature" ) );
1180+
QUrl getFeatureUrl( mUri.requestUrl( QStringLiteral( "GetFeature" ) ) );
11821181
getFeatureUrl.addQueryItem( QStringLiteral( "VERSION" ), WFSVersion );
11831182
if ( WFSVersion.startsWith( QLatin1String( "2.0" ) ) )
11841183
getFeatureUrl.addQueryItem( QStringLiteral( "TYPENAMES" ), mUri.typeName() );
@@ -1232,14 +1231,13 @@ QString QgsWFSFeatureHitsRequest::errorMessageWithReason( const QString &reason
12321231

12331232

12341233
QgsWFSSingleFeatureRequest::QgsWFSSingleFeatureRequest( QgsWFSSharedData *shared )
1235-
: QgsWfsRequest( shared->mURI.uri() ), mShared( shared )
1234+
: QgsWfsRequest( shared->mURI ), mShared( shared )
12361235
{
12371236
}
12381237

12391238
QgsRectangle QgsWFSSingleFeatureRequest::getExtent()
12401239
{
1241-
QUrl getFeatureUrl( mUri.baseURL() );
1242-
getFeatureUrl.addQueryItem( QStringLiteral( "REQUEST" ), QStringLiteral( "GetFeature" ) );
1240+
QUrl getFeatureUrl( mUri.requestUrl( QStringLiteral( "GetFeature" ) ) );
12431241
getFeatureUrl.addQueryItem( QStringLiteral( "VERSION" ), mShared->mWFSVersion );
12441242
if ( mShared->mWFSVersion .startsWith( QLatin1String( "2.0" ) ) )
12451243
getFeatureUrl.addQueryItem( QStringLiteral( "TYPENAMES" ), mUri.typeName() );

src/providers/wfs/qgswfstransactionrequest.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
#include "qgswfstransactionrequest.h"
1717
#include "qgslogger.h"
1818

19-
QgsWFSTransactionRequest::QgsWFSTransactionRequest( const QString &uri )
19+
QgsWFSTransactionRequest::QgsWFSTransactionRequest( const QgsWFSDataSourceURI &uri )
2020
: QgsWfsRequest( uri )
2121
{
2222
}
2323

2424
bool QgsWFSTransactionRequest::send( const QDomDocument &doc, QDomDocument &serverResponse )
2525
{
26-
QUrl url( baseURL() );
26+
QUrl url( mUri.requestUrl( QString( ) ) );
2727

2828
QgsDebugMsg( doc.toString() );
2929

src/providers/wfs/qgswfstransactionrequest.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class QgsWFSTransactionRequest : public QgsWfsRequest
2222
{
2323
Q_OBJECT
2424
public:
25-
explicit QgsWFSTransactionRequest( const QString &uri );
25+
explicit QgsWFSTransactionRequest( const QgsWFSDataSourceURI &uri );
2626

2727
//! Send the transaction document and return the server response
2828
bool send( const QDomDocument &doc, QDomDocument &serverResponse );

0 commit comments

Comments
 (0)