Roundup Issue Tracker - WSGI

Roundup is a simple-to-use and -install and highly configurable issue-tracking system with command-line, web and e-mail interfaces. It can be used to track bugs, features, user feedback, sales opportunities, milestones.

Its wsgi_handler.py requires start_response to return a write callable. According to Python WSGI spec, it is compliant, but it could/should have just return an iterable.

The start_response callable must return a write(body_data) callable that takes one positional parameter: a bytestring to be written as part of the HTTP response body. (Note: the write() callable is provided only to support certain existing frameworks' imperative output APIs; it should not be used by new applications or frameworks if it can be avoided.

  1. .

New WSGI applications and frameworks should not use the write() callable if it is possible to avoid doing so. The write() callable is strictly a hack to support imperative streaming APIs. In general, applications should produce their output via their returned iterable, as this makes it possible for web servers to interleave other tasks in the same Python thread, potentially providing better throughput for the server as a whole.

Also, because there are servers that does not return a write callable, so I have a hack to allow the wsgi_handler.py to return a list: request.__data if there is no write callable. (Change/addition is highlighted/bold)

 1 def __call__(self, environ, start_response):
2 """Initialize with apache.Request object"""
3 self.environ = environ
4 request = RequestDispatcher(self.home, self.debug, self.timing)
5 request.__start_response = start_response
6
7 request.wfile = Writer(request)
8 request.__wfile = None
9 request.__data = None
10
11 if environ ['REQUEST_METHOD'] == 'OPTIONS':
12 code = 501
13 message, explain = BaseHTTPRequestHandler.responses[code]
14 request.start_response([('Content-Type', 'text/html'),
15 ('Connection', 'close')], code)
16 request.wfile.write(DEFAULT_ERROR_MESSAGE % locals())
17 return request.__data or []
18
19 tracker = roundup.instance.open(self.home, not self.debug)
20
21 # need to strip the leading '/'
22 environ["PATH_INFO"] = environ["PATH_INFO"][1:]
23 if request.timing:
24 environ["CGI_SHOW_TIMING"] = request.timing
25
26 form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ)
27
28 client = tracker.Client(tracker, request, environ, form,
29 request.translator)
30 try:
31 client.main()
32 except roundup.cgi.client.NotFound:
33 request.start_response([('Content-Type', 'text/html')], 404)
34 request.wfile.write('Not found: %s'%client.path)
35
36 # all body data has been written using wfile
37 return request.__data or []
38
39 def start_response(self, headers, response_code):
40 """Set HTTP response code"""
41 message, explain = BaseHTTPRequestHandler.responses[response_code]
42 self.__wfile = self.__start_response('%d %s'%(response_code,
43 message), headers)
44
45 if (self.__wfile is None) and (self.__data is None):
46 self.__data = []
47 self.__wfile = self.__data.append
48

Comments

blog comments powered by Disqus