Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closing connection on client half close, not allowing response. #3659

Open
kbaston opened this issue Mar 21, 2019 · 4 comments
Open

Closing connection on client half close, not allowing response. #3659

kbaston opened this issue Mar 21, 2019 · 4 comments

Comments

@kbaston
Copy link

kbaston commented Mar 21, 2019

Long story short

A http client sends a request to aiohttp and immediately sends a fin, closing their side of the connection. Aiohttp calls the handler to generate the response, but closes the connection rather than sending it.

This is caused by eol_received returning None, as per Protocol. Having this function return True, fixes this issue.

I haven't been able to find any issues with this fix, even cleanly closing the connection after the response. But I am no expert on aiohttp.

Expected behavior

aiohttp sends the response to the client and then closes the connection. The client.py prints the headers of the response.

Actual behavior

aiohttp closes the connection without sending the response. client.py simply prints:

Received b''

Steps to reproduce

client.py ( it only prints the headers of the response on success, but sufficient for this) :

import socket

HOST = '127.0.0.1'
PORT = 8080
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.sendall(b'GET / HTTP/0.9\r\n\r\n')
    s.shutdown(socket.SHUT_WR)
    data = s.recv(1025)
print('Received', repr(data))

server.py:

import asyncio

from aiohttp import web

async def handle(request):
    print("handling request: {}".format(request))
    asyncio.sleep(0.1)  # ensure the fin shows up.
    return web.Response(text="Hello")

app = web.Application()
app.add_routes([web.get('/', handle)])
web.run_app(app)

Run server.py first then client.py on the same machine.

Your environment

aiohttp as a server
aiohttp version 3.5.4
Reproduced on Ubuntu and OSX. Python 3.6.5.

@aio-libs-bot
Copy link

GitMate.io thinks the contributor most likely able to help you is @asvetlov.

Possibly related issues are #1814 (Close websocket connection when pong not received), #2849 (Getting Connection closed with aiohttp client), #2595 (Server handler halts after client connection closed), #96 (Close connection if response body is not consumed.), and #691 (Websockets are automatically closed after response).

@renanvieira
Copy link

renanvieira commented May 3, 2019

Your code at client.py shoudnt to loop through the recv until receive nothing? It worked here with something like this:

HOST = '127.0.0.1'
PORT = 8080
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.sendall(b'GET / HTTP/0.9\r\n\r\n')
    chunk = s.recv(1025)
    result = chunk
    s.shutdown(socket.SHUT_WR)

    while len(chunk) > 0:
        data = s.recv(1025)
        result += chunk

print('Received', repr(result))

Besides that, I think you forgot to await the call to asyncio.sleep(0.1) in the server.py file.

@kbaston
Copy link
Author

kbaston commented May 3, 2019

The actual client I have the issue isn't written in python, I was just wrote that script to have a repro script with a half close before the receive.

Though I'll pay I missed await on the sleep. But both of these were quick scripts and are just for reproducing the issue of closing the server side after a client half close.

@Dreamsorcerer
Copy link
Member

I think implementing this may add some complexity, as we need to be sure that we're now closing the connection in the protocol ourselves in all possible circumstances.

Additionally, it seems like it'd be of limited use:

Some transports, including SSL, don’t support half-closed connections, in which case returning true from this method will result in the connection being closed.

So, I suspect nobody will volunteer to implement this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants