Compare commits

...

22 Commits

Author SHA1 Message Date
Benoit D.-M. - oslandia
83143a5c31
Merge 04ed226dc0bc06194e0e092012e5dff705eab9b0 into 08dd318614d21eb557a1311775b1a1dff509d3b4 2025-06-30 14:20:19 +02:00
bdm-oslandia
04ed226dc0 TEMP: add assert to this code as it seems useless 2025-06-27 09:19:57 +02:00
bdm-oslandia
7ce305f67f test(qgsdatasourceuri): add uri in uri test 2025-06-27 09:19:57 +02:00
bdm-oslandia
7579c7c6bc fix(httpheaders): add missing urlencode to headers when updating QUrlQuery 2025-06-27 09:19:57 +02:00
bdm-oslandia
230b4aa45e fix(QgsProjectStorageRegistry): project uri can be urlencoded and starts with XXX%3A 2025-06-27 09:19:57 +02:00
Max Tobias Weber
6fceaee3d0 fix double URL-encoding issue with curly braces in z,x,y placeholders of VectorTile Sources in QgsDataSurceUri 2025-06-27 09:19:57 +02:00
Max Tobias Weber
46ead260af fix most tests in tests/src/core/testqgsvectortilelayer.cpp 2025-06-27 09:19:57 +02:00
Max Tobias Weber
e02db8c490 fix tests tests/src/core/testqgshttpheaders.cpp 2025-06-27 09:19:57 +02:00
Max Tobias Weber
71fab90c74 fix test tests/src/server/wms/test_qgsserver_wms_parameters.cpp 2025-06-27 09:19:57 +02:00
Max Tobias Weber
2b366b066e fix test tests/src/python/test_qgsvectortile.py 2025-06-27 09:19:57 +02:00
Max Tobias Weber
a00fb44415 fix test tests/src/core/testqgsvectortileconnection.cpp 2025-06-27 09:19:57 +02:00
Max Tobias Weber
1e8aa1b60a fix test tests/src/core/testqgstiledsceneconnection.cpp 2025-06-27 09:19:57 +02:00
Max Tobias Weber
1e189669ab fix test tests/src/core/testqgssensorthingsconnection.cpp 2025-06-27 09:19:57 +02:00
Max Tobias Weber
987bfa729b fix test tests/src/core/testqgshttpheaders.cpp 2025-06-27 09:19:57 +02:00
Max Tobias Weber
ebf2256cdb adjust tests to QgsDataSourceUri full value URL-encoding 2025-06-27 09:19:56 +02:00
Max Tobias Weber
c44a773399 add decoding step before adding the "url" value to QgsDataSourceUri in TestQgsIdentify::identifyVectorTile(), as QgsDataSourceUri now reliably returns the values that were provided. 2025-06-27 09:19:56 +02:00
Max Tobias Weber
3f5ea98662 make sure QgsDataSourceUri values are FullyUrlDecoded when parsing QgsDataSourceUri strings in QgsDataSourceUri::setEncodedUri 2025-06-27 09:19:56 +02:00
Max Tobias Weber
5866c60b19 move QUrl::toPercentEncoding and QUrl::fromPercentEncoding steps from QgsDataSourceUri param setter and getter functions to URI serialization QgsDataSourceUri::encodedUri() 2025-06-27 09:19:56 +02:00
Max Tobias Weber
03eb6aa338 fix faulty assertion of URI parameter values not being fully URL-encoded in tests/src/providers/testqgswmsprovider.cpp 2025-06-27 09:19:56 +02:00
Max Tobias Weber
2f1ccd7a7d fix faulty assertion in tests/src/core/testqgsdatasourceuri.cpp
URl-encoded in URL-parameter values characters will be URL-decoded on retrieval.
2025-06-27 09:19:56 +02:00
Max Tobias Weber
96e64bfba1 ensure values in QgsDataSourceUri are URL-encoded when assigned and properly decoded when retrieved, preventing any potential loss of information. 2025-06-27 09:19:56 +02:00
Max Tobias Weber
d73288ebc7 make fromPercentEncoding in qgswmsprovider conditional.
We should not decode an entire URL if it includes parameters, as special characters in the query string (like `&`, `=`) must remain URL-encoded to avoid breaking the structure of the request. Within the URL-parameter values must never be URL-decoded as it leads to a loss of information, this is also the case if only non reserved characters are decoded. There is no way to know whether those characters have been encoded in the first place.
2025-06-27 09:19:56 +02:00
17 changed files with 150 additions and 54 deletions

View File

@ -73,7 +73,7 @@ bool QgsHttpHeaders::updateUrlQuery( QUrlQuery &uri ) const
{ {
for ( auto ite = mHeaders.constBegin(); ite != mHeaders.constEnd(); ++ite ) for ( auto ite = mHeaders.constBegin(); ite != mHeaders.constEnd(); ++ite )
{ {
uri.addQueryItem( QgsHttpHeaders::PARAM_PREFIX + ite.key().toUtf8(), ite.value().toString().toUtf8() ); uri.addQueryItem( QgsHttpHeaders::PARAM_PREFIX + ite.key().toUtf8(), QUrl::toPercentEncoding( ite.value().toString() ) );
} }
return true; return true;
} }

View File

@ -33,8 +33,7 @@ QgsProjectStorage *QgsProjectStorageRegistry::projectStorageFromUri( const QStri
for ( auto it = mBackends.constBegin(); it != mBackends.constEnd(); ++it ) for ( auto it = mBackends.constBegin(); it != mBackends.constEnd(); ++it )
{ {
QgsProjectStorage *storage = it.value(); QgsProjectStorage *storage = it.value();
const QString scheme = storage->type() + ':'; if ( uri.startsWith( storage->type() + ':' ) || uri.startsWith( storage->type() + "%3A" ) )
if ( uri.startsWith( scheme ) )
return storage; return storage;
} }

View File

@ -701,17 +701,17 @@ QByteArray QgsDataSourceUri::encodedUri() const
QUrlQuery url; QUrlQuery url;
for ( auto it = mParams.constBegin(); it != mParams.constEnd(); ++it ) for ( auto it = mParams.constBegin(); it != mParams.constEnd(); ++it )
{ {
url.addQueryItem( it.key(), it.value() ); url.addQueryItem( it.key(), QUrl::toPercentEncoding( it.value() ) );
} }
if ( !mUsername.isEmpty() ) if ( !mUsername.isEmpty() )
url.addQueryItem( QStringLiteral( "username" ), mUsername ); url.addQueryItem( QStringLiteral( "username" ), QUrl::toPercentEncoding( mUsername ) );
if ( !mPassword.isEmpty() ) if ( !mPassword.isEmpty() )
url.addQueryItem( QStringLiteral( "password" ), mPassword ); url.addQueryItem( QStringLiteral( "password" ), QUrl::toPercentEncoding( mPassword ) );
if ( !mAuthConfigId.isEmpty() ) if ( !mAuthConfigId.isEmpty() )
url.addQueryItem( QStringLiteral( "authcfg" ), mAuthConfigId ); url.addQueryItem( QStringLiteral( "authcfg" ), QUrl::toPercentEncoding( mAuthConfigId ) );
mHttpHeaders.updateUrlQuery( url ); mHttpHeaders.updateUrlQuery( url );
@ -731,7 +731,7 @@ void QgsDataSourceUri::setEncodedUri( const QByteArray &uri )
mHttpHeaders.setFromUrlQuery( query ); mHttpHeaders.setFromUrlQuery( query );
const auto constQueryItems = query.queryItems(); const auto constQueryItems = query.queryItems( QUrl::ComponentFormattingOption::FullyDecoded );
for ( const QPair<QString, QString> &item : constQueryItems ) for ( const QPair<QString, QString> &item : constQueryItems )
{ {
if ( !item.first.startsWith( QgsHttpHeaders::PARAM_PREFIX ) && item.first != QgsHttpHeaders::KEY_REFERER ) if ( !item.first.startsWith( QgsHttpHeaders::PARAM_PREFIX ) && item.first != QgsHttpHeaders::KEY_REFERER )
@ -928,7 +928,7 @@ QString QgsDataSourceUri::param( const QString &key ) const
else if ( key == QLatin1String( "authcfg" ) && !mAuthConfigId.isEmpty() ) else if ( key == QLatin1String( "authcfg" ) && !mAuthConfigId.isEmpty() )
return mAuthConfigId; return mAuthConfigId;
return mParams.value( key ); return mParams.value( key ).toUtf8();
} }
QStringList QgsDataSourceUri::params( const QString &key ) const QStringList QgsDataSourceUri::params( const QString &key ) const

View File

@ -147,7 +147,7 @@ QString QgsVectorTileProviderMetadata::absoluteToRelativeUri( const QString &uri
// relative path will become "file:./x.txt" // relative path will become "file:./x.txt"
const QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() ); const QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() );
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() ); dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString( QUrl::DecodeReserved ) );
return dsUri.encodedUri(); return dsUri.encodedUri();
} }
} }

