1 # WSGI interface for Roundup Issue Tracker
2 #
3 # This module is free software, you may redistribute it
4 # and/or modify under the same terms as Python.
5 #
7 import os
8 import cgi
9 import weakref
11 import roundup.instance
12 from roundup.cgi import TranslationService
13 from BaseHTTPServer import BaseHTTPRequestHandler, DEFAULT_ERROR_MESSAGE
16 class Writer(object):
17 '''Perform a start_response if need be when we start writing.'''
18 def __init__(self, request):
19 self.request = request #weakref.ref(request)
20 def write(self, data):
21 f = self.request.get_wfile()
22 self.write = f
23 return f(data)
25 class RequestDispatcher(object):
26 def __init__(self, home, debug=False, timing=False, lang=None):
27 assert os.path.isdir(home), '%r is not a directory'%(home,)
28 self.home = home
29 self.debug = debug
30 self.timing = timing
31 if lang:
32 self.translator = TranslationService.get_translation(lang,
33 tracker_home=home)
34 else:
35 self.translator = None
37 def __call__(self, environ, start_response):
38 """Initialize with `apache.Request` object"""
39 self.environ = environ
40 request = RequestDispatcher(self.home, self.debug, self.timing)
41 request.__start_response = start_response
43 request.wfile = Writer(request)
44 request.__wfile = None
46 if environ ['REQUEST_METHOD'] == 'OPTIONS':
47 code = 501
48 message, explain = BaseHTTPRequestHandler.responses[code]
49 request.start_response([('Content-Type', 'text/html'),
50 ('Connection', 'close')], code)
51 request.wfile.write(DEFAULT_ERROR_MESSAGE % locals())
52 return []
54 tracker = roundup.instance.open(self.home, not self.debug)
56 # need to strip the leading '/'
57 environ["PATH_INFO"] = environ["PATH_INFO"][1:]
58 if request.timing:
59 environ["CGI_SHOW_TIMING"] = request.timing
61 form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ)
63 client = tracker.Client(tracker, request, environ, form,
64 request.translator)
65 try:
66 client.main()
67 except roundup.cgi.client.NotFound:
68 request.start_response([('Content-Type', 'text/html')], 404)
69 request.wfile.write('Not found: %s'%client.path)
71 # all body data has been written using wfile
72 return []
74 def start_response(self, headers, response_code):
75 """Set HTTP response code"""
76 message, explain = BaseHTTPRequestHandler.responses[response_code]
77 self.__wfile = self.__start_response('%d %s'%(response_code,
78 message), headers)
80 def get_wfile(self):
81 if self.__wfile is None:
82 raise ValueError, 'start_response() not called'
83 return self.__wfile