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