Skip to content

Commit

Permalink
Merge pull request #8859 from elpaso/release-3_4-backports
Browse files Browse the repository at this point in the history
backport of [server] Use REQUEST_URI as default URL for FCGI requests
  • Loading branch information
elpaso committed Jan 15, 2019
2 parents 0dbe4d4 + dedbbd4 commit dafbef1
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 55 deletions.
57 changes: 57 additions & 0 deletions python/server/auto_generated/qgsfcgiserverrequest.sip.in
@@ -0,0 +1,57 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/server/qgsfcgiserverrequest.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/





class QgsFcgiServerRequest: QgsServerRequest
{
%Docstring
Class defining fcgi request

.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsfcgiserverrequest.h"
%End
public:
QgsFcgiServerRequest();

virtual QByteArray data() const;


bool hasError() const;
%Docstring
Returns true if an error occurred during initialization
%End

virtual QUrl url() const;

%Docstring

:return: the request url

Overrides base implementation because FCGI is typically behind
a proxy server and QGIS Server will see a rewritten QUERY_STRING.
FCGI implementation stores the REQUEST_URI (which is the URL seen
by the proxy before it gets rewritten) and returns it instead of
the rewritten one.
%End


};

/************************************************************************
* This file has been generated automatically from *
* *
* src/server/qgsfcgiserverrequest.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
6 changes: 5 additions & 1 deletion python/server/auto_generated/qgsserverrequest.sip.in
Expand Up @@ -56,10 +56,14 @@ Constructor

virtual ~QgsServerRequest();

QUrl url() const;
virtual QUrl url() const;
%Docstring

:return: the request url

Subclasses may override in case the original URL (not rewritten, e.g.from
a web server rewrite module) needs to be returned instead of the URL
seen by QGIS server.
%End

QgsServerRequest::Method method() const;
Expand Down
1 change: 1 addition & 0 deletions python/server/server_auto.sip
Expand Up @@ -8,6 +8,7 @@
%Include auto_generated/qgsserverparameters.sip
%Include auto_generated/qgsbufferserverrequest.sip
%Include auto_generated/qgsbufferserverresponse.sip
%Include auto_generated/qgsfcgiserverrequest.sip
%Include auto_generated/qgsrequesthandler.sip
%Include auto_generated/qgsserver.sip
%Include auto_generated/qgsserverexception.sip
Expand Down
84 changes: 35 additions & 49 deletions src/server/qgsfcgiserverrequest.cpp
Expand Up @@ -29,13 +29,11 @@

QgsFcgiServerRequest::QgsFcgiServerRequest()
{
mHasError = false;

// Rebuild the full URL

// Get the REQUEST_URI from the environment
QUrl url;
QString uri = getenv( "REQUEST_URI" );

if ( uri.isEmpty() )
{
uri = getenv( "SCRIPT_NAME" );
Expand Down Expand Up @@ -72,9 +70,12 @@ QgsFcgiServerRequest::QgsFcgiServerRequest()
: url.setScheme( QStringLiteral( "http" ) );
}

// XXX OGC paremetrs are passed with the query string
// we override the query string url in case it is
// defined independently of REQUEST_URI
// Store the URL before the server rewrite that could have been set in QUERY_STRING
mOriginalUrl = url;

// OGC parameters are passed with the query string, which is normally part of
// the REQUEST_URI, we override the query string url in case it is defined
// independently of REQUEST_URI
const char *qs = getenv( "QUERY_STRING" );
if ( qs )
{
Expand Down Expand Up @@ -132,6 +133,11 @@ QByteArray QgsFcgiServerRequest::data() const
return mData;
}

QUrl QgsFcgiServerRequest::url() const
{
return mOriginalUrl.isEmpty() ? QgsServerRequest::url() : mOriginalUrl;
}

// Read post put data
void QgsFcgiServerRequest::readData()
{
Expand Down Expand Up @@ -168,48 +174,28 @@ void QgsFcgiServerRequest::readData()
void QgsFcgiServerRequest::printRequestInfos()
{
QgsMessageLog::logMessage( QStringLiteral( "******************** New request ***************" ), QStringLiteral( "Server" ), Qgis::Info );
if ( getenv( "REMOTE_ADDR" ) )
{
QgsMessageLog::logMessage( "REMOTE_ADDR: " + QString( getenv( "REMOTE_ADDR" ) ), QStringLiteral( "Server" ), Qgis::Info );
}
if ( getenv( "REMOTE_HOST" ) )
{
QgsMessageLog::logMessage( "REMOTE_HOST: " + QString( getenv( "REMOTE_HOST" ) ), QStringLiteral( "Server" ), Qgis::Info );
}
if ( getenv( "REMOTE_USER" ) )
{
QgsMessageLog::logMessage( "REMOTE_USER: " + QString( getenv( "REMOTE_USER" ) ), QStringLiteral( "Server" ), Qgis::Info );
}
if ( getenv( "REMOTE_IDENT" ) )
{
QgsMessageLog::logMessage( "REMOTE_IDENT: " + QString( getenv( "REMOTE_IDENT" ) ), QStringLiteral( "Server" ), Qgis::Info );
}
if ( getenv( "CONTENT_TYPE" ) )
{
QgsMessageLog::logMessage( "CONTENT_TYPE: " + QString( getenv( "CONTENT_TYPE" ) ), QStringLiteral( "Server" ), Qgis::Info );
}
if ( getenv( "AUTH_TYPE" ) )
{
QgsMessageLog::logMessage( "AUTH_TYPE: " + QString( getenv( "AUTH_TYPE" ) ), QStringLiteral( "Server" ), Qgis::Info );
}
if ( getenv( "HTTP_USER_AGENT" ) )
{
QgsMessageLog::logMessage( "HTTP_USER_AGENT: " + QString( getenv( "HTTP_USER_AGENT" ) ), QStringLiteral( "Server" ), Qgis::Info );
}
if ( getenv( "HTTP_PROXY" ) )
{
QgsMessageLog::logMessage( "HTTP_PROXY: " + QString( getenv( "HTTP_PROXY" ) ), QStringLiteral( "Server" ), Qgis::Info );
}
if ( getenv( "HTTPS_PROXY" ) )
{
QgsMessageLog::logMessage( "HTTPS_PROXY: " + QString( getenv( "HTTPS_PROXY" ) ), QStringLiteral( "Server" ), Qgis::Info );
}
if ( getenv( "NO_PROXY" ) )
{
QgsMessageLog::logMessage( "NO_PROXY: " + QString( getenv( "NO_PROXY" ) ), QStringLiteral( "Server" ), Qgis::Info );
}
if ( getenv( "HTTP_AUTHORIZATION" ) )
{
QgsMessageLog::logMessage( "HTTP_AUTHORIZATION: " + QString( getenv( "HTTP_AUTHORIZATION" ) ), QStringLiteral( "Server" ), Qgis::Info );

const QStringList envVars
{
QStringLiteral( "SERVER_NAME" ),
QStringLiteral( "REQUEST_URI" ),
QStringLiteral( "REMOTE_ADDR" ),
QStringLiteral( "REMOTE_HOST" ),
QStringLiteral( "REMOTE_USER" ),
QStringLiteral( "REMOTE_IDENT" ),
QStringLiteral( "CONTENT_TYPE" ),
QStringLiteral( "AUTH_TYPE" ),
QStringLiteral( "HTTP_USER_AGENT" ),
QStringLiteral( "HTTP_PROXY" ),
QStringLiteral( "NO_PROXY" ),
QStringLiteral( "HTTP_AUTHORIZATION" )
};

for ( const auto &envVar : envVars )
{
if ( getenv( envVar.toStdString().c_str() ) )
{
QgsMessageLog::logMessage( envVar + QString( getenv( envVar.toStdString().c_str() ) ), QStringLiteral( "Server" ), Qgis::Info );
}
}
}
18 changes: 15 additions & 3 deletions src/server/qgsfcgiserverrequest.h
Expand Up @@ -19,8 +19,6 @@
#ifndef QGSFCGISERVERREQUEST_H
#define QGSFCGISERVERREQUEST_H

#define SIP_NO_FILE


#include "qgsserverrequest.h"

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

/**
* \returns the request url
*
* Overrides base implementation because FCGI is typically behind
* a proxy server and QGIS Server will see a rewritten QUERY_STRING.
* FCGI implementation stores the REQUEST_URI (which is the URL seen
* by the proxy before it gets rewritten) and returns it instead of
* the rewritten one.
*/
QUrl url() const override;


