def __init__(self, urls, status=None):
     import cherrypy
     request = cherrypy.serving.request
     
     if isinstance(urls, basestring):
         urls = [urls]
     
     abs_urls = []
     for url in urls:
         # Note that urljoin will "do the right thing" whether url is:
         #  1. a complete URL with host (e.g. "http://www.example.com/test")
         #  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(cherrypy.url(), url)
         abs_urls.append(url)
     self.urls = abs_urls
     
     # RFC 2616 indicates a 301 response code fits our goal; however,
     # browser support for 301 is quite messy. Do 302/303 instead. See
     # http://www.alanflavell.org.uk/www/post-redirect.html
     if status is None:
         if request.protocol >= (1, 1):
             status = 303
         else:
             status = 302
     else:
         status = int(status)
         if status < 300 or status > 399:
             raise ValueError("status must be between 300 and 399.")
     
     self.status = status
     CherryPyException.__init__(self, abs_urls, status)
Esempio n. 2
0
def _geoserver_api(url,
                   content,
                   base_url=GEOSERVER_BASE_URL,
                   username='******',
                   password='******',
                   method='POST',
                   content_type=XML_CONTENT_TYPE,
                   message=None):
    """
    Utility for creating various artifacts in geoserver (workspaces, layers,
    etc.).
    """
    if message:
        print('> GeoServer(%(meth)s): %(msg)s' %
              dict(meth=method, msg=message))

    # TODO(LB): It would be cleaner to use urllib2 or similar in pure Python,
    # but it was quicker to make this work just with curl.
    cmd = ("curl -u %(username)s:%(password)s -v -X%(method)s -H "
           "'Content-type:%(content_type)s' -d '%(content)s' %(url)s")
    cmd %= dict(username=username,
                password=password,
                content=content,
                url=_urljoin(base_url, url),
                method=method,
                content_type=content_type)

    _do_curl(cmd)
Esempio n. 3
0
    def request(self, event, request, response):
        path = request.path.strip("/")

        header = request.headers.get
        domain = header("X-Forwarded-Host", header("Host", ""))
        prefix = self.domains.get(domain, "")

        if prefix:
            path = _urljoin("/%s/" % prefix, path)
            request.path = path
Esempio n. 4
0
    def request(self, event, request, response):
        path = request.path.strip("/")

        header = request.headers.get
        domain = header("X-Forwarded-Host", header("Host", ""))
        prefix = self.domains.get(domain, "")

        if prefix:
            path = _urljoin("/%s/" % prefix, path)
            request.path = path
Esempio n. 5
0
def urljoin(base, url, allow_fragments=True):
    """
    >>>urljoin("http://www.baidu.com","../../../dd")
    'http://www.baidu.com/dd'
    >>>urljoin("http://www.baidu.com","/dd/./././")
    'http://www.baidu.com/dd
    """
    _ = _urljoin(base, url, allow_fragments=True)
    p = urlsplit(_)
    path = p.path + '/' if p.path.endswith('/') else p.path
    return urlunsplit((p.scheme,p.netloc,normpath(p.path),p.query,p.fragment))
Esempio n. 6
0
def urljoin(base, url, allow_fragments=True):
    """
    >>>urljoin("http://www.baidu.com","../../../dd")
    'http://www.baidu.com/dd'
    >>>urljoin("http://www.baidu.com","/dd/./././")
    'http://www.baidu.com/dd
    """
    _ = _urljoin(base, url, allow_fragments=True)
    p = urlsplit(_)
    path = p.path + '/' if p.path.endswith('/') else p.path
    return urlunsplit(
        (p.scheme, p.netloc, normpath(p.path), p.query, p.fragment))
Esempio n. 7
0
def capes_for(department_form_val):
    form, select = _search_form_and_select_tag()
    field_name = select.get(NAME)
    # method = form.get(HTTP_METHOD)
    # if method != HTTP_GET:
        # raise ValueError("Expected GET form submission method; Got "+repr(method))
    action = form.get(ACTION)
    dest_url = _urljoin(CAPE_SEARCH_URL, action)
    dept_url = "%s?%s" % (dest_url, _urlencode({field_name:department_form_val}))
    tree = url2tree(dept_url)
    for link in section_links(tree):
        cape = parse_detailed_page(link)
        if cape is not None:
            yield cape