View File

@ -316,7 +316,7 @@ QString QgsXyzVectorTileDataProviderMetadata::absoluteToRelativeUri( const QStri
// relative path will become "file:./x.txt" // relative path will become "file:./x.txt"
const QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() ); const QString relSrcUrl = context.pathResolver().writePath( sourceUrl.toLocalFile() );
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString() ); dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( relSrcUrl ).toString( QUrl::DecodeReserved ) );
return dsUri.encodedUri(); return dsUri.encodedUri();
} }
@ -335,7 +335,7 @@ QString QgsXyzVectorTileDataProviderMetadata::relativeToAbsoluteUri( const QStri
{ {
const QString absSrcUrl = context.pathResolver().readPath( sourceUrl.toLocalFile() ); const QString absSrcUrl = context.pathResolver().readPath( sourceUrl.toLocalFile() );
dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key dsUri.removeParam( QStringLiteral( "url" ) ); // needed because setParam() would insert second "url" key
dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString() ); dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( absSrcUrl ).toString( QUrl::DecodeReserved ) );
return dsUri.encodedUri(); return dsUri.encodedUri();
} }

View File

@ -276,7 +276,12 @@ QgsWmsProvider::QgsWmsProvider( QString const &uri, const ProviderOptions &optio
QString QgsWmsProvider::prepareUri( QString uri ) QString QgsWmsProvider::prepareUri( QString uri )
{ {
// some services provide a percent/url encoded (legend) uri string, always decode here // some services provide a percent/url encoded (legend) uri string, always decode here
uri = QUrl::fromPercentEncoding( uri.toUtf8() ); if ( uri.startsWith( "https%3A%2F%2F" ) || uri.startsWith( "http%3A%2F%2F" ) )
{
qDebug() << "========================================================================= QgsWmsProvider::prepareUri" << uri;
uri = QUrl::fromPercentEncoding( uri.toUtf8() );
Q_ASSERT( false );
}
if ( isUrlForWMTS( uri ) ) if ( isUrlForWMTS( uri ) )
{ {

View File

@ -933,7 +933,9 @@ void TestQgsIdentify::identifyVectorTile()
const QString vtPath = QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/vector_tile/{z}-{x}-{y}.pbf" ); const QString vtPath = QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/vector_tile/{z}-{x}-{y}.pbf" );
QgsDataSourceUri dsUri; QgsDataSourceUri dsUri;
dsUri.setParam( QStringLiteral( "type" ), QStringLiteral( "xyz" ) ); dsUri.setParam( QStringLiteral( "type" ), QStringLiteral( "xyz" ) );
dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( vtPath ).toString() ); // The values need to be passed to QgsDataSourceUri::setParam() in the same format they are expected to be retrieved.
// QUrl::fromPercentEncoding() is needed here because QUrl::fromLocalFile(vtPath).toString() returns the curly braces in an URL-encoded format.
dsUri.setParam( QStringLiteral( "url" ), QUrl::fromPercentEncoding( QUrl::fromLocalFile( vtPath ).toString().toUtf8() ) );
QgsVectorTileLayer *tempLayer = new QgsVectorTileLayer( dsUri.encodedUri(), QStringLiteral( "testlayer" ) ); QgsVectorTileLayer *tempLayer = new QgsVectorTileLayer( dsUri.encodedUri(), QStringLiteral( "testlayer" ) );
QVERIFY( tempLayer->isValid() ); QVERIFY( tempLayer->isValid() );

View File

@ -38,6 +38,7 @@ class TestQgsDataSourceUri : public QObject
void checkParameterKeys(); void checkParameterKeys();
void checkRemovePassword(); void checkRemovePassword();
void checkUnicodeUri(); void checkUnicodeUri();
void checkUriInUri();
}; };
void TestQgsDataSourceUri::checkparser_data() void TestQgsDataSourceUri::checkparser_data()
@ -775,7 +776,7 @@ void TestQgsDataSourceUri::checkAuthParams()
// issue GH #53654 // issue GH #53654
QgsDataSourceUri uri5; QgsDataSourceUri uri5;
uri5.setEncodedUri( QStringLiteral( "zmax=14&zmin=0&styleUrl=http://localhost:8000/&f=application%2Fvnd.geoserver.mbstyle%2Bjson" ) ); uri5.setEncodedUri( QStringLiteral( "zmax=14&zmin=0&styleUrl=http://localhost:8000/&f=application%2Fvnd.geoserver.mbstyle%2Bjson" ) );
QCOMPARE( uri5.param( QStringLiteral( "f" ) ), QStringLiteral( "application%2Fvnd.geoserver.mbstyle%2Bjson" ) ); QCOMPARE( uri5.param( QStringLiteral( "f" ) ), QStringLiteral( "application/vnd.geoserver.mbstyle+json" ) );
uri5.setEncodedUri( QStringLiteral( "zmax=14&zmin=0&styleUrl=http://localhost:8000/&f=application/vnd.geoserver.mbstyle+json" ) ); uri5.setEncodedUri( QStringLiteral( "zmax=14&zmin=0&styleUrl=http://localhost:8000/&f=application/vnd.geoserver.mbstyle+json" ) );
QCOMPARE( uri5.param( QStringLiteral( "f" ) ), QStringLiteral( "application/vnd.geoserver.mbstyle+json" ) ); QCOMPARE( uri5.param( QStringLiteral( "f" ) ), QStringLiteral( "application/vnd.geoserver.mbstyle+json" ) );
@ -822,6 +823,83 @@ void TestQgsDataSourceUri::checkUnicodeUri()
QCOMPARE( uri.param( QStringLiteral( "url" ) ), QStringLiteral( "file:///directory/テスト.mbtiles" ) ); QCOMPARE( uri.param( QStringLiteral( "url" ) ), QStringLiteral( "file:///directory/テスト.mbtiles" ) );
} }
void TestQgsDataSourceUri::checkUriInUri()
{
QString dataUri = QStringLiteral( "dpiMode=7&url=%1&SERVICE=WMS&REQUEST=GetCapabilities&username=username&password=qgis%C3%A8%C3%A9" );
// If the 'url' field references a QGIS server then the 'MAP' parameter can contain an url to the project file.
// When the project is saved in a postgresql db, the connection url will also contains '&' and '='.
{
QgsDataSourceUri uri;
// here the project url is encoded but the whole serverUrl is not encoded.
// The OGC server will receive a call with this url: http://localhost:8000/ows/?MAP=postgresql://?service=qgis_test&dbname&schema=project&project=luxembourg&SERVICE=WMS&REQUEST=GetCapabilities
// from the OGC server POV the 'schema' and 'project' keys will be parsed as main query parameters for 'http://localhost:8000/ows/?'
// and not associated to the project file uri.
QString project = "postgresql://?service=qgis_test&dbname&schema=project&project=luxembourg";
QString projectEnc = QUrl::toPercentEncoding( project );
QString serverUrl = QString( "http://localhost:8000/ows/?MAP=%1" );
uri.setEncodedUri( dataUri.arg( serverUrl.arg( projectEnc ) ) );
QCOMPARE( uri.param( QStringLiteral( "username" ) ), QStringLiteral( "username" ) );
QCOMPARE( uri.username(), QStringLiteral( "username" ) );
QCOMPARE( uri.param( QStringLiteral( "password" ) ), QStringLiteral( "qgisèé" ) );
QCOMPARE( uri.password(), QStringLiteral( "qgisèé" ) );
QCOMPARE( uri.param( QStringLiteral( "SERVICE" ) ), QStringLiteral( "WMS" ) );
QCOMPARE( uri.param( QStringLiteral( "REQUEST" ) ), QStringLiteral( "GetCapabilities" ) );
// not enough encoded at the beginning ==> bad encoding at the end
QCOMPARE( uri.param( QStringLiteral( "url" ) ), serverUrl.arg( project ) );
QgsDataSourceUri uri2;
// here the project url is encoded and the whole serverUrl is also encoded.
// The OGC server will receive a call with this url: http://localhost:8000/ows/?MAP=postgresql%3A%2F%2F%3Fservice%3Dqgis_test%26dbname%26schema%3Dproject%26project%3Dluxembourg&SERVICE=WMS&REQUEST=GetCapabilities
// and will be able to decode all parameters
QString serverUrlEnc = QUrl::toPercentEncoding( serverUrl.arg( projectEnc ) );
uri2.setEncodedUri( dataUri.arg( serverUrlEnc ) );
QCOMPARE( uri2.param( QStringLiteral( "username" ) ), QStringLiteral( "username" ) );
QCOMPARE( uri2.username(), QStringLiteral( "username" ) );
QCOMPARE( uri2.param( QStringLiteral( "password" ) ), QStringLiteral( "qgisèé" ) );
QCOMPARE( uri2.password(), QStringLiteral( "qgisèé" ) );
QCOMPARE( uri2.param( QStringLiteral( "SERVICE" ) ), QStringLiteral( "WMS" ) );
QCOMPARE( uri2.param( QStringLiteral( "REQUEST" ) ), QStringLiteral( "GetCapabilities" ) );
QCOMPARE( uri2.param( QStringLiteral( "url" ) ), serverUrl.arg( projectEnc ) );
}
// same as above but with extra param at the end of the
{
QgsDataSourceUri uri;
// here the project url is encoded but the whole serverUrl is not encoded.
// The OGC server will receive a call with this url: https://titiler.xyz/cog/tiles/WebMercatorQuad/16/34060/23336@1x?url=https://data.geo.admin.ch/ch.swisstopo.swissalti3d/swissalti3d_2019_2573-1085/swissalti3d_2019_2573-1085_0.5_2056_5728.tif&bidx=1&rescale=1600%2C2100&colormap_name=gist_earth
// from the OGC server POV the 'rescale' and 'colormap_name' keys could be parsed as sub query parameters for 'https://data.geo.admin.ch/'
QString project = "https://data.geo.admin.ch/ch.swisstopo.swissalti3d/swissalti3d_2019_2573-1085/swissalti3d_2019_2573-1085_0.5_2056_5728.tif";
QString projectEnc = QUrl::toPercentEncoding( project );
QString extraParam = "&bidx=1&rescale=1600%2C2100&colormap_name=gist_earth";
QString serverUrl = QString( "https://titiler.xyz/cog/tiles/WebMercatorQuad/16/34060/23336@1x?url=%1" );
uri.setEncodedUri( dataUri.arg( serverUrl.arg( projectEnc ) + extraParam ) );
QCOMPARE( uri.param( QStringLiteral( "username" ) ), QStringLiteral( "username" ) );
QCOMPARE( uri.username(), QStringLiteral( "username" ) );
QCOMPARE( uri.param( QStringLiteral( "password" ) ), QStringLiteral( "qgisèé" ) );
QCOMPARE( uri.password(), QStringLiteral( "qgisèé" ) );
QCOMPARE( uri.param( QStringLiteral( "SERVICE" ) ), QStringLiteral( "WMS" ) );
QCOMPARE( uri.param( QStringLiteral( "REQUEST" ) ), QStringLiteral( "GetCapabilities" ) );
// not enough encoded at the beginning ==> bad encoding at the end
QCOMPARE( uri.param( QStringLiteral( "url" ) ), serverUrl.arg( project ) );
QgsDataSourceUri uri2;
// here the project url is encoded and the whole serverUrl is also encoded.
// The OGC server will receive a call with this url: https://titiler.xyz/cog/tiles/WebMercatorQuad/16/34060/23336@1x?url=https%3A%2F%2Fdata.geo.admin.ch%2Fch.swisstopo.swissalti3d%2Fswissalti3d_2019_2573-1085%2Fswissalti3d_2019_2573-1085_0.5_2056_5728.tif&bidx=1&rescale=1600%2C2100&colormap_name=gist_earth
// and will be able to decode all parameters
QString serverUrlEnc = QUrl::toPercentEncoding( serverUrl.arg( projectEnc ) + extraParam );
uri2.setEncodedUri( dataUri.arg( serverUrlEnc ) );
QCOMPARE( uri2.param( QStringLiteral( "username" ) ), QStringLiteral( "username" ) );
QCOMPARE( uri2.username(), QStringLiteral( "username" ) );
QCOMPARE( uri2.param( QStringLiteral( "password" ) ), QStringLiteral( "qgisèé" ) );
QCOMPARE( uri2.password(), QStringLiteral( "qgisèé" ) );
QCOMPARE( uri2.param( QStringLiteral( "SERVICE" ) ), QStringLiteral( "WMS" ) );
QCOMPARE( uri2.param( QStringLiteral( "REQUEST" ) ), QStringLiteral( "GetCapabilities" ) );
QCOMPARE( uri2.param( QStringLiteral( "url" ) ), serverUrl.arg( projectEnc ) + extraParam );
}
}
QGSTEST_MAIN( TestQgsDataSourceUri ) QGSTEST_MAIN( TestQgsDataSourceUri )
#include "testqgsdatasourceuri.moc" #include "testqgsdatasourceuri.moc"

