QGIS API Documentation  3.23.0-Master (eb871beae0)
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 #include "qgsserverexception.h"
21 #include "qgsmessagelog.h"
22 #include <QObject>
23 #include <QUrl>
24 #include <QNetworkReply>
25 #include <QNetworkRequest>
26 #include <QEventLoop>
27 
28 //
29 // QgsServerParameterDefinition
30 //
32  const QVariant defaultValue )
33  : mType( type )
34  , mDefaultValue( defaultValue )
35 {
36 }
37 
39 {
40  return QVariant::typeToName( mType );
41 }
42 
43 QColor QgsServerParameterDefinition::toColor( bool &ok ) const
44 {
45  ok = true;
46  QColor color = mDefaultValue.value<QColor>();
47  QString cStr = mValue.toString();
48 
49  if ( !cStr.isEmpty() )
50  {
51  // support hexadecimal notation to define colors
52  if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
53  {
54  cStr.replace( 0, 2, QStringLiteral( "#" ) );
55  }
56 
57  color = QColor( cStr );
58 
59  ok = color.isValid();
60  }
61 
62  return color;
63 }
64 
65 QString QgsServerParameterDefinition::toString( const bool defaultValue ) const
66 {
67  QString value = mValue.toString();
68 
69  if ( value.isEmpty() && defaultValue )
70  value = mDefaultValue.toString();
71 
72  return value;
73 }
74 
75 QStringList QgsServerParameterDefinition::toStringList( const char delimiter, const bool skipEmptyParts ) const
76 {
77  if ( skipEmptyParts )
78  {
79 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
80  return toString().split( delimiter, QString::SkipEmptyParts );
81 #else
82  return toString().split( delimiter, Qt::SkipEmptyParts );
83 #endif
84  }
85  else
86  {
87  QStringList list;
88  if ( !toString().isEmpty() )
89  {
90 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
91  list = toString().split( delimiter, QString::KeepEmptyParts );
92 #else
93  list = toString().split( delimiter, Qt::KeepEmptyParts );
94 #endif
95  }
96  return list;
97  }
98 }
99 
100 QList<QgsGeometry> QgsServerParameterDefinition::toGeomList( bool &ok, const char delimiter ) const
101 {
102  ok = true;
103  QList<QgsGeometry> geoms;
104 
105  const auto constStringList( toStringList( delimiter ) );
106  for ( const auto &wkt : constStringList )
107  {
108  const QgsGeometry g( QgsGeometry::fromWkt( wkt ) );
109 
110  if ( g.isGeosValid() )
111  {
112  geoms.append( g );
113  }
114  else
115  {
116  ok = false;
117  return QList<QgsGeometry>();
118  }
119  }
120 
121  return geoms;
122 }
123 
124 QList<QColor> QgsServerParameterDefinition::toColorList( bool &ok, const char delimiter ) const
125 {
126  ok = true;
127  QList<QColor> colors;
128 
129  const auto constStringList( toStringList( delimiter ) );
130  for ( const auto &part : constStringList )
131  {
132  QString cStr( part );
133  if ( !cStr.isEmpty() )
134  {
135  // support hexadecimal notation to define colors
136  if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
137  {
138  cStr.replace( 0, 2, QStringLiteral( "#" ) );
139  }
140 
141  const QColor color = QColor( cStr );
142  ok = color.isValid();
143 
144  if ( !ok )
145  {
146  return QList<QColor>();
147  }
148 
149  colors.append( color );
150  }
151  }
152 
153  return colors;
154 }
155 
156 QList<int> QgsServerParameterDefinition::toIntList( bool &ok, const char delimiter ) const
157 {
158  ok = true;
159  QList<int> ints;
160 
161  const auto constStringList( toStringList( delimiter ) );
162  for ( const auto &part : constStringList )
163  {
164  const int val = part.toInt( &ok );
165 
166  if ( !ok )
167  {
168  return QList<int>();
169  }
170 
171  ints.append( val );
172  }
173 
174  return ints;
175 }
176 
177 QList<double> QgsServerParameterDefinition::toDoubleList( bool &ok, const char delimiter ) const
178 {
179  ok = true;
180  QList<double> vals;
181 
182  const auto constStringList( toStringList( delimiter ) );
183  for ( const auto &part : constStringList )
184  {
185  const double val = part.toDouble( &ok );
186 
187  if ( !ok )
188  {
189  return QList<double>();
190  }
191 
192  vals.append( val );
193  }
194 
195  return vals;
196 }
197 
199 {
200  ok = true;
201  QgsRectangle extent;
202 
203  if ( !mValue.toString().isEmpty() )
204  {
205  QStringList corners = mValue.toString().split( ',' );
206 
207  if ( corners.size() == 4 )
208  {
209  double d[4];
210 
211  for ( int i = 0; i < 4; i++ )
212  {
213  corners[i].replace( ' ', '+' );
214  d[i] = corners[i].toDouble( &ok );
215  if ( !ok )
216  {
217  return QgsRectangle();
218  }
219  }
220 
221  if ( d[0] > d[2] || d[1] > d[3] )
222  {
223  ok = false;
224  return QgsRectangle();
225  }
226 
227  extent = QgsRectangle( d[0], d[1], d[2], d[3] );
228  }
229  else
230  {
231  ok = false;
232  return QgsRectangle();
233  }
234  }
235 
236  return extent;
237 }
238 
239 QString QgsServerParameterDefinition::loadUrl( bool &ok ) const
240 {
241  ok = true;
242 
243  // Get URL
244  const QUrl url = toUrl( ok );
245  if ( !ok )
246  {
247  return QString();
248  }
249 
250  // fetching content
251  QgsNetworkContentFetcher fetcher;
252  QEventLoop loop;
253  QObject::connect( &fetcher, &QgsNetworkContentFetcher::finished, &loop, &QEventLoop::quit );
254 
256  QObject::tr( "Request started [url: %1]" ).arg( url.toString() ),
257  QStringLiteral( "Server" ) );
258  QNetworkRequest request( url );
259  request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
260  request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
261  fetcher.fetchContent( request );
262 
263  //wait until content fetched
264  loop.exec( QEventLoop::ExcludeUserInputEvents );
265 
266  QNetworkReply *reply = fetcher.reply();
267  if ( !reply )
268  {
269  ok = false;
271  QObject::tr( "Request failed [error: no reply - url: %1]" ).arg( url.toString() ),
272  QStringLiteral( "Server" ) );
273  return QString();
274  }
275 
276  const QVariant status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute );
277  if ( !status.isNull() && status.toInt() >= 400 )
278  {
279  ok = false;
280  if ( reply->error() != QNetworkReply::NoError )
281  {
283  QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( reply->errorString(), reply->url().toString() ),
284  QStringLiteral( "Server" ) );
285  }
286  const QVariant phrase = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute );
288  QObject::tr( "Request error [status: %1 - reason phrase: %2] for %3" ).arg( status.toInt() ).arg( phrase.toString(), reply->url().toString() ),
289  QStringLiteral( "Server" ) );
290  return QString();
291  }
292 
293  if ( reply->error() != QNetworkReply::NoError )
294  {
295  ok = false;
297  QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( reply->errorString(), reply->url().toString() ),
298  QStringLiteral( "Server" ) );
299  return QString();
300  }
301 
303  QObject::tr( "Request finished [url: %1]" ).arg( url.toString() ),
304  QStringLiteral( "Server" ) );
305 
306  QString content = fetcher.contentAsString();
307  ok = ( !content.isEmpty() );
308  return content;
309 }
310 
312 {
313  ok = true;
314  QUrl val;
315 
316  if ( !mValue.toString().isEmpty() )
317  {
318  val = mValue.toUrl();
319  }
320 
321  ok = ( !val.isEmpty() && val.isValid() );
322  return val;
323 }
324 
326 {
327  ok = true;
328  int val = mDefaultValue.toInt();
329 
330  if ( !mValue.toString().isEmpty() )
331  {
332  val = mValue.toInt( &ok );
333  }
334 
335  return val;
336 }
337 
339 {
340  int val = mDefaultValue.toBool();
341 
342  if ( !mValue.toString().isEmpty() )
343  {
344  val = mValue.toBool();
345  }
346 
347  return val;
348 }
349 
351 {
352  ok = true;
353  double val = mDefaultValue.toDouble();
354 
355  if ( !mValue.toString().isEmpty() )
356  {
357  val = mValue.toDouble( &ok );
358  }
359 
360  return val;
361 }
362 
364 {
365  return mValue.canConvert( mType );
366 }
367 
369 {
370  throw QgsBadRequestException( QStringLiteral( "Invalid Parameter" ), msg );
371 }
372 
373 //
374 // QgsServerParameter
375 //
377  const QVariant::Type type, const QVariant defaultValue )
378  : QgsServerParameterDefinition( type, defaultValue )
379  , mName( name )
380 {
381 }
382 
384 {
386  {
387  return QStringLiteral( "VERSION" );
388  }
389  else
390  {
391  const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
392  return metaEnum.valueToKey( name );
393  }
394 }
395 
397 {
398  if ( name.compare( QLatin1String( "VERSION" ) ) == 0 )
399  {
401  }
402  else
403  {
404  const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
405  return ( QgsServerParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
406  }
407 }
408 
410 {
411  const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), mValue.toString(), typeName() );
413 }
414 
415 //
416 // QgsServerParameters
417 //
419 {
425 }
426 
429 {
430  mUrlQuery = query;
431  load( query );
432 }
433 
434 void QgsServerParameters::save( const QgsServerParameter &parameter )
435 {
436  mParameters[ parameter.mName ] = parameter;
437 }
438 
439 void QgsServerParameters::add( const QString &key, const QString &value )
440 {
441  QUrlQuery query;
442  query.addQueryItem( key, value );
443  load( query );
444 }
445 
447 {
448  QUrlQuery query = mUrlQuery;
449 
450  if ( query.isEmpty() )
451  {
452  query.clear();
453 
454  const auto constMap( toMap().toStdMap() );
455  for ( const auto &param : constMap )
456  {
457  const QString value = QString( param.second ).replace( '+', QLatin1String( "%2B" ) );
458  query.addQueryItem( param.first, value );
459  }
460  }
461 
462  return query;
463 }
464 
466 {
467  remove( QgsServerParameter::name( name ) );
468 }
469 
470 void QgsServerParameters::remove( const QString &key )
471 {
472  if ( mUnmanagedParameters.contains( key ) )
473  {
474  mUnmanagedParameters.take( key );
475  }
476  else
477  {
478  const QgsServerParameter::Name paramName = QgsServerParameter::name( key );
479  if ( mParameters.contains( paramName ) )
480  {
481  mParameters.take( paramName );
482  }
483  }
484 }
485 
487 {
488  return value( QgsServerParameter::MAP ).toString();
489 }
490 
492 {
493  return value( QgsServerParameter::VERSION_SERVICE ).toString();
494 }
495 
497 {
498  return value( QgsServerParameter::FILE_NAME ).toString();
499 }
500 
502 {
503  QString serviceValue = value( QgsServerParameter::SERVICE ).toString();
504 
505  if ( serviceValue.isEmpty() )
506  {
507  // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo
508  if ( request() == QLatin1String( "GetMap" ) \
509  || request() == QLatin1String( "GetFeatureInfo" ) )
510  {
511  serviceValue = "WMS";
512  }
513  }
514 
515  return serviceValue;
516 }
517 
518 QMap<QString, QString> QgsServerParameters::toMap() const
519 {
520  QMap<QString, QString> params = mUnmanagedParameters;
521 
522  for ( const auto &parameter : mParameters.toStdMap() )
523  {
524  if ( parameter.second.mValue.isNull() )
525  continue;
526 
527  if ( parameter.second.mName == QgsServerParameter::VERSION_SERVICE )
528  {
529  params["VERSION"] = parameter.second.mValue.toString();
530  }
531  else
532  {
533  const QString paramName = QgsServerParameter::name( parameter.first );
534  params[paramName] = parameter.second.mValue.toString();
535  }
536  }
537 
538  return params;
539 }
540 
542 {
543  return value( QgsServerParameter::REQUEST ).toString();
544 }
545 
546 QString QgsServerParameters::value( const QString &key ) const
547 {
548  if ( ! mParameters.contains( QgsServerParameter::name( key ) ) )
549  {
550  return mUnmanagedParameters[key];
551  }
552  else
553  {
554  return value( QgsServerParameter::name( key ) ).toString();
555  }
556 }
557 
559 {
560  return mParameters[name].mValue;
561 }
562 
563 void QgsServerParameters::load( const QUrlQuery &query )
564 {
565  // clean query string first
566  QUrlQuery cleanQuery( query );
567  cleanQuery.setQuery( query.query().replace( '+', QLatin1String( "%20" ) ) );
568 
569  // load parameters
570  const auto constQueryItems( cleanQuery.queryItems( QUrl::FullyDecoded ) );
571  for ( const auto &item : constQueryItems )
572  {
573  const QgsServerParameter::Name name = QgsServerParameter::name( item.first );
574  if ( name >= 0 )
575  {
576  mParameters[name].mValue = item.second;
577  if ( ! mParameters[name].isValid() )
578  {
579  mParameters[name].raiseError();
580  }
581  }
582  else if ( item.first.compare( QLatin1String( "VERSION" ), Qt::CaseInsensitive ) == 0 )
583  {
585  mParameters[name].mValue = item.second;
586  if ( ! mParameters[name].isValid() )
587  {
588  mParameters[name].raiseError();
589  }
590  }
591  else if ( ! loadParameter( item.first, item.second ) )
592  {
593  mUnmanagedParameters[item.first.toUpper()] = item.second;
594  }
595  }
596 }
597 
598 bool QgsServerParameters::loadParameter( const QString &, const QString & )
599 {
600  return false;
601 }
602 
604 {
605  mParameters.clear();
606  mUnmanagedParameters.clear();
607 }
Exception thrown in case of malformed request.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
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).
HTTP network content fetcher.
void finished()
Emitted when content has loaded.
QNetworkReply * reply()
Returns a reference to the network reply.
QString contentAsString() const
Returns the fetched content as a string.
void fetchContent(const QUrl &url, const QString &authcfg=QString())
Fetches content from a remote URL and handles redirects.
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.
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.
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.