Esempio n. 8
0
def request_args_from_resource(method, service, resource, *args, **kwargs):
    """

    :rtype:
        (:func:`str`, :func:`str`, :obj:`object`\ ...),
        {:func:`str`: :obj:`object`}

    """
    uri = _urljoin(service + ('/' if not service.endswith('/') else ''),
                   resource)
    postext_match = _re.match('post(.+)', method)
    if postext_match:
        method = 'post'
        uri += '?' + postext_match.group(1)
    return (method, uri) + args, kwargs
Esempio n. 9
0
def capes_for(department_form_val):
    form, select = _search_form_and_select_tag()
    field_name = select.get(NAME)
    # method = form.get(HTTP_METHOD)
    # if method != HTTP_GET:
    # raise ValueError("Expected GET form submission method; Got "+repr(method))
    action = form.get(ACTION)
    dest_url = _urljoin(CAPE_SEARCH_URL, action)
    dept_url = "%s?%s" % (dest_url,
                          _urlencode({field_name: department_form_val}))
    tree = url2tree(dept_url)
    for link in section_links(tree):
        cape = parse_detailed_page(link)
        if cape is not None:
            yield cape
Esempio n. 10
0
def _geoserver_api(url, content, base_url=GEOSERVER_BASE_URL, username='******',
                   password='******', method='POST',
                   content_type=XML_CONTENT_TYPE, message=None):
    """
    Utility for creating various artifacts in geoserver (workspaces, layers,
    etc.).
    """
    if message:
        print('> GeoServer(%(meth)s): %(msg)s'
              % dict(meth=method, msg=message))

    # TODO(LB): It would be cleaner to use urllib2 or similar in pure Python,
    # but it was quicker to make this work just with curl.
    cmd = ("curl -u %(username)s:%(password)s -v -X%(method)s -H "
           "'Content-type:%(content_type)s' -d '%(content)s' %(url)s")
    cmd %= dict(username=username, password=password, content=content,
                url=_urljoin(base_url, url), method=method,
                content_type=content_type)

    _do_curl(cmd)
 def __init__(self, path, query_string=""):
     import cherrypy
     self.request = cherrypy.serving.request
     
     self.query_string = query_string
     if "?" in path:
         # Separate any params included in the path
         path, self.query_string = path.split("?", 1)
     
     # Note that urljoin will "do the right thing" whether url is:
     #  1. a URL relative to root (e.g. "/dummy")
     #  2. a URL relative to the current path
     # Note that any query string will be discarded.
     path = _urljoin(self.request.path_info, path)
     
     # Set a 'path' member attribute so that code which traps this
     # error can have access to it.
     self.path = path
     
     CherryPyException.__init__(self, path, self.query_string)
Esempio n. 12
0
def geoserver_rest(
        url, file_path=None, base_url=GEOSERVER_BASE_URL,
        username='******', password='******',
        content_type=XML_CONTENT_TYPE,
        method='POST',
        message=None,
        substitutions=None,
        raise_errors=True):
    headers = {}
    authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm()
    authinfo.add_password(None, base_url, username, password)
    urllib2.install_opener(
        urllib2.build_opener(
            urllib2.HTTPBasicAuthHandler(authinfo)))
    headers['Content-Type'] = content_type
    if file_path is not None:
        content = file(file_path).read()
        if substitutions:
            content = content % substitutions
        headers['Content-Length'] = len(content)
    else:
        content = None
    url = _urljoin(base_url, url)
    request = urllib2.Request(url,
                              data=content,
                              headers=headers)
    request.get_method = lambda: method
    if message is not None:
        print message
    else:
        print "Url: %s, method: %s" % (url, method)

    try:
        print urllib2.urlopen(request).read()
    except urllib2.HTTPError as e:
        print "Error %s: %s" % (e.code, e.reason)
        print "Url: %s, method: %s" % (url, method)
        print content
        if raise_errors:
            raise e
