'use strict'; /** * @license AngularJS * (c) 2010-2011 AngularJS http://angularjs.org * License: MIT */ (function(window) { var filename = /^(.*\/)angular-bootstrap.js(#.*)?$/, scripts = document.getElementsByTagName("SCRIPT"), serverPath, match, globalVars = {}; for(var j = 0; j < scripts.length; j++) { match = (scripts[j].src || "").match(filename); if (match) { serverPath = match[1]; } } function key(prop) { return "ng-clobber_" + prop; } window.angularClobberTest = function(file) { var varKey, prop, clobbered = []; for (prop in window) { varKey = key(prop); if (prop === 'event') { //skip special variables which keep on changing continue; } else if (!globalVars.hasOwnProperty(varKey)) { //console.log('new global variable found: ', prop); try { globalVars[varKey] = window[prop]; } catch(e) {} //ignore properties that throw exception when accessed (common in FF) } else if (globalVars[varKey] !== window[prop] && !isActuallyNaN(window[prop]) && prop != 'jqLite') { clobbered.push(prop); console.error("Global variable clobbered by script " + file + "! Variable name: " + prop); globalVars[varKey] = window[prop]; } } for (varKey in globalVars) { prop = varKey.substr(11); if (clobbered.indexOf(prop) == -1 && prop != 'event' && prop != 'jqLite' && !isActuallyNaN(globalVars[varKey]) && globalVars[varKey] !== window[prop]) { delete globalVars[varKey]; console.warn("Global variable unexpectedly deleted in script " + file + "! " + "Variable name: " + prop); } } function isActuallyNaN(val) { return isNaN(val) && (typeof val === 'number'); } }; function addScripts(){ var prop, i; // initialize the window property cache for (prop in window) { try { globalVars[key(prop)] = window[prop]; } catch(e) {} //ignore properties that throw exception when accessed (common in FF) } // load the js scripts for (i in Array.prototype.slice.call(arguments, 0)) { var file = arguments[i]; document.write(''); } } function addCss(file) { document.write(''); } addCss('angular.css'); addScripts('Angular.js', 'JSON.js', 'Compiler.js', 'Scope.js', 'Injector.js', 'jqLite.js', 'parser.js', 'Resource.js', 'Browser.js', 'sanitizer.js', 'AngularPublic.js', // Extension points 'service/cookieStore.js', 'service/cookies.js', 'service/defer.js', 'service/document.js', 'service/exceptionHandler.js', 'service/hover.js', 'service/invalidWidgets.js', 'service/location.js', 'service/log.js', 'service/resource.js', 'service/route.js', 'service/routeParams.js', 'service/sniffer.js', 'service/window.js', 'service/xhr.bulk.js', 'service/xhr.cache.js', 'service/xhr.error.js', 'service/xhr.js', 'service/locale.js', 'apis.js', 'filters.js', 'formatters.js', 'validators.js', 'directives.js', 'markups.js', 'widgets.js'); function onLoadListener(){ // empty the cache to prevent mem leaks globalVars = {}; var config = angularJsConfig(document); // angular-ie-compat.js needs to be pregenerated for development with IE<8 config.ie_compat = serverPath + '../build/angular-ie-compat.js'; angularInit(config, document); } if (window.addEventListener){ window.addEventListener('load', onLoadListener, false); } else if (window.attachEvent){ window.attachEvent('onload', onLoadListener); } })(window); #n23'>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 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
"""
The :mod:`request` module provides a :class:`Request` class used to wrap the standard `request`
object received in all the views.
The wrapped request then offers a richer API, in particular :
- content automatically parsed according to `Content-Type` header,
and available as :meth:`.DATA<Request.DATA>`
- full support of PUT method, including support for file uploads
- form overloading of HTTP method, content type and content
"""
from StringIO import StringIO
from django.http.multipartparser import parse_header
from rest_framework import exceptions
from rest_framework.settings import api_settings
def is_form_media_type(media_type):
"""
Return True if the media type is a valid form media type.
"""
base_media_type, params = parse_header(media_type)
return (base_media_type == 'application/x-www-form-urlencoded' or
base_media_type == 'multipart/form-data')
class Empty(object):
"""
Placeholder for unset attributes.
Cannot use `None`, as that may be a valid value.
"""
pass
def _hasattr(obj, name):
return not getattr(obj, name) is Empty
def clone_request(request, method):
"""
Internal helper method to clone a request, replacing with a different
HTTP method. Used for checking permissions against other methods.
"""
ret = Request(request._request,
request.parsers,
request.authenticators,
request.parser_context)
ret._data = request._data
ret._files = request._files
ret._content_type = request._content_type
ret._stream = request._stream
ret._method = method
if hasattr(request, '_user'):
ret._user = request._user
if hasattr(request, '_auth'):
ret._auth = request._auth
return ret
class Request(object):
"""
Wrapper allowing to enhance a standard `HttpRequest` instance.
Kwargs:
- request(HttpRequest). The original request instance.
- parsers_classes(list/tuple). The parsers to use for parsing the
request content.
- authentication_classes(list/tuple). The authentications used to try
authenticating the request's user.
"""
_METHOD_PARAM = api_settings.FORM_METHOD_OVERRIDE
_CONTENT_PARAM = api_settings.FORM_CONTENT_OVERRIDE
_CONTENTTYPE_PARAM = api_settings.FORM_CONTENTTYPE_OVERRIDE
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
self._request = request
self.parsers = parsers or ()
self.authenticators = authenticators or ()
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = Empty
self._files = Empty
self._method = Empty
self._content_type = Empty
self._stream = Empty
self._authenticator = None
if self.parser_context is None:
self.parser_context = {}
self.parser_context['request'] = self
def _default_negotiator(self):
return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS()
@property
def method(self):
"""
Returns the HTTP method.
This allows the `method` to be overridden by using a hidden `form`
field on a form POST request.
"""
if not _hasattr(self, '_method'):
self._load_method_and_content_type()
return self._method
@property
def content_type(self):
"""
Returns the content type header.
This should be used instead of `request.META.get('HTTP_CONTENT_TYPE')`,
as it allows the content type to be overridden by using a hidden form
field on a form POST request.
"""
if not _hasattr(self, '_content_type'):
self._load_method_and_content_type()
return self._content_type
@property
def stream(self):
"""
Returns an object that may be used to stream the request content.
"""
if not _hasattr(self, '_stream'):
self._load_stream()
return self._stream
@property
def QUERY_PARAMS(self):
"""
More semantically correct name for request.GET.
"""
return self._request.GET
@property
def DATA(self):
"""
Parses the request body and returns the data.
Similar to usual behaviour of `request.POST`, except that it handles
arbitrary parsers, and also works on methods other than POST (eg PUT).
"""
if not _hasattr(self, '_data'):
self._load_data_and_files()
return self._data
@property
def FILES(self):
"""
Parses the request body and returns any files uploaded in the request.
Similar to usual behaviour of `request.FILES`, except that it handles
arbitrary parsers, and also works on methods other than POST (eg PUT).
"""
if not _hasattr(self, '_files'):
self._load_data_and_files()
return self._files
@property
def user(self):
"""
Returns the user associated with the current request, as authenticated
by the authentication classes provided to the request.
"""
if not hasattr(self, '_user'):
self._authenticator, self._user, self._auth = self._authenticate()
return self._user
@user.setter
def user(self, value):
"""
Sets the user on the current request. This is necessary to maintain
compatilbility with django.contrib.auth where the user proprety is
set in the login and logout functions.
"""
self._user = value
@property
def auth(self):
"""
Returns any non-user authentication information associated with the
request, such as an authentication token.
"""
if not hasattr(self, '_auth'):
self._authenticator, self._user, self._auth = self._authenticate()
return self._auth
@auth.setter
def auth(self, value):
"""
Sets any non-user authentication information associated with the
request, such as an authentication token.
"""
self._auth = value
@property
def successful_authenticator(self):
"""
Return the instance of the authentication instance class that was used
to authenticate the request, or `None`.
"""
return self._authenticator
def _load_data_and_files(self):
"""
Parses the request content into self.DATA and self.FILES.
"""
if not _hasattr(self, '_content_type'):
self._load_method_and_content_type()
if not _hasattr(self, '_data'):
self._data, self._files = self._parse()
def _load_method_and_content_type(self):
"""
Sets the method and content_type, and then check if they've
been overridden.
"""
self._content_type = self.META.get('HTTP_CONTENT_TYPE',
self.META.get('CONTENT_TYPE', ''))
self._perform_form_overloading()
# if the HTTP method was not overloaded, we take the raw HTTP method
if not _hasattr(self, '_method'):
self._method = self._request.method
def _load_stream(self):
"""
Return the content body of the request, as a stream.
"""
try:
content_length = int(self.META.get('CONTENT_LENGTH',
self.META.get('HTTP_CONTENT_LENGTH')))
except (ValueError, TypeError):
content_length = 0
if content_length == 0:
self._stream = None
elif hasattr(self._request, 'read'):
self._stream = self._request
else:
self._stream = StringIO(self.raw_post_data)
def _perform_form_overloading(self):
"""
If this is a form POST request, then we need to check if the method and
content/content_type have been overridden by setting them in hidden
form fields or not.
"""
USE_FORM_OVERLOADING = (
self._METHOD_PARAM or
(self._CONTENT_PARAM and self._CONTENTTYPE_PARAM)
)
# We only need to use form overloading on form POST requests.
if (not USE_FORM_OVERLOADING
or self._request.method != 'POST'
or not is_form_media_type(self._content_type)):
return
# At this point we're committed to parsing the request as form data.
self._data = self._request.POST
self._files = self._request.FILES
# Method overloading - change the method and remove the param from the content.
if (self._METHOD_PARAM and
self._METHOD_PARAM in self._data):
self._method = self._data[self._METHOD_PARAM].upper()
# Content overloading - modify the content type, and force re-parse.
if (self._CONTENT_PARAM and
self._CONTENTTYPE_PARAM and
self._CONTENT_PARAM in self._data and
self._CONTENTTYPE_PARAM in self._data):
self._content_type = self._data[self._CONTENTTYPE_PARAM]
self._stream = StringIO(self._data[self._CONTENT_PARAM])
self._data, self._files = (Empty, Empty)
def _parse(self):
"""
Parse the request content, returning a two-tuple of (data, files)
May raise an `UnsupportedMediaType`, or `ParseError` exception.
"""
stream = self.stream
media_type = self.content_type
if stream is None or media_type is None:
return (None, None)
parser = self.negotiator.select_parser(self, self.parsers)
if not parser:
raise exceptions.UnsupportedMediaType(media_type)
parsed = parser.parse(stream, media_type, self.parser_context)
# Parser classes may return the raw data, or a
# DataAndFiles object. Unpack the result as required.
try:
return (parsed.data, parsed.files)
except AttributeError:
return (parsed, None)
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
Returns a three-tuple of (authenticator, user, authtoken).
"""
for authenticator in self.authenticators:
user_auth_tuple = authenticator.authenticate(self)
if not user_auth_tuple is None:
user, auth = user_auth_tuple
return (authenticator, user, auth)
return self._not_authenticated()
def _not_authenticated(self):
"""
Return a three-tuple of (authenticator, user, authtoken), representing
an unauthenticated request.
By default this will be (None, AnonymousUser, None).
"""
if api_settings.UNAUTHENTICATED_USER:
user = api_settings.UNAUTHENTICATED_USER()
else:
user = None
if api_settings.UNAUTHENTICATED_TOKEN:
auth = api_settings.UNAUTHENTICATED_TOKEN()
else:
auth = None
return (None, user, auth)
def __getattr__(self, attr):
"""
Proxy other attributes to the underlying HttpRequest object.
"""
return getattr(self._request, attr)