0001import re
0002import urllib
0003import traceback
0004from Cookie import SimpleCookie
0005from paste.util import classinit
0006from paste.util import classinstance
0007from paste import httpexceptions
0008from paste import wsgilib
0009import cgifields
0010import event
0011import cookiewriter
0012
0013__all__ = ['Servlet']
0014
0015class ForwardRequest(Exception):
0016 def __init__(self, app):
0017 self.application = app
0018
0019class Servlet(object):
0020
0021 encoding = 'utf8'
0022 app_name = 'app'
0023 listeners = []
0024 _title = None
0025 _html_title = None
0026
0027 __metaclass__ = classinit.ClassInitMeta
0028
0029 def __classinit__(cls, new_attrs):
0030 if not new_attrs.has_key('listeners'):
0031 cls.listeners = cls.listeners[:]
0032 for attr, value in new_attrs.items():
0033 cls.add_attr(attr, value, set=False)
0034 classinit.build_properties(cls, new_attrs)
0035
0036 @classmethod
0037 def add_attr(cls, attr, value, set=True):
0038 if set:
0039 setattr(cls, attr, value)
0040 if hasattr(value, '__addtoclass__'):
0041 value.__addtoclass__(attr, cls)
0042
0043 def __call__(self, environ, start_response):
0044 try:
0045 status, headers, app_iter = self._process(
0046 environ, start_response)
0047 except ForwardRequest, e:
0048 return e.application(environ, start_response)
0049 else:
0050 start_response(status, headers)
0051 return app_iter
0052
0053 def _process(self, environ, start_response):
0054 value = event.raise_event('call', self, environ, start_response)
0055 if value is not event.Continue:
0056 status, headers, app_iter = value
0057 return status, headers, app_iter
0058 self.environ = environ
0059 self.config = self.environ.get('paste.config', {})
0060 if self.config.get('app_name'):
0061 self.app_name = self.config['app_name']
0062 self._cached_output = []
0063 self.headers_out = {
0064 'content-type': 'text/html; charset=%s' % self.encoding}
0065 self.status = '200 OK'
0066 self._cookies_out = {}
0067 self.request_method = environ['REQUEST_METHOD'].upper()
0068 self.app_url = self.environ.get('%s.base_url' % self.app_name, '')
0069 self.app_static_url = self.config.get(
0070 'static_url', self.app_url + '/static')
0071 self.path_info = self.environ.get('PATH_INFO', '')
0072 if self.path_info:
0073 self.path_parts = filter(None, self.path_info[1:].split('/'))
0074 else:
0075
0076
0077 self.path_parts = []
0078 self.fields = cgifields.Fields(wsgilib.parse_formvars(environ))
0079 self.cookies = {}
0080 if 'HTTP_COOKIE' in environ:
0081 cookies = SimpleCookie()
0082 try:
0083 cookies.load(environ['HTTP_COOKIE'])
0084 except:
0085 traceback.print_exc(file=self._environ['wsgi.errors'])
0086 for key in cookies.keys():
0087 self.cookies[key] = cookies[key].value
0088 self.run()
0089 headers = []
0090 for name, value in self.headers_out.items():
0091 if isinstance(value, list):
0092 for v in value:
0093 headers.append((name, v))
0094 else:
0095 headers.append((name, value))
0096 for cookie in self._cookies_out.values():
0097 headers.append(('Set-Cookie', cookie.header()))
0098 return self.status, headers, self._cached_output
0099
0100 @event.wrap_func
0101 def run(self):
0102 __traceback_hide__ = 'before_and_this'
0103 try:
0104 event.wrap_func(self.awake.im_func)(self)
0105 event.wrap_func(self.respond.im_func)(self)
0106 finally:
0107 event.wrap_func(self.sleep.im_func)(self)
0108
0109 def awake(self, call_setup=True):
0110 if call_setup:
0111 self.setup()
0112
0113 def setup(self):
0114 pass
0115
0116 def respond(self):
0117 pass
0118
0119 def sleep(self, call_teardown=True):
0120 if call_teardown:
0121 self.teardown()
0122
0123 def teardown(self):
0124 pass
0125
0126
0127
0128
0129
0130 def session__get(self):
0131 if 'paste.session.factory' in self.environ:
0132 sess = self.environ['paste.session.factory']()
0133 elif 'paste.flup_session_service' in self.environ:
0134 sess = self.environ['paste.flup_session_service'].session
0135 self.__dict__['session'] = sess
0136 return sess
0137
0138
0139
0140
0141
0142 def title__get(self):
0143 return self._title or self.__class__.__name__
0144
0145 def title__set(self, value):
0146 self._title = value
0147
0148 def html_title__get(self):
0149 return self._html_title or self.title
0150
0151 def html_title__set(self, value):
0152 self._html_title = value
0153
0154 def set_cookie(self, cookie_name, value, path='/',
0155 expires='ONCLOSE', secure=False):
0156 c = cookiewriter.Cookie(cookie_name, value, path=path,
0157 expires=expires, secure=secure)
0158 self._cookies_out[cookie_name] = c
0159
0160 def set_header(self, header_name, header_value):
0161 header_name = header_name.lower()
0162 if header_name == 'status':
0163 self.status = header_value
0164 return
0165 self.headers_out[header_name] = header_value
0166
0167 def add_header(self, header_name, header_value):
0168 header_name = header_name.lower()
0169 if header_name == 'status':
0170 self.status = header_value
0171 return
0172 if self.headers_out.has_key(header_name):
0173 if not isinstance(self.headers_out[header_name], list):
0174 self.headers_out[header_name] = [self.headers_out[header_name],
0175 header_value]
0176 else:
0177 self.headers_out[header_name].append(header_value)
0178 else:
0179 self.headers_out[header_name] = header_value
0180
0181 def write(self, *obj):
0182 for v in obj:
0183 if v is None:
0184 continue
0185 elif isinstance(v, str):
0186 self._cached_output.append(v)
0187 elif isinstance(v, unicode):
0188 self._cached_output.append(
0189 v.encode(self.encoding))
0190 else:
0191 self._cached_output.append(
0192 unicode(v).encode(self.encoding))
0193
0194 def redirect(self, url, **query_vars):
0195 url = str(url)
0196 if not url.startswith('/') and not abs_regex.search(url):
0197 url = self.app_url + '/' + url
0198 if 'status' in query_vars:
0199 status = query_vars.pop('status')
0200 if isinstance(status, (str, unicode)):
0201 status = int(status.split()[0])
0202 else:
0203 status = 303
0204 if query_vars:
0205 if '?' in url:
0206 url += '&'
0207 else:
0208 url += '?'
0209 url += urllib.urlencode(query_vars)
0210 raise httpexceptions.get_exception(status)(
0211 "This resource has been redirected",
0212 headers=[('Location', url)])
0213
0214 def forward_to_wsgiapp(self, app):
0215 """
0216 Forwards the request to the given WSGI application
0217 """
0218 raise ForwardRequest(app)
0219
0220 @classinstance.classinstancemethod
0221 def wsgi_application(self, cls, environ, application):
0222 if self is not None:
0223 return self(environ, application)
0224 else:
0225 return cls()(environ, application)
0226
0227abs_regex = re.compile(r'^[a-zA-Z]+:')