Esempio n. 13
0
def url(path="", qs="", script_name=None, base=None, relative=False):
    """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 you call url(qs=cherrypy.request.query_string), you should get the
    original browser URL (assuming no Internal redirections).
    
    If relative is False (the default), the output will be an absolute URL
    (usually including the scheme, host, vhost, and script_name).
    If relative is True, the output will instead be a URL that is relative
    to the current request path, perhaps including '..' atoms.
    """
    if qs:
        qs = '?' + qs
    
    if request.app:
        if not path.startswith("/"):
            # Append/remove trailing slash from path_info as needed
            # (this is to support mistyped URL's without redirecting;
            # if you want to redirect, use tools.trailing_slash).
            pi = request.path_info
            if request.is_index is True:
                if not pi.endswith('/'):
                    pi = pi + '/'
            elif request.is_index is False:
                if pi.endswith('/') and pi != '/':
                    pi = pi[:-1]
            
            if path == "":
                path = pi
            else:
                path = _urljoin(pi, path)
        
        if script_name is None:
            script_name = request.app.script_name
        if base is None:
            base = request.base
        
        newurl = 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:
                    # The empty string signifies INADDR_ANY.
                    # Look up the host name, which should be
                    # the safest thing to spit out in a URL.
                    import socket
                    host = socket.gethostname()
                port = server.socket_port
                if 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
        newurl = base + path + qs
    
    if './' in newurl:
        # Normalize the URL by removing ./ and ../
        atoms = []
        for atom in newurl.split('/'):
            if atom == '.':
                pass
            elif atom == '..':
                atoms.pop()
            else:
                atoms.append(atom)
        newurl = '/'.join(atoms)
    
    if relative:
        old = url().split('/')[:-1]
        new = newurl.split('/')
        while old and new:
            a, b = old[0], new[0]
            if a != b:
                break
            old.pop(0)
            new.pop(0)
        new = (['..'] * len(old)) + new
        newurl = '/'.join(new)
    
    return newurl
Esempio n. 14
0
def _query(function, api_key=None, api_version=None, method='GET', data=None):
    '''
    HipChat object method function to construct and execute on the API URL.

    :param api_key:     The HipChat api key.
    :param function:    The HipChat api function to perform.
    :param api_version: The HipChat api version (v1 or v2).
    :param method:      The HTTP method, e.g. GET or POST.
    :param data:        The data to be sent for POST method.
    :return:            The json response from the API call or False.
    '''
    headers = {}
    query_params = {}

    if data is None:
        data = {}

    if data.get('room_id'):
        room_id = str(data.get('room_id'))
    else:
        room_id = '0'

    hipchat_functions = {
        'v1': {
            'rooms': {
                'request': 'rooms/list',
                'response': 'rooms',
            },
            'users': {
                'request': 'users/list',
                'response': 'users',
            },
            'message': {
                'request': 'rooms/message',
                'response': 'status',
            },
        },
        'v2': {
            'rooms': {
                'request': 'room',
                'response': 'items',
            },
            'users': {
                'request': 'user',
                'response': 'items',
            },
            'message': {
                'request': 'room/' + room_id + '/notification',
                'response': None,
            },
        },
    }

    if not api_key or not api_version:
        try:
            options = __salt__['config.option']('hipchat')
            if not api_key:
                api_key = options.get('api_key')
            if not api_version:
                api_version = options.get('api_version')
        except (NameError, KeyError, AttributeError):
            log.error("No HipChat api key or version found.")
            return False

    api_url = 'https://api.hipchat.com'
    base_url = _urljoin(api_url, api_version + '/')
    path = hipchat_functions.get(api_version).get(function).get('request')
    url = _urljoin(base_url, path, False)

    if api_version == 'v1':
        query_params['format'] = 'json'
        query_params['auth_token'] = api_key

        if method == 'POST':
            headers['Content-Type'] = 'application/x-www-form-urlencoded'

        if data.get('notify'):
            data['notify'] = 1
        else:
            data['notify'] = 0
    elif api_version == 'v2':
        headers['Authorization'] = 'Bearer {0}'.format(api_key)
        data = json.dumps(data)
    else:
        log.error('Unsupported HipChat API version')
        return False

    try:
        result = requests.request(
            method=method,
            url=url,
            headers=headers,
            params=query_params,
            data=data,
            verify=True,
        )
    except ConnectionError as e:
        log.error(e)
        return False

    if result.status_code == 200:
        result = result.json()
        response = hipchat_functions.get(api_version).get(function).get(
            'response')
        return result.get(response)
    elif result.status_code == 204:
        return True
    else:
        log.debug(url)
        log.debug(query_params)
        log.debug(data)
        log.debug(result)
        if result.json().get('error'):
            log.error(result.json())
        return False
