Skip to content

Commit dafbef1

Browse files
authoredJan 15, 2019
Merge pull request #8859 from elpaso/release-3_4-backports
backport of [server] Use REQUEST_URI as default URL for FCGI requests
2 parents 0dbe4d4 + dedbbd4 commit dafbef1

File tree

7 files changed

+162
-55
lines changed

7 files changed

+162
-55
lines changed
 
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/server/qgsfcgiserverrequest.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
12+
13+
class QgsFcgiServerRequest: QgsServerRequest
14+
{
15+
%Docstring
16+
Class defining fcgi request
17+
18+
.. versionadded:: 3.0
19+
%End
20+
21+
%TypeHeaderCode
22+
#include "qgsfcgiserverrequest.h"
23+
%End
24+
public:
25+
QgsFcgiServerRequest();
26+
27+
virtual QByteArray data() const;
28+
29+
30+
bool hasError() const;
31+
%Docstring
32+
Returns true if an error occurred during initialization
33+
%End
34+
35+
virtual QUrl url() const;
36+
37+
%Docstring
38+
39+
:return: the request url
40+
41+
Overrides base implementation because FCGI is typically behind
42+
a proxy server and QGIS Server will see a rewritten QUERY_STRING.
43+
FCGI implementation stores the REQUEST_URI (which is the URL seen
44+
by the proxy before it gets rewritten) and returns it instead of
45+
the rewritten one.
46+
%End
47+
48+
49+
};
50+
51+
/************************************************************************
52+
* This file has been generated automatically from *
53+
* *
54+
* src/server/qgsfcgiserverrequest.h *
55+
* *
56+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
57+
************************************************************************/

‎python/server/auto_generated/qgsserverrequest.sip.in

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,14 @@ Constructor
5656

5757
virtual ~QgsServerRequest();
5858

59-
QUrl url() const;
59+
virtual QUrl url() const;
6060
%Docstring
6161

6262
:return: the request url
63+
64+
Subclasses may override in case the original URL (not rewritten, e.g.from
65+
a web server rewrite module) needs to be returned instead of the URL
66+
seen by QGIS server.
6367
%End
6468

6569
QgsServerRequest::Method method() const;

‎python/server/server_auto.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
%Include auto_generated/qgsserverparameters.sip
99
%Include auto_generated/qgsbufferserverrequest.sip
1010
%Include auto_generated/qgsbufferserverresponse.sip
11+
%Include auto_generated/qgsfcgiserverrequest.sip
1112
%Include auto_generated/qgsrequesthandler.sip
1213
%Include auto_generated/qgsserver.sip
1314
%Include auto_generated/qgsserverexception.sip

‎src/server/qgsfcgiserverrequest.cpp

Lines changed: 35 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,11 @@
2929

