Commits

Robert Brewer committed 222e698

Collapsed request.url and tree.url into a single cherrypy.url function.

  • Participants
  • Parent commits c9a3d44

Comments (0)

Files changed (11)

cherrypy/__init__.py

             # expose is returning a decorator "@expose(alias=...)"
             return expose_
 
+def url(path="", qs="", script_name=None, base=None):
+    """Create an absolute URL for the given path.
+    
+    If 'path' starts with a slash ('/'), this will return
+        (base + script_name + path + qs).
+    If it does not start with a slash, this returns
+        (base + script_name [+ request.path_info] + path + qs).
+    
+    If script_name is None, cherrypy.request will be used
+    to find a script_name, if available.
+    
+    If base is None, cherrypy.request.base will be used if available.
+    Note that you can use cherrypy.tools.proxy to change this.
+    
+    Finally, note that this function can be used to obtain an absolute URL
+    for the current request path (minus the querystring) by passing no args.
+    """
+    if qs:
+        qs = '?' + qs
+    
+    if request.app:
+        if path == "":
+            path = request.path_info
+        if not path.startswith("/"):
+            path = request.path_info + "/" + path
+        if script_name is None:
+            script_name = request.app.script_name
+        if base is None:
+            base = request.base
+        
+        return base + script_name + path + qs
+    else:
+        # No request.app (we're being called outside a request).
+        # We'll have to guess the base from server.* attributes.
+        # This will produce very different results from the above
+        # if you're using vhosts or tools.proxy.
+        if base is None:
+            f = server.socket_file
+            if f:
+                base = f
+            else:
+                host = server.socket_host
+                if not host:
+                    import socket
+                    host = socket.gethostname()
+                port = server.socket_port
+                if (port in (443, 8443) or server.ssl_certificate):
+                    scheme = "https"
+                    if port != 443:
+                        host += ":%s" % port
+                else:
+                    scheme = "http"
+                    if port != 80:
+                        host += ":%s" % port
+                base = "%s://%s" % (scheme, host)
+        path = (script_name or "") + path
+        return base + path + qs
 
 # Set up config last so it can wrap other top-level objects
 from cherrypy import _cpconfig

cherrypy/_cperror.py

             #  2. a URL relative to root (e.g. "/dummy")
             #  3. a URL relative to the current path
             # Note that any query string in cherrypy.request is discarded.
-            url = _urljoin(request.url(), url)
+            url = _urljoin(cherrypy.url(), url)
             abs_urls.append(url)
         self.urls = abs_urls
         

cherrypy/_cprequest.py

         if request.config.get("request.redirect_on_missing_slash",
                               request.redirect_on_missing_slash):
             if pi[-1:] != '/':
-                new_url = request.url(pi + '/', request.query_string)
+                new_url = cherrypy.url(pi + '/', request.query_string)
                 raise cherrypy.HTTPRedirect(new_url)
     
     def check_extra_slash(self):
                               request.redirect_on_extra_slash):
             # If pi == '/', don't redirect to ''!
             if pi[-1:] == '/' and pi != '/':
-                new_url = request.url(pi[:-1], request.query_string)
+                new_url = cherrypy.url(pi[:-1], request.query_string)
                 raise cherrypy.HTTPRedirect(new_url)
 
 
                 tool = getattr(tools, toolname)
                 tool._setup()
     
-    def url(self, path_info="", qs=""):
-        """Create an absolute URL for the given path_info.
-        
-        If 'path_info' starts with a slash ('/'), this will return
-            (self.base + self.script_name + path_info + qs).
-        If it does not start with a slash, this returns
-            (self.base + self.script_name + self.path_info + path_info + qs).
-        """
-        if path_info == "":
-            path_info = self.path_info
-        if not path_info.startswith("/"):
-            path_info = self.path_info + "/" + path_info
-        
-        if qs:
-            qs = '?' + qs
-        return self.base + self.script_name + path_info + qs
-    
     def process_body(self):
         """Convert request.rfile into request.params (or request.body)."""
         # Guard against re-reading body (e.g. on InternalRedirect)

cherrypy/_cptree.py

         host = cherrypy.server.socket_host
         if port != 80:
             host += ":%s" % port
-        return scheme + host + self.script_name
+        return scheme + host + (self.script_name or "/")
     
     def wsgiapp(self, environ, start_response):
         # This is here instead of __call__ because it's really hard
             # Move one node up the tree and try again.
             path = path[:path.rfind("/")]
     
-    def url(self, path, script_name=None, base=None):
-        """Return 'path', prefixed with script_name and base.
-        
-        If script_name is None, cherrypy.request will be used
-        to find a script_name.
-        
-        If base is None, cherrypy.request.base will be used. Note that
-        you can use cherrypy.tools.proxy to change this.
-        """
-        
-        if script_name is None:
-            script_name = self.script_name()
-            if script_name is None:
-                return path
-        
-        if base is None:
-            base = cherrypy.request.base
-        
-        return base + http.urljoin(script_name, path)
-    
     def __call__(self, environ, start_response):
         # If you're calling this, then you're probably setting SCRIPT_NAME
         # to '' (some WSGI servers always set SCRIPT_NAME to '').

