diff -r 3ab2682a4b37 -r 50e1a6ad3e98 web/request.py --- a/web/request.py Thu May 06 08:24:46 2010 +0200 +++ b/web/request.py Mon Jul 19 15:36:16 2010 +0200 @@ -15,13 +15,12 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -"""abstract class for http request +"""abstract class for http request""" -""" __docformat__ = "restructuredtext en" import Cookie -import sha +import hashlib import time import random import base64 @@ -42,6 +41,8 @@ from cubicweb.view import STRICT_DOCTYPE, TRANSITIONAL_DOCTYPE_NOEXT from cubicweb.web import (INTERNAL_FIELD_VALUE, LOGGER, NothingToEdit, RequestError, StatusResponse, json) +from cubicweb.web.http_headers import Headers + dumps = json.dumps _MARKER = object() @@ -100,6 +101,8 @@ self.pageid = None self.datadir_url = self._datadir_url() self._set_pageid() + # prepare output header + self.headers_out = Headers() def _set_pageid(self): """initialize self.pageid @@ -131,11 +134,11 @@ self.set_page_data('rql_varmaker', varmaker) return varmaker - def set_connection(self, cnx, user=None): + def set_session(self, session, user=None): """method called by the session handler when the user is authenticated or an anonymous connection is open """ - super(CubicWebRequestBase, self).set_connection(cnx, user) + super(CubicWebRequestBase, self).set_session(session, user) # set request language vreg = self.vreg if self.user: @@ -160,8 +163,9 @@ gettext, self.pgettext = self.translations[lang] self._ = self.__ = gettext self.lang = lang - self.cnx.set_session_props(lang=lang) self.debug('request language: %s', lang) + if self.cnx: + self.cnx.set_session_props(lang=lang) # input form parameters management ######################################## @@ -245,7 +249,7 @@ @property def message(self): try: - return self.get_session_data(self._msgid, default=u'', pop=True) + return self.session.data.pop(self._msgid, '') except AttributeError: try: return self._msg @@ -266,17 +270,17 @@ def set_redirect_message(self, msg): assert isinstance(msg, unicode) msgid = self.redirect_message_id() - self.set_session_data(msgid, msg) + self.session.data[msgid] = msg return msgid def append_to_redirect_message(self, msg): msgid = self.redirect_message_id() - currentmsg = self.get_session_data(msgid) + currentmsg = self.session.data.get(msgid) if currentmsg is not None: currentmsg = '%s %s' % (currentmsg, msg) else: currentmsg = msg - self.set_session_data(msgid, currentmsg) + self.session.data[msgid] = currentmsg return msgid def reset_message(self): @@ -288,8 +292,8 @@ def update_search_state(self): """update the current search state""" searchstate = self.form.get('__mode') - if not searchstate and self.cnx is not None: - searchstate = self.get_session_data('search_state', 'normal') + if not searchstate and self.cnx: + searchstate = self.session.data.get('search_state', 'normal') self.set_search_state(searchstate) def set_search_state(self, searchstate): @@ -299,8 +303,8 @@ else: self.search_state = ('linksearch', searchstate.split(':')) assert len(self.search_state[-1]) == 4 - if self.cnx is not None: - self.set_session_data('search_state', searchstate) + if self.cnx: + self.session.data['search_state'] = searchstate def match_search_state(self, rset): """when searching an entity to create a relation, return True if entities in @@ -317,12 +321,12 @@ def update_breadcrumbs(self): """stores the last visisted page in session data""" - searchstate = self.get_session_data('search_state') + searchstate = self.session.data.get('search_state') if searchstate == 'normal': - breadcrumbs = self.get_session_data('breadcrumbs', None) + breadcrumbs = self.session.data.get('breadcrumbs') if breadcrumbs is None: breadcrumbs = SizeConstrainedList(10) - self.set_session_data('breadcrumbs', breadcrumbs) + self.session.data['breadcrumbs'] = breadcrumbs breadcrumbs.append(self.url()) else: url = self.url() @@ -330,7 +334,7 @@ breadcrumbs.append(url) def last_visited_page(self): - breadcrumbs = self.get_session_data('breadcrumbs', None) + breadcrumbs = self.session.data.get('breadcrumbs') if breadcrumbs: return breadcrumbs.pop() return self.base_url() @@ -355,15 +359,15 @@ def register_onetime_callback(self, func, *args): cbname = 'cb_%s' % ( - sha.sha('%s%s%s%s' % (time.time(), func.__name__, - random.random(), - self.user.login)).hexdigest()) + hashlib.sha1('%s%s%s%s' % (time.time(), func.__name__, + random.random(), + self.user.login)).hexdigest()) def _cb(req): try: ret = func(req, *args) except TypeError: from warnings import warn - warn('user callback should now take request as argument') + warn('[3.2] user callback should now take request as argument') ret = func(*args) self.unregister_callback(self.pageid, cbname) return ret @@ -377,11 +381,10 @@ self.del_page_data(cbname) def clear_user_callbacks(self): - if self.cnx is not None: - sessdata = self.session_data() - callbacks = [key for key in sessdata if key.startswith('cb_')] - for callback in callbacks: - self.del_session_data(callback) + if self.session is not None: # XXX + for key in self.session.data.keys(): + if key.startswith('cb_'): + del self.session.data[key] # web edition helpers ##################################################### @@ -447,13 +450,13 @@ This is needed when the edition is completed (whether it's validated or cancelled) """ - self.del_session_data('pending_insert') - self.del_session_data('pending_delete') + self.session.data.pop('pending_insert', None) + self.session.data.pop('pending_delete', None) def cancel_edition(self, errorurl): """remove pending operations and `errorurl`'s specific stored data """ - self.del_session_data(errorurl) + self.session.data.pop(errorurl, None) self.remove_pending_operations() # high level methods for HTTP headers management ########################## @@ -672,17 +675,26 @@ """ raise NotImplementedError() - def set_header(self, header, value): + def set_header(self, header, value, raw=True): """set an output HTTP header""" - raise NotImplementedError() + if raw: + # adding encoded header is important, else page content + # will be reconverted back to unicode and apart unefficiency, this + # may cause decoding problem (e.g. when downloading a file) + self.headers_out.setRawHeaders(header, [str(value)]) + else: + self.headers_out.setHeader(header, value) def add_header(self, header, value): """add an output HTTP header""" - raise NotImplementedError() + # adding encoded header is important, else page content + # will be reconverted back to unicode and apart unefficiency, this + # may cause decoding problem (e.g. when downloading a file) + self.headers_out.addRawHeader(header, str(value)) def remove_header(self, header): """remove an output HTTP header""" - raise NotImplementedError() + self.headers_out.removeHeader(header) def header_authorization(self): """returns a couple (auth-type, auth-value)""" @@ -747,27 +759,30 @@ # page data management #################################################### def get_page_data(self, key, default=None): - """return value associated to `key` in curernt page data""" - page_data = self.cnx.get_session_data(self.pageid, {}) + """return value associated to `key` in current page data""" + page_data = self.session.data.get(self.pageid) + if page_data is None: + return default return page_data.get(key, default) def set_page_data(self, key, value): """set value associated to `key` in current page data""" self.html_headers.add_unload_pagedata() - page_data = self.cnx.get_session_data(self.pageid, {}) + page_data = self.session.data.setdefault(self.pageid, {}) page_data[key] = value - return self.cnx.set_session_data(self.pageid, page_data) + self.session.data[self.pageid] = page_data def del_page_data(self, key=None): """remove value associated to `key` in current page data if `key` is None, all page data will be cleared """ if key is None: - self.cnx.del_session_data(self.pageid) + self.session.data.pop(self.pageid, None) else: - page_data = self.cnx.get_session_data(self.pageid, {}) - page_data.pop(key, None) - self.cnx.set_session_data(self.pageid, page_data) + try: + del self.session.data[self.pageid][key] + except KeyError: + pass # user-agent detection ####################################################