QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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 
125 {
126  mResponse.setStatusCode( code );
127 }
128 
130 {
131  return mResponse.statusCode();
132 }
133 
135 {
136  // Send data to output
137  mResponse.flush();
138 }
139 
141 {
142  // Safety measure to avoid potential leaks if called repeatedly
143  mExceptionRaised = true;
144  mResponse.write( ex );
145 }
146 
147 void QgsRequestHandler::setupParameters()
148 {
149  const QgsServerRequest::Parameters parameters = mRequest.parameters();
150 
151  //feature info format?
152  QString infoFormat = parameters.value( QStringLiteral( "INFO_FORMAT" ) );
153  if ( !infoFormat.isEmpty() )
154  {
155  mFormat = infoFormat;
156  }
157  else //capabilities format or GetMap format
158  {
159  mFormatString = parameters.value( QStringLiteral( "FORMAT" ) );
160  QString formatString = mFormatString;
161  if ( !formatString.isEmpty() )
162  {
163  //remove the image/ in front of the format
164  if ( formatString.contains( QLatin1String( "image/png" ), Qt::CaseInsensitive ) || formatString.compare( QLatin1String( "png" ), Qt::CaseInsensitive ) == 0 )
165  {
166  formatString = QStringLiteral( "PNG" );
167  }
168  else if ( formatString.contains( QLatin1String( "image/jpeg" ), Qt::CaseInsensitive ) || formatString.contains( QLatin1String( "image/jpg" ), Qt::CaseInsensitive )
169  || formatString.compare( QLatin1String( "jpg" ), Qt::CaseInsensitive ) == 0 )
170  {
171  formatString = QStringLiteral( "JPG" );
172  }
173  else if ( formatString.compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 )
174  {
175  formatString = QStringLiteral( "SVG" );
176  }
177  else if ( formatString.contains( QLatin1String( "pdf" ), Qt::CaseInsensitive ) )
178  {
179  formatString = QStringLiteral( "PDF" );
180  }
181 
182  mFormat = formatString;
183  }
184  }
185 
186 }
187 
189 {
190  if ( mRequest.method() == QgsServerRequest::PostMethod ||
191  mRequest.method() == QgsServerRequest::PutMethod ||
192  mRequest.method() == QgsServerRequest::PatchMethod )
193  {
194  if ( mRequest.header( QStringLiteral( "Content-Type" ) ).contains( QStringLiteral( "json" ) ) )
195  {
196  setupParameters();
197  }
198  else
199  {
200  QString inputString( mRequest.data() );
201  QDomDocument doc;
202  QString errorMsg;
203  int line = -1;
204  int column = -1;
205  if ( !doc.setContent( inputString, true, &errorMsg, &line, &column ) )
206  {
207  // XXX Output error but continue processing request ?
208  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." )
209  .arg( line ).arg( column ).arg( errorMsg ) );
210 
211  // Process input string as a simple query text
212 
213  typedef QPair<QString, QString> pair_t;
214  QUrlQuery query( inputString );
215  const QList<pair_t> items = query.queryItems();
216  for ( const pair_t &pair : items )
217  {
218  // QUrl::fromPercentEncoding doesn't replace '+' with space
219  const QString key = QUrl::fromPercentEncoding( QString( pair.first ).replace( '+', ' ' ).toUtf8() );
220  const QString value = QUrl::fromPercentEncoding( QString( pair.second ).replace( '+', ' ' ).toUtf8() );
221  mRequest.setParameter( key.toUpper(), value );
222  }
223  setupParameters();
224  }
225  else
226  {
227  // we have an XML document
228 
229  setupParameters();
230 
231  QDomElement docElem = doc.documentElement();
232  // the document element tag name is the request
233  mRequest.setParameter( QStringLiteral( "REQUEST" ), docElem.tagName() );
234  // loop through the attributes which are the parameters
235  // excepting the attributes started by xmlns or xsi
236  QDomNamedNodeMap map = docElem.attributes();
237  for ( int i = 0 ; i < map.length() ; ++i )
238  {
239  if ( map.item( i ).isNull() )
240  continue;
241 
242  const QDomNode attrNode = map.item( i );
243  const QDomAttr attr = attrNode.toAttr();
244  if ( attr.isNull() )
245  continue;
246 
247  const QString attrName = attr.name();
248  if ( attrName.startsWith( "xmlns" ) || attrName.startsWith( "xsi:" ) )
249  continue;
250 
251  mRequest.setParameter( attrName.toUpper(), attr.value() );
252  }
253  mRequest.setParameter( QStringLiteral( "REQUEST_BODY" ), inputString.replace( '+', QStringLiteral( "%2B" ) ) );
254  }
255  }
256  }
257  else
258  {
259  setupParameters();
260  }
261 }
262 
263 void QgsRequestHandler::setParameter( const QString &key, const QString &value )
264 {
265  if ( !( key.isEmpty() || value.isEmpty() ) )
266  {
267  // Warn for potential breaking change if plugin set the MAP parameter
268  // expecting changing the config file path, see PR #9773
269  if ( key.compare( QLatin1String( "MAP" ), Qt::CaseInsensitive ) == 0 )
270  {
271  QgsMessageLog::logMessage( QStringLiteral( "Changing the 'MAP' parameter will have no effect on config path: use QgsSerververInterface::setConfigFilePath instead" ),
272  "Server", Qgis::Warning );
273  }
274  mRequest.setParameter( key, value );
275  }
276 }
277 
278 
279 QString QgsRequestHandler::parameter( const QString &key ) const
280 {
281  return mRequest.parameter( key );
282 }
283 
284 void QgsRequestHandler::removeParameter( const QString &key )
285 {
286  mRequest.removeParameter( key );
287 }
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:104
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
Definition: qgsserverrequest.h:38
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:59
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::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:70
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:188
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:134
QgsRequestHandler::setStatusCode
void setStatusCode(int code)
Sets response http status code.
Definition: qgsrequesthandler.cpp:124
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:140
QgsServerException
Exception base class for server exceptions.
Definition: qgsserverexception.h:42
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:129
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:72
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:263
QgsRequestHandler::removeParameter
void removeParameter(const QString &key)
Remove a request parameter.
Definition: qgsrequesthandler.cpp:284
QgsServerRequest::PutMethod
@ PutMethod
Definition: qgsserverrequest.h:68
QgsServerResponse::headers
virtual QMap< QString, QString > headers() const =0
Returns the header value.
QgsServerResponse
Definition: qgsserverresponse.h:43
QgsRequestHandler::parameter
QString parameter(const QString &key) const
Returns a request parameter.
Definition: qgsrequesthandler.cpp:279
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