QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  const auto constStringList( toStringList( delimiter ) );
98  for ( const auto &wkt : constStringList )
99  {
100  const QgsGeometry g( QgsGeometry::fromWkt( wkt ) );
101 
102  if ( g.isGeosValid() )
103  {
104  geoms.append( g );
105  }
106  else
107  {
108  ok = false;
109  return QList<QgsGeometry>();
110  }
111  }
112 
113  return geoms;
114 }
115 
116 QList<QColor> QgsServerParameterDefinition::toColorList( bool &ok, const char delimiter ) const
117 {
118  ok = true;
119  QList<QColor> colors;
120 
121  const auto constStringList( toStringList( delimiter ) );
122  for ( const auto &part : constStringList )
123  {
124  QString cStr( part );
125  if ( !cStr.isEmpty() )
126  {
127  // support hexadecimal notation to define colors
128  if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
129  {
130  cStr.replace( 0, 2, QStringLiteral( "#" ) );
131  }
132 
133  const QColor color = QColor( cStr );
134  ok = color.isValid();
135 
136  if ( !ok )
137  {
138  return QList<QColor>();
139  }
140 
141  colors.append( color );
142  }
143  }
144 
145  return colors;
146 }
147 
148 QList<int> QgsServerParameterDefinition::toIntList( bool &ok, const char delimiter ) const
149 {
150  ok = true;
151  QList<int> ints;
152 
153  const auto constStringList( toStringList( delimiter ) );
154  for ( const auto &part : constStringList )
155  {
156  const int val = part.toInt( &ok );
157 
158  if ( !ok )
159  {
160  return QList<int>();
161  }
162 
163  ints.append( val );
164  }
165 
166  return ints;
167 }
168 
169 QList<double> QgsServerParameterDefinition::toDoubleList( bool &ok, const char delimiter ) const
170 {
171  ok = true;
172  QList<double> vals;
173 
174  const auto constStringList( toStringList( delimiter ) );
175  for ( const auto &part : constStringList )
176  {
177  const double val = part.toDouble( &ok );
178 
179  if ( !ok )
180  {
181  return QList<double>();
182  }
183 
184  vals.append( val );
185  }
186 
187  return vals;
188 }
189 
191 {
192  ok = true;
193  QgsRectangle extent;
194 
195  if ( !mValue.toString().isEmpty() )
196  {
197  QStringList corners = mValue.toString().split( ',' );
198 
199  if ( corners.size() == 4 )
200  {
201  double d[4];
202 
203  for ( int i = 0; i < 4; i++ )
204  {
205  corners[i].replace( ' ', '+' );
206  d[i] = corners[i].toDouble( &ok );
207  if ( !ok )
208  {
209  return QgsRectangle();
210  }
211  }
212 
213  if ( d[0] > d[2] || d[1] > d[3] )
214  {
215  ok = false;
216  return QgsRectangle();
217  }
218 
219  extent = QgsRectangle( d[0], d[1], d[2], d[3] );
220  }
221  else
222  {
223  ok = false;
224  return QgsRectangle();
225  }
226  }
227 
228  return extent;
229 }
230 
231 QString QgsServerParameterDefinition::loadUrl( bool &ok ) const
232 {
233  ok = true;
234 
235  // Get URL
236  QUrl url = toUrl( ok );
237  if ( !ok )
238  {
239  return QString();
240  }
241 
242  // fetching content
243  QgsNetworkContentFetcher fetcher;
244  QEventLoop loop;
245  QObject::connect( &fetcher, &QgsNetworkContentFetcher::finished, &loop, &QEventLoop::quit );
246 
248  QObject::tr( "Request started [url: %1]" ).arg( url.toString() ),
249  QStringLiteral( "Server" ) );
250  QNetworkRequest request( url );
251  request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
252  request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
253  fetcher.fetchContent( request );
254 
255  //wait until content fetched
256  loop.exec( QEventLoop::ExcludeUserInputEvents );
257 
258  QNetworkReply *reply = fetcher.reply();
259  if ( !reply )
260  {
261  ok = false;
263  QObject::tr( "Request failed [error: no reply - url: %1]" ).arg( url.toString() ),
264  QStringLiteral( "Server" ) );
265  return QString();
266  }
267 
268  QVariant status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute );
269  if ( !status.isNull() && status.toInt() >= 400 )
270  {
271  ok = false;
272  if ( reply->error() != QNetworkReply::NoError )
273  {
275  QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( reply->errorString(), reply->url().toString() ),
276  QStringLiteral( "Server" ) );
277  }
278  QVariant phrase = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute );
280  QObject::tr( "Request error [status: %1 - reason phrase: %2] for %3" ).arg( status.toInt() ).arg( phrase.toString(), reply->url().toString() ),
281  QStringLiteral( "Server" ) );
282  return QString();
283  }
284 
285  if ( reply->error() != QNetworkReply::NoError )
286  {
287  ok = false;
289  QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( reply->errorString(), reply->url().toString() ),
290  QStringLiteral( "Server" ) );
291  return QString();
292  }
293 
295  QObject::tr( "Request finished [url: %1]" ).arg( url.toString() ),
296  QStringLiteral( "Server" ) );
297 
298  QString content = fetcher.contentAsString();
299  ok = ( !content.isEmpty() );
300  return content;
301 }
302 
304 {
305  ok = true;
306  QUrl val;
307 
308  if ( !mValue.toString().isEmpty() )
309  {
310  val = mValue.toUrl();
311  }
312 
313  ok = ( !val.isEmpty() && val.isValid() );
314  return val;
315 }
316 
318 {
319  ok = true;
320  int val = mDefaultValue.toInt();
321 
322  if ( !mValue.toString().isEmpty() )
323  {
324  val = mValue.toInt( &ok );
325  }
326 
327  return val;
328 }
329 
331 {
332  int val = mDefaultValue.toBool();
333 
334  if ( !mValue.toString().isEmpty() )
335  {
336  val = mValue.toBool();
337  }
338 
339  return val;
340 }
341 
343 {
344  ok = true;
345  double val = mDefaultValue.toDouble();
346 
347  if ( !mValue.toString().isEmpty() )
348  {
349  val = mValue.toDouble( &ok );
350  }
351 
352  return val;
353 }
354 
356 {
357  return mValue.canConvert( mType );
358 }
359 
361 {
362  throw QgsBadRequestException( QStringLiteral( "Invalid Parameter" ), msg );
363 }
364 
365 //
366 // QgsServerParameter
367 //
369  const QVariant::Type type, const QVariant defaultValue )
370  : QgsServerParameterDefinition( type, defaultValue )
371  , mName( name )
372 {
373 }
374 
376 {
378  {
379  return QStringLiteral( "VERSION" );
380  }
381  else
382  {
383  const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
384  return metaEnum.valueToKey( name );
385  }
386 }
387 
389 {
390  if ( name.compare( QLatin1String( "VERSION" ) ) == 0 )
391  {
393  }
394  else
395  {
396  const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
397  return ( QgsServerParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
398  }
399 }
400 
402 {
403  const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), mValue.toString(), typeName() );
405 }
406 
407 //
408 // QgsServerParameters
409 //
411 {
417 }
418 
421 {
422  mUrlQuery = query;
423  load( query );
424 }
425 
426 void QgsServerParameters::save( const QgsServerParameter &parameter )
427 {
428  mParameters[ parameter.mName ] = parameter;
429 }
430 
431 void QgsServerParameters::add( const QString &key, const QString &value )
432 {
433  QUrlQuery query;
434  query.addQueryItem( key, value );
435  load( query );
436 }
437 
439 {
440  QUrlQuery query = mUrlQuery;
441 
442  if ( query.isEmpty() )
443  {
444  query.clear();
445 
446  const auto constMap( toMap().toStdMap() );
447  for ( const auto &param : constMap )
448  {
449  query.addQueryItem( param.first, param.second );
450  }
451  }
452 
453  return query;
454 }
455 
457 {
458  remove( QgsServerParameter::name( name ) );
459 }
460 
461 void QgsServerParameters::remove( const QString &key )
462 {
463  if ( mUnmanagedParameters.contains( key ) )
464  {
465  mUnmanagedParameters.take( key );
466  }
467  else
468  {
470  if ( mParameters.contains( paramName ) )
471  {
472  mParameters.take( paramName );
473  }
474  }
475 }
476 
478 {
479  return value( QgsServerParameter::MAP ).toString();
480 }
481 
483 {
484  return value( QgsServerParameter::VERSION_SERVICE ).toString();
485 }
486 
488 {
489  return value( QgsServerParameter::FILE_NAME ).toString();
490 }
491 
493 {
494  QString serviceValue = value( QgsServerParameter::SERVICE ).toString();
495 
496  if ( serviceValue.isEmpty() )
497  {
498  // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo
499  if ( request() == QLatin1String( "GetMap" ) \
500  || request() == QLatin1String( "GetFeatureInfo" ) )
501  {
502  serviceValue = "WMS";
503  }
504  }
505 
506  return serviceValue;
507 }
508 
509 QMap<QString, QString> QgsServerParameters::toMap() const
510 {
511  QMap<QString, QString> params = mUnmanagedParameters;
512 
513  for ( const auto &parameter : mParameters.toStdMap() )
514  {
515  if ( parameter.second.mValue.isNull() )
516  continue;
517 
518  if ( parameter.second.mName == QgsServerParameter::VERSION_SERVICE )
519  {
520  params["VERSION"] = parameter.second.mValue.toString();
521  }
522  else
523  {
524  const QString paramName = QgsServerParameter::name( parameter.first );
525  params[paramName] = parameter.second.mValue.toString();
526  }
527  }
528 
529  return params;
530 }
531 
533 {
534  return value( QgsServerParameter::REQUEST ).toString();
535 }
536 
537 QString QgsServerParameters::value( const QString &key ) const
538 {
539  if ( ! mParameters.contains( QgsServerParameter::name( key ) ) )
540  {
541  return mUnmanagedParameters[key];
542  }
543  else
544  {
545  return value( QgsServerParameter::name( key ) ).toString();
546  }
547 }
548 
550 {
551  return mParameters[name].mValue;
552 }
553 
554 void QgsServerParameters::load( const QUrlQuery &query )
555 {
556  // clean query string first
557  QUrlQuery cleanQuery( query );
558  cleanQuery.setQuery( query.query().replace( '+', QLatin1String( "%20" ) ) );
559 
560  // load parameters
561  const auto constQueryItems( cleanQuery.queryItems( QUrl::FullyDecoded ) );
562  for ( const auto &item : constQueryItems )
563  {
564  const QgsServerParameter::Name name = QgsServerParameter::name( item.first );
565  if ( name >= 0 )
566  {
567  mParameters[name].mValue = item.second;
568  if ( ! mParameters[name].isValid() )
569  {
570  mParameters[name].raiseError();
571  }
572  }
573  else if ( item.first.compare( QLatin1String( "VERSION" ), Qt::CaseInsensitive ) == 0 )
574  {
576  mParameters[name].mValue = item.second;
577  if ( ! mParameters[name].isValid() )
578  {
579  mParameters[name].raiseError();
580  }
581  }
582  else if ( ! loadParameter( item.first, item.second ) )
583  {
584  mUnmanagedParameters[item.first.toUpper()] = item.second;
585  }
586  }
587 }
588 
589 bool QgsServerParameters::loadParameter( const QString &, const QString & )
590 {
591  return false;
592 }
593 
595 {
596  mParameters.clear();
597  mUnmanagedParameters.clear();
598 }
Exception thrown in case of malformed request.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
bool isGeosValid(QgsGeometry::ValidityFlags flags=QgsGeometry::ValidityFlags()) const
Checks validity of the geometry using GEOS.
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).
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.
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.
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.