Repository: benoitc/gunicorn

Issue:
"Connection reset by peer" in handle_request isn't handled (or ignored)
We see a lot of these errors with HAProxy 1.5 in front of gunicorn:

```
2014-10-23 17:17:24,366 DEBUG OPTIONS /haproxy_check
2014-10-23 17:17:24,384 DEBUG Ignoring connection reset
2014-10-23 17:17:24,700 DEBUG OPTIONS /haproxy_check
2014-10-23 17:17:24,719 DEBUG Ignoring connection reset
2014-10-23 17:17:24,753 DEBUG OPTIONS /haproxy_check
2014-10-23 17:17:24,770 ERROR Error handling request
Traceback (most recent call last):
  File "/opt/lp-apps/webshell/lib/python2.7/site-packages/gunicorn/workers/async.py", line 108, in handle_request
    resp.write(item)
  File "/opt/lp-apps/webshell/lib/python2.7/site-packages/gunicorn/http/wsgi.py", line 344, in write
    util.write(self.sock, arg, self.chunked)
  File "/opt/lp-apps/webshell/lib/python2.7/site-packages/gunicorn/util.py", line 300, in write
    return write_chunk(sock, data)
  File "/opt/lp-apps/webshell/lib/python2.7/site-packages/gunicorn/util.py", line 295, in write_chunk
    sock.sendall(chunk)
  File "/opt/lp-apps/webshell/lib/python2.7/site-packages/gevent/socket.py", line 458, in sendall
    data_sent += self.send(_get_memory(data, data_sent), flags)
  File "/opt/lp-apps/webshell/lib/python2.7/site-packages/gevent/socket.py", line 435, in send
    return sock.send(data, flags)
error: [Errno 104] Connection reset by peer
2014-10-23 17:17:24,770 DEBUG Closing connection.
```

It seems that in the async worker, the error is sometimes caught and ignored in `handle`, but it also sometimes happens in `handle_request`. It should probably be ignored there as well?



Discussion:
Newest version of Gunicorn?

We're running 19.1.1. I haven't tested against unreleased versions, but the code seems very similar to me. (Is it by design that your `develop` branch seems to be older than `master` btw?)

 I know that a similar issue had crept up before on version 18, but as mentioned in the initial report, this time the exception happens in `handle_request`. Looking at the async handler code in [master:async.py](https://github.com/benoitc/gunicorn/blob/master/gunicorn/workers/async.py) `handle_request` does not have the same Exception handling for `socket.error` that `handle` has, but it logs and then reraises `socket.error` just as my supplied logs show.

I personally believe that "connection reset by peer" should be ignored there as well.

Btw: That code resulted from #630.

I also see this with gunicorn + nginx. I set gunicorn to have max_request 20 and I can reproduce it very reliably.

2014/10/31 00:10:15 [error] 75#0: *451 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 10.123.47.121, server: _, request: "GET /app/images/placeholders/small/14.png HTTP/1.1", upstream: "http://unix:/tmp/nginx.socket:/app/images/placeholders/small/14.png", host: "dw.betterworks.com", referrer: "https://dw.betterworks.com/app/"


Resolving patch:
diff --git a/gunicorn/workers/async.py b/gunicorn/workers/async.py
--- a/gunicorn/workers/async.py
+++ b/gunicorn/workers/async.py
@@ -118,6 +118,10 @@ def handle_request(self, listener_name, req, sock, addr):
                 raise StopIteration()
         except StopIteration:
             raise
+        except socket.error:
+            # If the original exception was a socket.error we delegate
+            # handling it to the caller (where handle() might ignore it 
+            six.reraise(*sys.exc_info())
         except Exception:
             if resp and resp.headers_sent:
                 # If the requests have already been sent, we should close the


Test patch: