QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
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 "qgsrequesthandler.h"
21
22#include "qgis.h"
23#include "qgsmessagelog.h"
24#include "qgsserverrequest.h"
25#include "qgsserverresponse.h"
26
27#include <QByteArray>
28#include <QDomDocument>
29#include <QString>
30#include <QUrl>
31#include <QUrlQuery>
32
33using namespace Qt::StringLiterals;
34
36 : mRequest( request )
37 , mResponse( response )
38{
39}
40
41QMap<QString, QString> QgsRequestHandler::parameterMap() const
42{
43 return mRequest.parameters();
44}
45
47{
48 return mExceptionRaised;
49}
50
51void QgsRequestHandler::setResponseHeader( const QString &name, const QString &value )
52{
53 mResponse.setHeader( name, value );
54}
55
57{
58 mResponse.clear();
59}
60
61void QgsRequestHandler::removeResponseHeader( const QString &name )
62{
63 mResponse.removeHeader( name );
64}
65
66QString QgsRequestHandler::responseHeader( const QString &name ) const
67{
68 return mResponse.header( name );
69}
70
71QMap<QString, QString> QgsRequestHandler::responseHeaders() const
72{
73 return mResponse.headers();
74}
75
76void QgsRequestHandler::setRequestHeader( const QString &name, const QString &value )
77{
78 mRequest.setHeader( name, value );
79}
80
81void QgsRequestHandler::removeRequestHeader( const QString &name )
82{
83 mRequest.removeHeader( name );
84}
85
86QString QgsRequestHandler::requestHeader( const QString &name ) const
87{
88 return mRequest.header( name );
89}
90
91
92QMap<QString, QString> QgsRequestHandler::requestHeaders() const
93{
94 return mRequest.headers();
95}
96
97
99{
100 return mResponse.headersSent();
101}
102
103void QgsRequestHandler::appendBody( const QByteArray &body )
104{
105 mResponse.write( body );
106}
107
109{
110 mResponse.truncate();
111}
112
113QByteArray QgsRequestHandler::body() const
114{
115 return mResponse.data();
116}
117
118QByteArray QgsRequestHandler::data() const
119{
120 return mRequest.data();
121}
122
124{
125 return mRequest.url().toString();
126}
127
129{
130 return mRequest.url().path();
131}
132
134{
135 mResponse.setStatusCode( code );
136}
137
139{
140 return mResponse.statusCode();
141}
142
144{
145 // Send data to output
146 mResponse.flush();
147}
148
150{
151 // Safety measure to avoid potential leaks if called repeatedly
152 mExceptionRaised = true;
153 mResponse.write( ex );
154}
155
156void QgsRequestHandler::setupParameters()
157{
158 const QgsServerRequest::Parameters parameters = mRequest.parameters();
159
160 //feature info format?
161 const QString infoFormat = parameters.value( u"INFO_FORMAT"_s );
162 if ( !infoFormat.isEmpty() )
163 {
164 mFormat = infoFormat;
165 }
166 else //capabilities format or GetMap format
167 {
168 mFormatString = parameters.value( u"FORMAT"_s );
169 QString formatString = mFormatString;
170 if ( !formatString.isEmpty() )
171 {
172 //remove the image/ in front of the format
173 if ( formatString.contains( "image/png"_L1, Qt::CaseInsensitive ) || formatString.compare( "png"_L1, Qt::CaseInsensitive ) == 0 )
174 {
175 formatString = u"PNG"_s;
176 }
177 else if ( formatString.contains( "image/jpeg"_L1, Qt::CaseInsensitive ) || formatString.contains( "image/jpg"_L1, Qt::CaseInsensitive )
178 || formatString.compare( "jpg"_L1, Qt::CaseInsensitive ) == 0 )
179 {
180 formatString = u"JPG"_s;
181 }
182 else if ( formatString.compare( "svg"_L1, Qt::CaseInsensitive ) == 0 )
183 {
184 formatString = u"SVG"_s;
185 }
186 else if ( formatString.contains( "pdf"_L1, Qt::CaseInsensitive ) )
187 {
188 formatString = u"PDF"_s;
189 }
190
191 mFormat = formatString;
192 }
193 }
194}
195
197{
198 if ( mRequest.method() == QgsServerRequest::PostMethod || mRequest.method() == QgsServerRequest::PutMethod || mRequest.method() == QgsServerRequest::PatchMethod )
199 {
200 if ( mRequest.header( u"Content-Type"_s ).contains( u"json"_s ) )
201 {
202 setupParameters();
203 }
204 else
205 {
206 QString inputString( mRequest.data() );
207 QDomDocument doc;
208 QString errorMsg;
209 int line = -1;
210 int column = -1;
211 if ( !doc.setContent( inputString, true, &errorMsg, &line, &column ) )
212 {
213 // Output Warning about POST without XML content
214 QgsMessageLog::logMessage( u"Error parsing post data as XML: at line %1, column %2: %3. Assuming urlencoded query string sent in the post body."_s.arg( line ).arg( column ).arg( errorMsg ), u"Server"_s, Qgis::MessageLevel::Warning );
215
216 // Process input string as a simple query text
217
218 typedef QPair<QString, QString> pair_t;
219 const QUrlQuery query( inputString );
220 const QList<pair_t> items = query.queryItems();
221 for ( const pair_t &pair : items )
222 {
223 mRequest.setParameter( pair.first, pair.second );
224 }
225 setupParameters();
226 }
227 else
228 {
229 // we have an XML document
230
231 setupParameters();
232
233 const QDomElement docElem = doc.documentElement();
234 // the document element tag name is the request
235 mRequest.setParameter( u"REQUEST"_s, docElem.tagName() );
236 // loop through the attributes which are the parameters
237 // excepting the attributes started by xmlns or xsi
238 const QDomNamedNodeMap map = docElem.attributes();
239 for ( int i = 0; i < map.length(); ++i )
240 {
241 if ( map.item( i ).isNull() )
242 continue;
243
244 const QDomNode attrNode = map.item( i );
245 const QDomAttr attr = attrNode.toAttr();
246 if ( attr.isNull() )
247 continue;
248
249 const QString attrName = attr.name();
250 if ( attrName.startsWith( "xmlns" ) || attrName.startsWith( "xsi:" ) )
251 continue;
252
253 mRequest.setParameter( attrName.toUpper(), attr.value() );
254 }
255 mRequest.setParameter( u"REQUEST_BODY"_s, inputString.replace( '+', "%2B"_L1 ) );
256 }
257 }
258 }
259 else
260 {
261 setupParameters();
262 }
263}
264
265void QgsRequestHandler::setParameter( const QString &key, const QString &value )
266{
267 if ( !( key.isEmpty() || value.isEmpty() ) )
268 {
269 // Warn for potential breaking change if plugin set the MAP parameter
270 // expecting changing the config file path, see PR #9773
271 if ( key.compare( "MAP"_L1, Qt::CaseInsensitive ) == 0 )
272 {
273 QgsMessageLog::logMessage( u"Changing the 'MAP' parameter will have no effect on config path: use QgsSerververInterface::setConfigFilePath instead"_s, u"Server"_s, Qgis::MessageLevel::Warning );
274 }
275 mRequest.setParameter( key, value );
276 }
277}
278
279
280QString QgsRequestHandler::parameter( const QString &key ) const
281{
282 return mRequest.parameter( key );
283}
284
285void QgsRequestHandler::removeParameter( const QString &key )
286{
287 mRequest.removeParameter( key );
288}
@ Warning
Warning message.
Definition qgis.h:161
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
void removeParameter(const QString &key)
Remove a request parameter.
void removeRequestHeader(const QString &name)
Remove an HTTP request header.
QString responseHeader(const QString &name) const
Retrieve response header value.
void clearBody()
Clear response buffer.
QString requestHeader(const QString &name) const
Retrieve request header value.
QMap< QString, QString > parameterMap() const
Returns the parsed parameters as a key-value pair.
QString path() const
Returns the path component of the request URL.
QByteArray data() const
Returns the request POST data (can be null).
bool exceptionRaised() const
Pointer to last raised exception.
bool headersSent() const
Returns true if the HTTP headers were already sent to the client.
void parseInput()
Parses the input and creates a request neutral Parameter/Value map.
void setServiceException(const QgsServerException &ex)
Allow plugins to return a QgsMapServiceException.
void removeResponseHeader(const QString &name)
Remove an HTTP response header.
void sendResponse()
Send out HTTP headers and flush output buffer.
QMap< QString, QString > responseHeaders() const
Returns the response headers.
void setRequestHeader(const QString &name, const QString &value)
Sets an HTTP request header.
void appendBody(const QByteArray &body)
Sets the info format string such as "text/xml".
QString parameter(const QString &key) const
Returns a request parameter.
QMap< QString, QString > requestHeaders() const
Returns the the Request headers.
QString url() const
Returns the request url.
void setStatusCode(int code)
Sets response http status code.
QgsRequestHandler(QgsServerRequest &request, QgsServerResponse &response)
Constructor.
QByteArray body() const
Returns the response body data.
void clear()
Clears the response body and headers.
void setResponseHeader(const QString &name, const QString &value)
Sets an HTTP response header.
int statusCode() const
Returns the response http status code.
void setParameter(const QString &key, const QString &value)
Sets a request parameter.
Exception base class for server exceptions.
Defines requests passed to QgsService classes.
QgsServerRequest::Parameters parameters() const
Returns a map of query parameters with keys converted to uppercase.
QMap< QString, QString > Parameters
Defines the response interface passed to QgsService.