[Inteproxy-commits] r192 - in trunk: . inteproxy test

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Thu Sep 10 19:56:28 CEST 2009


Author: bh
Date: 2009-09-10 19:56:25 +0200 (Thu, 10 Sep 2009)
New Revision: 192

Modified:
   trunk/ChangeLog
   trunk/inteproxy/transcoder.py
   trunk/test/test_inteproxy.py
   trunk/test/test_transcoder_map.py
Log:
* inteproxy/transcoder.py (pattern_to_regex): New.  Create regular
expressions for wild-card patterns
(TranscoderMap.__init__): Adapt to wild-card patterns.  A simple
dictionary mapping (host, path) pairs to classnames doesn't work
anymore.  Use a list of tuples with regular expression objects and
the class name.
(TranscoderMap.add_host, TranscoderMap.lookup)
(TranscoderMap.rewrite_urls): Adapt to new internal
representation.  Implement the pattern matching

* test/test_transcoder_map.py (TranscoderMapTest): New base class
for transcoder map tests.
(TestTranscoderMapNoWildcards, TestTranscoderMap): Renamed
TestTranscoderMap to TestTranscoderMapNoWildcards and use the new
base class
(TestTranscoderMapWithHostWildcards)
(TestTranscoderMapWithPathWildcards): New classes for transcoder
map tests with wild-cards.

* test/test_inteproxy.py
(TestInteProxyURLRewriting.test_httpproxy_url_rewriting_with_patterns)
(TestInteProxyURLRewriting.test_httpproxy_url_rewriting_with_host_patterns):
New.  Test cases for url-rewriting with wild-cards in the host
configuration


Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2009-09-01 15:45:54 UTC (rev 191)
+++ trunk/ChangeLog	2009-09-10 17:56:25 UTC (rev 192)
@@ -1,3 +1,30 @@
+2009-09-10  Bernhard Herzog  <bh at intevation.de>
+
+	* inteproxy/transcoder.py (pattern_to_regex): New.  Create regular
+	expressions for wild-card patterns
+	(TranscoderMap.__init__): Adapt to wild-card patterns.  A simple
+	dictionary mapping (host, path) pairs to classnames doesn't work
+	anymore.  Use a list of tuples with regular expression objects and
+	the class name.
+	(TranscoderMap.add_host, TranscoderMap.lookup)
+	(TranscoderMap.rewrite_urls): Adapt to new internal
+	representation.  Implement the pattern matching
+
+	* test/test_transcoder_map.py (TranscoderMapTest): New base class
+	for transcoder map tests.
+	(TestTranscoderMapNoWildcards, TestTranscoderMap): Renamed
+	TestTranscoderMap to TestTranscoderMapNoWildcards and use the new
+	base class
+	(TestTranscoderMapWithHostWildcards)
+	(TestTranscoderMapWithPathWildcards): New classes for transcoder
+	map tests with wild-cards.
+
+	* test/test_inteproxy.py
+	(TestInteProxyURLRewriting.test_httpproxy_url_rewriting_with_patterns)
+	(TestInteProxyURLRewriting.test_httpproxy_url_rewriting_with_host_patterns):
+	New.  Test cases for url-rewriting with wild-cards in the host
+	configuration
+
 2009-09-01  Bernhard Herzog  <bh at intevation.de>
 
 	* test/test_transcoder_map.py (TestTranscoderMap.setUp)

Modified: trunk/inteproxy/transcoder.py
===================================================================
--- trunk/inteproxy/transcoder.py	2009-09-01 15:45:54 UTC (rev 191)
+++ trunk/inteproxy/transcoder.py	2009-09-10 17:56:25 UTC (rev 192)
@@ -151,6 +151,17 @@
             request.headers["Authorization"] = basicauth
 
 
+def pattern_to_regex(pattern, character_set="."):
+    """Returns a regular expression string for a wild-card pattern.
+    The wild-card character is '*'.  The character_set argument should
+    be a regular expression matching exactly one of the characters
+    matched by the wild-card character.  The default value of
+    character_set is '.'
+    """
+    wildcard_regex = character_set + "*"
+    return wildcard_regex.join(re.escape(part) for part in pattern.split("*"))
+
+
 class TranscoderMap(object):
 
     """Manages the host specific transcoder settings"""
