1
2 """Standard TurboGears request filters.
3
4 Provides the following filter classes:
5
6 ``MonkeyDecodingFilter``
7 For decoding request data
8 ``NestedvariablesFilter``
9 For decoding request variables from dotted notation to nested dicts
10 ``VirtualPathFilter``
11 For handling dynamic application roots
12
13 """
14
15 __all__ = [
16 'MoneyDecodingFilter',
17 'NestedVariablesFilter',
18 'VirtualPathFilter',
19 ]
20
21 import logging
22
23 from cherrypy import NotFound, request
24 from cherrypy.filters.basefilter import BaseFilter
25
26 from turbogears import config
27
28 from formencode.variabledecode import NestedVariables
29
30
31 log = logging.getLogger('turbogears.filters')
35 """Request filter which decodes the request data according to the encoding
36 specified in the request or the encoding set in the configuration.
37
38 The decoding filter is only used if the configuration setting
39 ``decoding_filter.on`` is set to ``True``. It defaults to `False``.
40
41 The configuration setting ``decoding_filter.encoding`` can be used to force
42 always decoding the request with the given encoding. If this is not set,
43 the encoding will be determined from the request headers.
44
45 If neither of the two is specified, the default encoding is used. This can
46 be set with the ``decoding_filter.default_encoding`` configuration setting.
47
48 Falls back to UTF-8 decoding or ISO-8859-1 for requests with a main content
49 type of "text". Also falls back to ISO-8859-1 if decoding using the
50 requested encoding fails.
51
52 """
53 @staticmethod
55 """Recursively decode all values in an iterable from specified encoding.
56 """
57
58 def decode_from(value, from_enc):
59 if isinstance(value, dict):
60 for k, v in value.items():
61 value[k] = decode_from(v, from_enc)
62 elif isinstance(value, list):
63 newlist = list()
64 for item in value:
65 newlist.append(decode_from(item, from_enc))
66 value = newlist
67 elif isinstance(value, str):
68 return value.decode(from_enc)
69 return value
70
71 decoded_params = decode_from(request.params, from_enc)
72
73
74
75 request.params = decoded_params
76
77 - def before_main(self):
78 """Decode the request data.
79
80 Substituted for CherryPy's decoding filter in
81 ``startup.startTurboGears()``.
82
83 See class docstring for details.
84
85 """
86 get = config.get
87 if not get('decoding_filter.on', False):
88 return
89 if getattr(request, "_decoding_attempted", False):
90 return
91 request._decoding_attempted = True
92 encoding = get('decoding_filter.encoding', None)
93 if not encoding:
94 content_type = request.headers.elements("Content-Type")
95 if content_type:
96 content_type = content_type[0]
97 encoding = content_type.params.get("charset", None)
98 if not encoding and content_type.value.lower().startswith("text/"):
99
100
101
102
103
104 encoding = "ISO-8859-1"
105 if not encoding:
106 encoding = get('decoding_filter.default_encoding', "utf-8")
107 try:
108 self.decode(encoding)
109 except UnicodeDecodeError:
110
111
112
113
114 self.decode("ISO-8859-1")
115
118 """Request filter that turns request params with names in special dotted
119 notation into nested dictionaries via FormEncode's NestedVariables
120 validator.
121
122 """
123 - def before_main(self):
124 if hasattr(request, 'params'):
125 request.params = NestedVariables.to_python(request.params or {})
126
129 """Filter that makes CherryPy ignorant of a URL root path.
130
131 That is, you can mount your app so the URI "/users/~rdel/myapp/" maps to
132 the root object "/".
133
134 """
140
142 """Determine the relevant path info by stripping off prefixes.
143
144 Strips webpath and SCRIPT_NAME from request.object_path and
145 sets request.path_info (since CherryPy 2 does not set it).
146
147 """
148 webpath = self.webpath
149 try:
150 webpath += request.wsgi_environ['SCRIPT_NAME'].rstrip('/')
151 except (AttributeError, KeyError):
152 pass
153 if webpath:
154 if request.object_path.startswith(webpath):
155 request.object_path = request.object_path[len(webpath):] or '/'
156 if request.path.startswith(webpath):
157 request.path_info = request.path[len(webpath):] or '/'
158 else:
159 request.path_info = request.path
160
161 try:
162 if not request.wsgi_environ['HTTP_X_FORWARDED_SERVER']:
163 raise KeyError
164 except (AttributeError, KeyError):
165 raise NotFound(request.path)
166 else:
167 request.path_info = request.path
168