QGIS API Documentation  3.9.0-Master (d9ef585e47)
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  QgsMessageLog::logMessage( QStringLiteral( "formatString is: %1" ).arg( formatString ) );
164 
165  //remove the image/ in front of the format
166  if ( formatString.contains( QLatin1String( "image/png" ), Qt::CaseInsensitive ) || formatString.compare( QLatin1String( "png" ), Qt::CaseInsensitive ) == 0 )
167  {
168  formatString = QStringLiteral( "PNG" );
169  }
170  else if ( formatString.contains( QLatin1String( "image/jpeg" ), Qt::CaseInsensitive ) || formatString.contains( QLatin1String( "image/jpg" ), Qt::CaseInsensitive )
171  || formatString.compare( QLatin1String( "jpg" ), Qt::CaseInsensitive ) == 0 )
172  {
173  formatString = QStringLiteral( "JPG" );
174  }
175  else if ( formatString.compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 )
176  {
177  formatString = QStringLiteral( "SVG" );
178  }
179  else if ( formatString.contains( QLatin1String( "pdf" ), Qt::CaseInsensitive ) )
180  {
181  formatString = QStringLiteral( "PDF" );
182  }
183 
184  mFormat = formatString;
185  }
186  }
187 
188 }
189 
191 {
192  if ( mRequest.method() == QgsServerRequest::PostMethod )
193  {
194  QString inputString( mRequest.data() );
195 
196  QDomDocument doc;
197  QString errorMsg;
198  int line = -1;
199  int column = -1;
200  if ( !doc.setContent( inputString, true, &errorMsg, &line, &column ) )
201  {
202  // XXX Output error but continue processing request ?
203  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." )
204  .arg( line ).arg( column ).arg( errorMsg ) );
205 
206  // Process input string as a simple query text
207 
208  typedef QPair<QString, QString> pair_t;
209  QUrlQuery query( inputString );
210  QList<pair_t> items = query.queryItems();
211  for ( pair_t pair : items )
212  {
213  // QUrl::fromPercentEncoding doesn't replace '+' with space
214  const QString key = QUrl::fromPercentEncoding( pair.first.replace( '+', ' ' ).toUtf8() );
215  const QString value = QUrl::fromPercentEncoding( pair.second.replace( '+', ' ' ).toUtf8() );
216  mRequest.setParameter( key.toUpper(), value );
217  }
218  setupParameters();
219  }
220  else
221  {
222  // we have an XML document
223 
224  setupParameters();
225 
226  QDomElement docElem = doc.documentElement();
227  // the document element tag name is the request
228  mRequest.setParameter( QStringLiteral( "REQUEST" ), docElem.tagName() );
229  // loop through the attributes which are the parameters
230  // excepting the attributes started by xmlns or xsi
231  QDomNamedNodeMap map = docElem.attributes();
232  for ( int i = 0 ; i < map.length() ; ++i )
233  {
234  if ( map.item( i ).isNull() )
235  continue;
236 
237  const QDomNode attrNode = map.item( i );
238  const QDomAttr attr = attrNode.toAttr();
239  if ( attr.isNull() )
240  continue;
241 
242  const QString attrName = attr.name();
243  if ( attrName.startsWith( "xmlns" ) || attrName.startsWith( "xsi:" ) )
244  continue;
245 
246  mRequest.setParameter( attrName.toUpper(), attr.value() );
247  }
248  mRequest.setParameter( QStringLiteral( "REQUEST_BODY" ), inputString );
249  }
250  }
251  else
252  {
253  setupParameters();
254  }
255 
256 }
257 
258 void QgsRequestHandler::setParameter( const QString &key, const QString &value )
259 {
260  if ( !( key.isEmpty() || value.isEmpty() ) )
261  {
262  // Warn for potential breaking change if plugin set the MAP parameter
263  // expecting changing the config file path, see PR #9773
264  if ( key.compare( QLatin1String( "MAP" ), Qt::CaseInsensitive ) == 0 )
265  {
266  QgsMessageLog::logMessage( QStringLiteral( "Changing the 'MAP' parameter will have no effect on config path: use QgsSerververInterface::setConfigFilePath instead" ),
267  "Server", Qgis::Warning );
268  }
269  mRequest.setParameter( key, value );
270  }
271 }
272 
273 
274 QString QgsRequestHandler::parameter( const QString &key ) const
275 {
276  return mRequest.parameter( key );
277 }
278 
279 void QgsRequestHandler::removeParameter( const QString &key )
280 {
281  mRequest.removeParameter( key );
282 }
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.
QString requestHeader(const QString &name) const
Retrieve request header value.
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.
QString header(const QString &name) const
Returns the header value.
QString parameter(const QString &key, const QString &defaultValue=QString()) const
Gets a parameter value.
QString parameter(const QString &key) const
Returns a request parameter.
QMap< QString, QString > responseHeaders() const
Returns the response headers.
virtual int statusCode() const =0
Returns the http status code.
QByteArray data() const
Returns the request POST data (can be null)
virtual void clear()=0
Reset all headers and content for this response.
QMap< QString, QString > requestHeaders() const
Returns the the Request headers.
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device...
virtual QByteArray data() const
Returns post/put data Check for QByteArray::isNull() to check if data is available.
bool headersSent() const
Returns true if the HTTP headers were already sent to the client.
virtual void removeHeader(const QString &key)=0
Clear header Undo a previous &#39;setHeader&#39; call.
QByteArray body() const
Returns the response body data.
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.
void setResponseHeader(const QString &name, const QString &value)
Sets an HTTP response header.
QMap< QString, QString > headers() const
Returns the header map.
QgsServerRequest::Parameters parameters() const
Returns a map of query parameters with keys converted to uppercase.
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).
QString responseHeader(const QString &name) const
Retrieve response header value.
void setServiceException(const QgsServerException &ex)
Allow plugins to return a QgsMapServiceException.
int statusCode() const
Returns the response http status code.
void appendBody(const QByteArray &body)
Sets the info format string such as "text/xml".
Exception base class for server exceptions.
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 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.
QgsServerRequest::Method method() const
bool exceptionRaised() const
Pointer to last raised exception.
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...
void removeRequestHeader(const QString &name)
Remove an HTTP request header.
QMap< QString, QString > parameterMap() const
Returns the parsed parameters as a key-value pair, to modify a parameter setParameter( const QString ...
void clear()
Clears the response body and headers.
void removeResponseHeader(const QString &name)
Remove an HTTP response header.
QMap< QString, QString > Parameters
QString url() const
Returns the request url.
virtual void flush() SIP_THROW(QgsServerException)
Flushes the current output buffer to the network.