@@ -163,7 +174,7 @@
         add_class method.  The first item in classes will become the
         default class.
         """
-        self.hostmap = dict()
+        self.hosts = []
         self.classmap = dict()
         self.default_classname = None
 
@@ -189,7 +200,10 @@
         A connection path on host will be done with the appropriate
         transcoder from the class given by classname.
         """
-        self.hostmap[(host, path)] = classname
+        self.hosts.append((re.compile(pattern_to_regex(host,
+                                                       character_set="[^/]")),
+                           re.compile(pattern_to_regex(path)),
+                           classname))
 
     def add_hosts(self, hosts):
         for entry in hosts:
@@ -198,7 +212,14 @@
     def lookup(self, method, host, path):
         """Returns the python class implementing the transcoder for path on host
         """
-        classname = self.hostmap.get((host, path), self.default_classname)
+        for host_regex, path_regex, classname in self.hosts:
+            host_match = host_regex.match(host)
+            if host_match and host_match.group(0) == host:
+                path_match = path_regex.match(path)
+                if path_match and path_match.group(0) == path:
+                    break
+        else:
+            classname = self.default_classname
         return self.classmap[classname][method]
 
     def get_transcoder(self, method, url):
@@ -258,33 +279,22 @@
         messages, usually the log_debug method of the
         InteProxyHTTPRequestHandler.
         """
-        pairs = dict()
-        for (host, path), cls in self.hostmap.items():
-            if not host:
-                log_debug("rewrite_urls: ignoring host %r", host)
-                continue
-            local_url = "%s%s%s" % (prefix, host, path)
-            for protocol in ["http", "https"]:
-                pairs["%s://%s%s" % (protocol, host, path)] = local_url
-        regex = re.compile("(" + "|".join([re.escape(url)
-                                           for url in pairs.keys()])
-                           + ")")
-        rewritten = StringIO()
-        while data:
-            match = regex.search(data)
-            if match:
-                log_debug("rewriting %r to %r at %d",
-                          match.group(0), pairs[match.group(0)], match.start(0))
-                rewritten.write(data[:match.start()])
-                rewritten.write(pairs[match.group(0)])
-                data = data[match.end():]
-            else:
-                rewritten.write(data)
-                data = ""
+        url_patterns = []
+        for host_regex, path_regex, classname in self.hosts:
+            url_patterns.append("%s%s"
+                                % (host_regex.pattern, path_regex.pattern))
+        regex = ("(?:http|https)://(?:"
+                 + "|".join("(" + pattern + ")"
+                            for pattern in url_patterns)
+                 + ")")
 
-        return rewritten.getvalue()
+        def make_inteprox_url(match):
+            url = match.group(match.lastindex)
+            return prefix + url
 
+        return re.sub(regex, make_inteprox_url, data)
 
+
 def create_transcoder_map():
     return TranscoderMap([
         ("identity", IdentityTranscoder, IdentityTranscoder),

Modified: trunk/test/test_inteproxy.py
===================================================================
--- trunk/test/test_inteproxy.py	2009-09-01 15:45:54 UTC (rev 191)
+++ trunk/test/test_inteproxy.py	2009-09-10 17:56:25 UTC (rev 192)
@@ -128,12 +128,22 @@
          "An URL that may be rewritten: https://example.com/a/wms\n"
          "and one that may not: http://example.com/foo\n"
          "and one that may: http://example.com/another/wms\n"),
+        ("/rewrite-04", [("Content-Type", "text/plain")],
+         "An URL that may be rewritten: https://example.com/pattern/wms\n"
+         "and one that may not: http://example.com/wms\n"
+         "and one that may: http://example.com/pattern/bar/baz\n"),
+        ("/rewrite-05", [("Content-Type", "text/plain")],
+         "An URL that may be rewritten: https://data.intevation.de/wms\n"
+         "and one that may not: http://data.intevation.de/gis/wms\n"
+         "and one that may: http://frida.intevation.org/wms/simple\n"),
         ]
 
 
     transcoder_definitions = [
         ("example.com", "/a/wms", "owsproxy"),
         ("example.com", "/another/wms", "owsproxy"),
+        ("example.com", "/pattern/*", "owsproxy"),
+        ("*.intevation.*", "/wms*", "owsproxy"),
         ]
 
     rewrite_urls = True
@@ -188,7 +198,42 @@
                           % (self.server.server_port,
                              self.server.server_port))
 
+    def test_httpproxy_url_rewriting_with_patterns(self):
+        http = httplib.HTTPConnection("localhost", self.server.server_port)
+        http.request("GET",
+                     "http://localhost:%d/localhost:%d/rewrite-04"
+                     % (self.server.server_port,
+                        self.remote_server.server_port))
+        response = http.getresponse()
+        self.assertEquals(response.status, 200)
+        data = response.read()
+        self.assertEquals(data,
+                          "An URL that may be rewritten:"
+                          " http://localhost:%d/example.com/pattern/wms\n"
+                          "and one that may not: http://example.com/wms\n"
+                          "and one that may:"
+                          " http://localhost:%d/example.com/pattern/bar/baz\n"
+                          % (self.server.server_port,
+                             self.server.server_port))
 
+    def test_httpproxy_url_rewriting_with_host_patterns(self):
+        http = httplib.HTTPConnection("localhost", self.server.server_port)
+        http.request("GET",
+                     "http://localhost:%d/localhost:%d/rewrite-05"
+                     % (self.server.server_port,
+                        self.remote_server.server_port))
+        response = http.getresponse()
+        self.assertEquals(response.status, 200)
+        data = response.read()
+        self.assertEquals(data,
+                          "An URL that may be rewritten:"
+                   " http://localhost:%d/data.intevation.de/wms\n"
+                   "and one that may not: http://data.intevation.de/gis/wms\n"
+                   "and one that may:"
+                   " http://localhost:%d/frida.intevation.org/wms/simple\n"
+                          % (self.server.server_port,
+                             self.server.server_port))
+
 class TestInteProxyWithExtraProxy(ServerTest):
 
     remote_contents = [

Modified: trunk/test/test_transcoder_map.py
===================================================================
--- trunk/test/test_transcoder_map.py	2009-09-01 15:45:54 UTC (rev 191)
+++ trunk/test/test_transcoder_map.py	2009-09-10 17:56:25 UTC (rev 192)
@@ -16,8 +16,19 @@
      IdentityTranscoder
 import inteproxy.config
 
-class TestTranscoderMap(unittest.TestCase, support.FileTestMixin):
+class TranscoderMapTest(unittest.TestCase, support.FileTestMixin):
 
+    config_contents = ""
+
+    def setUp(self):
+        config_filename = self.create_temp_file(self.id(), self.config_contents)
+        config = inteproxy.config.read_config(config_filename)
+        self.transcoder_map = create_transcoder_map()
+        self.transcoder_map.add_hosts(config.hosts)
+
+
+class TestTranscoderMapNoWildcards(TranscoderMapTest):
+
     config_contents = """\
 [inteproxy-demo.intevation.org]
 host=inteproxy-demo.intevation.org
