QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
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
18#include "qgsserverparameters.h"
19
21#include "qgsmessagelog.h"
22#include "qgsserverexception.h"
23#include "qgsvariantutils.h"
24
25#include <QEventLoop>
26#include <QNetworkReply>
27#include <QNetworkRequest>
28#include <QObject>
29#include <QString>
30#include <QUrl>
31
32#include "moc_qgsserverparameters.cpp"
33
34using namespace Qt::StringLiterals;
35
36//
37// QgsServerParameterDefinition
38//
39QgsServerParameterDefinition::QgsServerParameterDefinition( const QMetaType::Type type, const QVariant defaultValue )
40 : mType( type )
41 , mDefaultValue( defaultValue )
42{}
43
44QgsServerParameterDefinition::QgsServerParameterDefinition( const QVariant::Type type, const QVariant defaultValue )
45 : QgsServerParameterDefinition( QgsVariantUtils::variantTypeToMetaType( type ), defaultValue )
46{}
47
49{
50 return QVariant::typeToName( mType );
51}
52
54{
55 ok = true;
56 QColor color = mDefaultValue.value<QColor>();
57 QString cStr = mValue.toString();
58
59 if ( !cStr.isEmpty() )
60 {
61 // support hexadecimal notation to define colors
62 if ( cStr.startsWith( "0x"_L1, Qt::CaseInsensitive ) )
63 {
64 cStr.replace( 0, 2, u"#"_s );
65 }
66
67 color = QColor( cStr );
68
69 ok = color.isValid();
70 }
71
72 return color;
73}
74
75QString QgsServerParameterDefinition::toString( const bool defaultValue ) const
76{
77 QString value = mValue.toString();
78
79 if ( value.isEmpty() && defaultValue )
80 value = mDefaultValue.toString();
81
82 return value;
83}
84
85QStringList QgsServerParameterDefinition::toStringList( const char delimiter, const bool skipEmptyParts ) const
86{
87 if ( skipEmptyParts )
88 {
89 return toString().split( delimiter, Qt::SkipEmptyParts );
90 }
91 else
92 {
93 QStringList list;
94 if ( !toString().isEmpty() )
95 {
96 list = toString().split( delimiter, Qt::KeepEmptyParts );
97 }
98 return list;
99 }
100}
101
102QList<QgsGeometry> QgsServerParameterDefinition::toGeomList( bool &ok, const char delimiter, const bool skipEmptyParts ) const
103{
104 ok = true;
105 QList<QgsGeometry> geoms;
106
107 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
108 for ( const auto &wkt : constStringList )
109 {
110 const QgsGeometry g( QgsGeometry::fromWkt( wkt ) );
111
112 if ( g.isGeosValid() )
113 {
114 geoms.append( g );
115 }
116 else
117 {
118 ok = false;
119 return QList<QgsGeometry>();
120 }
121 }
122
123 return geoms;
124}
125
127{
128 int pos = 0;
129 QStringList filters;
130 const QString filter = toString();
131
132 while ( pos < filter.size() )
133 {
134 if ( pos + 1 < filter.size() && filter[pos] == '(' && filter[pos + 1] == '<' )
135 {
136 // OGC filter on multiple layers
137 int posEnd = filter.indexOf( "Filter>)", pos );
138 if ( posEnd < 0 )
139 {
140 posEnd = filter.size();
141 }
142 filters.append( filter.mid( pos + 1, posEnd - pos + 6 ) );
143 pos = posEnd + 8;
144 }
145 else if ( pos + 1 < filter.size() && filter[pos] == '(' && filter[pos + 1] == ')' )
146 {
147 // empty OGC filter
148 filters.append( "" );
149 pos += 2;
150 }
151 else if ( filter[pos] == '<' && pos + 7 < filter.size() && filter.mid( pos + 1, 6 ).compare( "Filter"_L1 ) == 0 )
152 {
153 // Single OGC filter
154 filters.append( filter.mid( pos ) );
155 break;
156 }
157 else
158 {
159 pos += 1;
160 }
161 }
162
163 return filters;
164}
165
167{
168 int pos = 0;
169 QStringList filters;
170 const QString filter = toString();
171
172 auto isOgcFilter = [filter]() { return filter.contains( u"<Filter>"_s ) || filter.contains( u"()"_s ); };
173
174 while ( pos < filter.size() )
175 {
176 int posEnd = filter.indexOf( ';', pos );
177
178 if ( posEnd == pos + 1 )
179 {
180 if ( !isOgcFilter() )
181 filters.append( QString() );
182 pos = posEnd;
183 continue;
184 }
185
186 if ( !isOgcFilter() )
187 filters.append( filter.mid( pos, posEnd - pos ) );
188
189 if ( posEnd < 0 )
190 {
191 pos = filter.size();
192 }
193 else
194 {
195 pos = posEnd + 1;
196 }
197 }
198
199 if ( !filter.isEmpty() && filter.back() == ';' )
200 {
201 filters.append( QString() );
202 }
203
204 return filters;
205}
206
207QList<QColor> QgsServerParameterDefinition::toColorList( bool &ok, const char delimiter, bool skipEmptyParts ) const
208{
209 ok = true;
210 QList<QColor> colors;
211
212 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
213 for ( const auto &part : constStringList )
214 {
215 QString cStr( part );
216 if ( !cStr.isEmpty() )
217 {
218 // support hexadecimal notation to define colors
219 if ( cStr.startsWith( "0x"_L1, Qt::CaseInsensitive ) )
220 {
221 cStr.replace( 0, 2, u"#"_s );
222 }
223
224 const QColor color = QColor( cStr );
225 ok = color.isValid();
226
227 if ( !ok )
228 {
229 return QList<QColor>();
230 }
231
232 colors.append( color );
233 }
234 }
235
236 return colors;
237}
238
239QList<int> QgsServerParameterDefinition::toIntList( bool &ok, const char delimiter, bool skipEmptyParts ) const
240{
241 ok = true;
242 QList<int> ints;
243
244 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
245 for ( const auto &part : constStringList )
246 {
247 const int val = part.toInt( &ok );
248
249 if ( !ok )
250 {
251 return QList<int>();
252 }
253
254 ints.append( val );
255 }
256
257 return ints;
258}
259
260QList<double> QgsServerParameterDefinition::toDoubleList( bool &ok, const char delimiter, bool skipEmptyParts ) const
261{
262 ok = true;
263 QList<double> vals;
264
265 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
266 for ( const auto &part : constStringList )
267 {
268 const double val = part.toDouble( &ok );
269
270 if ( !ok )
271 {
272 return QList<double>();
273 }
274
275 vals.append( val );
276 }
277
278 return vals;
279}
280
282{
283 ok = true;
284 QgsRectangle extent;
285
286 if ( !mValue.toString().isEmpty() )
287 {
288 QStringList corners = mValue.toString().split( ',' );
289
290 if ( corners.size() == 4 )
291 {
292 double d[4];
293
294 for ( int i = 0; i < 4; i++ )
295 {
296 corners[i].replace( ' ', '+' );
297 d[i] = corners[i].toDouble( &ok );
298 if ( !ok )
299 {
300 return QgsRectangle();
301 }
302 }
303
304 if ( d[0] > d[2] || d[1] > d[3] )
305 {
306 ok = false;
307 return QgsRectangle();
308 }
309
310 extent = QgsRectangle( d[0], d[1], d[2], d[3] );
311 }
312 else
313 {
314 ok = false;
315 return QgsRectangle();
316 }
317 }
318
319 return extent;
320}
321
323{
324 ok = true;
325
326 // Get URL
327 const QUrl url = toUrl( ok );
328 if ( !ok )
329 {
330 return QString();
331 }
332
333 QNetworkRequest request( url );
334 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
335 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
336
337 // fetching content
339 const QgsBlockingNetworkRequest::ErrorCode errorCode = newReq.get( request, false );
340
341 if ( errorCode != QgsBlockingNetworkRequest::NoError )
342 {
343 ok = false;
344 QgsMessageLog::logMessage( QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( newReq.errorMessage(), url.toString() ), u"Server"_s );
345 return QString();
346 }
347
348 QgsNetworkReplyContent reply = newReq.reply();
349
350 ok = !reply.content().isEmpty();
351 return reply.content();
352}
353
355{
356 ok = true;
357 QUrl val;
358
359 if ( !mValue.toString().isEmpty() )
360 {
361 val = mValue.toUrl();
362 }
363
364 ok = ( !val.isEmpty() && val.isValid() );
365 return val;
366}
367
369{
370 ok = true;
371 int val = mDefaultValue.toInt();
372
373 if ( !mValue.toString().isEmpty() )
374 {
375 val = mValue.toInt( &ok );
376 }
377
378 return val;
379}
380
382{
383 int val = mDefaultValue.toBool();
384
385 if ( !mValue.toString().isEmpty() )
386 {
387 val = mValue.toBool();
388 }
389
390 return val;
391}
392
394{
395 ok = true;
396 double val = mDefaultValue.toDouble();
397
398 if ( !mValue.toString().isEmpty() )
399 {
400 val = mValue.toDouble( &ok );
401 }
402
403 return val;
404}
405
407{
408 return mValue.canConvert( mType );
409}
410
412{
413 throw QgsBadRequestException( u"Invalid Parameter"_s, msg );
414}
415
416//
417// QgsServerParameter
418//
419QgsServerParameter::QgsServerParameter( const QgsServerParameter::Name name, const QMetaType::Type type, const QVariant defaultValue )
420 : QgsServerParameterDefinition( type, defaultValue )
421 , mName( name )
422{}
423
424QgsServerParameter::QgsServerParameter( const QgsServerParameter::Name name, const QVariant::Type type, const QVariant defaultValue )
425 : QgsServerParameter( name, QgsVariantUtils::variantTypeToMetaType( type ), defaultValue )
426{}
427
429{
431 {
432 return u"VERSION"_s;
433 }
434 else
435 {
436 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
437 return metaEnum.valueToKey( name );
438 }
439}
440
442{
443 if ( name.compare( "VERSION"_L1 ) == 0 )
444 {
446 }
447 else
448 {
449 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
450 return ( QgsServerParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
451 }
452}
453
455{
456 const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), mValue.toString(), typeName() );
458}
459
460//
461// QgsServerParameters
462//
471
474{
475 mUrlQuery = query;
476 load( query );
477}
478
479void QgsServerParameters::save( const QgsServerParameter &parameter )
480{
481 mParameters[parameter.mName] = parameter;
482}
483
484void QgsServerParameters::add( const QString &key, const QString &value )
485{
486 QUrlQuery query;
487 query.addQueryItem( key, value );
488 load( query );
489}
490
492{
493 QUrlQuery query = mUrlQuery;
494
495 if ( query.isEmpty() )
496 {
497 query.clear();
498
499 const auto constMap( toMap().toStdMap() );
500 for ( const auto &param : constMap )
501 {
502 const QString value = QUrl::toPercentEncoding( QString( param.second ) );
503 query.addQueryItem( param.first, value );
504 }
505 }
506
507 return query;
508}
509
514
515void QgsServerParameters::remove( const QString &key )
516{
517 if ( mUnmanagedParameters.contains( key ) )
518 {
519 mUnmanagedParameters.take( key );
520 }
521 else
522 {
523 const QgsServerParameter::Name paramName = QgsServerParameter::name( key );
524 if ( mParameters.contains( paramName ) )
525 {
526 mParameters.take( paramName );
527 }
528 }
529}
530
532{
533 return value( QgsServerParameter::MAP ).toString();
534}
535
537{
538 return value( QgsServerParameter::VERSION_SERVICE ).toString();
539}
540
542{
543 return value( QgsServerParameter::FILE_NAME ).toString();
544}
545
547{
548 QString serviceValue = value( QgsServerParameter::SERVICE ).toString();
549
550 if ( serviceValue.isEmpty() )
551 {
552 // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo
553 if ( request() == "GetMap"_L1 || request() == "GetFeatureInfo"_L1 )
554 {
555 serviceValue = "WMS";
556 }
557 }
558
559 return serviceValue;
560}
561
562QMap<QString, QString> QgsServerParameters::toMap() const
563{
564 QMap<QString, QString> params = mUnmanagedParameters;
565
566 for ( const auto &parameter : mParameters.toStdMap() )
567 {
568 if ( QgsVariantUtils::isNull( parameter.second.mValue ) )
569 continue;
570
571 if ( parameter.second.mName == QgsServerParameter::VERSION_SERVICE )
572 {
573 params["VERSION"] = parameter.second.mValue.toString();
574 }
575 else
576 {
577 const QString paramName = QgsServerParameter::name( parameter.first );
578 params[paramName] = parameter.second.mValue.toString();
579 }
580 }
581
582 return params;
583}
584
586{
587 return value( QgsServerParameter::REQUEST ).toString();
588}
589
590QString QgsServerParameters::value( const QString &key ) const
591{
592 if ( !mParameters.contains( QgsServerParameter::name( key ) ) )
593 {
594 return mUnmanagedParameters[key];
595 }
596 else
597 {
598 return value( QgsServerParameter::name( key ) ).toString();
599 }
600}
601
603{
604 return mParameters[name].mValue;
605}
606
607void QgsServerParameters::load( const QUrlQuery &query )
608{
609 // clean query string first
610 QUrlQuery cleanQuery( query );
611 cleanQuery.setQuery( query.query().replace( '+', "%20"_L1 ) );
612
613 // load parameters
614 const auto constQueryItems( cleanQuery.queryItems( QUrl::FullyDecoded ) );
615 for ( const auto &item : constQueryItems )
616 {
617 const QgsServerParameter::Name name = QgsServerParameter::name( item.first );
618 if ( name >= 0 )
619 {
620 mParameters[name].mValue = item.second;
621 if ( !mParameters[name].isValid() )
622 {
623 mParameters[name].raiseError();
624 }
625 }
626 else if ( item.first.compare( "VERSION"_L1, Qt::CaseInsensitive ) == 0 )
627 {
629 mParameters[name].mValue = item.second;
630 if ( !mParameters[name].isValid() )
631 {
632 mParameters[name].raiseError();
633 }
634 }
635 else if ( !loadParameter( item.first, item.second ) )
636 {
637 mUnmanagedParameters[item.first.toUpper()] = item.second;
638 }
639 }
640}
641
642bool QgsServerParameters::loadParameter( const QString &, const QString & )
643{
644 return false;
645}
646
648{
649 mParameters.clear();
650 mUnmanagedParameters.clear();
651}
Exception thrown in case of malformed requests.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
Performs a "get" operation on the specified request.
@ 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.
static Q_INVOKABLE QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
bool isGeosValid(Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Checks validity of the geometry using GEOS.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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.
QList< QColor > toColorList(bool &ok, char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of colors.
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.
QList< int > toIntList(bool &ok, char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of integers.
QString toString(bool defaultValue=false) const
Converts the parameter into a string.
bool toBool() const
Converts the parameter into a boolean.
QgsServerParameterDefinition(const QMetaType::Type type=QMetaType::Type::QString, const QVariant defaultValue=QVariant(""))
Constructor for QgsServerParameterDefinition.
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.
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< QgsGeometry > toGeomList(bool &ok, char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of geometries.
QColor toColor(bool &ok) const
Converts the parameter into a color.
double toDouble(bool &ok) const
Converts the parameter into a double.
QList< double > toDoubleList(bool &ok, char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of doubles.
QgsRectangle toRectangle(bool &ok) const
Converts the parameter into a rectangle.
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 QMetaType::Type type=QMetaType::Type::QString, 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.
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.
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.
Contains utility functions for working with QVariants and QVariant types.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.