1 import os |
1 import os |
2 import re |
2 import re |
3 from Cookie import SimpleCookie, CookieError |
3 from Cookie import BaseCookie, SimpleCookie, CookieError |
4 from pprint import pformat |
4 from pprint import pformat |
5 from urllib import urlencode |
5 from urllib import urlencode |
6 from urlparse import urljoin |
6 from urlparse import urljoin |
7 try: |
7 try: |
8 # The mod_python version is more efficient, so try importing it first. |
8 # The mod_python version is more efficient, so try importing it first. |
181 for key, value in dict.items(self): |
181 for key, value in dict.items(self): |
182 dict.__setitem__(result, key, value) |
182 dict.__setitem__(result, key, value) |
183 return result |
183 return result |
184 |
184 |
185 def __deepcopy__(self, memo): |
185 def __deepcopy__(self, memo): |
186 import copy |
186 import django.utils.copycompat as copy |
187 result = self.__class__('', mutable=True) |
187 result = self.__class__('', mutable=True) |
188 memo[id(self)] = result |
188 memo[id(self)] = result |
189 for key, value in dict.items(self): |
189 for key, value in dict.items(self): |
190 dict.__setitem__(result, copy.deepcopy(key, memo), copy.deepcopy(value, memo)) |
190 dict.__setitem__(result, copy.deepcopy(key, memo), copy.deepcopy(value, memo)) |
191 return result |
191 return result |
246 for k, list_ in self.lists(): |
246 for k, list_ in self.lists(): |
247 k = smart_str(k, self.encoding) |
247 k = smart_str(k, self.encoding) |
248 output.extend([urlencode({k: smart_str(v, self.encoding)}) for v in list_]) |
248 output.extend([urlencode({k: smart_str(v, self.encoding)}) for v in list_]) |
249 return '&'.join(output) |
249 return '&'.join(output) |
250 |
250 |
|
251 class CompatCookie(SimpleCookie): |
|
252 """ |
|
253 Cookie class that handles some issues with browser compatibility. |
|
254 """ |
|
255 def value_encode(self, val): |
|
256 # Some browsers do not support quoted-string from RFC 2109, |
|
257 # including some versions of Safari and Internet Explorer. |
|
258 # These browsers split on ';', and some versions of Safari |
|
259 # are known to split on ', '. Therefore, we encode ';' and ',' |
|
260 |
|
261 # SimpleCookie already does the hard work of encoding and decoding. |
|
262 # It uses octal sequences like '\\012' for newline etc. |
|
263 # and non-ASCII chars. We just make use of this mechanism, to |
|
264 # avoid introducing two encoding schemes which would be confusing |
|
265 # and especially awkward for javascript. |
|
266 |
|
267 # NB, contrary to Python docs, value_encode returns a tuple containing |
|
268 # (real val, encoded_val) |
|
269 val, encoded = super(CompatCookie, self).value_encode(val) |
|
270 |
|
271 encoded = encoded.replace(";", "\\073").replace(",","\\054") |
|
272 # If encoded now contains any quoted chars, we need double quotes |
|
273 # around the whole string. |
|
274 if "\\" in encoded and not encoded.startswith('"'): |
|
275 encoded = '"' + encoded + '"' |
|
276 |
|
277 return val, encoded |
|
278 |
251 def parse_cookie(cookie): |
279 def parse_cookie(cookie): |
252 if cookie == '': |
280 if cookie == '': |
253 return {} |
281 return {} |
254 try: |
282 if not isinstance(cookie, BaseCookie): |
255 c = SimpleCookie() |
283 try: |
256 c.load(cookie) |
284 c = CompatCookie() |
257 except CookieError: |
285 c.load(cookie) |
258 # Invalid cookie |
286 except CookieError: |
259 return {} |
287 # Invalid cookie |
260 |
288 return {} |
|
289 else: |
|
290 c = cookie |
261 cookiedict = {} |
291 cookiedict = {} |
262 for key in c.keys(): |
292 for key in c.keys(): |
263 cookiedict[key] = c.get(key).value |
293 cookiedict[key] = c.get(key).value |
264 return cookiedict |
294 return cookiedict |
265 |
295 |
284 self._container = content |
314 self._container = content |
285 self._is_string = False |
315 self._is_string = False |
286 else: |
316 else: |
287 self._container = [content] |
317 self._container = [content] |
288 self._is_string = True |
318 self._is_string = True |
289 self.cookies = SimpleCookie() |
319 self.cookies = CompatCookie() |
290 if status: |
320 if status: |
291 self.status_code = status |
321 self.status_code = status |
292 |
322 |
293 # _headers is a mapping of the lower-case name to the original case of |
323 # _headers is a mapping of the lower-case name to the original case of |
294 # the header (required for working with legacy systems) and the header |
324 # the header (required for working with legacy systems) and the header |
402 class HttpResponseRedirect(HttpResponse): |
432 class HttpResponseRedirect(HttpResponse): |
403 status_code = 302 |
433 status_code = 302 |
404 |
434 |
405 def __init__(self, redirect_to): |
435 def __init__(self, redirect_to): |
406 HttpResponse.__init__(self) |
436 HttpResponse.__init__(self) |
407 self['Location'] = redirect_to |
437 self['Location'] = iri_to_uri(redirect_to) |
408 |
438 |
409 class HttpResponsePermanentRedirect(HttpResponse): |
439 class HttpResponsePermanentRedirect(HttpResponse): |
410 status_code = 301 |
440 status_code = 301 |
411 |
441 |
412 def __init__(self, redirect_to): |
442 def __init__(self, redirect_to): |
413 HttpResponse.__init__(self) |
443 HttpResponse.__init__(self) |
414 self['Location'] = redirect_to |
444 self['Location'] = iri_to_uri(redirect_to) |
415 |
445 |
416 class HttpResponseNotModified(HttpResponse): |
446 class HttpResponseNotModified(HttpResponse): |
417 status_code = 304 |
447 status_code = 304 |
418 |
448 |
419 class HttpResponseBadRequest(HttpResponse): |
449 class HttpResponseBadRequest(HttpResponse): |