@@ -31,12 +42,6 @@
 """
     #
 
-    def setUp(self):
-        config_filename = self.create_temp_file(self.id(), self.config_contents)
-        config = inteproxy.config.read_config(config_filename)
-        self.transcoder_map = create_transcoder_map()
-        self.transcoder_map.add_hosts(config.hosts)
-
     def test_lookup(self):
         """Test the lookup method"""
         test_cases = [
@@ -115,3 +120,105 @@
             msg=("Wrong class for %(method)s %(url)s:"
                  " got %(cls)s expected %(expectedcls)s" % locals())
             self.assertEquals(cls, expectedcls, msg)
+
+
+class TestTranscoderMapWithPathWildcards(TranscoderMapTest):
+
+    config_contents = """\
+[inteproxy-demo.intevation.org]
+host=inteproxy-demo.intevation.org
+path=/cgi-bin/*
+class=owsproxy
+
+[intevation-01]
+host=intevation.de
+path=/prefix*suffix
+class=basicauth
+"""
+    #
+
+    def test_get_transcoder_http_proxy(self):
+        """Test the get_transcoder method in http-proxy mode with wildcards"""
+        test_cases = [
+            ("GET", "http://inteproxy-demo.intevation.org/cgi-bin/frida-wms",
+             OWSProxyGETTranscoder),
+            ("POST", "http://inteproxy-demo.intevation.org/cgi-bin/frida-wms",
+             OWSProxyPOSTTranscoder),
+            ("GET", "http://inteproxy-demo.intevation.org/otherdir",
+             IdentityTranscoder),
+            ("POST", "http://inteproxy-demo.intevation.org/otherdir",
+             IdentityTranscoder),
+
+            ("GET", "http://intevation.de/prefix/bla/blub/suffix",
+             BasicAuthTranscoder),
+            ("POST", "http://intevation.de/prefix/bla/blub/suffix",
+             BasicAuthTranscoder),
+            ("GET", "http://intevation.de/prefix/bla/", IdentityTranscoder),
+            ("POST", "http://intevation.de/prefix/bla/", IdentityTranscoder),
+            ]
+
+        for method, url, expectedcls in test_cases:
+            transcoder = self.transcoder_map.get_transcoder(method, url)
+            cls = transcoder.__class__
+            msg=("Wrong class for %(method)s %(url)s:"
+                 " got %(cls)s expected %(expectedcls)s" % locals())
+            self.assertEquals(cls, expectedcls, msg)
+
+
+class TestTranscoderMapWithHostWildcards(TranscoderMapTest):
+
+    config_contents = """\
+[intevation-01]
+host=*intevation.*
+path=/wms/*
+class=owsproxy
+
+[example.com-01]
+host=*.example.com
+path=*
+class=basicauth
+"""
+    #
+
+    def test_get_transcoder_http_proxy(self):
+        """Test the get_transcoder method in http-proxy mode with wildcards"""
+        test_cases = [
+            # matched by the first rule
+            ("GET", "http://intevation.de/wms/demo",
+             OWSProxyGETTranscoder),
+            ("POST", "http://intevation.org/wms/demo",
+             OWSProxyPOSTTranscoder),
+            ("GET", "http://gis.intevation.org/wms/bla/",
+             OWSProxyGETTranscoder),
+            ("POST", "http://data.intevation.de/wms/frida",
+             OWSProxyPOSTTranscoder),
+
+            # not matched by the first rule
+            ("GET", "http://intevation.de/prefix/wms/demo",
+             IdentityTranscoder),
+            ("POST", "http://intevation.de/prefix/wms/demo",
+             IdentityTranscoder),
+
+            # matched by the second rule
+            ("GET", "http://geodata.example.com/prefix/frida/wms",
+             BasicAuthTranscoder),
+            ("POST", "http://geodata.example.com/prefix/wms",
+             BasicAuthTranscoder),
+            ("GET", "http://frida.example.com/", BasicAuthTranscoder),
+            ("POST", "http://gis.data.example.com/", BasicAuthTranscoder),
+
+            # not matched by the second rule
+            ("GET", "http://geodata.example.org/frida/wms",
+             IdentityTranscoder),
+            ("POST", "http://geodata.example.net/prefix/wms",
+             IdentityTranscoder),
+            ("GET", "http://frida.example.org/", IdentityTranscoder),
+            ("POST", "http://data.example.net/", IdentityTranscoder),
+            ]
+
+        for method, url, expectedcls in test_cases:
+            transcoder = self.transcoder_map.get_transcoder(method, url)
+            cls = transcoder.__class__
+            msg=("Wrong class for %(method)s %(url)s:"
+                 " got %(cls)s expected %(expectedcls)s" % locals())
+            self.assertEquals(cls, expectedcls, msg)



More information about the Inteproxy-commits mailing list