View File

@ -59,7 +59,7 @@ void TestQgsGdalCloudConnection::encodeDecode()
data.rootPath = QStringLiteral( "some/path" ); data.rootPath = QStringLiteral( "some/path" );
data.credentialOptions = QVariantMap { { "pw", QStringLiteral( "xxxx" ) }, { "key", QStringLiteral( "yyy" ) } }; data.credentialOptions = QVariantMap { { "pw", QStringLiteral( "xxxx" ) }, { "key", QStringLiteral( "yyy" ) } };
QCOMPARE( QgsGdalCloudProviderConnection::encodedUri( data ), QStringLiteral( "container=my_container&credentialOptions=key%3Dyyy%7Cpw%3Dxxxx&handler=vsis3&rootPath=some/path" ) ); QCOMPARE( QgsGdalCloudProviderConnection::encodedUri( data ), QStringLiteral( "container=my_container&credentialOptions=key%3Dyyy%7Cpw%3Dxxxx&handler=vsis3&rootPath=some%2Fpath" ) );
const QgsGdalCloudProviderConnection::Data data2 = QgsGdalCloudProviderConnection::decodedUri( QStringLiteral( "container=my_container&credentialOptions=key%3Dyyy%7Cpw%3Dxxxx&handler=vsis3&rootPath=some/path" ) ); const QgsGdalCloudProviderConnection::Data data2 = QgsGdalCloudProviderConnection::decodedUri( QStringLiteral( "container=my_container&credentialOptions=key%3Dyyy%7Cpw%3Dxxxx&handler=vsis3&rootPath=some/path" ) );
QCOMPARE( data2.vsiHandler, QStringLiteral( "vsis3" ) ); QCOMPARE( data2.vsiHandler, QStringLiteral( "vsis3" ) );
@ -94,7 +94,7 @@ void TestQgsGdalCloudConnection::testConnections()
// retrieve stored connection // retrieve stored connection
conn = QgsGdalCloudProviderConnection( QStringLiteral( "my connection" ) ); conn = QgsGdalCloudProviderConnection( QStringLiteral( "my connection" ) );
QCOMPARE( conn.uri(), QStringLiteral( "container=my_container&credentialOptions=key%3Dyyy%7Cpw%3Dxxxx&handler=vsis3&rootPath=some/path" ) ); QCOMPARE( conn.uri(), QStringLiteral( "container=my_container&credentialOptions=key%3Dyyy%7Cpw%3Dxxxx&handler=vsis3&rootPath=some%2Fpath" ) );
// add a second connection // add a second connection
QgsGdalCloudProviderConnection::Data data2; QgsGdalCloudProviderConnection::Data data2;

