QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsrequesthandler.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgshttprequesthandler.cpp
3  -------------------------
4  begin : June 29, 2007
5  copyright : (C) 2007 by Marco Hugentobler
6  (C) 2014 by Alessandro Pasotti
7  email : marco dot hugentobler at karto dot baug dot ethz dot ch
8  a dot pasotti at itopen dot it
9  ***************************************************************************/
10 
11 /***************************************************************************
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * *
18  ***************************************************************************/
19 
20 #include "qgis.h"
21 #include "qgsrequesthandler.h"
22 #include "qgsmessagelog.h"
23 #include "qgsserverrequest.h"
24 #include "qgsserverresponse.h"
25 #include <QByteArray>
26 #include <QDomDocument>
27 #include <QUrl>
28 #include <QUrlQuery>
29 
31  : mExceptionRaised( false )
32  , mRequest( request )
33  , mResponse( response )
34 {
35 }
36 
37 QMap<QString, QString> QgsRequestHandler::parameterMap() const
38 {
39  return mRequest.parameters();
40 }
41 
43 {
44  return mExceptionRaised;
45 }
46 
47 void QgsRequestHandler::setResponseHeader( const QString &name, const QString &value )
48 {
49  mResponse.setHeader( name, value );
50 }
51 
53 {
54  mResponse.clear();
55 }
56 
57 void QgsRequestHandler::removeResponseHeader( const QString &name )
58 {
59  mResponse.removeHeader( name );
60 }
61 
62 QString QgsRequestHandler::responseHeader( const QString &name ) const
63 {
64  return mResponse.header( name );
65 }
66 
67 QMap<QString, QString> QgsRequestHandler::responseHeaders() const
68 {
69  return mResponse.headers();
70 }
71 
72 void QgsRequestHandler::setRequestHeader( const QString &name, const QString &value )
73 {
74  mRequest.setHeader( name, value );
75 }
76 
77 void QgsRequestHandler::removeRequestHeader( const QString &name )
78 {
79  mRequest.removeHeader( name );
80 }
81 
82 QString QgsRequestHandler::requestHeader( const QString &name ) const
83 {
84  return mRequest.header( name );
85 }
86 
87 
88 QMap<QString, QString> QgsRequestHandler::requestHeaders() const
89 {
90  return mRequest.headers();
91 }
92 
93 
95 {
96  return mResponse.headersSent();
97 }
98 
99 void QgsRequestHandler::appendBody( const QByteArray &body )
100 {
101  mResponse.write( body );
102 }
103 
105 {
106  mResponse.truncate();
107 }
108 
109 QByteArray QgsRequestHandler::body() const
110 {
111  return mResponse.data();
112 }
113 
114 QByteArray QgsRequestHandler::data() const
115 {
116  return mRequest.data();
117 }
118 
119 QString QgsRequestHandler::url() const
120 {
121  return mRequest.url().toString();
122 }
123 
124 QString QgsRequestHandler::path() const
125 {
126  return mRequest.url().path();
127 }
128 
130 {
131  mResponse.setStatusCode( code );
132 }
133 
135 {
136  return mResponse.statusCode();
137 }
138 
140 {
141  // Send data to output
142  mResponse.flush();
143 }
144 
146 {
147  // Safety measure to avoid potential leaks if called repeatedly
148  mExceptionRaised = true;
149  mResponse.write( ex );
150 }
151 
152 void QgsRequestHandler::setupParameters()
153 {
154  const QgsServerRequest::Parameters parameters = mRequest.parameters();
155 
156  //feature info format?
157  QString infoFormat = parameters.value( QStringLiteral( "INFO_FORMAT" ) );
158  if ( !infoFormat.isEmpty() )
159  {
160  mFormat = infoFormat;
161  }
162  else //capabilities format or GetMap format
163  {
164  mFormatString = parameters.value( QStringLiteral( "FORMAT" ) );
165  QString formatString = mFormatString;
166  if ( !formatString.isEmpty() )
167  {
168  //remove the image/ in front of the format
169  if ( formatString.contains( QLatin1String( "image/png" ), Qt::CaseInsensitive ) || formatString.compare( QLatin1String( "png" ), Qt::CaseInsensitive ) == 0 )
170  {
171  formatString = QStringLiteral( "PNG" );
172  }
173  else if ( formatString.contains( QLatin1String( "image/jpeg" ), Qt::CaseInsensitive ) || formatString.contains( QLatin1String( "image/jpg" ), Qt::CaseInsensitive )
174  || formatString.compare( QLatin1String( "jpg" ), Qt::CaseInsensitive ) == 0 )
175  {
176  formatString = QStringLiteral( "JPG" );
177  }
178  else if ( formatString.compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 )
179  {
180  formatString = QStringLiteral( "SVG" );
181  }
182  else if ( formatString.contains( QLatin1String( "pdf" ), Qt::CaseInsensitive ) )
183  {
184  formatString = QStringLiteral( "PDF" );
185  }
186 
187  mFormat = formatString;
188  }
189  }
190 
191 }
192 
194 {
195  if ( mRequest.method() == QgsServerRequest::PostMethod ||
196  mRequest.method() == QgsServerRequest::PutMethod ||
197  mRequest.method() == QgsServerRequest::PatchMethod )
198  {
199  if ( mRequest.header( QStringLiteral( "Content-Type" ) ).contains( QStringLiteral( "json" ) ) )
200  {
201  setupParameters();
202  }
203  else
204  {
205  QString inputString( mRequest.data() );
206  QDomDocument doc;
207  QString errorMsg;
208  int line = -1;
209  int column = -1;
210  if ( !doc.setContent( inputString, true, &errorMsg, &line, &column ) )
211  {
212  // XXX Output error but continue processing request ?
213  QgsMessageLog::logMessage( QStringLiteral( "Warning: error parsing post data as XML: at line %1, column %2: %3. Assuming urlencoded query string sent in the post body." )
214  .arg( line ).arg( column ).arg( errorMsg ) );
215 
216  // Process input string as a simple query text
217 
218  typedef QPair<QString, QString> pair_t;
219  QUrlQuery query( inputString );
220  const QList<pair_t> items = query.queryItems();
221  for ( const pair_t &pair : items )
222  {
223  // QUrl::fromPercentEncoding doesn't replace '+' with space
224  const QString key = QUrl::fromPercentEncoding( QString( pair.first ).replace( '+', ' ' ).toUtf8() );
225  const QString value = QUrl::fromPercentEncoding( QString( pair.second ).replace( '+', ' ' ).toUtf8() );
226  mRequest.setParameter( key.toUpper(), value );
227  }
228  setupParameters();
229  }
230  else
231  {
232  // we have an XML document
233 
234  setupParameters();
235 
236  QDomElement docElem = doc.documentElement();
237  // the document element tag name is the request
238  mRequest.setParameter( QStringLiteral( "REQUEST" ), docElem.tagName() );
239  // loop through the attributes which are the parameters
240  // excepting the attributes started by xmlns or xsi
241  QDomNamedNodeMap map = docElem.attributes();
242  for ( int i = 0 ; i < map.length() ; ++i )
243  {
244  if ( map.item( i ).isNull() )
245  continue;
246 
247  const QDomNode attrNode = map.item( i );
248  const QDomAttr attr = attrNode.toAttr();
249  if ( attr.isNull() )
250  continue;
251 
252  const QString attrName = attr.name();
253  if ( attrName.startsWith( "xmlns" ) || attrName.startsWith( "xsi:" ) )
254  continue;
255 
256  mRequest.setParameter( attrName.toUpper(), attr.value() );
257  }
258  mRequest.setParameter( QStringLiteral( "REQUEST_BODY" ), inputString.replace( '+', QLatin1String( "%2B" ) ) );
259  }
260  }
261  }
262  else
263  {
264  setupParameters();
265  }
266 }
267 
268 void QgsRequestHandler::setParameter( const QString &key, const QString &value )
269 {
270  if ( !( key.isEmpty() || value.isEmpty() ) )
271  {
272  // Warn for potential breaking change if plugin set the MAP parameter
273  // expecting changing the config file path, see PR #9773
274  if ( key.compare( QLatin1String( "MAP" ), Qt::CaseInsensitive ) == 0 )
275  {
276  QgsMessageLog::logMessage( QStringLiteral( "Changing the 'MAP' parameter will have no effect on config path: use QgsSerververInterface::setConfigFilePath instead" ),
277  "Server", Qgis::Warning );
278  }
279  mRequest.setParameter( key, value );
280  }
281 }
282 
283 
284 QString QgsRequestHandler::parameter( const QString &key ) const
285 {
286  return mRequest.parameter( key );
287 }
288 
289 void QgsRequestHandler::removeParameter( const QString &key )
290 {
291  mRequest.removeParameter( key );
292 }
QgsServerRequest::parameters
QgsServerRequest::Parameters parameters() const
Returns a map of query parameters with keys converted to uppercase.
Definition: qgsserverrequest.cpp:85
QgsRequestHandler::removeRequestHeader
void removeRequestHeader(const QString &name)
Remove an HTTP request header.
Definition: qgsrequesthandler.cpp:77
QgsServerRequest::setHeader
void setHeader(const QString &name, const QString &value)
Set an header.
Definition: qgsserverrequest.cpp:49
QgsRequestHandler::headersSent
bool headersSent() const
Returns true if the HTTP headers were already sent to the client.
Definition: qgsrequesthandler.cpp:94
QgsRequestHandler::clear
void clear()
Clears the response body and headers.
Definition: qgsrequesthandler.cpp:52
QgsRequestHandler::body
QByteArray body() const
Returns the response body data.
Definition: qgsrequesthandler.cpp:109
QgsServerResponse::flush
virtual void flush() SIP_THROW(QgsServerException)
Flushes the current output buffer to the network.
Definition: qgsserverresponse.cpp:73
QgsRequestHandler::url
QString url() const
Returns the request url.
Definition: qgsrequesthandler.cpp:119
Qgis::Warning
@ Warning
Definition: qgis.h:91
QgsServerResponse::truncate
virtual void truncate()=0
Truncate data.
qgis.h
QgsServerResponse::clear
virtual void clear()=0
Reset all headers and content for this response.
QgsServerRequest
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
Definition: qgsserverrequest.h:39
QgsRequestHandler::clearBody
void clearBody()
Clear response buffer.
Definition: qgsrequesthandler.cpp:104
QgsServerRequest::removeHeader
void removeHeader(const QString &name)
Remove an header.
Definition: qgsserverrequest.cpp:60
QgsServerResponse::statusCode
virtual int statusCode() const =0
Returns the http status code.
QgsServerRequest::Parameters
QMap< QString, QString > Parameters
Definition: qgsserverrequest.h:44
QgsServerRequest::removeParameter
void removeParameter(const QString &key)
Remove a parameter.
Definition: qgsserverrequest.cpp:116
QgsServerResponse::write
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device.
Definition: qgsserverresponse.cpp:25
QgsRequestHandler::path
QString path() const
Returns the path component of the request URL.
Definition: qgsrequesthandler.cpp:124
QgsRequestHandler::responseHeader
QString responseHeader(const QString &name) const
Retrieve response header value.
Definition: qgsrequesthandler.cpp:62
QgsServerRequest::setParameter
void setParameter(const QString &key, const QString &value)
Set a parameter.
Definition: qgsserverrequest.cpp:100
qgsserverrequest.h
QgsRequestHandler::requestHeaders
QMap< QString, QString > requestHeaders() const
Returns the the Request headers.
Definition: qgsrequesthandler.cpp:88
qgsserverresponse.h
QgsServerRequest::PostMethod
@ PostMethod
Definition: qgsserverrequest.h:55
QgsServerRequest::method
QgsServerRequest::Method method() const
Definition: qgsserverrequest.cpp:80
QgsRequestHandler::appendBody
void appendBody(const QByteArray &body)
Sets the info format string such as "text/xml".
Definition: qgsrequesthandler.cpp:99
QgsServerResponse::header
virtual QString header(const QString &key) const =0
Returns the header value.
QgsServerResponse::setStatusCode
virtual void setStatusCode(int code)=0
Set the http status code.
QgsServerResponse::removeHeader
virtual void removeHeader(const QString &key)=0
Clear header Undo a previous 'setHeader' call.
QgsRequestHandler::parseInput
void parseInput()
Parses the input and creates a request neutral Parameter/Value map.
Definition: qgsrequesthandler.cpp:193
QgsRequestHandler::setRequestHeader
void setRequestHeader(const QString &name, const QString &value)
Sets an HTTP request header.
Definition: qgsrequesthandler.cpp:72
QgsServerRequest::header
QString header(const QString &name) const
Returns the header value.
Definition: qgsserverrequest.cpp:43
QgsRequestHandler::sendResponse
void sendResponse()
Send out HTTP headers and flush output buffer.
Definition: qgsrequesthandler.cpp:139
QgsRequestHandler::setStatusCode
void setStatusCode(int code)
Sets response http status code.
Definition: qgsrequesthandler.cpp:129
QgsServerResponse::data
virtual QByteArray data() const =0
Gets the data written so far.
QgsRequestHandler::setResponseHeader
void setResponseHeader(const QString &name, const QString &value)
Sets an HTTP response header.
Definition: qgsrequesthandler.cpp:47
QgsRequestHandler::exceptionRaised
bool exceptionRaised() const
Pointer to last raised exception.
Definition: qgsrequesthandler.cpp:42
QgsRequestHandler::parameterMap
QMap< QString, QString > parameterMap() const
Returns the parsed parameters as a key-value pair, to modify a parameter setParameter( const QString ...
Definition: qgsrequesthandler.cpp:37
QgsServerRequest::data
virtual QByteArray data() const
Returns post/put data Check for QByteArray::isNull() to check if data is available.
Definition: qgsserverrequest.cpp:95
QgsServerResponse::headersSent
virtual bool headersSent() const =0
Returns true if the headers have already been sent.
QgsRequestHandler::setServiceException
void setServiceException(const QgsServerException &ex)
Allow plugins to return a QgsMapServiceException.
Definition: qgsrequesthandler.cpp:145
QgsServerException
Exception base class for server exceptions.
Definition: qgsserverexception.h:43
QgsServerRequest::parameter
QString parameter(const QString &key, const QString &defaultValue=QString()) const
Gets a parameter value.
Definition: qgsserverrequest.cpp:106
QgsRequestHandler::statusCode
int statusCode() const
Returns the response http status code.
Definition: qgsrequesthandler.cpp:134
QgsMessageLog::logMessage
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).
Definition: qgsmessagelog.cpp:27
QgsRequestHandler::requestHeader
QString requestHeader(const QString &name) const
Retrieve request header value.
Definition: qgsrequesthandler.cpp:82
QgsServerRequest::url
QUrl url() const
Definition: qgsserverrequest.cpp:65
QgsRequestHandler::removeResponseHeader
void removeResponseHeader(const QString &name)
Remove an HTTP response header.
Definition: qgsrequesthandler.cpp:57
QgsRequestHandler::QgsRequestHandler
QgsRequestHandler(QgsServerRequest &request, QgsServerResponse &response)
Constructor.
Definition: qgsrequesthandler.cpp:30
QgsServerRequest::PatchMethod
@ PatchMethod
Definition: qgsserverrequest.h:57
qgsrequesthandler.h
QgsRequestHandler::data
QByteArray data() const
Returns the request POST data (can be null)
Definition: qgsrequesthandler.cpp:114
QgsRequestHandler::setParameter
void setParameter(const QString &key, const QString &value)
Sets a request parameter.
Definition: qgsrequesthandler.cpp:268
QgsRequestHandler::removeParameter
void removeParameter(const QString &key)
Remove a request parameter.
Definition: qgsrequesthandler.cpp:289
QgsServerRequest::PutMethod
@ PutMethod
Definition: qgsserverrequest.h:53
QgsServerResponse::headers
virtual QMap< QString, QString > headers() const =0
Returns the header value.
QgsServerResponse
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
Definition: qgsserverresponse.h:44
QgsRequestHandler::parameter
QString parameter(const QString &key) const
Returns a request parameter.
Definition: qgsrequesthandler.cpp:284
QgsRequestHandler::responseHeaders
QMap< QString, QString > responseHeaders() const
Returns the response headers.
Definition: qgsrequesthandler.cpp:67
QgsServerResponse::setHeader
virtual void setHeader(const QString &key, const QString &value)=0
Set Header entry Add Header entry to the response Note that it is usually an error to set Header afte...
qgsmessagelog.h
QgsServerRequest::headers
QMap< QString, QString > headers() const
Returns the header map.
Definition: qgsserverrequest.cpp:54