{"action":"opened","issue":{"url":"https://api.github.com/repos/eventlet/eventlet/issues/274","labels_url":"https://api.github.com/repos/eventlet/eventlet/issues/274/labels{/name}","comments_url":"https://api.github.com/repos/eventlet/eventlet/issues/274/comments","events_url":"https://api.github.com/repos/eventlet/eventlet/issues/274/events","html_url":"https://github.com/eventlet/eventlet/issues/274","id":122551664,"number":274,"title":"On Python 3, sock.makefile('rb').readline() doesn't handle blocking errors correctly","user":{"login":"haypo","id":194129,"avatar_url":"https://avatars.githubusercontent.com/u/194129?v=3","gravatar_id":"","url":"https://api.github.com/users/haypo","html_url":"https://github.com/haypo","followers_url":"https://api.github.com/users/haypo/followers","following_url":"https://api.github.com/users/haypo/following{/other_user}","gists_url":"https://api.github.com/users/haypo/gists{/gist_id}","starred_url":"https://api.github.com/users/haypo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/haypo/subscriptions","organizations_url":"https://api.github.com/users/haypo/orgs","repos_url":"https://api.github.com/users/haypo/repos","events_url":"https://api.github.com/users/haypo/events{/privacy}","received_events_url":"https://api.github.com/users/haypo/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-12-16T16:52:28Z","updated_at":"2015-12-16T16:52:28Z","closed_at":null,"body":"On Python 3, socket.socket is monkey-patched to GreenSocket (of eventlet.greenio.base) object. When sock.makefile('rb') is called, \r\n\r\nsock.makefile('rb')  creates a SocketIO object (of socket). SocketIO.readline() calls GreenSocket.recv_into() until it gets enough data. It stops when recv_into() returns 0 byte... but also when it returns None.\r\n\r\nGreenSocket.recv_into() starts with a trampoline to check if we have data to read, but *sometimes* this check is not enough: recv_into() raises a BlockingIOError. Sadly, GreenSocket.recv_into() only calls the trampoline once, it doesn't handle BlockingIOError.\r\n\r\nIn case of BlockingIOError, recv_into() is indirectly converted to None, and readline() interprets None as \"end of line\" so readline() returns an incomplete or empty line.\r\n\r\nIn the unit test of the OpenStack Glance project, an unit test fails because the HTTP client gets a BadStatusLine (of http.client). In fact, the underlying recv_into() raised BlockingIOError and the read is not retried.\r\n\r\nI will propose a fix."}}