View File

@ -187,11 +187,14 @@ void TestQgsHttpheaders::createQgsOwsConnection()
QgsOwsConnection ows( "service", "name" ); QgsOwsConnection ows( "service", "name" );
QCOMPARE( ows.connectionInfo(), ",authcfg=,referer=http://test.com" ); QCOMPARE( ows.connectionInfo(), ",authcfg=,referer=http://test.com" );
QCOMPARE( ows.uri().encodedUri(), "url&http-header:other_http_header=value&http-header:referer=http://test.com" ); if ( ows.uri().encodedUri().startsWith( "url=" ) )
QCOMPARE( ows.uri().encodedUri(), "url=&http-header:other_http_header=value&http-header:referer=http%3A%2F%2Ftest.com" );
else
QCOMPARE( ows.uri().encodedUri(), "url&http-header:other_http_header=value&http-header:referer=http%3A%2F%2Ftest.com" );
QgsDataSourceUri uri( QString( "https://www.ogc.org/?p1=v1" ) ); QgsDataSourceUri uri( QString( "https://www.ogc.org/?p1=v1" ) );
QgsDataSourceUri uri2 = ows.addWmsWcsConnectionSettings( uri, "service", "name" ); QgsDataSourceUri uri2 = ows.addWmsWcsConnectionSettings( uri, "service", "name" );
QCOMPARE( uri2.encodedUri(), "https://www.ogc.org/?p1=v1&http-header:other_http_header=value&http-header:referer=http://test.com" ); QCOMPARE( uri2.encodedUri(), "https://www.ogc.org/?p1=v1&http-header:other_http_header=value&http-header:referer=http%3A%2F%2Ftest.com" );
// check space separated string // check space separated string
QCOMPARE( uri2.uri(), " https://www.ogc.org/?p1='v1' http-header:other_http_header='value' http-header:referer='http://test.com' referer='http://test.com'" ); QCOMPARE( uri2.uri(), " https://www.ogc.org/?p1='v1' http-header:other_http_header='value' http-header:referer='http://test.com' referer='http://test.com'" );
@ -199,7 +202,7 @@ void TestQgsHttpheaders::createQgsOwsConnection()
QgsDataSourceUri uri3( uri2.uri() ); QgsDataSourceUri uri3( uri2.uri() );
QCOMPARE( uri3.httpHeader( QgsHttpHeaders::KEY_REFERER ), "http://test.com" ); QCOMPARE( uri3.httpHeader( QgsHttpHeaders::KEY_REFERER ), "http://test.com" );
QCOMPARE( uri3.httpHeader( "other_http_header" ), "value" ); QCOMPARE( uri3.httpHeader( "other_http_header" ), "value" );
QCOMPARE( uri3.encodedUri(), "https://www.ogc.org/?p1=v1&referer=http://test.com&http-header:other_http_header=value&http-header:referer=http://test.com" ); QCOMPARE( uri3.encodedUri(), "https://www.ogc.org/?p1=v1&referer=http%3A%2F%2Ftest.com&http-header:other_http_header=value&http-header:referer=http%3A%2F%2Ftest.com" );
} }

View File

