1
"""Miscellaneous WSGI-related Utilities"""
6
'FileWrapper', 'guess_scheme', 'application_uri', 'request_uri',
7
'shift_path_info', 'setup_testing_defaults',
12
"""Wrapper to convert file-like objects to iterables"""
14
def __init__(self, filelike, blksize=8192):
15
self.filelike = filelike
16
self.blksize = blksize
17
if hasattr(filelike,'close'):
18
self.close = filelike.close
20
def __getitem__(self,key):
21
data = self.filelike.read(self.blksize)
30
data = self.filelike.read(self.blksize)
42
def guess_scheme(environ):
43
"""Return a guess for whether 'wsgi.url_scheme' should be 'http' or 'https'
45
if environ.get("HTTPS") in ('yes','on','1'):
50
def application_uri(environ):
51
"""Return the application's base URI (no PATH_INFO or QUERY_STRING)"""
52
url = environ['wsgi.url_scheme']+'://'
53
from urllib import quote
55
if environ.get('HTTP_HOST'):
56
url += environ['HTTP_HOST']
58
url += environ['SERVER_NAME']
60
if environ['wsgi.url_scheme'] == 'https':
61
if environ['SERVER_PORT'] != '443':
62
url += ':' + environ['SERVER_PORT']
64
if environ['SERVER_PORT'] != '80':
65
url += ':' + environ['SERVER_PORT']
67
url += quote(environ.get('SCRIPT_NAME') or '/')
70
def request_uri(environ, include_query=1):
71
"""Return the full request URI, optionally including the query string"""
72
url = application_uri(environ)
73
from urllib import quote
74
path_info = quote(environ.get('PATH_INFO',''))
75
if not environ.get('SCRIPT_NAME'):
79
if include_query and environ.get('QUERY_STRING'):
80
url += '?' + environ['QUERY_STRING']
83
def shift_path_info(environ):
84
"""Shift a name from PATH_INFO to SCRIPT_NAME, returning it
86
If there are no remaining path segments in PATH_INFO, return None.
87
Note: 'environ' is modified in-place; use a copy if you need to keep
88
the original PATH_INFO or SCRIPT_NAME.
90
Note: when PATH_INFO is just a '/', this returns '' and appends a trailing
91
'/' to SCRIPT_NAME, even though empty path segments are normally ignored,
92
and SCRIPT_NAME doesn't normally end in a '/'. This is intentional
93
behavior, to ensure that an application can tell the difference between
94
'/x' and '/x/' when traversing to objects.
96
path_info = environ.get('PATH_INFO','')
100
path_parts = path_info.split('/')
101
path_parts[1:-1] = [p for p in path_parts[1:-1] if p and p != '.']
105
script_name = environ.get('SCRIPT_NAME','')
106
script_name = posixpath.normpath(script_name+'/'+name)
107
if script_name.endswith('/'):
108
script_name = script_name[:-1]
109
if not name and not script_name.endswith('/'):
112
environ['SCRIPT_NAME'] = script_name
113
environ['PATH_INFO'] = '/'.join(path_parts)
115
# Special case: '/.' on PATH_INFO doesn't get stripped,
116
# because we don't strip the last element of PATH_INFO
117
# if there's only one path part left. Instead of fixing this
118
# above, we fix it here so that PATH_INFO gets normalized to
119
# an empty string in the environ.
124
def setup_testing_defaults(environ):
125
"""Update 'environ' with trivial defaults for testing purposes
127
This adds various parameters required for WSGI, including HTTP_HOST,
128
SERVER_NAME, SERVER_PORT, REQUEST_METHOD, SCRIPT_NAME, PATH_INFO,
129
and all of the wsgi.* variables. It only supplies default values,
130
and does not replace any existing settings for these variables.
132
This routine is intended to make it easier for unit tests of WSGI
133
servers and applications to set up dummy environments. It should *not*
134
be used by actual WSGI servers or applications, since the data is fake!
137
environ.setdefault('SERVER_NAME','127.0.0.1')
138
environ.setdefault('SERVER_PROTOCOL','HTTP/1.0')
140
environ.setdefault('HTTP_HOST',environ['SERVER_NAME'])
141
environ.setdefault('REQUEST_METHOD','GET')
143
if 'SCRIPT_NAME' not in environ and 'PATH_INFO' not in environ:
144
environ.setdefault('SCRIPT_NAME','')
145
environ.setdefault('PATH_INFO','/')
147
environ.setdefault('wsgi.version', (1,0))
148
environ.setdefault('wsgi.run_once', 0)
149
environ.setdefault('wsgi.multithread', 0)
150
environ.setdefault('wsgi.multiprocess', 0)
152
from StringIO import StringIO
153
environ.setdefault('wsgi.input', StringIO(""))
154
environ.setdefault('wsgi.errors', StringIO())
155
environ.setdefault('wsgi.url_scheme',guess_scheme(environ))
157
if environ['wsgi.url_scheme']=='http':
158
environ.setdefault('SERVER_PORT', '80')
159
elif environ['wsgi.url_scheme']=='https':
160
environ.setdefault('SERVER_PORT', '443')
166
'connection':1, 'keep-alive':1, 'proxy-authenticate':1,
167
'proxy-authorization':1, 'te':1, 'trailers':1, 'transfer-encoding':1,
171
def is_hop_by_hop(header_name):
172
"""Return true if 'header_name' is an HTTP/1.1 "Hop-by-Hop" header"""
173
return _hoppish(header_name.lower())