Esempio n. 15
0
def url(path="", qs="", script_name=None, base=None, relative=False):
    """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 you call url(qs=cherrypy.request.query_string), you should get the
    original browser URL (assuming no Internal redirections).
    
    If relative is False (the default), the output will be an absolute URL
    (usually including the scheme, host, vhost, and script_name).
    If relative is True, the output will instead be a URL that is relative
    to the current request path, perhaps including '..' atoms.
    """
    if qs:
        qs = '?' + qs
    
    if request.app:
        if not path.startswith("/"):
            # Append/remove trailing slash from path_info as needed
            # (this is to support mistyped URL's without redirecting;
            # if you want to redirect, use tools.trailing_slash).
            pi = request.path_info
            if request.is_index is True:
                if not pi.endswith('/'):
                    pi = pi + '/'
            elif request.is_index is False:
                if pi.endswith('/') and pi != '/':
                    pi = pi[:-1]
            
            if path == "":
                path = pi
            else:
                path = _urljoin(pi, path)
        
        if script_name is None:
            script_name = request.app.script_name
        if base is None:
            base = request.base
        
        newurl = 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:
            base = server.base()
        
        path = (script_name or "") + path
        newurl = base + path + qs
    
    if './' in newurl:
        # Normalize the URL by removing ./ and ../
        atoms = []
        for atom in newurl.split('/'):
            if atom == '.':
                pass
            elif atom == '..':
                atoms.pop()
            else:
                atoms.append(atom)
        newurl = '/'.join(atoms)
    
    if relative:
        old = url().split('/')[:-1]
        new = newurl.split('/')
        while old and new:
            a, b = old[0], new[0]
            if a != b:
                break
            old.pop(0)
            new.pop(0)
        new = (['..'] * len(old)) + new
        newurl = '/'.join(new)
    
    return newurl