@ -60,7 +60,7 @@ void TestQgsSensorThingsConnection::encodeDecode()
data.password = QStringLiteral( "my_pw" ); data.password = QStringLiteral( "my_pw" );
data.httpHeaders.insert( QStringLiteral( "my_header" ), QStringLiteral( "value" ) ); data.httpHeaders.insert( QStringLiteral( "my_header" ), QStringLiteral( "value" ) );
QCOMPARE( QgsSensorThingsProviderConnection::encodedUri( data ), QStringLiteral( "url=http://testurl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) ); QCOMPARE( QgsSensorThingsProviderConnection::encodedUri( data ), QStringLiteral( "url=http%3A%2F%2Ftesturl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) );
QCOMPARE( QgsSensorThingsProviderConnection::encodedLayerUri( data ), QStringLiteral( "user='my_user' password='my_pw' authcfg=my_auth url='http://testurl' http-header:my_header='value'" ) ); QCOMPARE( QgsSensorThingsProviderConnection::encodedLayerUri( data ), QStringLiteral( "user='my_user' password='my_pw' authcfg=my_auth url='http://testurl' http-header:my_header='value'" ) );
const QgsSensorThingsProviderConnection::Data data2 = QgsSensorThingsProviderConnection::decodedUri( QStringLiteral( "url=http://testurl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) ); const QgsSensorThingsProviderConnection::Data data2 = QgsSensorThingsProviderConnection::decodedUri( QStringLiteral( "url=http://testurl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) );
@ -93,7 +93,7 @@ void TestQgsSensorThingsConnection::testConnections()
// retrieve stored connection // retrieve stored connection
conn = QgsSensorThingsProviderConnection( QStringLiteral( "my connection" ) ); conn = QgsSensorThingsProviderConnection( QStringLiteral( "my connection" ) );
QCOMPARE( conn.uri(), QStringLiteral( "url=http://testurl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) ); QCOMPARE( conn.uri(), QStringLiteral( "url=http%3A%2F%2Ftesturl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) );
// add a second connection // add a second connection
QgsSensorThingsProviderConnection::Data data2; QgsSensorThingsProviderConnection::Data data2;
@ -104,7 +104,7 @@ void TestQgsSensorThingsConnection::testConnections()
data2.httpHeaders.insert( QStringLiteral( "my_header" ), QStringLiteral( "value2" ) ); data2.httpHeaders.insert( QStringLiteral( "my_header" ), QStringLiteral( "value2" ) );
// construct connection using encoded uri // construct connection using encoded uri
QgsSensorThingsProviderConnection conn2( QgsSensorThingsProviderConnection::encodedUri( data2 ), {} ); QgsSensorThingsProviderConnection conn2( QgsSensorThingsProviderConnection::encodedUri( data2 ), {} );
QCOMPARE( conn2.uri(), QStringLiteral( "url=http://testurl2&username=my_user2&password=my_pw2&authcfg=my_auth2&http-header:my_header=value2" ) ); QCOMPARE( conn2.uri(), QStringLiteral( "url=http%3A%2F%2Ftesturl2&username=my_user2&password=my_pw2&authcfg=my_auth2&http-header:my_header=value2" ) );
conn2.store( QStringLiteral( "second connection" ) ); conn2.store( QStringLiteral( "second connection" ) );
// retrieve stored connections // retrieve stored connections

View File

@ -61,8 +61,8 @@ void TestQgsTiledSceneConnection::encodeDecode()
data.password = QStringLiteral( "my_pw" ); data.password = QStringLiteral( "my_pw" );
data.httpHeaders.insert( QStringLiteral( "my_header" ), QStringLiteral( "value" ) ); data.httpHeaders.insert( QStringLiteral( "my_header" ), QStringLiteral( "value" ) );
QCOMPARE( QgsTiledSceneProviderConnection::encodedUri( data ), QStringLiteral( "url=http://testurl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) ); QCOMPARE( QgsTiledSceneProviderConnection::encodedUri( data ), QStringLiteral( "url=http%3A%2F%2Ftesturl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) );
QCOMPARE( QgsTiledSceneProviderConnection::encodedLayerUri( data ), QStringLiteral( "url=http://testurl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) ); QCOMPARE( QgsTiledSceneProviderConnection::encodedLayerUri( data ), QStringLiteral( "url=http%3A%2F%2Ftesturl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) );
const QgsTiledSceneProviderConnection::Data data2 = QgsTiledSceneProviderConnection::decodedUri( QStringLiteral( "url=http://testurl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) ); const QgsTiledSceneProviderConnection::Data data2 = QgsTiledSceneProviderConnection::decodedUri( QStringLiteral( "url=http://testurl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) );
QCOMPARE( data2.url, QStringLiteral( "http://testurl" ) ); QCOMPARE( data2.url, QStringLiteral( "http://testurl" ) );
@ -97,7 +97,7 @@ void TestQgsTiledSceneConnection::testConnections()
// retrieve stored connection // retrieve stored connection
conn = QgsTiledSceneProviderConnection( QStringLiteral( "my connection" ) ); conn = QgsTiledSceneProviderConnection( QStringLiteral( "my connection" ) );
QCOMPARE( conn.uri(), QStringLiteral( "url=http://testurl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) ); QCOMPARE( conn.uri(), QStringLiteral( "url=http%3A%2F%2Ftesturl&username=my_user&password=my_pw&authcfg=my_auth&http-header:my_header=value" ) );
QCOMPARE( qgis::down_cast<QgsTiledSceneProviderConnection *>( &conn )->providerKey(), QStringLiteral( "test_provider" ) ); QCOMPARE( qgis::down_cast<QgsTiledSceneProviderConnection *>( &conn )->providerKey(), QStringLiteral( "test_provider" ) );
// add a second connection // add a second connection
@ -110,7 +110,7 @@ void TestQgsTiledSceneConnection::testConnections()
data2.httpHeaders.insert( QStringLiteral( "my_header" ), QStringLiteral( "value2" ) ); data2.httpHeaders.insert( QStringLiteral( "my_header" ), QStringLiteral( "value2" ) );
// construct connection using encoded uri // construct connection using encoded uri
QgsTiledSceneProviderConnection conn2( QgsTiledSceneProviderConnection::encodedUri( data2 ), QStringLiteral( "test_provider2" ), {} ); QgsTiledSceneProviderConnection conn2( QgsTiledSceneProviderConnection::encodedUri( data2 ), QStringLiteral( "test_provider2" ), {} );
QCOMPARE( conn2.uri(), QStringLiteral( "url=http://testurl2&username=my_user2&password=my_pw2&authcfg=my_auth2&http-header:my_header=value2" ) ); QCOMPARE( conn2.uri(), QStringLiteral( "url=http%3A%2F%2Ftesturl2&username=my_user2&password=my_pw2&authcfg=my_auth2&http-header:my_header=value2" ) );
QCOMPARE( qgis::down_cast<QgsTiledSceneProviderConnection *>( &conn2 )->providerKey(), QStringLiteral( "test_provider2" ) ); QCOMPARE( qgis::down_cast<QgsTiledSceneProviderConnection *>( &conn2 )->providerKey(), QStringLiteral( "test_provider2" ) );
conn2.store( QStringLiteral( "second connection" ) ); conn2.store( QStringLiteral( "second connection" ) );

View File

@ -62,13 +62,13 @@ void TestQgsVectorTileConnection::test_encodedUri()
conn.zMin = 0; conn.zMin = 0;
conn.zMax = 18; conn.zMax = 18;
QString uri = QgsVectorTileProviderConnection::encodedUri( conn ); QString uri = QgsVectorTileProviderConnection::encodedUri( conn );
QCOMPARE( uri, QStringLiteral( "type=xyz&url=https://api.maptiler.com/tiles/v3/%7Bz%7D/%7Bx%7D/%7By%7D.pbf?key%3Dabcdef12345&zmax=18&zmin=0" ) ); QCOMPARE( uri, QStringLiteral( "type=xyz&url=https%3A%2F%2Fapi.maptiler.com%2Ftiles%2Fv3%2F%7Bz%7D%2F%7Bx%7D%2F%7By%7D.pbf%3Fkey%3Dabcdef12345&zmax=18&zmin=0" ) );
conn.url = QStringLiteral( "file:///home/user/tiles.mbtiles" ); conn.url = QStringLiteral( "file:///home/user/tiles.mbtiles" );
conn.zMin = 0; conn.zMin = 0;
conn.zMax = 18; conn.zMax = 18;
uri = QgsVectorTileProviderConnection::encodedUri( conn ); uri = QgsVectorTileProviderConnection::encodedUri( conn );
QCOMPARE( uri, QStringLiteral( "type=mbtiles&url=file:///home/user/tiles.mbtiles&zmax=18&zmin=0" ) ); QCOMPARE( uri, QStringLiteral( "type=mbtiles&url=file%3A%2F%2F%2Fhome%2Fuser%2Ftiles.mbtiles&zmax=18&zmin=0" ) );
} }

View File

@ -260,11 +260,12 @@ void TestQgsVectorTileLayer::testMbtilesProviderMetadata()
QCOMPARE( vectorTileMetadata->validLayerTypesForUri( QStringLiteral( "type=mbtiles&url=%1/vector_tile/mbtiles_vt.mbtiles" ).arg( TEST_DATA_DIR ) ), { Qgis::LayerType::VectorTile } ); QCOMPARE( vectorTileMetadata->validLayerTypesForUri( QStringLiteral( "type=mbtiles&url=%1/vector_tile/mbtiles_vt.mbtiles" ).arg( TEST_DATA_DIR ) ), { Qgis::LayerType::VectorTile } );
// query sublayers // query sublayers
QString localMbtilesPath = QStringLiteral( "%1%2" ).arg( QUrl::toPercentEncoding( TEST_DATA_DIR ), QUrl::toPercentEncoding( QStringLiteral("/vector_tile/mbtiles_vt.mbtiles") ) );
QList<QgsProviderSublayerDetails> sublayers = vectorTileMetadata->querySublayers( QStringLiteral( "%1/vector_tile/mbtiles_vt.mbtiles" ).arg( TEST_DATA_DIR ) ); QList<QgsProviderSublayerDetails> sublayers = vectorTileMetadata->querySublayers( QStringLiteral( "%1/vector_tile/mbtiles_vt.mbtiles" ).arg( TEST_DATA_DIR ) );
QCOMPARE( sublayers.size(), 1 ); QCOMPARE( sublayers.size(), 1 );
QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "mbtilesvectortiles" ) ); QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "mbtilesvectortiles" ) );
QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "mbtiles_vt" ) ); QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "mbtiles_vt" ) );
QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=mbtiles&url=%1/vector_tile/mbtiles_vt.mbtiles" ).arg( TEST_DATA_DIR ) ); QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=mbtiles&url=%1" ).arg( localMbtilesPath ) );
QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile ); QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile );
QVERIFY( !sublayers.at( 0 ).skippedContainerScan() ); QVERIFY( !sublayers.at( 0 ).skippedContainerScan() );
QVERIFY( !QgsProviderUtils::sublayerDetailsAreIncomplete( sublayers ) ); QVERIFY( !QgsProviderUtils::sublayerDetailsAreIncomplete( sublayers ) );
@ -273,7 +274,7 @@ void TestQgsVectorTileLayer::testMbtilesProviderMetadata()
QCOMPARE( sublayers.size(), 1 ); QCOMPARE( sublayers.size(), 1 );
QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "mbtilesvectortiles" ) ); QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "mbtilesvectortiles" ) );
QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "mbtiles_vt" ) ); QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "mbtiles_vt" ) );
QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=mbtiles&url=%1/vector_tile/mbtiles_vt.mbtiles" ).arg( TEST_DATA_DIR ) ); QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=mbtiles&url=%1" ).arg( localMbtilesPath ) );
QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile ); QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile );
QVERIFY( !sublayers.at( 0 ).skippedContainerScan() ); QVERIFY( !sublayers.at( 0 ).skippedContainerScan() );
@ -282,7 +283,7 @@ void TestQgsVectorTileLayer::testMbtilesProviderMetadata()
QCOMPARE( sublayers.size(), 1 ); QCOMPARE( sublayers.size(), 1 );
QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "mbtilesvectortiles" ) ); QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "mbtilesvectortiles" ) );
QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "mbtiles_vt" ) ); QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "mbtiles_vt" ) );
QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=mbtiles&url=%1/vector_tile/mbtiles_vt.mbtiles" ).arg( TEST_DATA_DIR ) ); QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=mbtiles&url=%1" ).arg( localMbtilesPath ) );
QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile ); QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile );
QVERIFY( sublayers.at( 0 ).skippedContainerScan() ); QVERIFY( sublayers.at( 0 ).skippedContainerScan() );
QVERIFY( QgsProviderUtils::sublayerDetailsAreIncomplete( sublayers ) ); QVERIFY( QgsProviderUtils::sublayerDetailsAreIncomplete( sublayers ) );
@ -291,17 +292,19 @@ void TestQgsVectorTileLayer::testMbtilesProviderMetadata()
QCOMPARE( sublayers.size(), 1 ); QCOMPARE( sublayers.size(), 1 );
QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "mbtilesvectortiles" ) ); QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "mbtilesvectortiles" ) );
QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "mbtiles_vt" ) ); QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "mbtiles_vt" ) );
QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=mbtiles&url=%1/vector_tile/mbtiles_vt.mbtiles" ).arg( TEST_DATA_DIR ) ); QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=mbtiles&url=%1" ).arg( localMbtilesPath ) );
QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile ); QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile );
QVERIFY( sublayers.at( 0 ).skippedContainerScan() ); QVERIFY( sublayers.at( 0 ).skippedContainerScan() );
// fast scan mode means that any mbtile file will be reported, including those with only raster tiles // fast scan mode means that any mbtile file will be reported, including those with only raster tiles
// (we are skipping a potentially expensive db open and format check) // (we are skipping a potentially expensive db open and format check)
QString localIsleOfManPath = QStringLiteral( "%1%2" ).arg( QUrl::toPercentEncoding( TEST_DATA_DIR ), QUrl::toPercentEncoding( QStringLiteral("/isle_of_man.mbtiles") ) );
sublayers = vectorTileMetadata->querySublayers( QStringLiteral( "%1/isle_of_man.mbtiles" ).arg( TEST_DATA_DIR ), Qgis::SublayerQueryFlag::FastScan ); sublayers = vectorTileMetadata->querySublayers( QStringLiteral( "%1/isle_of_man.mbtiles" ).arg( TEST_DATA_DIR ), Qgis::SublayerQueryFlag::FastScan );
QCOMPARE( sublayers.size(), 1 ); QCOMPARE( sublayers.size(), 1 );
QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "mbtilesvectortiles" ) ); QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "mbtilesvectortiles" ) );
QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "isle_of_man" ) ); QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "isle_of_man" ) );
QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=mbtiles&url=%1/isle_of_man.mbtiles" ).arg( TEST_DATA_DIR ) ); QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=mbtiles&url=%1" ).arg( localIsleOfManPath ) );
QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile ); QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile );
QVERIFY( sublayers.at( 0 ).skippedContainerScan() ); QVERIFY( sublayers.at( 0 ).skippedContainerScan() );
@ -332,8 +335,9 @@ void TestQgsVectorTileLayer::test_relativePathsMbTiles()
QgsReadWriteContext contextRel; QgsReadWriteContext contextRel;
contextRel.setPathResolver( QgsPathResolver( QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/project.qgs" ) ) ); contextRel.setPathResolver( QgsPathResolver( QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/project.qgs" ) ) );
const QgsReadWriteContext contextAbs; const QgsReadWriteContext contextAbs;
QString localMbtilesPath = QStringLiteral( "%1%2" ).arg( QUrl::toPercentEncoding( TEST_DATA_DIR ), QUrl::toPercentEncoding( QStringLiteral("/vector_tile/mbtiles_vt.mbtiles") ) );
const QString srcMbtiles = QStringLiteral( "type=mbtiles&url=%1/vector_tile/mbtiles_vt.mbtiles" ).arg( TEST_DATA_DIR ); const QString srcMbtiles = QStringLiteral( "type=mbtiles&url=%1" ).arg( localMbtilesPath );
auto layer = std::make_unique<QgsVectorTileLayer>( srcMbtiles ); auto layer = std::make_unique<QgsVectorTileLayer>( srcMbtiles );
QVERIFY( layer->isValid() ); QVERIFY( layer->isValid() );
@ -341,7 +345,7 @@ void TestQgsVectorTileLayer::test_relativePathsMbTiles()
// encode source: converting absolute paths to relative // encode source: converting absolute paths to relative
const QString srcMbtilesRel = layer->encodedSource( srcMbtiles, contextRel ); const QString srcMbtilesRel = layer->encodedSource( srcMbtiles, contextRel );
QCOMPARE( srcMbtilesRel, QStringLiteral( "type=mbtiles&url=./vector_tile/mbtiles_vt.mbtiles" ) ); QCOMPARE( srcMbtilesRel, QStringLiteral( "type=mbtiles&url=.%2Fvector_tile%2Fmbtiles_vt.mbtiles" ) );
// encode source: keeping absolute paths // encode source: keeping absolute paths
QCOMPARE( layer->encodedSource( srcMbtiles, contextAbs ), srcMbtiles ); QCOMPARE( layer->encodedSource( srcMbtiles, contextAbs ), srcMbtiles );
@ -392,7 +396,7 @@ void TestQgsVectorTileLayer::test_relativePathsXyz()
contextRel.setPathResolver( QgsPathResolver( "/home/qgis/project.qgs" ) ); contextRel.setPathResolver( QgsPathResolver( "/home/qgis/project.qgs" ) );
const QgsReadWriteContext contextAbs; const QgsReadWriteContext contextAbs;
const QString srcXyzLocal = "type=xyz&url=file:///home/qgis/%7Bz%7D/%7Bx%7D/%7By%7D.pbf"; const QString srcXyzLocal = "type=xyz&url=file%3A%2F%2F%2Fhome%2Fqgis%2F%7Bz%7D%2F%7Bx%7D%2F%7By%7D.pbf";
const QString srcXyzRemote = "type=xyz&url=http://www.example.com/%7Bz%7D/%7Bx%7D/%7By%7D.pbf"; const QString srcXyzRemote = "type=xyz&url=http://www.example.com/%7Bz%7D/%7Bx%7D/%7By%7D.pbf";
auto layer = std::make_unique<QgsVectorTileLayer>( srcXyzLocal ); auto layer = std::make_unique<QgsVectorTileLayer>( srcXyzLocal );
@ -400,7 +404,7 @@ void TestQgsVectorTileLayer::test_relativePathsXyz()
// encode source: converting absolute paths to relative // encode source: converting absolute paths to relative
const QString srcXyzLocalRel = layer->encodedSource( srcXyzLocal, contextRel ); const QString srcXyzLocalRel = layer->encodedSource( srcXyzLocal, contextRel );
QCOMPARE( srcXyzLocalRel, QStringLiteral( "type=xyz&url=file:./%7Bz%7D/%7Bx%7D/%7By%7D.pbf" ) ); QCOMPARE( srcXyzLocalRel, QStringLiteral( "type=xyz&url=file%3A.%2F%7Bz%7D%2F%7Bx%7D%2F%7By%7D.pbf" ) );
QCOMPARE( layer->encodedSource( srcXyzRemote, contextRel ), srcXyzRemote ); QCOMPARE( layer->encodedSource( srcXyzRemote, contextRel ), srcXyzRemote );
// encode source: keeping absolute paths // encode source: keeping absolute paths
@ -436,7 +440,8 @@ void TestQgsVectorTileLayer::test_absoluteRelativeUriXyz()
QString absoluteUri = dsAbs.encodedUri(); QString absoluteUri = dsAbs.encodedUri();
QString relativeUri = dsRel.encodedUri(); QString relativeUri = dsRel.encodedUri();
QCOMPARE( vectorTileMetadata->absoluteToRelativeUri( absoluteUri, context ), relativeUri ); QString absToRelUri = vectorTileMetadata->absoluteToRelativeUri( absoluteUri, context );
QCOMPARE( absToRelUri, relativeUri );
QCOMPARE( vectorTileMetadata->relativeToAbsoluteUri( relativeUri, context ), absoluteUri ); QCOMPARE( vectorTileMetadata->relativeToAbsoluteUri( relativeUri, context ), absoluteUri );
} }
@ -458,22 +463,24 @@ void TestQgsVectorTileLayer::testVtpkProviderMetadata()
QVERIFY( vectorTileMetadata->querySublayers( QStringLiteral( "type=vtpk&url=%1/points.shp" ).arg( TEST_DATA_DIR ) ).isEmpty() ); QVERIFY( vectorTileMetadata->querySublayers( QStringLiteral( "type=vtpk&url=%1/points.shp" ).arg( TEST_DATA_DIR ) ).isEmpty() );
// vtpk uris // vtpk uris
QString localVtpkPath = QStringLiteral( "%1%2" ).arg( QUrl::toPercentEncoding( TEST_DATA_DIR ), QUrl::toPercentEncoding( QStringLiteral("/testvtpk.vtpk") ) );
QCOMPARE( vectorTileMetadata->priorityForUri( QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/testvtpk.vtpk" ) ), 100 ); QCOMPARE( vectorTileMetadata->priorityForUri( QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/testvtpk.vtpk" ) ), 100 );
QCOMPARE( vectorTileMetadata->validLayerTypesForUri( QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/testvtpk.vtpk" ) ), { Qgis::LayerType::VectorTile } ); QCOMPARE( vectorTileMetadata->validLayerTypesForUri( QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/testvtpk.vtpk" ) ), { Qgis::LayerType::VectorTile } );
QList<QgsProviderSublayerDetails> sublayers = vectorTileMetadata->querySublayers( QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/testvtpk.vtpk" ) ); QList<QgsProviderSublayerDetails> sublayers = vectorTileMetadata->querySublayers( QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/testvtpk.vtpk" ) );
QCOMPARE( sublayers.size(), 1 ); QCOMPARE( sublayers.size(), 1 );
QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "vtpkvectortiles" ) ); QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "vtpkvectortiles" ) );
QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "testvtpk" ) ); QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "testvtpk" ) );
QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=vtpk&url=%1/testvtpk.vtpk" ).arg( TEST_DATA_DIR ) ); QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=vtpk&url=%1" ).arg( localVtpkPath ) );
QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile ); QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile );
QCOMPARE( vectorTileMetadata->priorityForUri( QStringLiteral( "type=vtpk&url=%1/testvtpk.vtpk" ).arg( TEST_DATA_DIR ) ), 100 ); QCOMPARE( vectorTileMetadata->priorityForUri( QStringLiteral( "type=vtpk&url=%1" ).arg( localVtpkPath ) ), 100 );
QCOMPARE( vectorTileMetadata->validLayerTypesForUri( QStringLiteral( "type=vtpk&url=%1/testvtpk.vtpk" ).arg( TEST_DATA_DIR ) ), { Qgis::LayerType::VectorTile } ); QCOMPARE( vectorTileMetadata->validLayerTypesForUri( QStringLiteral( "type=vtpk&url=%1" ).arg( localVtpkPath ) ), {Qgis::LayerType::VectorTile} );
sublayers = vectorTileMetadata->querySublayers( QStringLiteral( "type=vtpk&url=%1/testvtpk.vtpk" ).arg( TEST_DATA_DIR ) ); sublayers = vectorTileMetadata->querySublayers( QStringLiteral( "type=vtpk&url=%1" ).arg( localVtpkPath ) );
QCOMPARE( sublayers.size(), 1 ); QCOMPARE( sublayers.size(), 1 );
QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "vtpkvectortiles" ) ); QCOMPARE( sublayers.at( 0 ).providerKey(), QStringLiteral( "vtpkvectortiles" ) );
QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "testvtpk" ) ); QCOMPARE( sublayers.at( 0 ).name(), QStringLiteral( "testvtpk" ) );
QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=vtpk&url=%1/testvtpk.vtpk" ).arg( TEST_DATA_DIR ) ); QCOMPARE( sublayers.at( 0 ).uri(), QStringLiteral( "type=vtpk&url=%1" ).arg( localVtpkPath ) );
QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile ); QCOMPARE( sublayers.at( 0 ).type(), Qgis::LayerType::VectorTile );
// test that vtpk provider is the preferred provider for vtpk files // test that vtpk provider is the preferred provider for vtpk files
@ -500,7 +507,9 @@ void TestQgsVectorTileLayer::test_relativePathsVtpk()
contextRel.setPathResolver( QgsPathResolver( QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/project.qgs" ) ) ); contextRel.setPathResolver( QgsPathResolver( QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/project.qgs" ) ) );
const QgsReadWriteContext contextAbs; const QgsReadWriteContext contextAbs;
const QString srcVtpk = QStringLiteral( "type=vtpk&url=%1/testvtpk.vtpk" ).arg( TEST_DATA_DIR ); QString localVtpkPath = QStringLiteral( "%1%2" ).arg( QUrl::toPercentEncoding( TEST_DATA_DIR ), QUrl::toPercentEncoding( QStringLiteral("/testvtpk.vtpk") ) );
const QString srcVtpk = QStringLiteral( "type=vtpk&url=%1" ).arg( localVtpkPath );
auto layer = std::make_unique<QgsVectorTileLayer>( srcVtpk ); auto layer = std::make_unique<QgsVectorTileLayer>( srcVtpk );
QVERIFY( layer->isValid() ); QVERIFY( layer->isValid() );
@ -508,7 +517,7 @@ void TestQgsVectorTileLayer::test_relativePathsVtpk()
// encode source: converting absolute paths to relative // encode source: converting absolute paths to relative
const QString srcVtpkRel = layer->encodedSource( srcVtpk, contextRel ); const QString srcVtpkRel = layer->encodedSource( srcVtpk, contextRel );
QCOMPARE( srcVtpkRel, QStringLiteral( "type=vtpk&url=./testvtpk.vtpk" ) ); QCOMPARE( srcVtpkRel, QStringLiteral( "type=vtpk&url=.%2Ftestvtpk.vtpk" ) );
// encode source: keeping absolute paths // encode source: keeping absolute paths
QCOMPARE( layer->encodedSource( srcVtpk, contextAbs ), srcVtpk ); QCOMPARE( layer->encodedSource( srcVtpk, contextAbs ), srcVtpk );