3030
QgsFcgiServerRequest::QgsFcgiServerRequest()
3131
{
32-
mHasError = false;
33-
34-
// Rebuild the full URL
3532

3633
// Get the REQUEST_URI from the environment
3734
QUrl url;
3835
QString uri = getenv( "REQUEST_URI" );
36+
3937
if ( uri.isEmpty() )
4038
{
4139
uri = getenv( "SCRIPT_NAME" );
@@ -72,9 +70,12 @@ QgsFcgiServerRequest::QgsFcgiServerRequest()
7270
: url.setScheme( QStringLiteral( "http" ) );
7371
}
7472

75-
// XXX OGC paremetrs are passed with the query string
76-
// we override the query string url in case it is
77-
// defined independently of REQUEST_URI
73+
// Store the URL before the server rewrite that could have been set in QUERY_STRING
74+
mOriginalUrl = url;
75+
76+
// OGC parameters are passed with the query string, which is normally part of
77+
// the REQUEST_URI, we override the query string url in case it is defined
78+
// independently of REQUEST_URI
7879
const char *qs = getenv( "QUERY_STRING" );
7980
if ( qs )
8081
{
@@ -132,6 +133,11 @@ QByteArray QgsFcgiServerRequest::data() const
132133
return mData;
133134
}
134135

136+
QUrl QgsFcgiServerRequest::url() const
137+
{
138+
return mOriginalUrl.isEmpty() ? QgsServerRequest::url() : mOriginalUrl;
139+
}
140+
135141
// Read post put data
136142
void QgsFcgiServerRequest::readData()
137143
{
@@ -168,48 +174,28 @@ void QgsFcgiServerRequest::readData()
168174
void QgsFcgiServerRequest::printRequestInfos()
169175
{
170176
QgsMessageLog::logMessage( QStringLiteral( "******************** New request ***************" ), QStringLiteral( "Server" ), Qgis::Info );
171-
if ( getenv( "REMOTE_ADDR" ) )
172-
{
173-
QgsMessageLog::logMessage( "REMOTE_ADDR: " + QString( getenv( "REMOTE_ADDR" ) ), QStringLiteral( "Server" ), Qgis::Info );
174-
}
175-
if ( getenv( "REMOTE_HOST" ) )
176-
{
177-
QgsMessageLog::logMessage( "REMOTE_HOST: " + QString( getenv( "REMOTE_HOST" ) ), QStringLiteral( "Server" ), Qgis::Info );
178-
}
179-
if ( getenv( "REMOTE_USER" ) )
180-
{
181-
QgsMessageLog::logMessage( "REMOTE_USER: " + QString( getenv( "REMOTE_USER" ) ), QStringLiteral( "Server" ), Qgis::Info );
182-
}
183-
if ( getenv( "REMOTE_IDENT" ) )
184-
{
185-
QgsMessageLog::logMessage( "REMOTE_IDENT: " + QString( getenv( "REMOTE_IDENT" ) ), QStringLiteral( "Server" ), Qgis::Info );
186-
}
187-
if ( getenv( "CONTENT_TYPE" ) )
188-
{
189-
QgsMessageLog::logMessage( "CONTENT_TYPE: " + QString( getenv( "CONTENT_TYPE" ) ), QStringLiteral( "Server" ), Qgis::Info );
190-
}
191-
if ( getenv( "AUTH_TYPE" ) )
192-
{
193-
QgsMessageLog::logMessage( "AUTH_TYPE: " + QString( getenv( "AUTH_TYPE" ) ), QStringLiteral( "Server" ), Qgis::Info );
194-
}
195-
if ( getenv( "HTTP_USER_AGENT" ) )
196-
{
197-
QgsMessageLog::logMessage( "HTTP_USER_AGENT: " + QString( getenv( "HTTP_USER_AGENT" ) ), QStringLiteral( "Server" ), Qgis::Info );
198-
}
199-
if ( getenv( "HTTP_PROXY" ) )
200-
{
201-
QgsMessageLog::logMessage( "HTTP_PROXY: " + QString( getenv( "HTTP_PROXY" ) ), QStringLiteral( "Server" ), Qgis::Info );
202-
}
203-
if ( getenv( "HTTPS_PROXY" ) )
204-
{
205-
QgsMessageLog::logMessage( "HTTPS_PROXY: " + QString( getenv( "HTTPS_PROXY" ) ), QStringLiteral( "Server" ), Qgis::Info );
206-
}
207-
if ( getenv( "NO_PROXY" ) )
208-
{
209-
QgsMessageLog::logMessage( "NO_PROXY: " + QString( getenv( "NO_PROXY" ) ), QStringLiteral( "Server" ), Qgis::Info );
210-
}
211-
if ( getenv( "HTTP_AUTHORIZATION" ) )
212-
{
213-
QgsMessageLog::logMessage( "HTTP_AUTHORIZATION: " + QString( getenv( "HTTP_AUTHORIZATION" ) ), QStringLiteral( "Server" ), Qgis::Info );
177+
178+
const QStringList envVars
179+
{
180+
QStringLiteral( "SERVER_NAME" ),
181+
QStringLiteral( "REQUEST_URI" ),
182+
QStringLiteral( "REMOTE_ADDR" ),
183+
QStringLiteral( "REMOTE_HOST" ),
184+
QStringLiteral( "REMOTE_USER" ),
185+
QStringLiteral( "REMOTE_IDENT" ),
186+
QStringLiteral( "CONTENT_TYPE" ),
187+
QStringLiteral( "AUTH_TYPE" ),
188+
QStringLiteral( "HTTP_USER_AGENT" ),
189+
QStringLiteral( "HTTP_PROXY" ),
190+
QStringLiteral( "NO_PROXY" ),
191+
QStringLiteral( "HTTP_AUTHORIZATION" )
192+
};
193+
194+
for ( const auto &envVar : envVars )
195+
{
196+
if ( getenv( envVar.toStdString().c_str() ) )
197+
{
198+
QgsMessageLog::logMessage( envVar + QString( getenv( envVar.toStdString().c_str() ) ), QStringLiteral( "Server" ), Qgis::Info );
199+
}
214200
}
215201
}

‎src/server/qgsfcgiserverrequest.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#ifndef QGSFCGISERVERREQUEST_H
2020
#define QGSFCGISERVERREQUEST_H
2121

22-
#define SIP_NO_FILE
23-
2422

2523
#include "qgsserverrequest.h"
2624

@@ -44,6 +42,18 @@ class SERVER_EXPORT QgsFcgiServerRequest: public QgsServerRequest
4442
*/
4543
bool hasError() const { return mHasError; }
4644

45+
/**
46+
* \returns the request url
47+
*
48+
* Overrides base implementation because FCGI is typically behind
49+
* a proxy server and QGIS Server will see a rewritten QUERY_STRING.
50+
* FCGI implementation stores the REQUEST_URI (which is the URL seen
51+
* by the proxy before it gets rewritten) and returns it instead of
52+
* the rewritten one.
53+
*/
54+
QUrl url() const override;
55+
56+
4757
private:
4858
void readData();
4959

@@ -53,7 +63,9 @@ class SERVER_EXPORT QgsFcgiServerRequest: public QgsServerRequest
5363

5464

5565
QByteArray mData;
56-
bool mHasError;
66+
bool mHasError = false;
67+
//! Url before the server rewrite
68+
QUrl mOriginalUrl;
5769
};
5870

5971
#endif

‎src/server/qgsserverrequest.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,12 @@ class SERVER_EXPORT QgsServerRequest
8383

8484
/**
8585
* \returns the request url
86+
*
87+
* Subclasses may override in case the original URL (not rewritten, e.g.from
88+
* a web server rewrite module) needs to be returned instead of the URL
89+
* seen by QGIS server.
8690
*/
87-
QUrl url() const;
91+
virtual QUrl url() const;
8892

8993
/**
9094
* \returns the request method

‎tests/src/python/test_qgsserver_request.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
1111
"""
1212
import unittest
13+
import os
14+
from urllib.parse import parse_qs, urlparse
1315

1416
__author__ = 'Alessandro Pasotti'
1517
__date__ = '29/04/2017'
@@ -19,7 +21,7 @@
1921

2022

2123
from qgis.PyQt.QtCore import QUrl
22-
from qgis.server import QgsServerRequest
24+
from qgis.server import QgsServerRequest, QgsFcgiServerRequest
2325

2426

2527
class QgsServerRequestTest(unittest.TestCase):
@@ -66,6 +68,47 @@ def test_requestMethod(self):
6668
request.setMethod(QgsServerRequest.PostMethod)
6769
self.assertEqual(request.method(), QgsServerRequest.PostMethod)
6870

71+
def test_fcgiRequest(self):
72+
"""Test various combinations of FCGI env parameters with rewritten urls"""
73+
74+
def _test_url(url, env={}):
75+
for k in ('QUERY_STRING', 'REQUEST_URI', 'SERVER_NAME', 'SERVER_PORT', 'SCRIPT_NAME'):
76+
try:
77+
del os.environ[k]
78+
except KeyError:
79+
pass
80+
try:
81+
os.environ[k] = env[k]
82+
except KeyError:
83+
pass
84+
request = QgsFcgiServerRequest()
85+
self.assertEqual(request.url().toString(), url)
86+
# Check MAP
87+
if 'QUERY_STRING' in env:
88+
map = {k.upper(): v[0] for k, v in parse_qs(env['QUERY_STRING']).items()}['MAP']
89+
else:
90+
map = {k.upper(): v[0] for k, v in parse_qs(urlparse(env['REQUEST_URI']).query).items()}['MAP']
91+
self.assertEqual(request.parameter('MAP'), map)
92+
93+
_test_url('http://somesite.com/somepath/index.html?map=/my/path.qgs', {
94+
'REQUEST_URI': '/somepath/index.html?map=/my/path.qgs',
95+
'SERVER_NAME': 'somesite.com',
96+
})
97+
_test_url('http://somesite.com/somepath?map=/my/path.qgs', {
98+
'REQUEST_URI': '/somepath?map=/my/path.qgs',
99+
'SERVER_NAME': 'somesite.com',
100+
})
101+
_test_url('http://somesite.com/somepath/path', {
102+
'REQUEST_URI': '/somepath/path',
103+
'SERVER_NAME': 'somesite.com',
104+
'QUERY_STRING': 'map=/my/path.qgs'
105+
})
106+
_test_url('http://somesite.com/somepath/path/?token=QGIS2019', {
107+
'REQUEST_URI': '/somepath/path/?token=QGIS2019',
108+
'SERVER_NAME': 'somesite.com',
109+
'QUERY_STRING': 'map=/my/path.qgs',
110+
})
111+
69112

70113
if __name__ == '__main__':
71114
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.