QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsserverparameters.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsserverparameters.cpp
3 --------------------
4 begin : Jun 27, 2018
5 copyright : (C) 2018 by Paul Blottiere
6 email : paul dot blottiere at oslandia dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19#include "qgsserverparameters.h"
20#include "qgsserverexception.h"
21#include "qgsmessagelog.h"
22#include "qgsvariantutils.h"
23#include <QObject>
24#include <QUrl>
25#include <QNetworkReply>
26#include <QNetworkRequest>
27#include <QEventLoop>
28
29//
30// QgsServerParameterDefinition
31//
33 const QVariant defaultValue )
34 : mType( type )
35 , mDefaultValue( defaultValue )
36{
37}
38
40{
41 return QVariant::typeToName( mType );
42}
43
45{
46 ok = true;
47 QColor color = mDefaultValue.value<QColor>();
48 QString cStr = mValue.toString();
49
50 if ( !cStr.isEmpty() )
51 {
52 // support hexadecimal notation to define colors
53 if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
54 {
55 cStr.replace( 0, 2, QStringLiteral( "#" ) );
56 }
57
58 color = QColor( cStr );
59
60 ok = color.isValid();
61 }
62
63 return color;
64}
65
66QString QgsServerParameterDefinition::toString( const bool defaultValue ) const
67{
68 QString value = mValue.toString();
69
70 if ( value.isEmpty() && defaultValue )
71 value = mDefaultValue.toString();
72
73 return value;
74}
75
76QStringList QgsServerParameterDefinition::toStringList( const char delimiter, const bool skipEmptyParts ) const
77{
78 if ( skipEmptyParts )
79 {
80 return toString().split( delimiter, Qt::SkipEmptyParts );
81 }
82 else
83 {
84 QStringList list;
85 if ( !toString().isEmpty() )
86 {
87 list = toString().split( delimiter, Qt::KeepEmptyParts );
88 }
89 return list;
90 }
91}
92
93QList<QgsGeometry> QgsServerParameterDefinition::toGeomList( bool &ok, const char delimiter ) const
94{
95 ok = true;
96 QList<QgsGeometry> geoms;
97
98 const auto constStringList( toStringList( delimiter ) );
99 for ( const auto &wkt : constStringList )
100 {
101 const QgsGeometry g( QgsGeometry::fromWkt( wkt ) );
102
103 if ( g.isGeosValid() )
104 {
105 geoms.append( g );
106 }
107 else
108 {
109 ok = false;
110 return QList<QgsGeometry>();
111 }
112 }
113
114 return geoms;
115}
116
118{
119 int pos = 0;
120 QStringList filters;
121 const QString filter = toString();
122
123 while ( pos < filter.size() )
124 {
125 if ( pos + 1 < filter.size() && filter[pos] == '(' && filter[pos + 1] == '<' )
126 {
127 // OGC filter on multiple layers
128 int posEnd = filter.indexOf( "Filter>)", pos );
129 if ( posEnd < 0 )
130 {
131 posEnd = filter.size();
132 }
133 filters.append( filter.mid( pos + 1, posEnd - pos + 6 ) );
134 pos = posEnd + 8;
135 }
136 else if ( pos + 1 < filter.size() && filter[pos] == '(' && filter[pos + 1] == ')' )
137 {
138 // empty OGC filter
139 filters.append( "" );
140 pos += 2;
141 }
142 else if ( filter[pos] == '<' && pos + 7 < filter.size() && filter.mid( pos + 1, 6 ).compare( QLatin1String( "Filter" ) ) == 0 )
143 {
144 // Single OGC filter
145 filters.append( filter.mid( pos ) );
146 break;
147 }
148 else
149 {
150 pos += 1;
151 }
152 }
153
154 return filters;
155}
156
158{
159 int pos = 0;
160 QStringList filters;
161 const QString filter = toString();
162
163 auto isOgcFilter = [filter]()
164 {
165 return filter.contains( QStringLiteral( "<Filter>" ) ) || filter.contains( QStringLiteral( "()" ) );
166 };
167
168 while ( pos < filter.size() )
169 {
170 int posEnd = filter.indexOf( ';', pos );
171
172 if ( posEnd == pos + 1 )
173 {
174 if ( ! isOgcFilter() )
175 filters.append( QString() );
176 pos = posEnd;
177 continue;
178 }
179
180 if ( ! isOgcFilter() )
181 filters.append( filter.mid( pos, posEnd - pos ) );
182
183 if ( posEnd < 0 )
184 {
185 pos = filter.size();
186 }
187 else
188 {
189 pos = posEnd + 1;
190 }
191 }
192
193 if ( ! filter.isEmpty() && filter.back() == ';' )
194 {
195 filters.append( QString() );
196 }
197
198 return filters;
199}
200
201QList<QColor> QgsServerParameterDefinition::toColorList( bool &ok, const char delimiter ) const
202{
203 ok = true;
204 QList<QColor> colors;
205
206 const auto constStringList( toStringList( delimiter ) );
207 for ( const auto &part : constStringList )
208 {
209 QString cStr( part );
210 if ( !cStr.isEmpty() )
211 {
212 // support hexadecimal notation to define colors
213 if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
214 {
215 cStr.replace( 0, 2, QStringLiteral( "#" ) );
216 }
217
218 const QColor color = QColor( cStr );
219 ok = color.isValid();
220
221 if ( !ok )
222 {
223 return QList<QColor>();
224 }
225
226 colors.append( color );
227 }
228 }
229
230 return colors;
231}
232
233QList<int> QgsServerParameterDefinition::toIntList( bool &ok, const char delimiter ) const
234{
235 ok = true;
236 QList<int> ints;
237
238 const auto constStringList( toStringList( delimiter ) );
239 for ( const auto &part : constStringList )
240 {
241 const int val = part.toInt( &ok );
242
243 if ( !ok )
244 {
245 return QList<int>();
246 }
247
248 ints.append( val );
249 }
250
251 return ints;
252}
253
254QList<double> QgsServerParameterDefinition::toDoubleList( bool &ok, const char delimiter ) const
255{
256 ok = true;
257 QList<double> vals;
258
259 const auto constStringList( toStringList( delimiter ) );
260 for ( const auto &part : constStringList )
261 {
262 const double val = part.toDouble( &ok );
263
264 if ( !ok )
265 {
266 return QList<double>();
267 }
268
269 vals.append( val );
270 }
271
272 return vals;
273}
274
276{
277 ok = true;
278 QgsRectangle extent;
279
280 if ( !mValue.toString().isEmpty() )
281 {
282 QStringList corners = mValue.toString().split( ',' );
283
284 if ( corners.size() == 4 )
285 {
286 double d[4];
287
288 for ( int i = 0; i < 4; i++ )
289 {
290 corners[i].replace( ' ', '+' );
291 d[i] = corners[i].toDouble( &ok );
292 if ( !ok )
293 {
294 return QgsRectangle();
295 }
296 }
297
298 if ( d[0] > d[2] || d[1] > d[3] )
299 {
300 ok = false;
301 return QgsRectangle();
302 }
303
304 extent = QgsRectangle( d[0], d[1], d[2], d[3] );
305 }
306 else
307 {
308 ok = false;
309 return QgsRectangle();
310 }
311 }
312
313 return extent;
314}
315
317{
318 ok = true;
319
320 // Get URL
321 const QUrl url = toUrl( ok );
322 if ( !ok )
323 {
324 return QString();
325 }
326
327 QNetworkRequest request( url );
328 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
329 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
330
331 // fetching content
333 const QgsBlockingNetworkRequest::ErrorCode errorCode = newReq.get( request, false );
334
335 if ( errorCode != QgsBlockingNetworkRequest::NoError )
336 {
337 ok = false;
339 QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( newReq.errorMessage(), url.toString() ),
340 QStringLiteral( "Server" ) );
341 return QString();
342 }
343
344 QgsNetworkReplyContent reply = newReq.reply();
345
346 ok = !reply.content().isEmpty();
347 return reply.content();
348}
349
351{
352 ok = true;
353 QUrl val;
354
355 if ( !mValue.toString().isEmpty() )
356 {
357 val = mValue.toUrl();
358 }
359
360 ok = ( !val.isEmpty() && val.isValid() );
361 return val;
362}
363
365{
366 ok = true;
367 int val = mDefaultValue.toInt();
368
369 if ( !mValue.toString().isEmpty() )
370 {
371 val = mValue.toInt( &ok );
372 }
373
374 return val;
375}
376
378{
379 int val = mDefaultValue.toBool();
380
381 if ( !mValue.toString().isEmpty() )
382 {
383 val = mValue.toBool();
384 }
385
386 return val;
387}
388
390{
391 ok = true;
392 double val = mDefaultValue.toDouble();
393
394 if ( !mValue.toString().isEmpty() )
395 {
396 val = mValue.toDouble( &ok );
397 }
398
399 return val;
400}
401
403{
404 return mValue.canConvert( mType );
405}
406
408{
409 throw QgsBadRequestException( QStringLiteral( "Invalid Parameter" ), msg );
410}
411
412//
413// QgsServerParameter
414//
416 const QVariant::Type type, const QVariant defaultValue )
417 : QgsServerParameterDefinition( type, defaultValue )
418 , mName( name )
419{
420}
421
423{
425 {
426 return QStringLiteral( "VERSION" );
427 }
428 else
429 {
430 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
431 return metaEnum.valueToKey( name );
432 }
433}
434
436{
437 if ( name.compare( QLatin1String( "VERSION" ) ) == 0 )
438 {
440 }
441 else
442 {
443 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
444 return ( QgsServerParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
445 }
446}
447
449{
450 const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), mValue.toString(), typeName() );
452}
453
454//
455// QgsServerParameters
456//
458{
464}
465
468{
469 mUrlQuery = query;
470 load( query );
471}
472
473void QgsServerParameters::save( const QgsServerParameter &parameter )
474{
475 mParameters[ parameter.mName ] = parameter;
476}
477
478void QgsServerParameters::add( const QString &key, const QString &value )
479{
480 QUrlQuery query;
481 query.addQueryItem( key, value );
482 load( query );
483}
484
486{
487 QUrlQuery query = mUrlQuery;
488
489 if ( query.isEmpty() )
490 {
491 query.clear();
492
493 const auto constMap( toMap().toStdMap() );
494 for ( const auto &param : constMap )
495 {
496 const QString value = QUrl::toPercentEncoding( QString( param.second ) );
497 query.addQueryItem( param.first, value );
498 }
499 }
500
501 return query;
502}
503
505{
507}
508
509void QgsServerParameters::remove( const QString &key )
510{
511 if ( mUnmanagedParameters.contains( key ) )
512 {
513 mUnmanagedParameters.take( key );
514 }
515 else
516 {
517 const QgsServerParameter::Name paramName = QgsServerParameter::name( key );
518 if ( mParameters.contains( paramName ) )
519 {
520 mParameters.take( paramName );
521 }
522 }
523}
524
526{
527 return value( QgsServerParameter::MAP ).toString();
528}
529
531{
532 return value( QgsServerParameter::VERSION_SERVICE ).toString();
533}
534
536{
537 return value( QgsServerParameter::FILE_NAME ).toString();
538}
539
541{
542 QString serviceValue = value( QgsServerParameter::SERVICE ).toString();
543
544 if ( serviceValue.isEmpty() )
545 {
546 // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo
547 if ( request() == QLatin1String( "GetMap" ) \
548 || request() == QLatin1String( "GetFeatureInfo" ) )
549 {
550 serviceValue = "WMS";
551 }
552 }
553
554 return serviceValue;
555}
556
557QMap<QString, QString> QgsServerParameters::toMap() const
558{
559 QMap<QString, QString> params = mUnmanagedParameters;
560
561 for ( const auto &parameter : mParameters.toStdMap() )
562 {
563 if ( QgsVariantUtils::isNull( parameter.second.mValue ) )
564 continue;
565
566 if ( parameter.second.mName == QgsServerParameter::VERSION_SERVICE )
567 {
568 params["VERSION"] = parameter.second.mValue.toString();
569 }
570 else
571 {
572 const QString paramName = QgsServerParameter::name( parameter.first );
573 params[paramName] = parameter.second.mValue.toString();
574 }
575 }
576
577 return params;
578}
579
581{
582 return value( QgsServerParameter::REQUEST ).toString();
583}
584
585QString QgsServerParameters::value( const QString &key ) const
586{
587 if ( ! mParameters.contains( QgsServerParameter::name( key ) ) )
588 {
589 return mUnmanagedParameters[key];
590 }
591 else
592 {
593 return value( QgsServerParameter::name( key ) ).toString();
594 }
595}
596
598{
599 return mParameters[name].mValue;
600}
601
602void QgsServerParameters::load( const QUrlQuery &query )
603{
604 // clean query string first
605 QUrlQuery cleanQuery( query );
606 cleanQuery.setQuery( query.query().replace( '+', QLatin1String( "%20" ) ) );
607
608 // load parameters
609 const auto constQueryItems( cleanQuery.queryItems( QUrl::FullyDecoded ) );
610 for ( const auto &item : constQueryItems )
611 {
612 const QgsServerParameter::Name name = QgsServerParameter::name( item.first );
613 if ( name >= 0 )
614 {
615 mParameters[name].mValue = item.second;
616 if ( ! mParameters[name].isValid() )
617 {
618 mParameters[name].raiseError();
619 }
620 }
621 else if ( item.first.compare( QLatin1String( "VERSION" ), Qt::CaseInsensitive ) == 0 )
622 {
624 mParameters[name].mValue = item.second;
625 if ( ! mParameters[name].isValid() )
626 {
627 mParameters[name].raiseError();
628 }
629 }
630 else if ( ! loadParameter( item.first, item.second ) )
631 {
632 mUnmanagedParameters[item.first.toUpper()] = item.second;
633 }
634 }
635}
636
637bool QgsServerParameters::loadParameter( const QString &, const QString & )
638{
639 return false;
640}
641
643{
644 mParameters.clear();
645 mUnmanagedParameters.clear();
646}
Exception thrown in case of malformed request.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
@ NoError
No error was encountered.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get(), post(), head() or put() request has been mad...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:162
bool isGeosValid(Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Checks validity of the geometry using GEOS.
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
Definition of a parameter with basic conversion methods.
QList< QgsGeometry > toGeomList(bool &ok, char delimiter=',') const
Converts the parameter into a list of geometries.
QString loadUrl(bool &ok) const
Loads the data associated to the parameter converted into an url.
QUrl toUrl(bool &ok) const
Converts the parameter into an url.
QString toString(bool defaultValue=false) const
Converts the parameter into a string.
bool toBool() const
Converts the parameter into a boolean.
QList< double > toDoubleList(bool &ok, char delimiter=',') const
Converts the parameter into a list of doubles.
QStringList toStringList(char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of strings.
virtual bool isValid() const
Returns true if the parameter is valid, false otherwise.
QgsServerParameterDefinition(const QVariant::Type type=QVariant::String, const QVariant defaultValue=QVariant(""))
Constructor for QgsServerParameterDefinition.
QString typeName() const
Returns the type of the parameter as a string.
static void raiseError(const QString &msg)
Raises an exception in case of an invalid parameters.
QStringList toExpressionList() const
Converts the parameter into a list of QGIS expressions.
int toInt(bool &ok) const
Converts the parameter into an integer.
QList< int > toIntList(bool &ok, char delimiter=',') const
Converts the parameter into a list of integers.
QColor toColor(bool &ok) const
Converts the parameter into a color.
double toDouble(bool &ok) const
Converts the parameter into a double.
QgsRectangle toRectangle(bool &ok) const
Converts the parameter into a rectangle.
QList< QColor > toColorList(bool &ok, char delimiter=',') const
Converts the parameter into a list of colors.
QStringList toOgcFilterList() const
Converts the parameter into a list of OGC filters.
Parameter common to all services (WMS, WFS, ...)
QgsServerParameter::Name mName
QgsServerParameter(const QgsServerParameter::Name name=QgsServerParameter::UNKNOWN, const QVariant::Type type=QVariant::String, const QVariant defaultValue=QVariant(""))
Constructor for QgsServerParameter.
Name
Parameter's name common to all services.
void raiseError() const
Raises an error in case of an invalid conversion.
static QString name(const QgsServerParameter::Name name)
Converts a parameter's name into its string representation.
QgsServerParameters provides an interface to retrieve and manipulate global parameters received from ...
QMap< QString, QString > toMap() const
Returns all parameters in a map.
QString map() const
Returns MAP parameter as a string or an empty string if not defined.
QgsServerParameters()
Constructor.
void add(const QString &key, const QString &value)
Adds a parameter.
QString service() const
Returns SERVICE parameter as a string or an empty string if not defined.
virtual QString request() const
Returns REQUEST parameter as a string or an empty string if not defined.
void clear()
Removes all parameters.
QString fileName() const
Returns FILE_NAME parameter as a string or an empty string if not defined.
virtual bool loadParameter(const QString &name, const QString &value)
Loads a parameter with a specific value.
QUrlQuery urlQuery() const
Returns a url query with underlying parameters.
QMap< QString, QString > mUnmanagedParameters
void load(const QUrlQuery &query)
Loads new parameters.
void remove(const QString &key)
Removes a parameter.
virtual QString version() const
Returns VERSION parameter as a string or an empty string if not defined.
QString value(const QString &key) const
Returns the value of a parameter.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.