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