private:
void readData();

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


QByteArray mData;
bool mHasError;
bool mHasError = false;
//! Url before the server rewrite
QUrl mOriginalUrl;
};

#endif
6 changes: 5 additions & 1 deletion src/server/qgsserverrequest.h
Expand Up @@ -83,8 +83,12 @@ class SERVER_EXPORT QgsServerRequest

/**
* \returns the request url
*
* Subclasses may override in case the original URL (not rewritten, e.g.from
* a web server rewrite module) needs to be returned instead of the URL
* seen by QGIS server.
*/
QUrl url() const;
virtual QUrl url() const;

/**
* \returns the request method
Expand Down
45 changes: 44 additions & 1 deletion tests/src/python/test_qgsserver_request.py
Expand Up @@ -10,6 +10,8 @@
"""
import unittest
import os
from urllib.parse import parse_qs, urlparse

__author__ = 'Alessandro Pasotti'
__date__ = '29/04/2017'
Expand All @@ -19,7 +21,7 @@


from qgis.PyQt.QtCore import QUrl
from qgis.server import QgsServerRequest
from qgis.server import QgsServerRequest, QgsFcgiServerRequest


class QgsServerRequestTest(unittest.TestCase):
Expand Down Expand Up @@ -66,6 +68,47 @@ def test_requestMethod(self):
request.setMethod(QgsServerRequest.PostMethod)
self.assertEqual(request.method(), QgsServerRequest.PostMethod)

def test_fcgiRequest(self):
"""Test various combinations of FCGI env parameters with rewritten urls"""

def _test_url(url, env={}):
for k in ('QUERY_STRING', 'REQUEST_URI', 'SERVER_NAME', 'SERVER_PORT', 'SCRIPT_NAME'):
try:
del os.environ[k]
except KeyError:
pass
try:
os.environ[k] = env[k]
except KeyError:
pass
request = QgsFcgiServerRequest()
self.assertEqual(request.url().toString(), url)
# Check MAP
if 'QUERY_STRING' in env:
map = {k.upper(): v[0] for k, v in parse_qs(env['QUERY_STRING']).items()}['MAP']
else:
map = {k.upper(): v[0] for k, v in parse_qs(urlparse(env['REQUEST_URI']).query).items()}['MAP']
self.assertEqual(request.parameter('MAP'), map)

_test_url('http://somesite.com/somepath/index.html?map=/my/path.qgs', {
'REQUEST_URI': '/somepath/index.html?map=/my/path.qgs',
'SERVER_NAME': 'somesite.com',
})
_test_url('http://somesite.com/somepath?map=/my/path.qgs', {
'REQUEST_URI': '/somepath?map=/my/path.qgs',
'SERVER_NAME': 'somesite.com',
})
_test_url('http://somesite.com/somepath/path', {
'REQUEST_URI': '/somepath/path',
'SERVER_NAME': 'somesite.com',
'QUERY_STRING': 'map=/my/path.qgs'
})
_test_url('http://somesite.com/somepath/path/?token=QGIS2019', {
'REQUEST_URI': '/somepath/path/?token=QGIS2019',
'SERVER_NAME': 'somesite.com',
'QUERY_STRING': 'map=/my/path.qgs',
})


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

0 comments on commit dafbef1

Please sign in to comment.