QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  return toString().split( delimiter, QString::SkipEmptyParts );
80  }
81  else
82  {
83  QStringList list;
84  if ( !toString().isEmpty() )
85  {
86  list = toString().split( delimiter, QString::KeepEmptyParts );
87  }
88  return list;
89  }
90 }
91 
92 QList<QgsGeometry> QgsServerParameterDefinition::toGeomList( bool &ok, const char delimiter ) const
93 {
94  ok = true;
95  QList<QgsGeometry> geoms;
96 
97  for ( const auto &wkt : toStringList( delimiter ) )
98  {
99  const QgsGeometry g( QgsGeometry::fromWkt( wkt ) );
100 
101  if ( g.isGeosValid() )
102  {
103  geoms.append( g );
104  }
105  else
106  {
107  ok = false;
108  return QList<QgsGeometry>();
109  }
110  }
111 
112  return geoms;
113 }
114 
115 QList<QColor> QgsServerParameterDefinition::toColorList( bool &ok, const char delimiter ) const
116 {
117  ok = true;
118  QList<QColor> colors;
119 
120  for ( const auto &part : toStringList( delimiter ) )
121  {
122  QString cStr( part );
123  if ( !cStr.isEmpty() )
124  {
125  // support hexadecimal notation to define colors
126  if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
127  {
128  cStr.replace( 0, 2, QStringLiteral( "#" ) );
129  }
130 
131  const QColor color = QColor( cStr );
132  ok = color.isValid();
133 
134  if ( !ok )
135  {
136  return QList<QColor>();
137  }
138 
139  colors.append( color );
140  }
141  }
142 
143  return colors;
144 }
145 
146 QList<int> QgsServerParameterDefinition::toIntList( bool &ok, const char delimiter ) const
147 {
148  ok = true;
149  QList<int> ints;
150 
151  for ( const auto &part : toStringList( delimiter ) )
152  {
153  const int val = part.toInt( &ok );
154 
155  if ( !ok )
156  {
157  return QList<int>();
158  }
159 
160  ints.append( val );
161  }
162 
163  return ints;
164 }
165 
166 QList<double> QgsServerParameterDefinition::toDoubleList( bool &ok, const char delimiter ) const
167 {
168  ok = true;
169  QList<double> vals;
170 
171  for ( const auto &part : toStringList( delimiter ) )
172  {
173  const double val = part.toDouble( &ok );
174 
175  if ( !ok )
176  {
177  return QList<double>();
178  }
179 
180  vals.append( val );
181  }
182 
183  return vals;
184 }
185 
187 {
188  ok = true;
189  QgsRectangle extent;
190 
191  if ( !mValue.toString().isEmpty() )
192  {
193  QStringList corners = mValue.toString().split( ',' );
194 
195  if ( corners.size() == 4 )
196  {
197  double d[4];
198 
199  for ( int i = 0; i < 4; i++ )
200  {
201  corners[i].replace( ' ', '+' );
202  d[i] = corners[i].toDouble( &ok );
203  if ( !ok )
204  {
205  return QgsRectangle();
206  }
207  }
208 
209  if ( d[0] > d[2] || d[1] > d[3] )
210  {
211  ok = false;
212  return QgsRectangle();
213  }
214 
215  extent = QgsRectangle( d[0], d[1], d[2], d[3] );
216  }
217  else
218  {
219  ok = false;
220  return QgsRectangle();
221  }
222  }
223 
224  return extent;
225 }
226 
227 QString QgsServerParameterDefinition::loadUrl( bool &ok ) const
228 {
229  ok = true;
230 
231  // Get URL
232  QUrl url = toUrl( ok );
233  if ( !ok )
234  {
235  return QString();
236  }
237 
238  // fetching content
239  QgsNetworkContentFetcher fetcher;
240  QEventLoop loop;
241  QObject::connect( &fetcher, &QgsNetworkContentFetcher::finished, &loop, &QEventLoop::quit );
242 
244  QObject::tr( "Request started [url: %1]" ).arg( url.toString() ),
245  QStringLiteral( "Server" ) );
246  QNetworkRequest request( url );
247  request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
248  request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
249  fetcher.fetchContent( request );
250 
251  //wait until content fetched
252  loop.exec( QEventLoop::ExcludeUserInputEvents );
253 
254  QNetworkReply *reply = fetcher.reply();
255  if ( !reply )
256  {
257  ok = false;
259  QObject::tr( "Request failed [error: no reply - url: %1]" ).arg( url.toString() ),
260  QStringLiteral( "Server" ) );
261  return QString();
262  }
263 
264  QVariant status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute );
265  if ( !status.isNull() && status.toInt() >= 400 )
266  {
267  ok = false;
268  if ( reply->error() != QNetworkReply::NoError )
269  {
271  QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( reply->errorString(), reply->url().toString() ),
272  QStringLiteral( "Server" ) );
273  }
274  QVariant phrase = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute );
276  QObject::tr( "Request error [status: %1 - reason phrase: %2] for %3" ).arg( status.toInt() ).arg( phrase.toString(), reply->url().toString() ),
277  QStringLiteral( "Server" ) );
278  return QString();
279  }
280 
281  if ( reply->error() != QNetworkReply::NoError )
282  {
283  ok = false;
285  QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( reply->errorString(), reply->url().toString() ),
286  QStringLiteral( "Server" ) );
287  return QString();
288  }
289 
291  QObject::tr( "Request finished [url: %1]" ).arg( url.toString() ),
292  QStringLiteral( "Server" ) );
293 
294  QString content = fetcher.contentAsString();
295  ok = ( !content.isEmpty() );
296  return content;
297 }
298 
300 {
301  ok = true;
302  QUrl val;
303 
304  if ( !mValue.toString().isEmpty() )
305  {
306  val = mValue.toUrl();
307  }
308 
309  ok = ( !val.isEmpty() && val.isValid() );
310  return val;
311 }
312 
314 {
315  ok = true;
316  int val = mDefaultValue.toInt();
317 
318  if ( !mValue.toString().isEmpty() )
319  {
320  val = mValue.toInt( &ok );
321  }
322 
323  return val;
324 }
325 
327 {
328  int val = mDefaultValue.toBool();
329 
330  if ( !mValue.toString().isEmpty() )
331  {
332  val = mValue.toBool();
333  }
334 
335  return val;
336 }
337 
339 {
340  ok = true;
341  double val = mDefaultValue.toDouble();
342 
343  if ( !mValue.toString().isEmpty() )
344  {
345  val = mValue.toDouble( &ok );
346  }
347 
348  return val;
349 }
350 
352 {
353  return mValue.canConvert( mType );
354 }
355 
357 {
358  throw QgsBadRequestException( QStringLiteral( "Invalid Parameter" ), msg );
359 }
360 
361 //
362 // QgsServerParameter
363 //
365  const QVariant::Type type, const QVariant defaultValue )
366  : QgsServerParameterDefinition( type, defaultValue )
367  , mName( name )
368 {
369 }
370 
372 {
374  {
375  return QStringLiteral( "VERSION" );
376  }
377  else
378  {
379  const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
380  return metaEnum.valueToKey( name );
381  }
382 }
383 
385 {
386  if ( name.compare( QLatin1String( "VERSION" ) ) == 0 )
387  {
389  }
390  else
391  {
392  const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
393  return ( QgsServerParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
394  }
395 }
396 
398 {
399  const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), mValue.toString(), typeName() );
401 }
402 
403 //
404 // QgsServerParameters
405 //
407 {
413 }
414 
417 {
418  mUrlQuery = query;
419  load( query );
420 }
421 
422 void QgsServerParameters::save( const QgsServerParameter &parameter )
423 {
424  mParameters[ parameter.mName ] = parameter;
425 }
426 
427 void QgsServerParameters::add( const QString &key, const QString &value )
428 {
429  QUrlQuery query;
430  query.addQueryItem( key, value );
431  load( query );
432 }
433 
435 {
436  QUrlQuery query = mUrlQuery;
437 
438  if ( query.isEmpty() )
439  {
440  query.clear();
441 
442  for ( auto param : toMap().toStdMap() )
443  {
444  query.addQueryItem( param.first, param.second );
445  }
446  }
447 
448  return query;
449 }
450 
452 {
453  remove( QgsServerParameter::name( name ) );
454 }
455 
456 void QgsServerParameters::remove( const QString &key )
457 {
458  if ( mUnmanagedParameters.contains( key ) )
459  {
460  mUnmanagedParameters.take( key );
461  }
462  else
463  {
465  if ( mParameters.contains( paramName ) )
466  {
467  mParameters.take( paramName );
468  }
469  }
470 }
471 
473 {
474  return value( QgsServerParameter::MAP ).toString();
475 }
476 
478 {
479  return value( QgsServerParameter::VERSION_SERVICE ).toString();
480 }
481 
483 {
484  return value( QgsServerParameter::FILE_NAME ).toString();
485 }
486 
488 {
489  QString serviceValue = value( QgsServerParameter::SERVICE ).toString();
490 
491  if ( serviceValue.isEmpty() )
492  {
493  // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo
494  if ( request() == QLatin1String( "GetMap" ) \
495  || request() == QLatin1String( "GetFeatureInfo" ) )
496  {
497  serviceValue = "WMS";
498  }
499  }
500 
501  return serviceValue;
502 }
503 
504 QMap<QString, QString> QgsServerParameters::toMap() const
505 {
506  QMap<QString, QString> params = mUnmanagedParameters;
507 
508  for ( const auto &parameter : mParameters.toStdMap() )
509  {
510  if ( parameter.second.mValue.isNull() )
511  continue;
512 
513  if ( parameter.second.mName == QgsServerParameter::VERSION_SERVICE )
514  {
515  params["VERSION"] = parameter.second.mValue.toString();
516  }
517  else
518  {
519  const QString paramName = QgsServerParameter::name( parameter.first );
520  params[paramName] = parameter.second.mValue.toString();
521  }
522  }
523 
524  return params;
525 }
526 
528 {
529  return value( QgsServerParameter::REQUEST ).toString();
530 }
531 
532 QString QgsServerParameters::value( const QString &key ) const
533 {
534  if ( ! mParameters.contains( QgsServerParameter::name( key ) ) )
535  {
536  return mUnmanagedParameters[key];
537  }
538  else
539  {
540  return value( QgsServerParameter::name( key ) ).toString();
541  }
542 }
543 
545 {
546  return mParameters[name].mValue;
547 }
548 
549 void QgsServerParameters::load( const QUrlQuery &query )
550 {
551  // clean query string first
552  QUrlQuery cleanQuery( query );
553  cleanQuery.setQuery( query.query().replace( '+', QStringLiteral( "%20" ) ) );
554 
555  // load parameters
556  for ( const auto &item : cleanQuery.queryItems( QUrl::FullyDecoded ) )
557  {
558  const QgsServerParameter::Name name = QgsServerParameter::name( item.first );
559  if ( name >= 0 )
560  {
561  mParameters[name].mValue = item.second;
562  if ( ! mParameters[name].isValid() )
563  {
564  mParameters[name].raiseError();
565  }
566  }
567  else if ( item.first.compare( QLatin1String( "VERSION" ), Qt::CaseInsensitive ) == 0 )
568  {
570  mParameters[name].mValue = item.second;
571  if ( ! mParameters[name].isValid() )
572  {
573  mParameters[name].raiseError();
574  }
575  }
576  else if ( ! loadParameter( item.first, item.second ) )
577  {
578  mUnmanagedParameters[item.first.toUpper()] = item.second;
579  }
580  }
581 }
582 
583 bool QgsServerParameters::loadParameter( const QString &, const QString & )
584 {
585  return false;
586 }
587 
589 {
590  mParameters.clear();
591  mUnmanagedParameters.clear();
592 }
QMap< QString, QString > toMap() const
Returns all parameters in a map.
QString request() const
Returns REQUEST parameter as a string or an empty string if not defined.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Name
Parameter&#39;s name common to all services.
QString typeName() const
Returns the type of the parameter as a string.
QMap< QString, QString > mUnmanagedParameters
Exception thrown in case of malformed request.
QString value(const QString &key) const
Returns the value of a parameter.
static void raiseError(const QString &msg)
Raises an exception in case of an invalid parameters.
void remove(const QString &key)
Removes a parameter.
QString loadUrl(bool &ok) const
Loads the data associated to the parameter converted into an url.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
void load(const QUrlQuery &query)
Loads new parameters.
QNetworkReply * reply()
Returns a reference to the network reply.
QString contentAsString() const
Returns the fetched content as a string.
QgsServerParameter(const QgsServerParameter::Name name=QgsServerParameter::UNKNOWN, const QVariant::Type type=QVariant::String, const QVariant defaultValue=QVariant(""))
Constructor for QgsServerParameter.
QString map() const
Returns MAP parameter as a string or an empty string if not defined.
double toDouble(bool &ok) const
Converts the parameter into a double.
static QString name(const QgsServerParameter::Name name)
Converts a parameter&#39;s name into its string representation.
QgsServerParameters()
Constructor.
QUrl toUrl(bool &ok) const
Converts the parameter into an url.
bool isGeosValid(QgsGeometry::ValidityFlags flags=nullptr) const
Checks validity of the geometry using GEOS.
QList< double > toDoubleList(bool &ok, char delimiter=',') const
Converts the parameter into a list of doubles.
HTTP network content fetcher.
QList< int > toIntList(bool &ok, char delimiter=',') const
Converts the parameter into a list of integers.
QgsRectangle toRectangle(bool &ok) const
Converts the parameter into a rectangle.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
QString version() const
Returns VERSION parameter as a string or an empty string if not defined.
QUrlQuery urlQuery() const
Returns a url query with underlying parameters.
virtual bool loadParameter(const QString &name, const QString &value)
Loads a parameter with a specific value.
void finished()
Emitted when content has loaded.
Parameter common to all services (WMS, WFS, ...)
QgsServerParameterDefinition(const QVariant::Type type=QVariant::String, const QVariant defaultValue=QVariant(""))
Constructor for QgsServerParameterDefinition.
QColor toColor(bool &ok) const
Converts the parameter into a color.
QStringList toStringList(char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of strings.
QgsServerParameter::Name mName
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
QString service() const
Returns SERVICE parameter as a string or an empty string if not defined.
int toInt(bool &ok) const
Converts the parameter into an integer.
void add(const QString &key, const QString &value)
Adds a parameter.
QgsServerParameters provides an interface to retrieve and manipulate global parameters received from ...
QString toString(bool defaultValue=false) const
Converts the parameter into a string.
virtual bool isValid() const
Returns true if the parameter is valid, false otherwise.
QList< QgsGeometry > toGeomList(bool &ok, char delimiter=',') const
Converts the parameter into a list of geometries.
void clear()
Removes all parameters.
void raiseError() const
Raises an error in case of an invalid conversion.
void fetchContent(const QUrl &url)
Fetches content from a remote URL and handles redirects.
QList< QColor > toColorList(bool &ok, char delimiter=',') const
Converts the parameter into a list of colors.
bool toBool() const
Converts the parameter into a boolean.
QString fileName() const
Returns FILE_NAME parameter as a string or an empty string if not defined.
Definition of a parameter with basic conversion methods.