1 from Cookie
import SimpleCookie
2 from pprint
import pformat
3 from urllib
import urlencode
4 from django
.utils
.datastructures
import MultiValueDict
7 # The mod_python version is more efficient, so try importing it first.
8 from mod_python
.util
import parse_qsl
10 from cgi
import parse_qsl
12 class HttpRequest(object): # needs to be new-style class because subclasses define "property"s
13 "A basic HTTP request"
15 self
.GET
, self
.POST
, self
.COOKIES
, self
.META
, self
.FILES
= {}, {}, {}, {}, {}
19 return '<HttpRequest\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \
20 (pformat(self
.GET
), pformat(self
.POST
), pformat(self
.COOKIES
),
23 def __getitem__(self
, key
):
24 for d
in (self
.POST
, self
.GET
):
27 raise KeyError, "%s not found in either POST or GET" % key
29 def has_key(self
, key
):
30 return self
.GET
.has_key(key
) or self
.POST
.has_key(key
)
32 def get_full_path(self
):
35 def parse_file_upload(header_dict
, post_data
):
36 "Returns a tuple of (POST MultiValueDict, FILES MultiValueDict)"
37 import email
, email
.Message
38 from cgi
import parse_header
39 raw_message
= '\r\n'.join(['%s:%s' % pair
for pair
in header_dict
.items()])
40 raw_message
+= '\r\n\r\n' + post_data
41 msg
= email
.message_from_string(raw_message
)
42 POST
= MultiValueDict()
43 FILES
= MultiValueDict()
44 for submessage
in msg
.get_payload():
45 if isinstance(submessage
, email
.Message
.Message
):
46 name_dict
= parse_header(submessage
['Content-Disposition'])[1]
47 # name_dict is something like {'name': 'file', 'filename': 'test.txt'} for file uploads
48 # or {'name': 'blah'} for POST fields
49 # We assume all uploaded files have a 'filename' set.
50 if name_dict
.has_key('filename'):
51 assert type([]) != type(submessage
.get_payload()), "Nested MIME messages are not supported"
52 if not name_dict
['filename'].strip():
54 # IE submits the full path, so trim everything but the basename.
55 # (We can't use os.path.basename because it expects Linux paths.)
56 filename
= name_dict
['filename'][name_dict
['filename'].rfind("\\")+1:]
57 FILES
.appendlist(name_dict
['name'], {
59 'content-type': (submessage
.has_key('Content-Type') and submessage
['Content-Type'] or None),
60 'content': submessage
.get_payload(),
63 POST
.appendlist(name_dict
['name'], submessage
.get_payload())
66 class QueryDict(MultiValueDict
):
67 """A specialized MultiValueDict that takes a query string when initialized.
68 This is immutable unless you create a copy of it."""
69 def __init__(self
, query_string
):
70 MultiValueDict
.__init
__(self
)
72 for key
, value
in parse_qsl((query_string
or ''), True): # keep_blank_values=True
73 self
.appendlist(key
, value
)
76 def _assert_mutable(self
):
78 raise AttributeError, "This QueryDict instance is immutable"
80 def _setitem_if_mutable(self
, key
, value
):
81 self
._assert
_mutable
()
82 MultiValueDict
.__setitem
__(self
, key
, value
)
83 __setitem__
= _setitem_if_mutable
85 def setlist(self
, key
, list_
):
86 self
._assert
_mutable
()
87 MultiValueDict
.setlist(self
, key
, list_
)
89 def appendlist(self
, key
, value
):
90 self
._assert
_mutable
()
91 MultiValueDict
.appendlist(self
, key
, value
)
93 def update(self
, other_dict
):
94 self
._assert
_mutable
()
95 MultiValueDict
.update(self
, other_dict
)
98 self
._assert
_mutable
()
99 return MultiValueDict
.pop(self
, key
)
102 self
._assert
_mutable
()
103 return MultiValueDict
.popitem(self
)
106 self
._assert
_mutable
()
107 MultiValueDict
.clear(self
)
109 def setdefault(self
, *args
):
110 self
._assert
_mutable
()
111 return MultiValueDict
.setdefault(self
, *args
)
114 "Returns a mutable copy of this object."
116 # Our custom __setitem__ must be disabled for copying machinery.
117 QueryDict
.__setitem
__ = dict.__setitem
__
118 cp
= copy
.deepcopy(self
)
119 QueryDict
.__setitem
__ = QueryDict
._setitem
_if
_mutable
125 for k
, list_
in self
.lists():
126 output
.extend([urlencode({k
: v
}) for v
in list_
])
127 return '&'.join(output
)
129 def parse_cookie(cookie
):
136 cookiedict
[key
] = c
.get(key
).value
140 "A basic HTTP response, with content and dictionary-accessed headers"
141 def __init__(self
, content
='', mimetype
=None):
143 from django
.conf
.settings
import DEFAULT_CONTENT_TYPE
, DEFAULT_CHARSET
144 mimetype
= "%s; charset=%s" % (DEFAULT_CONTENT_TYPE
, DEFAULT_CHARSET
)
145 self
.content
= content
146 self
.headers
= {'Content-Type':mimetype
}
147 self
.cookies
= SimpleCookie()
148 self
.status_code
= 200
151 "Full HTTP message, including headers"
152 return '\n'.join(['%s: %s' % (key
, value
)
153 for key
, value
in self
.headers
.items()]) \
154 + '\n\n' + self
.content
156 def __setitem__(self
, header
, value
):
157 self
.headers
[header
] = value
159 def __delitem__(self
, header
):
161 del self
.headers
[header
]
165 def __getitem__(self
, header
):
166 return self
.headers
[header
]
168 def has_header(self
, header
):
169 "Case-insensitive check for a header"
170 header
= header
.lower()
171 for key
in self
.headers
.keys():
172 if key
.lower() == header
:
176 def set_cookie(self
, key
, value
='', max_age
=None, expires
=None, path
='/', domain
=None, secure
=None):
177 self
.cookies
[key
] = value
178 for var
in ('max_age', 'path', 'domain', 'secure', 'expires'):
181 self
.cookies
[key
][var
.replace('_', '-')] = val
183 def delete_cookie(self
, key
):
185 self
.cookies
[key
]['max_age'] = 0
189 def get_content_as_string(self
, encoding
):
191 Returns the content as a string, encoding it from a Unicode object if
194 if isinstance(self
.content
, unicode):
195 return self
.content
.encode(encoding
)
198 # The remaining methods partially implement the file-like object interface.
199 # See http://docs.python.org/lib/bltin-file-objects.html
200 def write(self
, content
):
201 self
.content
+= content
207 return len(self
.content
)
209 class HttpResponseRedirect(HttpResponse
):
210 def __init__(self
, redirect_to
):
211 HttpResponse
.__init
__(self
)
212 self
['Location'] = redirect_to
213 self
.status_code
= 302
215 class HttpResponsePermanentRedirect(HttpResponse
):
216 def __init__(self
, redirect_to
):
217 HttpResponse
.__init
__(self
)
218 self
['Location'] = redirect_to
219 self
.status_code
= 301
221 class HttpResponseNotModified(HttpResponse
):
223 HttpResponse
.__init
__(self
)
224 self
.status_code
= 304
226 class HttpResponseNotFound(HttpResponse
):
227 def __init__(self
, *args
, **kwargs
):
228 HttpResponse
.__init
__(self
, *args
, **kwargs
)
229 self
.status_code
= 404
231 class HttpResponseForbidden(HttpResponse
):
232 def __init__(self
, *args
, **kwargs
):
233 HttpResponse
.__init
__(self
, *args
, **kwargs
)
234 self
.status_code
= 403
236 class HttpResponseGone(HttpResponse
):
237 def __init__(self
, *args
, **kwargs
):
238 HttpResponse
.__init
__(self
, *args
, **kwargs
)
239 self
.status_code
= 410
241 class HttpResponseServerError(HttpResponse
):
242 def __init__(self
, *args
, **kwargs
):
243 HttpResponse
.__init
__(self
, *args
, **kwargs
)
244 self
.status_code
= 500