Esempio n. 16
0
    def __init__(self, request, response, urls, status=None):
        if isinstance(urls, basestring):
            urls = [urls]
        
        abs_urls = []
        for url in urls:
            # Note that urljoin will "do the right thing" whether url is:
            #  1. a complete URL with host (e.g. "http://www.example.com/test")
            #  2. a URL relative to root (e.g. "/dummy")
            #  3. a URL relative to the current path
            # Note that any query string in request is discarded.
            url = _urljoin(utils.url(request), url)
            abs_urls.append(url)
        self.urls = urls = abs_urls
        
        # RFC 2616 indicates a 301 response code fits our goal; however,
        # browser support for 301 is quite messy. Do 302/303 instead. See
        # http://ppewww.ph.gla.ac.uk/~flavell/www/post-redirect.html
        if status is None:
            if request.protocol >= (1, 1):
                status = 303
            else:
                status = 302
        else:
            status = int(status)
            if status < 300 or status > 399:
                raise ValueError("status must be between 300 and 399.")

        super(Redirect, self).__init__(request, response, status)
        
        if status in (300, 301, 302, 303, 307):
            response.headers["Content-Type"] = "text/html"
            # "The ... URI SHOULD be given by the Location field
            # in the response."
            response.headers["Location"] = urls[0]
            
            # "Unless the request method was HEAD, the entity of the response
            # SHOULD contain a short hypertext note with a hyperlink to the
            # new URI(s)."
            msg = {300: "This resource can be found at <a href='%s'>%s</a>.",
                   301: "This resource has permanently moved to <a href='%s'>%s</a>.",
                   302: "This resource resides temporarily at <a href='%s'>%s</a>.",
                   303: "This resource can be found at <a href='%s'>%s</a>.",
                   307: "This resource has moved temporarily to <a href='%s'>%s</a>.",
                   }[status]
            response.body = "<br />\n".join([msg % (u, u) for u in urls])
            # Previous code may have set C-L, so we have to reset it
            # (allow finalize to set it).
            response.headers.pop("Content-Length", None)
        elif status == 304:
            # Not Modified.
            # "The response MUST include the following header fields:
            # Date, unless its omission is required by section 14.18.1"
            # The "Date" header should have been set in Response.__init__
            
            # "...the response SHOULD NOT include other entity-headers."
            for key in ("Allow", "Content-Encoding", "Content-Language",
                        "Content-Length", "Content-Location", "Content-MD5",
                        "Content-Range", "Content-Type", "Expires",
                        "Last-Modified"):
                if key in response.headers:
                    del response.headers[key]
            
            # "The 304 response MUST NOT contain a message-body."
            response.body = None
            # Previous code may have set C-L, so we have to reset it.
            response.headers.pop("Content-Length", None)
        elif status == 305:
            # Use Proxy.
            # urls[0] should be the URI of the proxy.
            response.headers["Location"] = urls[0]
            response.body = None
            # Previous code may have set C-L, so we have to reset it.
            response.headers.pop("Content-Length", None)
        else:
            raise ValueError("The %s status code is unknown." % status)
