QGIS API Documentation  3.6.0-Noosa (5873452)
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 
66 {
67  return mValue.toString();
68 }
69 
70 QStringList QgsServerParameterDefinition::toStringList( const char delimiter ) const
71 {
72  return toString().split( delimiter, QString::SkipEmptyParts );
73 }
74 
75 QList<QgsGeometry> QgsServerParameterDefinition::toGeomList( bool &ok, const char delimiter ) const
76 {
77  ok = true;
78  QList<QgsGeometry> geoms;
79 
80  for ( const auto &wkt : toStringList( delimiter ) )
81  {
82  const QgsGeometry g( QgsGeometry::fromWkt( wkt ) );
83 
84  if ( g.isGeosValid() )
85  {
86  geoms.append( g );
87  }
88  else
89  {
90  ok = false;
91  return QList<QgsGeometry>();
92  }
93  }
94 
95  return geoms;
96 }
97 
98 QList<QColor> QgsServerParameterDefinition::toColorList( bool &ok, const char delimiter ) const
99 {
100  ok = true;
101  QList<QColor> colors;
102 
103  for ( const auto &part : toStringList( delimiter ) )
104  {
105  QString cStr( part );
106  if ( !cStr.isEmpty() )
107  {
108  // support hexadecimal notation to define colors
109  if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
110  {
111  cStr.replace( 0, 2, QStringLiteral( "#" ) );
112  }
113 
114  const QColor color = QColor( cStr );
115  ok = color.isValid();
116 
117  if ( !ok )
118  {
119  return QList<QColor>();
120  }
121 
122  colors.append( color );
123  }
124  }
125 
126  return colors;
127 }
128 
129 QList<int> QgsServerParameterDefinition::toIntList( bool &ok, const char delimiter ) const
130 {
131  ok = true;
132  QList<int> ints;
133 
134  for ( const auto &part : toStringList( delimiter ) )
135  {
136  const int val = part.toInt( &ok );
137 
138  if ( !ok )
139  {
140  return QList<int>();
141  }
142 
143  ints.append( val );
144  }
145 
146  return ints;
147 }
148 
149 QList<double> QgsServerParameterDefinition::toDoubleList( bool &ok, const char delimiter ) const
150 {
151  ok = true;
152  QList<double> vals;
153 
154  for ( const auto &part : toStringList( delimiter ) )
155  {
156  const double val = part.toDouble( &ok );
157 
158  if ( !ok )
159  {
160  return QList<double>();
161  }
162 
163  vals.append( val );
164  }
165 
166  return vals;
167 }
168 
170 {
171  ok = true;
172  QgsRectangle extent;
173 
174  if ( !mValue.toString().isEmpty() )
175  {
176  QStringList corners = mValue.toString().split( ',' );
177 
178  if ( corners.size() == 4 )
179  {
180  double d[4];
181 
182  for ( int i = 0; i < 4; i++ )
183  {
184  corners[i].replace( ' ', '+' );
185  d[i] = corners[i].toDouble( &ok );
186  if ( !ok )
187  {
188  return QgsRectangle();
189  }
190  }
191 
192  if ( d[0] > d[2] || d[1] > d[3] )
193  {
194  ok = false;
195  return QgsRectangle();
196  }
197 
198  extent = QgsRectangle( d[0], d[1], d[2], d[3] );
199  }
200  else
201  {
202  ok = false;
203  return QgsRectangle();
204  }
205  }
206 
207  return extent;
208 }
209 
210 QString QgsServerParameterDefinition::loadUrl( bool &ok ) const
211 {
212  ok = true;
213 
214  // Get URL
215  QUrl url = toUrl( ok );
216  if ( !ok )
217  {
218  return QString();
219  }
220 
221  // fetching content
222  QgsNetworkContentFetcher fetcher;
223  QEventLoop loop;
224  QObject::connect( &fetcher, &QgsNetworkContentFetcher::finished, &loop, &QEventLoop::quit );
225 
227  QObject::tr( "Request started [url: %1]" ).arg( url.toString() ),
228  QStringLiteral( "Server" ) );
229  QNetworkRequest request( url );
230  request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
231  request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
232  fetcher.fetchContent( request );
233 
234  //wait until content fetched
235  loop.exec( QEventLoop::ExcludeUserInputEvents );
236 
237  QNetworkReply *reply = fetcher.reply();
238  if ( !reply )
239  {
240  ok = false;
242  QObject::tr( "Request failed [error: no reply - url: %1]" ).arg( url.toString() ),
243  QStringLiteral( "Server" ) );
244  return QString();
245  }
246 
247  QVariant status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute );
248  if ( !status.isNull() && status.toInt() >= 400 )
249  {
250  ok = false;
251  if ( reply->error() != QNetworkReply::NoError )
252  {
254  QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( reply->errorString(), reply->url().toString() ),
255  QStringLiteral( "Server" ) );
256  }
257  QVariant phrase = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute );
259  QObject::tr( "Request error [status: %1 - reason phrase: %2] for %3" ).arg( status.toInt() ).arg( phrase.toString(), reply->url().toString() ),
260  QStringLiteral( "Server" ) );
261  return QString();
262  }
263 
264  if ( reply->error() != QNetworkReply::NoError )
265  {
266  ok = false;
268  QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( reply->errorString(), reply->url().toString() ),
269  QStringLiteral( "Server" ) );
270  return QString();
271  }
272 
274  QObject::tr( "Request finished [url: %1]" ).arg( url.toString() ),
275  QStringLiteral( "Server" ) );
276 
277  QString content = fetcher.contentAsString();
278  ok = ( !content.isEmpty() );
279  return content;
280 }
281 
283 {
284  ok = true;
285  QUrl val;
286 
287  if ( !mValue.toString().isEmpty() )
288  {
289  val = mValue.toUrl();
290  }
291 
292  ok = ( !val.isEmpty() && val.isValid() );
293  return val;
294 }
295 
297 {
298  ok = true;
299  int val = mDefaultValue.toInt();
300 
301  if ( !mValue.toString().isEmpty() )
302  {
303  val = mValue.toInt( &ok );
304  }
305 
306  return val;
307 }
308 
310 {
311  int val = mDefaultValue.toBool();
312 
313  if ( !mValue.toString().isEmpty() )
314  {
315  val = mValue.toBool();
316  }
317 
318  return val;
319 }
320 
322 {
323  ok = true;
324  double val = mDefaultValue.toDouble();
325 
326  if ( !mValue.toString().isEmpty() )
327  {
328  val = mValue.toDouble( &ok );
329  }
330 
331  return val;
332 }
333 
335 {
336  return mValue.canConvert( mType );
337 }
338 
340 {
341  throw QgsBadRequestException( QStringLiteral( "Invalid Parameter" ), msg );
342 }
343 
344 //
345 // QgsServerParameter
346 //
348  const QVariant::Type type, const QVariant defaultValue )
349  : QgsServerParameterDefinition( type, defaultValue )
350  , mName( name )
351 {
352 }
353 
355 {
357  {
358  return QStringLiteral( "VERSION" );
359  }
360  else
361  {
362  const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
363  return metaEnum.valueToKey( name );
364  }
365 }
366 
368 {
369  if ( name.compare( QLatin1String( "VERSION" ) ) == 0 )
370  {
372  }
373  else
374  {
375  const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
376  return ( QgsServerParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
377  }
378 }
379 
381 {
382  const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), mValue.toString(), typeName() );
384 }
385 
386 //
387 // QgsServerParameters
388 //
390 {
396 }
397 
400 {
401  mUrlQuery = query;
402  load( query );
403 }
404 
405 void QgsServerParameters::save( const QgsServerParameter &parameter )
406 {
407  mParameters[ parameter.mName ] = parameter;
408 }
409 
410 void QgsServerParameters::add( const QString &key, const QString &value )
411 {
412  QUrlQuery query;
413  query.addQueryItem( key, value );
414  load( query );
415 }
416 
418 {
419  QUrlQuery query = mUrlQuery;
420 
421  if ( query.isEmpty() )
422  {
423  query.clear();
424 
425  for ( auto param : toMap().toStdMap() )
426  {
427  query.addQueryItem( param.first, param.second );
428  }
429  }
430 
431  return query;
432 }
433 
435 {
436  remove( QgsServerParameter::name( name ) );
437 }
438 
439 void QgsServerParameters::remove( const QString &key )
440 {
441  if ( mUnmanagedParameters.contains( key ) )
442  {
443  mUnmanagedParameters.take( key );
444  }
445  else
446  {
448  if ( mParameters.contains( paramName ) )
449  {
450  mParameters.take( paramName );
451  }
452  }
453 }
454 
456 {
457  return value( QgsServerParameter::MAP ).toString();
458 }
459 
461 {
462  return value( QgsServerParameter::VERSION_SERVICE ).toString();
463 }
464 
466 {
467  return value( QgsServerParameter::FILE_NAME ).toString();
468 }
469 
471 {
472  QString serviceValue = value( QgsServerParameter::SERVICE ).toString();
473 
474  if ( serviceValue.isEmpty() )
475  {
476  // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo
477  if ( request() == QLatin1String( "GetMap" ) \
478  || request() == QLatin1String( "GetFeatureInfo" ) )
479  {
480  serviceValue = "WMS";
481  }
482  }
483 
484  return serviceValue;
485 }
486 
487 QMap<QString, QString> QgsServerParameters::toMap() const
488 {
489  QMap<QString, QString> params = mUnmanagedParameters;
490 
491  for ( const auto &parameter : mParameters.toStdMap() )
492  {
493  if ( parameter.second.mValue.isNull() )
494  continue;
495 
496  if ( parameter.second.mName == QgsServerParameter::VERSION_SERVICE )
497  {
498  params["VERSION"] = parameter.second.mValue.toString();
499  }
500  else
501  {
502  const QString paramName = QgsServerParameter::name( parameter.first );
503  params[paramName] = parameter.second.mValue.toString();
504  }
505  }
506 
507  return params;
508 }
509 
511 {
512  return value( QgsServerParameter::REQUEST ).toString();
513 }
514 
515 QString QgsServerParameters::value( const QString &key ) const
516 {
517  return value( QgsServerParameter::name( key ) ).toString();
518 }
519 
521 {
522  return mParameters[name].mValue;
523 }
524 
525 void QgsServerParameters::load( const QUrlQuery &query )
526 {
527  // clean query string first
528  QUrlQuery cleanQuery( query );
529  cleanQuery.setQuery( query.query().replace( '+', QStringLiteral( "%20" ) ) );
530 
531  // load parameters
532  for ( const auto &item : cleanQuery.queryItems( QUrl::FullyDecoded ) )
533  {
534  const QgsServerParameter::Name name = QgsServerParameter::name( item.first );
535  if ( name >= 0 )
536  {
537  mParameters[name].mValue = item.second;
538  if ( ! mParameters[name].isValid() )
539  {
540  mParameters[name].raiseError();
541  }
542  }
543  else if ( item.first.compare( QLatin1String( "VERSION" ), Qt::CaseInsensitive ) == 0 )
544  {
546  mParameters[name].mValue = item.second;
547  if ( ! mParameters[name].isValid() )
548  {
549  mParameters[name].raiseError();
550  }
551  }
552  else if ( ! loadParameter( item.first, item.second ) )
553  {
554  mUnmanagedParameters[item.first.toUpper()] = item.second;
555  }
556  }
557 }
558 
559 bool QgsServerParameters::loadParameter( const QString &, const QString & )
560 {
561  return false;
562 }
563 
565 {
566  mParameters.clear();
567  mUnmanagedParameters.clear();
568 }
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:106
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.
bool isGeosValid() const
Checks validity of the geometry using GEOS.
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.
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.
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 ...
virtual bool isValid() const
Returns true if the parameter is valid, false otherwise.
QString toString() const
Converts the parameter into a string.
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.
QStringList toStringList(char delimiter=',') const
Converts the parameter into a list of strings.
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.