Repository: benoitc/gunicorn

Issue:
Errors in code not displayed on the page
Starting from this commit https://github.com/benoitc/gunicorn/commit/03a944d66854e8c3a873973c2732a99f205b13fd gunicorn doesn't serve errors in code(ex SyntaxError or IndentationError), with [traceback.format_tb](https://github.com/benoitc/gunicorn/blob/master/gunicorn/workers/base.py#L158), ```tb_string``` is an array while [make_fail_app](https://github.com/benoitc/gunicorn/blob/master/gunicorn/util.py#L563) is expecting a string so if you have an error somewhere, you get this printed in the console instead showing the real error on the webpage

```
[2016-11-29 19:23:47 +0000] [8872] [ERROR] Error handling request
Traceback (most recent call last):
  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 182, in handle_request
    resp.write(item)
  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/http/wsgi.py", line 344, in write
    raise TypeError('%r is not a byte' % arg)
TypeError: ['  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/workers/base.py", line 143, in load_wsgi\n    self.wsgi = self.app.wsgi()\n', '  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/app/base.py", line 67, in wsgi\n    self.callable = self.load()\n', '  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 65, in load\n    return self.load_wsgiapp()\n', '  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 52, in load_wsgiapp\n    return util.import_app(self.app_uri)\n', '  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/util.py", line 378, in import_app\n    __import__(module)\n'] is not a byte
```
You only get the real error on the console when gunicorn starts but if you hit the webpage you get nothing(```ERR_CONTENT_LENGTH_MISMATCH```) and the ```...is not a byte``` error is displayed on the console

```
[2016-11-29 19:20:53 +0000] [8867] [INFO] Starting gunicorn 19.6.0
[2016-11-29 19:20:53 +0000] [8867] [INFO] Listening at: http://0.0.0.0:8000 (8867)
[2016-11-29 19:20:53 +0000] [8867] [INFO] Using worker: sync
[2016-11-29 19:20:53 +0000] [8872] [INFO] Booting worker with pid: 8872
[2016-11-29 19:20:53 +0000] [8872] [ERROR] unexpected indent (wsgi.py, line 7)
Traceback (most recent call last):
  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/workers/base.py", line 143, in load_wsgi
    self.wsgi = self.app.wsgi()
  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/app/base.py", line 67, in wsgi
    self.callable = self.load()
  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 65, in load
    return self.load_wsgiapp()
  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 52, in load_wsgiapp
    return util.import_app(self.app_uri)
  File "/home/daker/Projets/guni/env/local/lib/python2.7/site-packages/gunicorn/util.py", line 378, in import_app
    __import__(module)
  File "/home/daker/Projets/guni/wsgi.py", line 7
    start_response(status, response_headers)
    ^
IndentationError: unexpected indent
```


Discussion:

Resolving patch:
diff --git a/gunicorn/util.py b/gunicorn/util.py
--- a/gunicorn/util.py
+++ b/gunicorn/util.py
@@ -561,6 +561,7 @@ def warn(msg):
 
 
 def make_fail_app(msg):
+    msg = to_bytestring(msg)
 
     def app(environ, start_response):
         start_response("500 Internal Server Error", [
diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py
--- a/gunicorn/workers/base.py
+++ b/gunicorn/workers/base.py
@@ -12,6 +12,7 @@
 import time
 import traceback
 
+from gunicorn import six
 from gunicorn import util
 from gunicorn.workers.workertmp import WorkerTmp
 from gunicorn.reloader import preferred_reloader, Reloader, InotifyReloader
@@ -155,8 +156,9 @@ def load_wsgi(self):
                 exc_type, exc_val, exc_tb = sys.exc_info()
                 self.reloader.add_extra_file(exc_val.filename)
 
-                tb_string = traceback.format_tb(exc_tb)
-                self.wsgi = util.make_fail_app(tb_string)
+                tb_string = six.StringIO()
+                traceback.print_tb(exc_tb, file=tb_string)
+                self.wsgi = util.make_fail_app(tb_string.getvalue())
             finally:
                 del exc_tb
 


Test patch: