Permalink
Browse files

Merge branch 'maintenance' into devel

  • Loading branch information...
2 parents e847b35 + 2952b26 commit d28e0988fb5fe1e1dd34152bd955863e7c762a3e @foosel committed Nov 7, 2016
Showing with 138 additions and 4 deletions.
  1. +49 −3 src/octoprint/server/util/flask.py
  2. +89 −1 tests/server/util/flask.py
@@ -236,6 +236,15 @@ def to_header_candidates(values):
to_wsgi_format = lambda header: "HTTP_" + header.upper().replace("-", "_")
return map(to_wsgi_format, values)
+ @staticmethod
+ def valid_ip(address):
+ import netaddr
+ try:
+ netaddr.IPAddress(address)
+ return True
+ except:
+ return False
+
def __init__(self,
header_prefix=None,
header_scheme=None,
@@ -290,11 +299,43 @@ def host_to_server_and_port(host, scheme):
if host is None:
return None, None
+ default_port = "443" if scheme == "https" else "80"
+ host = host.strip()
+
if ":" in host:
- server, port = host.split(":", 1)
+ # we might have an ipv6 address here, or a port, or both
+
+ if host[0] == "[":
+ # that looks like an ipv6 address with port, e.g. [fec1::1]:80
+ address_end = host.find("]")
+ if address_end == -1:
+ # no ], that looks like a seriously broken address
+ return None, None
+
+ # extract server ip, skip enclosing [ and ]
+ server = host[1:address_end]
+ tail = host[address_end + 1:]
+
+ # now check if there's also a port
+ if len(tail) and tail[0] == ":":
+ # port included as well
+ port = tail[1:]
+ else:
+ # no port, use default one
+ port = default_port
+
+ elif self.__class__.valid_ip(host):
+ # ipv6 address without port
+ server = host
+ port = default_port
+
+ else:
+ # ipv4 address with port
+ server, port = host.rsplit(":", 1)
+
else:
server = host
- port = "443" if scheme == "https" else "80"
+ port = default_port
return server, port
@@ -352,7 +393,12 @@ def host_to_server_and_port(host, scheme):
# default port for scheme, can be skipped
environ["HTTP_HOST"] = environ["SERVER_NAME"]
else:
- environ["HTTP_HOST"] = environ["SERVER_NAME"] + ":" + environ["SERVER_PORT"]
+ server_name_component = environ["SERVER_NAME"]
+ if ":" in server_name_component and self.__class__.valid_ip(server_name_component):
+ # this is an ipv6 address, we need to wrap that in [ and ] before appending the port
+ server_name_component = "[" + server_name_component + "]"
+
+ environ["HTTP_HOST"] = server_name_component + ":" + environ["SERVER_PORT"]
# call wrapped app with rewritten environment
return environ
@@ -143,7 +143,95 @@ class ReverseProxiedEnvironmentTest(unittest.TestCase):
"HTTP_HOST": "example.com",
"SERVER_NAME": "example.com",
"SERVER_PORT": "80"
- })
+ }),
+
+ # host = none, default port -> server & port used for reconstruction (ipv4)
+ ({
+ "HTTP_HOST": None,
+ "SERVER_NAME": "127.0.0.1",
+ "SERVER_PORT": "80"
+ }, {
+ "HTTP_HOST": "127.0.0.1",
+ "SERVER_NAME": "127.0.0.1",
+ "SERVER_PORT": "80"
+ }),
+
+ # host = none, non standard port -> server & port used for reconstruction (ipv4)
+ ({
+ "HTTP_HOST": None,
+ "SERVER_NAME": "127.0.0.1",
+ "SERVER_PORT": "444"
+ }, {
+ "HTTP_HOST": "127.0.0.1:444",
+ "SERVER_NAME": "127.0.0.1",
+ "SERVER_PORT": "444"
+ }),
+
+ # host = none, default port -> server & port used for reconstruction (ipv6)
+ ({
+ "HTTP_HOST": None,
+ "SERVER_NAME": "fec1::1",
+ "SERVER_PORT": "80"
+ }, {
+ "HTTP_HOST": "fec1::1",
+ "SERVER_NAME": "fec1::1",
+ "SERVER_PORT": "80"
+ }),
+
+ # host = none, non standard port -> server & port used for reconstruction (ipv6)
+ ({
+ "HTTP_HOST": None,
+ "SERVER_NAME": "fec1::1",
+ "SERVER_PORT": "444"
+ }, {
+ "HTTP_HOST": "[fec1::1]:444",
+ "SERVER_NAME": "fec1::1",
+ "SERVER_PORT": "444"
+ }),
+
+ # host set, server and port not, default port -> server & port derived from host (ipv4)
+ ({
+ "HTTP_HOST": "127.0.0.1",
+ "SERVER_NAME": None,
+ "SERVER_PORT": None
+ }, {
+ "HTTP_HOST": "127.0.0.1",
+ "SERVER_NAME": "127.0.0.1",
+ "SERVER_PORT": "80"
+ }),
+
+ # host set, server and port not, non standard port -> server & port derived from host (ipv4)
+ ({
+ "HTTP_HOST": "127.0.0.1:444",
+ "SERVER_NAME": None,
+ "SERVER_PORT": None
+ }, {
+ "HTTP_HOST": "127.0.0.1:444",
+ "SERVER_NAME": "127.0.0.1",
+ "SERVER_PORT": "444"
+ }),
+
+ # host set, server and port not, default port -> server & port derived from host (ipv6)
+ ({
+ "HTTP_HOST": "fec1::1",
+ "SERVER_NAME": None,
+ "SERVER_PORT": None
+ }, {
+ "HTTP_HOST": "fec1::1",
+ "SERVER_NAME": "fec1::1",
+ "SERVER_PORT": "80"
+ }),
+
+ # host set, server and port not, non standard port -> server & port derived from host (ipv6)
+ ({
+ "HTTP_HOST": "[fec1::1]:444",
+ "SERVER_NAME": None,
+ "SERVER_PORT": None
+ }, {
+ "HTTP_HOST": "[fec1::1]:444",
+ "SERVER_NAME": "fec1::1",
+ "SERVER_PORT": "444"
+ }),
)
@unpack
def test_stock(self, environ, expected):

0 comments on commit d28e098

Please sign in to comment.