cherrypy/lib/caching.py

     
     def _key(self):
         request = cherrypy.request
-        return request.config.get("tools.caching.key", request.url(qs=request.query_string))
+        return request.config.get("tools.caching.key", cherrypy.url(qs=request.query_string))
     key = property(_key)
     
     def expire_cache(self):

cherrypy/lib/cptools.py

         if not username:
             sess[self.session_key] = username = self.anonymous()
         if not username:
-            cherrypy.response.body = self.login_screen(request.url(qs=request.query_string))
+            cherrypy.response.body = self.login_screen(cherrypy.url(qs=request.query_string))
             return True
         
         self.on_check(username)

cherrypy/test/helper.py

 class CPWebCase(webtest.WebCase):
     
     script_name = ""
+    scheme = "http"
     
     def prefix(self):
         return self.script_name.rstrip("/")
 def testmain(conf=None):
     """Run __main__ as a test module, with webtest debugging."""
     if conf is None:
-        conf = {}
+        conf = {'server.socket_host': '127.0.0.1'}
     setConfig(conf)
     try:
         cherrypy.server.quickstart()

cherrypy/test/test.py

         from cherrypy.test import helper, webtest
         webtest.WebCase.PORT = self.port
         webtest.WebCase.harness = self
-        webtest.WebCase.scheme = self.scheme
+        helper.CPWebCase.scheme = self.scheme
         if self.scheme == "https":
             webtest.WebCase.HTTP_CONN = httplib.HTTPSConnection
         print

cherrypy/test/test_objectmapping.py

             return cherrypy.tree.script_name()
         script_name.exposed = True
         
-        def tree_url(self):
-            return cherrypy.tree.url("/extra")
-        tree_url.exposed = True
+        def cherrypy_url(self):
+            return cherrypy.url("/extra")
+        cherrypy_url.exposed = True
         
         def posparam(self, *vpath):
             return "/".join(vpath)
             
             self.getPage("/dir1/dir2/script_name")
             self.assertBody(url)
-            self.getPage("/dir1/dir2/tree_url")
+            self.getPage("/dir1/dir2/cherrypy_url")
             self.assertBody("%s://%s:%s%s/extra" %
                             (self.scheme, self.HOST, self.PORT, prefix))
             

cherrypy/test/test_proxy.py

         
         def newurl(self):
             return ("Browse to <a href='%s'>this page</a>."
-                    % cherrypy.tree.url("/this/new/page"))
+                    % cherrypy.url("/this/new/page"))
         newurl.exposed = True
     
     for sn in script_names:
     def testProxy(self):
         self.getPage("/")
         self.assertHeader('Location',
-                          "%s://www.mydomain.com%s/dummy" % (self.scheme, self.prefix()))
+                          "%s://www.mydomain.com%s/dummy" %
+                          (self.scheme, self.prefix()))
         
         # Test X-Forwarded-Host (Apache 1.3.33+ and Apache 2)
         self.getPage("/", headers=[('X-Forwarded-Host', 'http://www.yetanother.com')])
         self.getPage("/base", headers=[('X-Forwarded-Proto', 'https')])
         self.assertBody("https://www.mydomain.com")
         
-        # Test tree.url()
+        # Test cherrypy.url()
         for sn in script_names:
+            # Test the value inside requests
             self.getPage(sn + "/newurl")
             self.assertBody("Browse to <a href='%s://www.mydomain.com" % self.scheme
                             + sn + "/this/new/page'>this page</a>.")
                                                    'http://www.yetanother.com')])
             self.assertBody("Browse to <a href='http://www.yetanother.com"
                             + sn + "/this/new/page'>this page</a>.")
+            
+            # Test the value outside requests
+            port = ""
+            if self.scheme == "http" and self.PORT != 80:
+                port = ":%s" % self.PORT
+            elif self.scheme == "https" and self.PORT != 443:
+                port = ":%s" % self.PORT
+            self.assertEqual(cherrypy.url("/this/new/page", script_name=sn),
+                             "%s://127.0.0.1%s%s/this/new/page"
+                             % (self.scheme, port, sn))
 
 
 if __name__ == '__main__':

cherrypy/test/webtest.py

             found = True
             break
     if not found:
-        headers.append(("Host", "%s:%s" % (host, port)))
+        if port == 80:
+            headers.append(("Host", host))
+        else:
+            headers.append(("Host", "%s:%s" % (host, port)))
     
     if method in methods_with_bodies:
         # Stick in default type and length headers if not present