Esempio n. 17
0
def url(path="", qs="", script_name=None, base=None, relative=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 you call url(qs=cherrypy.request.query_string), you should get the
    original browser URL (assuming no internal redirections).
    
    If relative is None or not provided, request.app.relative_urls will
    be used (if available, else False). If False, the output will be an
    absolute URL (including the scheme, host, vhost, and script_name).
    If True, the output will instead be a URL that is relative to the
    current request path, perhaps including '..' atoms. If relative is
    the string 'server', the output will instead be a URL that is
    relative to the server root; i.e., it will start with a slash.
    """
    if qs:
        qs = '?' + qs
    
    if request.app:
        if not path.startswith("/"):
            # Append/remove trailing slash from path_info as needed
            # (this is to support mistyped URL's without redirecting;
            # if you want to redirect, use tools.trailing_slash).
            pi = request.path_info
            if request.is_index is True:
                if not pi.endswith('/'):
                    pi = pi + '/'
            elif request.is_index is False:
                if pi.endswith('/') and pi != '/':
                    pi = pi[:-1]
            
            if path == "":
                path = pi
            else:
                path = _urljoin(pi, path)
        
        if script_name is None:
            script_name = request.script_name
        if base is None:
            base = request.base
        
        newurl = 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:
            base = server.base()
        
        path = (script_name or "") + path
        newurl = base + path + qs
    
    if './' in newurl:
        # Normalize the URL by removing ./ and ../
        atoms = []
        for atom in newurl.split('/'):
            if atom == '.':
                pass
            elif atom == '..':
                atoms.pop()
            else:
                atoms.append(atom)
        newurl = '/'.join(atoms)
    
    # At this point, we should have a fully-qualified absolute URL.
    
    if relative is None:
        relative = getattr(request.app, "relative_urls", False)
    
    # See http://www.ietf.org/rfc/rfc2396.txt
    if relative == 'server':
        # "A relative reference beginning with a single slash character is
        # termed an absolute-path reference, as defined by <abs_path>..."
        # This is also sometimes called "server-relative".
        newurl = '/' + '/'.join(newurl.split('/', 3)[3:])
    elif relative:
        # "A relative reference that does not begin with a scheme name
        # or a slash character is termed a relative-path reference."
        old = url().split('/')[:-1]
        new = newurl.split('/')
        while old and new:
            a, b = old[0], new[0]
            if a != b:
                break
            old.pop(0)
            new.pop(0)
        new = (['..'] * len(old)) + new
        newurl = '/'.join(new)
    
    return newurl
Esempio n. 18
0
def _query(function, api_key=None, method='GET', data=None):
    '''
    Slack object method function to construct and execute on the API URL.

    :param api_key:     The Slack api key.
    :param function:    The Slack api function to perform.
    :param method:      The HTTP method, e.g. GET or POST.
    :param data:        The data to be sent for POST method.
    :return:            The json response from the API call or False.
    '''
    headers = {}
    query_params = {}

    if data is None:
        data = {}

    ret = {'message': '',
           'res': True}

    slack_functions = {
        'rooms': {
            'request': 'channels.list',
            'response': 'channels',
        },
        'users': {
            'request': 'users.list',
            'response': 'members',
        },
        'message': {
            'request': 'chat.postMessage',
            'response': 'channel',
        },
    }

    if not api_key:
        try:
            options = __salt__['config.option']('slack')
            if not api_key:
                api_key = options.get('api_key')
        except (NameError, KeyError, AttributeError):
            log.error('No Slack api key found.')
            ret['message'] = 'No Slack api key found.'
            ret['res'] = False
            return ret

    api_url = 'https://slack.com'
    base_url = _urljoin(api_url, '/api/')
    path = slack_functions.get(function).get('request')
    url = _urljoin(base_url, path, False)
    query_params['token'] = api_key

    try:
        result = requests.request(
            method=method,
            url=url,
            headers=headers,
            params=query_params,
            data=data,
            verify=True,
        )
    except ConnectionError as e:
        ret['message'] = e
        ret['res'] = False
        return ret

    if result.status_code == 200:
        result = result.json()
        response = slack_functions.get(function).get('response')
        if 'error' in result:
            ret['message'] = result['error']
            ret['res'] = False
            return ret
        ret['message'] = result.get(response)
        return ret
    elif result.status_code == 204:
        return True
    else:
        log.debug(url)
        log.debug(query_params)
        log.debug(data)
        log.debug(result)
        if 'error' in result:
            ret['message'] = result['error']
            ret['res'] = False
            return ret
        ret['message'] = result
        return ret
Esempio n. 19
0
    def __init__(self, request, response, urls, status=None):
        if isinstance(urls, basestring):
            urls = [urls]

        abs_urls = []
        for url in urls:
            # Note that urljoin will "do the right thing" whether url is:
            #  1. a complete URL with host (e.g. "http://www.example.com/test")
            #  2. a URL relative to root (e.g. "/dummy")
            #  3. a URL relative to the current path
            # Note that any query string in request is discarded.
            url = _urljoin(utils.url(request), url)
            abs_urls.append(url)
        self.urls = urls = abs_urls

        # RFC 2616 indicates a 301 response code fits our goal; however,
        # browser support for 301 is quite messy. Do 302/303 instead. See
        # http://ppewww.ph.gla.ac.uk/~flavell/www/post-redirect.html
        if status is None:
            if request.protocol >= (1, 1):
                status = 303
            else:
                status = 302
        else:
            status = int(status)
            if status < 300 or status > 399:
                raise ValueError("status must be between 300 and 399.")

        super(Redirect, self).__init__(request, response, status)

        if status in (300, 301, 302, 303, 307):
            response.headers["Content-Type"] = "text/html"
            # "The ... URI SHOULD be given by the Location field
            # in the response."
            response.headers["Location"] = urls[0]

            # "Unless the request method was HEAD, the entity of the response
            # SHOULD contain a short hypertext note with a hyperlink to the
            # new URI(s)."
            msg = {
                300: "This resource can be found at <a href='%s'>%s</a>.",
                301:
                "This resource has permanently moved to <a href='%s'>%s</a>.",
                302:
                "This resource resides temporarily at <a href='%s'>%s</a>.",
                303: "This resource can be found at <a href='%s'>%s</a>.",
                307:
                "This resource has moved temporarily to <a href='%s'>%s</a>.",
            }[status]
            response.body = "<br />\n".join([msg % (u, u) for u in urls])
            # Previous code may have set C-L, so we have to reset it
            # (allow finalize to set it).
            response.headers.pop("Content-Length", None)
        elif status == 304:
            # Not Modified.
            # "The response MUST include the following header fields:
            # Date, unless its omission is required by section 14.18.1"
            # The "Date" header should have been set in Response.__init__

            # "...the response SHOULD NOT include other entity-headers."
            for key in ("Allow", "Content-Encoding", "Content-Language",
                        "Content-Length", "Content-Location", "Content-MD5",
                        "Content-Range", "Content-Type", "Expires",
                        "Last-Modified"):
                if key in response.headers:
                    del response.headers[key]

            # "The 304 response MUST NOT contain a message-body."
            response.body = None
            # Previous code may have set C-L, so we have to reset it.
            response.headers.pop("Content-Length", None)
        elif status == 305:
            # Use Proxy.
            # urls[0] should be the URI of the proxy.
            response.headers["Location"] = urls[0]
            response.body = None
            # Previous code may have set C-L, so we have to reset it.
            response.headers.pop("Content-Length", None)
        else:
            raise ValueError("The %s status code is unknown." % status)
Esempio n. 20
0
def urljoin(base, *fragments):
    for f in fragments:
        base = _urljoin(base, f, allow_fragments=True)
    return base
Esempio n. 21
0
def urljoin(base, *fragments):
    for f in fragments:
        base = _urljoin(base, f, allow_fragments=True)
    return base
Esempio n. 22
0
def url(path="", qs="", script_name=None, base=None, relative=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 you call url(qs=cherrypy.request.query_string), you should get the
    original browser URL (assuming no internal redirections).
    
    If relative is None or not provided, request.app.relative_urls will
    be used (if available, else False). If False, the output will be an
    absolute URL (including the scheme, host, vhost, and script_name).
    If True, the output will instead be a URL that is relative to the
    current request path, perhaps including '..' atoms. If relative is
    the string 'server', the output will instead be a URL that is
    relative to the server root; i.e., it will start with a slash.
    """
    if qs:
        qs = '?' + qs

    if request.app:
        if not path.startswith("/"):
            # Append/remove trailing slash from path_info as needed
            # (this is to support mistyped URL's without redirecting;
            # if you want to redirect, use tools.trailing_slash).
            pi = request.path_info
            if request.is_index is True:
                if not pi.endswith('/'):
                    pi = pi + '/'
            elif request.is_index is False:
                if pi.endswith('/') and pi != '/':
                    pi = pi[:-1]

            if path == "":
                path = pi
            else:
                path = _urljoin(pi, path)

        if script_name is None:
            script_name = request.script_name
        if base is None:
            base = request.base

        newurl = 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:
            base = server.base()

        path = (script_name or "") + path
        newurl = base + path + qs

    if './' in newurl:
        # Normalize the URL by removing ./ and ../
        atoms = []
        for atom in newurl.split('/'):
            if atom == '.':
                pass
            elif atom == '..':
                atoms.pop()
            else:
                atoms.append(atom)
        newurl = '/'.join(atoms)

    # At this point, we should have a fully-qualified absolute URL.

    if relative is None:
        relative = getattr(request.app, "relative_urls", False)

    # See http://www.ietf.org/rfc/rfc2396.txt
    if relative == 'server':
        # "A relative reference beginning with a single slash character is
        # termed an absolute-path reference, as defined by <abs_path>..."
        # This is also sometimes called "server-relative".
        newurl = '/' + '/'.join(newurl.split('/', 3)[3:])
    elif relative:
        # "A relative reference that does not begin with a scheme name
        # or a slash character is termed a relative-path reference."
        old = url().split('/')[:-1]
        new = newurl.split('/')
        while old and new:
            a, b = old[0], new[0]
            if a != b:
                break
            old.pop(0)
            new.pop(0)
        new = (['..'] * len(old)) + new
        newurl = '/'.join(new)

    return newurl