View File

@ -469,8 +469,8 @@ void TestQgsWmsProvider::absoluteRelativeUri()
QgsProviderMetadata *wmsMetadata = QgsProviderRegistry::instance()->providerMetadata( "wms" ); QgsProviderMetadata *wmsMetadata = QgsProviderRegistry::instance()->providerMetadata( "wms" );
QVERIFY( wmsMetadata ); QVERIFY( wmsMetadata );
QString absoluteUri = "type=mbtiles&url=file://" + QStringLiteral( TEST_DATA_DIR ) + "/isle_of_man.mbtiles"; QString absoluteUri = "type=mbtiles&url=" + QString( QUrl::toPercentEncoding( "file://" + QStringLiteral( TEST_DATA_DIR ) + "/isle_of_man.mbtiles" ) );
QString relativeUri = "type=mbtiles&url=file:./isle_of_man.mbtiles"; QString relativeUri = "type=mbtiles&url=file%3A.%2Fisle_of_man.mbtiles";
QCOMPARE( wmsMetadata->absoluteToRelativeUri( absoluteUri, context ), relativeUri ); QCOMPARE( wmsMetadata->absoluteToRelativeUri( absoluteUri, context ), relativeUri );
QCOMPARE( wmsMetadata->relativeToAbsoluteUri( relativeUri, context ), absoluteUri ); QCOMPARE( wmsMetadata->relativeToAbsoluteUri( relativeUri, context ), absoluteUri );
} }

