miscellaneous wsgirelated utilities import posixpath all filewrapper guessscheme applicationuri requesturi shiftpathinfo setuptestingdefaults ishopbyhop class filewrapper return a guess for whether wsgi urlscheme should be http or https return the application s base uri no pathinfo or querystring url environ wsgi urlscheme from urllib parse import quote if environ get httphost url environ httphost else url environ servername if environ wsgi urlscheme https if environ serverport 443 url environ serverport else if environ serverport 80 url environ serverport url quoteenviron get scriptname or encoding latin1 return url def requesturienviron includequerytrue shift a name from pathinfo to scriptname returning it if there are no remaining path segments in pathinfo return none note environ is modified inplace use a copy if you need to keep the original pathinfo or scriptname note when pathinfo is just a this returns and appends a trailing to scriptname even though empty path segments are normally ignored and scriptname doesn t normally end in a this is intentional behavior to ensure that an application can tell the difference between x and x when traversing to objects special case on pathinfo doesn t get stripped because we don t strip the last element of pathinfo if there s only one path part left instead of fixing this above we fix it here so that pathinfo gets normalized to an empty string in the environ update environ with trivial defaults for testing purposes this adds various parameters required for wsgi including httphost servername serverport requestmethod scriptname pathinfo and all of the wsgi variables it only supplies default values and does not replace any existing settings for these variables this routine is intended to make it easier for unit tests of wsgi servers and applications to set up dummy environments it should not be used by actual wsgi servers or applications since the data is fake return true if headername is an http1 1 hopbyhop header return hoppishheadername lower wrapper to convert file like objects to iterables return a guess for whether wsgi url_scheme should be http or https return the application s base uri no path_info or query_string return the full request uri optionally including the query string shift a name from path_info to script_name returning it if there are no remaining path segments in path_info return none note environ is modified in place use a copy if you need to keep the original path_info or script_name note when path_info is just a this returns and appends a trailing to script_name even though empty path segments are normally ignored and script_name doesn t normally end in a this is intentional behavior to ensure that an application can tell the difference between x and x when traversing to objects special case on path_info doesn t get stripped because we don t strip the last element of path_info if there s only one path part left instead of fixing this above we fix it here so that path_info gets normalized to an empty string in the environ update environ with trivial defaults for testing purposes this adds various parameters required for wsgi including http_host server_name server_port request_method script_name path_info and all of the wsgi variables it only supplies default values and does not replace any existing settings for these variables this routine is intended to make it easier for unit tests of wsgi servers and applications to set up dummy environments it should not be used by actual wsgi servers or applications since the data is fake return true if header_name is an http 1 1 hop by hop header
import posixpath

__all__ = [
    'FileWrapper', 'guess_scheme', 'application_uri', 'request_uri',
    'shift_path_info', 'setup_testing_defaults', 'is_hop_by_hop',
]


class FileWrapper:
    

    def __init__(self, filelike, blksize=8192):
        self.filelike = filelike
        self.blksize = blksize
        if hasattr(filelike,'close'):
            self.close = filelike.close

    def __iter__(self):
        return self

    def __next__(self):
        data = self.filelike.read(self.blksize)
        if data:
            return data
        raise StopIteration

def guess_scheme(environ):
    
    if environ.get("HTTPS") in ('yes','on','1'):
        return 'https'
    else:
        return 'http'

def application_uri(environ):
    
    url = environ['wsgi.url_scheme']+'://'
    from urllib.parse import quote

    if environ.get('HTTP_HOST'):
        url += environ['HTTP_HOST']
    else:
        url += environ['SERVER_NAME']

        if environ['wsgi.url_scheme'] == 'https':
            if environ['SERVER_PORT'] != '443':
                url += ':' + environ['SERVER_PORT']
        else:
            if environ['SERVER_PORT'] != '80':
                url += ':' + environ['SERVER_PORT']

    url += quote(environ.get('SCRIPT_NAME') or '/', encoding='latin1')
    return url

def request_uri(environ, include_query=True):
    
    url = application_uri(environ)
    from urllib.parse import quote
    path_info = quote(environ.get('PATH_INFO',''), safe='/;=,', encoding='latin1')
    if not environ.get('SCRIPT_NAME'):
        url += path_info[1:]
    else:
        url += path_info
    if include_query and environ.get('QUERY_STRING'):
        url += '?' + environ['QUERY_STRING']
    return url

def shift_path_info(environ):
    
    path_info = environ.get('PATH_INFO','')
    if not path_info:
        return None

    path_parts = path_info.split('/')
    path_parts[1:-1] = [p for p in path_parts[1:-1] if p and p != '.']
    name = path_parts[1]
    del path_parts[1]

    script_name = environ.get('SCRIPT_NAME','')
    script_name = posixpath.normpath(script_name+'/'+name)
    if script_name.endswith('/'):
        script_name = script_name[:-1]
    if not name and not script_name.endswith('/'):
        script_name += '/'

    environ['SCRIPT_NAME'] = script_name
    environ['PATH_INFO']   = '/'.join(path_parts)

    
    
    
    
    
    if name=='.':
        name = None
    return name

def setup_testing_defaults(environ):
    

    environ.setdefault('SERVER_NAME','127.0.0.1')
    environ.setdefault('SERVER_PROTOCOL','HTTP/1.0')

    environ.setdefault('HTTP_HOST',environ['SERVER_NAME'])
    environ.setdefault('REQUEST_METHOD','GET')

    if 'SCRIPT_NAME' not in environ and 'PATH_INFO' not in environ:
        environ.setdefault('SCRIPT_NAME','')
        environ.setdefault('PATH_INFO','/')

    environ.setdefault('wsgi.version', (1,0))
    environ.setdefault('wsgi.run_once', 0)
    environ.setdefault('wsgi.multithread', 0)
    environ.setdefault('wsgi.multiprocess', 0)

    from io import StringIO, BytesIO
    environ.setdefault('wsgi.input', BytesIO())
    environ.setdefault('wsgi.errors', StringIO())
    environ.setdefault('wsgi.url_scheme',guess_scheme(environ))

    if environ['wsgi.url_scheme']=='http':
        environ.setdefault('SERVER_PORT', '80')
    elif environ['wsgi.url_scheme']=='https':
        environ.setdefault('SERVER_PORT', '443')



_hoppish = {
    'connection', 'keep-alive', 'proxy-authenticate',
    'proxy-authorization', 'te', 'trailers', 'transfer-encoding',
    'upgrade'
}.__contains__

def is_hop_by_hop(header_name):
    
    return _hoppish(header_name.lower())