30 |
30 |
31 from logilab.common.decorators import cached |
31 from logilab.common.decorators import cached |
32 |
32 |
33 from cubicweb.web.request import CubicWebRequestBase |
33 from cubicweb.web.request import CubicWebRequestBase |
34 from cubicweb.wsgi import (pformat, qs2dict, safe_copyfileobj, parse_file_upload, |
34 from cubicweb.wsgi import (pformat, qs2dict, safe_copyfileobj, parse_file_upload, |
35 normalize_header) |
35 normalize_header) |
|
36 from cubicweb.web.http_headers import Headers |
36 |
37 |
37 |
38 |
38 |
39 |
39 class CubicWebWsgiRequest(CubicWebRequestBase): |
40 class CubicWebWsgiRequest(CubicWebRequestBase): |
40 """most of this code COMES FROM DJANO |
41 """most of this code COMES FROM DJANO |
42 |
43 |
43 def __init__(self, environ, vreg): |
44 def __init__(self, environ, vreg): |
44 self.environ = environ |
45 self.environ = environ |
45 self.path = environ['PATH_INFO'] |
46 self.path = environ['PATH_INFO'] |
46 self.method = environ['REQUEST_METHOD'].upper() |
47 self.method = environ['REQUEST_METHOD'].upper() |
47 self._headers = dict([(normalize_header(k[5:]), v) for k, v in self.environ.items() |
48 |
48 if k.startswith('HTTP_')]) |
49 headers_in = dict((normalize_header(k[5:]), v) for k, v in self.environ.items() |
|
50 if k.startswith('HTTP_')) |
49 https = environ.get("HTTPS") in ('yes', 'on', '1') |
51 https = environ.get("HTTPS") in ('yes', 'on', '1') |
50 post, files = self.get_posted_data() |
52 post, files = self.get_posted_data() |
51 super(CubicWebWsgiRequest, self).__init__(vreg, https, post) |
53 |
|
54 super(CubicWebWsgiRequest, self).__init__(vreg, https, post, |
|
55 headers= headers_in) |
52 if files is not None: |
56 if files is not None: |
53 for key, (name, _, stream) in files.iteritems(): |
57 for key, (name, _, stream) in files.iteritems(): |
54 name = unicode(name, self.encoding) |
58 if name is not None: |
|
59 name = unicode(name, self.encoding) |
55 self.form[key] = (name, stream) |
60 self.form[key] = (name, stream) |
56 # prepare output headers |
|
57 self.headers_out = {} |
|
58 |
61 |
59 def __repr__(self): |
62 def __repr__(self): |
60 # Since this is called as part of error handling, we need to be very |
63 # Since this is called as part of error handling, we need to be very |
61 # robust against potentially malformed input. |
64 # robust against potentially malformed input. |
62 form = pformat(self.form) |
65 form = pformat(self.form) |
85 if qs: |
88 if qs: |
86 return '%s?%s' % (path, qs) |
89 return '%s?%s' % (path, qs) |
87 |
90 |
88 return path |
91 return path |
89 |
92 |
90 def get_header(self, header, default=None): |
|
91 """return the value associated with the given input HTTP header, |
|
92 raise KeyError if the header is not set |
|
93 """ |
|
94 return self._headers.get(normalize_header(header), default) |
|
95 |
|
96 def set_header(self, header, value, raw=True): |
|
97 """set an output HTTP header""" |
|
98 assert raw, "don't know anything about non-raw headers for wsgi requests" |
|
99 self.headers_out[header] = value |
|
100 |
|
101 def add_header(self, header, value): |
|
102 """add an output HTTP header""" |
|
103 self.headers_out[header] = value |
|
104 |
|
105 def remove_header(self, header): |
|
106 """remove an output HTTP header""" |
|
107 self.headers_out.pop(header, None) |
|
108 |
|
109 def header_if_modified_since(self): |
|
110 """If the HTTP header If-modified-since is set, return the equivalent |
|
111 mx date time value (GMT), else return None |
|
112 """ |
|
113 return None |
|
114 |
|
115 ## wsgi request helpers ################################################### |
93 ## wsgi request helpers ################################################### |
116 |
94 |
117 def instance_uri(self): |
95 def instance_uri(self): |
118 """Return the instance's base URI (no PATH_INFO or QUERY_STRING) |
96 """Return the instance's base URI (no PATH_INFO or QUERY_STRING) |
119 |
97 |
140 def is_secure(self): |
118 def is_secure(self): |
141 return 'wsgi.url_scheme' in self.environ \ |
119 return 'wsgi.url_scheme' in self.environ \ |
142 and self.environ['wsgi.url_scheme'] == 'https' |
120 and self.environ['wsgi.url_scheme'] == 'https' |
143 |
121 |
144 def get_posted_data(self): |
122 def get_posted_data(self): |
|
123 # The WSGI spec says 'QUERY_STRING' may be absent. |
|
124 post = qs2dict(self.environ.get('QUERY_STRING', '')) |
145 files = None |
125 files = None |
146 if self.method == 'POST': |
126 if self.method == 'POST': |
147 if self.environ.get('CONTENT_TYPE', '').startswith('multipart'): |
127 if self.environ.get('CONTENT_TYPE', '').startswith('multipart'): |
148 header_dict = dict((normalize_header(k[5:]), v) |
128 header_dict = dict((normalize_header(k[5:]), v) |
149 for k, v in self.environ.items() |
129 for k, v in self.environ.items() |
150 if k.startswith('HTTP_')) |
130 if k.startswith('HTTP_')) |
151 header_dict['Content-Type'] = self.environ.get('CONTENT_TYPE', '') |
131 header_dict['Content-Type'] = self.environ.get('CONTENT_TYPE', '') |
152 post, files = parse_file_upload(header_dict, self.raw_post_data) |
132 post_, files = parse_file_upload(header_dict, self.raw_post_data) |
|
133 post.update(post_) |
153 else: |
134 else: |
154 post = qs2dict(self.raw_post_data) |
135 post.update(qs2dict(self.raw_post_data)) |
155 else: |
|
156 # The WSGI spec says 'QUERY_STRING' may be absent. |
|
157 post = qs2dict(self.environ.get('QUERY_STRING', '')) |
|
158 return post, files |
136 return post, files |
159 |
137 |
160 @property |
138 @property |
161 @cached |
139 @cached |
162 def raw_post_data(self): |
140 def raw_post_data(self): |
175 |
153 |
176 def _validate_cache(self): |
154 def _validate_cache(self): |
177 """raise a `DirectResponse` exception if a cached page along the way |
155 """raise a `DirectResponse` exception if a cached page along the way |
178 exists and is still usable |
156 exists and is still usable |
179 """ |
157 """ |
180 # XXX |
158 if self.get_header('Cache-Control') in ('max-age=0', 'no-cache'): |
181 # if self.get_header('Cache-Control') in ('max-age=0', 'no-cache'): |
159 # Expires header seems to be required by IE7 |
182 # # Expires header seems to be required by IE7 |
160 self.add_header('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT') |
183 # self.add_header('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT') |
161 return |
184 # return |
|
185 # try: |
162 # try: |
186 # http.checkPreconditions(self._twreq, _PreResponse(self)) |
163 # http.checkPreconditions(self._twreq, _PreResponse(self)) |
187 # except http.HTTPError, ex: |
164 # except http.HTTPError, ex: |
188 # self.info('valid http cache, no actual rendering') |
165 # self.info('valid http cache, no actual rendering') |
189 # raise DirectResponse(ex.response) |
166 # raise DirectResponse(ex.response) |