1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
|
<html>
<head>
<title>pylons.controllers.util</title>
</head>
<body>
pylons.controllers.util
<style>
.coverage pre {float: left; margin: 0px 1em; border: none;
padding: 0px; }
.num pre { margin: 0px }
.nocov, .nocov pre {background-color: #faa}
.cov, .cov pre {background-color: #cfc}
div.coverage div { clear: both; height: 1.1em}
</style>
<div class="stats">
Covered: 118 lines<br/>
Missed: 33 lines<br/>
Skipped 58 lines<br/>
Percent: 78 %<br/>
</div>
<div class="coverage">
<div class="cov"><span class="num"><pre> 1</pre></span><pre>"""Utility functions and classes available for use by Controllers</pre></div>
<div class="skip"><span class="num"><pre> 2</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 3</pre></span><pre>Pylons subclasses the `WebOb <http://pythonpaste.org/webob/>`_</pre></div>
<div class="cov"><span class="num"><pre> 4</pre></span><pre>:class:`webob.Request` and :class:`webob.Response` classes to provide</pre></div>
<div class="cov"><span class="num"><pre> 5</pre></span><pre>backwards compatible functions for earlier versions of Pylons as well</pre></div>
<div class="cov"><span class="num"><pre> 6</pre></span><pre>as add a few helper functions to assist with signed cookies.</pre></div>
<div class="skip"><span class="num"><pre> 7</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 8</pre></span><pre>For reference use, refer to the :class:`Request` and :class:`Response`</pre></div>
<div class="cov"><span class="num"><pre> 9</pre></span><pre>below.</pre></div>
<div class="skip"><span class="num"><pre> 10</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 11</pre></span><pre>Functions available:</pre></div>
<div class="skip"><span class="num"><pre> 12</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 13</pre></span><pre>:func:`abort`, :func:`forward`, :func:`etag_cache`, </pre></div>
<div class="cov"><span class="num"><pre> 14</pre></span><pre>:func:`mimetype` and :func:`redirect`</pre></div>
<div class="cov"><span class="num"><pre> 15</pre></span><pre>"""</pre></div>
<div class="cov"><span class="num"><pre> 16</pre></span><pre>import base64</pre></div>
<div class="cov"><span class="num"><pre> 17</pre></span><pre>import binascii</pre></div>
<div class="cov"><span class="num"><pre> 18</pre></span><pre>import hmac</pre></div>
<div class="cov"><span class="num"><pre> 19</pre></span><pre>import logging</pre></div>
<div class="cov"><span class="num"><pre> 20</pre></span><pre>import re</pre></div>
<div class="cov"><span class="num"><pre> 21</pre></span><pre>try:</pre></div>
<div class="cov"><span class="num"><pre> 22</pre></span><pre> import cPickle as pickle</pre></div>
<div class="nocov"><span class="num"><pre> 23</pre></span><pre>except ImportError:</pre></div>
<div class="nocov"><span class="num"><pre> 24</pre></span><pre> import pickle</pre></div>
<div class="cov"><span class="num"><pre> 25</pre></span><pre>try:</pre></div>
<div class="cov"><span class="num"><pre> 26</pre></span><pre> from hashlib import sha1</pre></div>
<div class="nocov"><span class="num"><pre> 27</pre></span><pre>except ImportError:</pre></div>
<div class="nocov"><span class="num"><pre> 28</pre></span><pre> import sha as sha1</pre></div>
<div class="skip"><span class="num"><pre> 29</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 30</pre></span><pre>from webob import Request as WebObRequest</pre></div>
<div class="cov"><span class="num"><pre> 31</pre></span><pre>from webob import Response as WebObResponse</pre></div>
<div class="cov"><span class="num"><pre> 32</pre></span><pre>from webob.exc import status_map</pre></div>
<div class="skip"><span class="num"><pre> 33</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 34</pre></span><pre>import pylons</pre></div>
<div class="skip"><span class="num"><pre> 35</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 36</pre></span><pre>__all__ = ['abort', 'etag_cache', 'redirect', 'redirect_to', 'Request',</pre></div>
<div class="cov"><span class="num"><pre> 37</pre></span><pre> 'Response']</pre></div>
<div class="skip"><span class="num"><pre> 38</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 39</pre></span><pre>log = logging.getLogger(__name__)</pre></div>
<div class="skip"><span class="num"><pre> 40</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 41</pre></span><pre>IF_NONE_MATCH = re.compile('(?:W/)?(?:"([^"]*)",?\s*)')</pre></div>
<div class="skip"><span class="num"><pre> 42</pre></span><pre></pre></div>
<div class="skip"><span class="num"><pre> 43</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 44</pre></span><pre>class Request(WebObRequest):</pre></div>
<div class="cov"><span class="num"><pre> 45</pre></span><pre> """WebOb Request subclass</pre></div>
<div class="skip"><span class="num"><pre> 46</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 47</pre></span><pre> The WebOb :class:`webob.Request` has no charset, or other defaults. This subclass</pre></div>
<div class="cov"><span class="num"><pre> 48</pre></span><pre> adds defaults, along with several methods for backwards </pre></div>
<div class="cov"><span class="num"><pre> 49</pre></span><pre> compatibility with paste.wsgiwrappers.WSGIRequest.</pre></div>
<div class="skip"><span class="num"><pre> 50</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 51</pre></span><pre> """ </pre></div>
<div class="cov"><span class="num"><pre> 52</pre></span><pre> def determine_browser_charset(self):</pre></div>
<div class="cov"><span class="num"><pre> 53</pre></span><pre> """Legacy method to return the</pre></div>
<div class="cov"><span class="num"><pre> 54</pre></span><pre> :attr:`webob.Request.accept_charset`"""</pre></div>
<div class="nocov"><span class="num"><pre> 55</pre></span><pre> return self.accept_charset</pre></div>
<div class="skip"><span class="num"><pre> 56</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 57</pre></span><pre> def languages(self):</pre></div>
<div class="cov"><span class="num"><pre> 58</pre></span><pre> return self.accept_language.best_matches(self.language)</pre></div>
<div class="cov"><span class="num"><pre> 59</pre></span><pre> languages = property(languages)</pre></div>
<div class="skip"><span class="num"><pre> 60</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 61</pre></span><pre> def match_accept(self, mimetypes):</pre></div>
<div class="nocov"><span class="num"><pre> 62</pre></span><pre> return self.accept.first_match(mimetypes)</pre></div>
<div class="skip"><span class="num"><pre> 63</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 64</pre></span><pre> def signed_cookie(self, name, secret):</pre></div>
<div class="cov"><span class="num"><pre> 65</pre></span><pre> """Extract a signed cookie of ``name`` from the request</pre></div>
<div class="skip"><span class="num"><pre> 66</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 67</pre></span><pre> The cookie is expected to have been created with</pre></div>
<div class="cov"><span class="num"><pre> 68</pre></span><pre> ``Response.signed_cookie``, and the ``secret`` should be the</pre></div>
<div class="cov"><span class="num"><pre> 69</pre></span><pre> same as the one used to sign it.</pre></div>
<div class="skip"><span class="num"><pre> 70</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 71</pre></span><pre> Any failure in the signature of the data will result in None</pre></div>
<div class="cov"><span class="num"><pre> 72</pre></span><pre> being returned.</pre></div>
<div class="skip"><span class="num"><pre> 73</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 74</pre></span><pre> """</pre></div>
<div class="nocov"><span class="num"><pre> 75</pre></span><pre> cookie = self.str_cookies.get(name)</pre></div>
<div class="nocov"><span class="num"><pre> 76</pre></span><pre> if not cookie:</pre></div>
<div class="nocov"><span class="num"><pre> 77</pre></span><pre> return</pre></div>
<div class="nocov"><span class="num"><pre> 78</pre></span><pre> try:</pre></div>
<div class="nocov"><span class="num"><pre> 79</pre></span><pre> sig, pickled = cookie[:40], base64.decodestring(cookie[40:])</pre></div>
<div class="nocov"><span class="num"><pre> 80</pre></span><pre> except binascii.Error:</pre></div>
<div class="skip"><span class="num"><pre> 81</pre></span><pre> # Badly formed data can make base64 die</pre></div>
<div class="nocov"><span class="num"><pre> 82</pre></span><pre> return</pre></div>
<div class="nocov"><span class="num"><pre> 83</pre></span><pre> if hmac.new(secret, pickled, sha1).hexdigest() == sig:</pre></div>
<div class="nocov"><span class="num"><pre> 84</pre></span><pre> return pickle.loads(pickled)</pre></div>
<div class="skip"><span class="num"><pre> 85</pre></span><pre></pre></div>
<div class="skip"><span class="num"><pre> 86</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre> 87</pre></span><pre>class Response(WebObResponse):</pre></div>
<div class="cov"><span class="num"><pre> 88</pre></span><pre> """WebOb Response subclass</pre></div>
<div class="skip"><span class="num"><pre> 89</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 90</pre></span><pre> The WebOb Response has no default content type, or error defaults.</pre></div>
<div class="cov"><span class="num"><pre> 91</pre></span><pre> This subclass adds defaults, along with several methods for </pre></div>
<div class="cov"><span class="num"><pre> 92</pre></span><pre> backwards compatibility with paste.wsgiwrappers.WSGIResponse.</pre></div>
<div class="skip"><span class="num"><pre> 93</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 94</pre></span><pre> """</pre></div>
<div class="cov"><span class="num"><pre> 95</pre></span><pre> content = WebObResponse.body</pre></div>
<div class="skip"><span class="num"><pre> 96</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre> 97</pre></span><pre> def determine_charset(self):</pre></div>
<div class="nocov"><span class="num"><pre> 98</pre></span><pre> return self.charset</pre></div>
<div class="skip"><span class="num"><pre> 99</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>100</pre></span><pre> def has_header(self, header):</pre></div>
<div class="nocov"><span class="num"><pre>101</pre></span><pre> return header in self.headers</pre></div>
<div class="skip"><span class="num"><pre>102</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>103</pre></span><pre> def get_content(self):</pre></div>
<div class="nocov"><span class="num"><pre>104</pre></span><pre> return self.body</pre></div>
<div class="skip"><span class="num"><pre>105</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>106</pre></span><pre> def write(self, content):</pre></div>
<div class="cov"><span class="num"><pre>107</pre></span><pre> self.body_file.write(content)</pre></div>
<div class="skip"><span class="num"><pre>108</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>109</pre></span><pre> def wsgi_response(self):</pre></div>
<div class="nocov"><span class="num"><pre>110</pre></span><pre> return self.status, self.headers, self.body</pre></div>
<div class="skip"><span class="num"><pre>111</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>112</pre></span><pre> def signed_cookie(self, name, data, secret=None, **kwargs):</pre></div>
<div class="cov"><span class="num"><pre>113</pre></span><pre> """Save a signed cookie with ``secret`` signature</pre></div>
<div class="skip"><span class="num"><pre>114</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>115</pre></span><pre> Saves a signed cookie of the pickled data. All other keyword</pre></div>
<div class="cov"><span class="num"><pre>116</pre></span><pre> arguments that ``WebOb.set_cookie`` accepts are usable and</pre></div>
<div class="cov"><span class="num"><pre>117</pre></span><pre> passed to the WebOb set_cookie method after creating the signed</pre></div>
<div class="cov"><span class="num"><pre>118</pre></span><pre> cookie value.</pre></div>
<div class="skip"><span class="num"><pre>119</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>120</pre></span><pre> """</pre></div>
<div class="nocov"><span class="num"><pre>121</pre></span><pre> pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)</pre></div>
<div class="nocov"><span class="num"><pre>122</pre></span><pre> sig = hmac.new(secret, pickled, sha1).hexdigest()</pre></div>
<div class="nocov"><span class="num"><pre>123</pre></span><pre> self.set_cookie(name, sig + base64.encodestring(pickled), **kwargs)</pre></div>
<div class="skip"><span class="num"><pre>124</pre></span><pre></pre></div>
<div class="skip"><span class="num"><pre>125</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre>126</pre></span><pre>def etag_cache(key=None):</pre></div>
<div class="cov"><span class="num"><pre>127</pre></span><pre> """Use the HTTP Entity Tag cache for Browser side caching</pre></div>
<div class="skip"><span class="num"><pre>128</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>129</pre></span><pre> If a "If-None-Match" header is found, and equivilant to ``key``,</pre></div>
<div class="cov"><span class="num"><pre>130</pre></span><pre> then a ``304`` HTTP message will be returned with the ETag to tell</pre></div>
<div class="cov"><span class="num"><pre>131</pre></span><pre> the browser that it should use its current cache of the page.</pre></div>
<div class="skip"><span class="num"><pre>132</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>133</pre></span><pre> Otherwise, the ETag header will be added to the response headers.</pre></div>
<div class="skip"><span class="num"><pre>134</pre></span><pre></pre></div>
<div class="skip"><span class="num"><pre>135</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>136</pre></span><pre> Suggested use is within a Controller Action like so:</pre></div>
<div class="skip"><span class="num"><pre>137</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>138</pre></span><pre> .. code-block:: python</pre></div>
<div class="skip"><span class="num"><pre>139</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>140</pre></span><pre> import pylons</pre></div>
<div class="skip"><span class="num"><pre>141</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>142</pre></span><pre> class YourController(BaseController):</pre></div>
<div class="cov"><span class="num"><pre>143</pre></span><pre> def index(self):</pre></div>
<div class="cov"><span class="num"><pre>144</pre></span><pre> etag_cache(key=1)</pre></div>
<div class="cov"><span class="num"><pre>145</pre></span><pre> return render('/splash.mako')</pre></div>
<div class="skip"><span class="num"><pre>146</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>147</pre></span><pre> .. note::</pre></div>
<div class="cov"><span class="num"><pre>148</pre></span><pre> This works because etag_cache will raise an HTTPNotModified</pre></div>
<div class="cov"><span class="num"><pre>149</pre></span><pre> exception if the ETag received matches the key provided.</pre></div>
<div class="skip"><span class="num"><pre>150</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>151</pre></span><pre> """</pre></div>
<div class="cov"><span class="num"><pre>152</pre></span><pre> if_none_matches = IF_NONE_MATCH.findall(</pre></div>
<div class="cov"><span class="num"><pre>153</pre></span><pre> pylons.request.environ.get('HTTP_IF_NONE_MATCH', ''))</pre></div>
<div class="cov"><span class="num"><pre>154</pre></span><pre> response = pylons.response._current_obj()</pre></div>
<div class="cov"><span class="num"><pre>155</pre></span><pre> response.headers['ETag'] = '"%s"' % key</pre></div>
<div class="cov"><span class="num"><pre>156</pre></span><pre> if str(key) in if_none_matches:</pre></div>
<div class="nocov"><span class="num"><pre>157</pre></span><pre> log.debug("ETag match, returning 304 HTTP Not Modified Response")</pre></div>
<div class="nocov"><span class="num"><pre>158</pre></span><pre> response.headers.pop('Content-Type', None)</pre></div>
<div class="nocov"><span class="num"><pre>159</pre></span><pre> response.headers.pop('Cache-Control', None)</pre></div>
<div class="nocov"><span class="num"><pre>160</pre></span><pre> response.headers.pop('Pragma', None)</pre></div>
<div class="nocov"><span class="num"><pre>161</pre></span><pre> raise status_map[304]().exception</pre></div>
<div class="cov"><span class="num"><pre>162</pre></span><pre> else:</pre></div>
<div class="cov"><span class="num"><pre>163</pre></span><pre> log.debug("ETag didn't match, returning response object")</pre></div>
<div class="skip"><span class="num"><pre>164</pre></span><pre></pre></div>
<div class="skip"><span class="num"><pre>165</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre>166</pre></span><pre>def forward(wsgi_app):</pre></div>
<div class="cov"><span class="num"><pre>167</pre></span><pre> """Forward the request to a WSGI application. Returns its response.</pre></div>
<div class="skip"><span class="num"><pre>168</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>169</pre></span><pre> .. code-block:: python</pre></div>
<div class="skip"><span class="num"><pre>170</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>171</pre></span><pre> return forward(FileApp('filename'))</pre></div>
<div class="skip"><span class="num"><pre>172</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>173</pre></span><pre> """</pre></div>
<div class="nocov"><span class="num"><pre>174</pre></span><pre> environ = pylons.request.environ</pre></div>
<div class="nocov"><span class="num"><pre>175</pre></span><pre> controller = environ.get('pylons.controller')</pre></div>
<div class="nocov"><span class="num"><pre>176</pre></span><pre> if not controller or not hasattr(controller, 'start_response'):</pre></div>
<div class="nocov"><span class="num"><pre>177</pre></span><pre> raise RuntimeError("Unable to forward: environ['pylons.controller'] "</pre></div>
<div class="nocov"><span class="num"><pre>178</pre></span><pre> "is not a valid Pylons controller")</pre></div>
<div class="nocov"><span class="num"><pre>179</pre></span><pre> return wsgi_app(environ, controller.start_response)</pre></div>
<div class="skip"><span class="num"><pre>180</pre></span><pre></pre></div>
<div class="skip"><span class="num"><pre>181</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre>182</pre></span><pre>def abort(status_code=None, detail="", headers=None, comment=None):</pre></div>
<div class="cov"><span class="num"><pre>183</pre></span><pre> """Aborts the request immediately by returning an HTTP exception</pre></div>
<div class="skip"><span class="num"><pre>184</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>185</pre></span><pre> In the event that the status_code is a 300 series error, the detail</pre></div>
<div class="cov"><span class="num"><pre>186</pre></span><pre> attribute will be used as the Location header should one not be</pre></div>
<div class="cov"><span class="num"><pre>187</pre></span><pre> specified in the headers attribute.</pre></div>
<div class="skip"><span class="num"><pre>188</pre></span><pre> </pre></div>
<div class="cov"><span class="num"><pre>189</pre></span><pre> """</pre></div>
<div class="cov"><span class="num"><pre>190</pre></span><pre> exc = status_map[status_code](detail=detail, headers=headers, </pre></div>
<div class="cov"><span class="num"><pre>191</pre></span><pre> comment=comment)</pre></div>
<div class="cov"><span class="num"><pre>192</pre></span><pre> log.debug("Aborting request, status: %s, detail: %r, headers: %r, "</pre></div>
<div class="cov"><span class="num"><pre>193</pre></span><pre> "comment: %r", status_code, detail, headers, comment)</pre></div>
<div class="cov"><span class="num"><pre>194</pre></span><pre> raise exc.exception</pre></div>
<div class="skip"><span class="num"><pre>195</pre></span><pre></pre></div>
<div class="skip"><span class="num"><pre>196</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre>197</pre></span><pre>def redirect(url, code=302):</pre></div>
<div class="cov"><span class="num"><pre>198</pre></span><pre> """Raises a redirect exception to the specified URL</pre></div>
<div class="skip"><span class="num"><pre>199</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre>200</pre></span><pre> Optionally, a code variable may be passed with the status code of</pre></div>
<div class="cov"><span class="num"><pre>201</pre></span><pre> the redirect, ie::</pre></div>
<div class="skip"><span class="num"><pre>202</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre>203</pre></span><pre> redirect(url(controller='home', action='index'), code=303)</pre></div>
<div class="skip"><span class="num"><pre>204</pre></span><pre></pre></div>
<div class="cov"><span class="num"><pre>205</pre></span><pre> """</pre></div>
<div class="cov"><span class="num"><pre>206</pre></span><pre> log.debug("Generating %s redirect" % code)</pre></div>
<div class="cov"><span class="num"><pre>207</pre></span><pre> exc = status_map[code]</pre></div>
<div class="cov"><span class="num"><pre>208</pre></span><pre> raise exc(location=url).exception</pre></div>
<div class="skip"><span class="num"><pre>209</pre></span><pre></pre></div>
</div>
</body>
</html>
|