Reverse proxy wrapper now supports configuration of the http headers to utilize for determining prefix and scheme
Introduced two new configuration settings, server.reverseProxy.prefixHeader and server.reverseProxy.schemeHeader to define the headers to evaluate for prefix and scheme to use respectively, also moved server.baseUrl and server.scheme to server.reverseProxy.fallbackPrefix and server.reverseProxy.fallbackScheme. Also fixed SockJS URI as generated in index.jinja to include BASE_URL. Should do what PR #507 intended, but with less code duplication.
This commit is contained in:
parent
02212bde21
commit
17d3d9deb7
4 changed files with 76 additions and 20 deletions
|
|
@ -153,7 +153,13 @@ class Server():
|
|||
except AttributeError, e:
|
||||
logger.exception("Could not instantiate user manager %s, will run with accessControl disabled!" % userManagerName)
|
||||
|
||||
app.wsgi_app = util.ReverseProxied(app.wsgi_app)
|
||||
app.wsgi_app = util.ReverseProxied(
|
||||
app.wsgi_app,
|
||||
settings().get(["server", "reverseProxy", "prefixHeader"]),
|
||||
settings().get(["server", "reverseProxy", "schemeHeader"]),
|
||||
settings().get(["server", "reverseProxy", "prefixFallback"]),
|
||||
settings().get(["server", "reverseProxy", "prefixScheme"])
|
||||
)
|
||||
|
||||
app.secret_key = "k3PuVYgtxNm8DXKKTw2nWmFQQun9qceV"
|
||||
loginManager = LoginManager()
|
||||
|
|
|
|||
|
|
@ -72,29 +72,43 @@ class ReverseProxied(object):
|
|||
:param app: the WSGI application
|
||||
:param header_script_name: the HTTP header in the wsgi environment from which to determine the prefix
|
||||
:param header_scheme: the HTTP header in the wsgi environment from which to determine the scheme
|
||||
:param base_url: the prefix to use as fallback if headers are not set
|
||||
"""
|
||||
|
||||
def __init__(self, app, header_script_name="HTTP_X_SCRIPT_NAME", header_scheme="HTTP_X_SCHEME"):
|
||||
def __init__(self, app, header_prefix="x-script-name", header_scheme="x-scheme", base_url="", scheme=""):
|
||||
self.app = app
|
||||
self._header_script_name = header_script_name
|
||||
self._header_scheme = header_scheme
|
||||
|
||||
# headers for prefix & scheme, converted to conform to WSGI format
|
||||
to_wsgi_format = lambda header: "HTTP_" + header.upper().replace("-", "_")
|
||||
self._header_prefix = to_wsgi_format(header_prefix)
|
||||
self._header_scheme = to_wsgi_format(header_scheme)
|
||||
|
||||
# fallback prefix & scheme from config
|
||||
self._fallback_prefix = base_url
|
||||
self._fallback_scheme = scheme
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
script_name = environ.get(self._header_script_name, '')
|
||||
if not script_name:
|
||||
script_name = settings().get(["server", "baseUrl"])
|
||||
# determine prefix
|
||||
prefix = environ.get(self._header_prefix, "")
|
||||
if not prefix:
|
||||
prefix = self._fallback_prefix
|
||||
|
||||
if script_name:
|
||||
environ['SCRIPT_NAME'] = script_name
|
||||
path_info = environ['PATH_INFO']
|
||||
if path_info.startswith(script_name):
|
||||
environ['PATH_INFO'] = path_info[len(script_name):]
|
||||
# rewrite SCRIPT_NAME and if necessary also PATH_INFO based on prefix
|
||||
if prefix:
|
||||
environ["SCRIPT_NAME"] = prefix
|
||||
path_info = environ["PATH_INFO"]
|
||||
if path_info.startswith(prefix):
|
||||
environ["PATH_INFO"] = path_info[len(prefix):]
|
||||
|
||||
scheme = environ.get(self._header_scheme, '')
|
||||
# determine scheme
|
||||
scheme = environ.get(self._header_scheme, "")
|
||||
if not scheme:
|
||||
scheme = settings().get(["server", "scheme"])
|
||||
scheme = self._fallback_scheme
|
||||
|
||||
# rewrite wsgi.url_scheme based on scheme
|
||||
if scheme:
|
||||
environ['wsgi.url_scheme'] = scheme
|
||||
environ["wsgi.url_scheme"] = scheme
|
||||
|
||||
# call wrapped app with rewritten environment
|
||||
return self.app(environ, start_response)
|
||||
|
||||
|
|
|
|||
|
|
@ -41,8 +41,12 @@ default_settings = {
|
|||
"host": "0.0.0.0",
|
||||
"port": 5000,
|
||||
"firstRun": True,
|
||||
"baseUrl": "",
|
||||
"scheme": "",
|
||||
"reverseProxy": {
|
||||
"prefixHeader": "X-Script-Name",
|
||||
"schemeHeader": "X-Scheme",
|
||||
"prefixFallback": "",
|
||||
"schemeFallback": ""
|
||||
},
|
||||
"uploads": {
|
||||
"maxSize": 1 * 1024 * 1024 * 1024, # 1GB
|
||||
"nameSuffix": ".name",
|
||||
|
|
@ -198,7 +202,7 @@ class Settings(object):
|
|||
if os.path.exists(self._configfile) and os.path.isfile(self._configfile):
|
||||
with open(self._configfile, "r") as f:
|
||||
self._config = yaml.safe_load(f)
|
||||
# chamged from else to handle cases where the file exists, but is empty / 0 bytes
|
||||
# changed from else to handle cases where the file exists, but is empty / 0 bytes
|
||||
if not self._config:
|
||||
self._config = {}
|
||||
|
||||
|
|
@ -209,6 +213,36 @@ class Settings(object):
|
|||
if not self._config:
|
||||
return
|
||||
|
||||
dirty = False
|
||||
for migrate in (self._migrate_event_config, self._migrate_reverse_proxy_config):
|
||||
dirty = migrate() or dirty
|
||||
if dirty:
|
||||
self.save(force=True)
|
||||
|
||||
def _migrate_reverse_proxy_config(self):
|
||||
if "server" in self._config.keys() and ("baseUrl" in self._config["server"] or "scheme" in self._config["server"]):
|
||||
prefix = ""
|
||||
if "baseUrl" in self._config["server"]:
|
||||
prefix = self._config["server"]["baseUrl"]
|
||||
del self._config["server"]["baseUrl"]
|
||||
|
||||
scheme = ""
|
||||
if "scheme" in self._config["server"]:
|
||||
scheme = self._config["server"]["scheme"]
|
||||
del self._config["server"]["scheme"]
|
||||
|
||||
if not "reverseProxy" in self._config["server"] or not isinstance(self._config["server"]["reverseProxy"], dict):
|
||||
self._config["server"]["reverseProxy"] = dict()
|
||||
if prefix:
|
||||
self._config["server"]["reverseProxy"]["prefixFallback"] = prefix
|
||||
if scheme:
|
||||
self._config["server"]["reverseProxy"]["schemeFallback"] = scheme
|
||||
self._logger.info("Migrated reverse proxy configuration to new structure")
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def _migrate_event_config(self):
|
||||
if "events" in self._config.keys() and ("gcodeCommandTrigger" in self._config["events"] or "systemCommandTrigger" in self._config["events"]):
|
||||
self._logger.info("Migrating config (event subscriptions)...")
|
||||
|
||||
|
|
@ -290,8 +324,10 @@ class Settings(object):
|
|||
newEvents["subscriptions"].append(newTrigger)
|
||||
|
||||
self._config["events"] = newEvents
|
||||
self.save(force=True)
|
||||
self._logger.info("Migrated %d event subscriptions to new format and structure" % len(newEvents["subscriptions"]))
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def save(self, force=False):
|
||||
if not self._dirty and not force:
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
var CONFIG_GCODE_SIZE_THRESHOLD = {{ gcodeThreshold }};
|
||||
var CONFIG_GCODE_MOBILE_SIZE_THRESHOLD = {{ gcodeMobileThreshold }};
|
||||
|
||||
var SOCKJS_URI = window.location.protocol.slice(0, -1) + "://" + (window.document ? window.document.domain : window.location.hostname) + ":" + window.location.port + "/sockjs";
|
||||
var SOCKJS_URI = window.location.protocol.slice(0, -1) + "://" + (window.document ? window.document.domain : window.location.hostname) + ":" + window.location.port + BASEURL + "sockjs";
|
||||
var SOCKJS_DEBUG = {% if debug -%} true; {% else %} false; {%- endif %}
|
||||
|
||||
var UI_API_KEY = "{{ uiApiKey }}";
|
||||
|
|
|
|||
Loading…
Reference in a new issue