View File

@ -105,7 +105,7 @@ class TestVectorTile(QgisTestCase):
parts["path"] = "/my/new/file.mbtiles" parts["path"] = "/my/new/file.mbtiles"
uri = md.encodeUri(parts) uri = md.encodeUri(parts)
self.assertEqual(uri, "type=mbtiles&url=/my/new/file.mbtiles") self.assertEqual(uri, "type=mbtiles&url=%2Fmy%2Fnew%2Ffile.mbtiles")
uri = ( uri = (
"type=xyz&url=https://fake.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmin=0&zmax=2" "type=xyz&url=https://fake.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmin=0&zmax=2"
@ -125,7 +125,7 @@ class TestVectorTile(QgisTestCase):
uri = md.encodeUri(parts) uri = md.encodeUri(parts)
self.assertEqual( self.assertEqual(
uri, uri,
"type=xyz&url=https://fake.new.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmax=2&zmin=0", "type=xyz&url=https%3A%2F%2Ffake.new.server%2F%7Bx%7D%2F%7By%7D%2F%7Bz%7D.png&zmax=2&zmin=0",
) )
uri = "type=xyz&serviceType=arcgis&url=https://fake.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmax=2&http-header:referer=https://qgis.org/&styleUrl=https://qgis.org/" uri = "type=xyz&serviceType=arcgis&url=https://fake.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmax=2&http-header:referer=https://qgis.org/&styleUrl=https://qgis.org/"
@ -147,7 +147,7 @@ class TestVectorTile(QgisTestCase):
uri = md.encodeUri(parts) uri = md.encodeUri(parts)
self.assertEqual( self.assertEqual(
uri, uri,
"serviceType=arcgis&styleUrl=https://qgis.org/&type=xyz&url=https://fake.new.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmax=2&http-header:referer=https://qgis.org/", "serviceType=arcgis&styleUrl=https%3A%2F%2Fqgis.org%2F&type=xyz&url=https%3A%2F%2Ffake.new.server%2F%7Bx%7D%2F%7By%7D%2F%7Bz%7D.png&zmax=2&http-header:referer=https%3A%2F%2Fqgis.org%2F",
) )
def testZoomRange(self): def testZoomRange(self):

View File

@ -64,14 +64,14 @@ void TestQgsServerWmsParameters::external_layers()
QgsWms::QgsWmsParametersLayer layer_params = layers_params[0]; QgsWms::QgsWmsParametersLayer layer_params = layers_params[0];
QCOMPARE( layer_params.mNickname, QString( "external_layer_1" ) ); QCOMPARE( layer_params.mNickname, QString( "external_layer_1" ) );
QCOMPARE( layer_params.mExternalUri, QString( "layers=layer_1_name&url=http://url_1" ) ); QCOMPARE( layer_params.mExternalUri, QString( "layers=layer_1_name&url=http%3A%2F%2Furl_1" ) );
layer_params = layers_params[1]; layer_params = layers_params[1];
QCOMPARE( layer_params.mNickname, QString( "layer" ) ); QCOMPARE( layer_params.mNickname, QString( "layer" ) );
layer_params = layers_params[2]; layer_params = layers_params[2];
QCOMPARE( layer_params.mNickname, QString( "external_layer_2" ) ); QCOMPARE( layer_params.mNickname, QString( "external_layer_2" ) );
QCOMPARE( layer_params.mExternalUri, QString( "layers=layer_2_name&opacities=100&url=http://url_2" ) ); QCOMPARE( layer_params.mExternalUri, QString( "layers=layer_2_name&opacities=100&url=http%3A%2F%2Furl_2" ) );
//test if opacities are also applied to external layers //test if opacities are also applied to external layers
QCOMPARE( layers_params[0].mOpacity, 255 ); QCOMPARE( layers_params[0].mOpacity, 255 );
@ -94,7 +94,7 @@ void TestQgsServerWmsParameters::external_layers()
QgsWms::QgsWmsParametersLayer layer_params2 = layers_params2[0]; QgsWms::QgsWmsParametersLayer layer_params2 = layers_params2[0];
QCOMPARE( layer_params2.mNickname, QString( "external_layer_1" ) ); QCOMPARE( layer_params2.mNickname, QString( "external_layer_1" ) );
QCOMPARE( layer_params2.mExternalUri, QString( "layers=layer_1_name&url=http://url_1" ) ); QCOMPARE( layer_params2.mExternalUri, QString( "layers=layer_1_name&url=http%3A%2F%2Furl_1" ) );
} }
void TestQgsServerWmsParameters::percent_encoding() void TestQgsServerWmsParameters::percent_encoding()