Comments (18)
@bdraco I'm asking for an update.
from aiohttp.
Not sure what I did to strike through the OS but that is all correct.
from aiohttp.
It does look a little odd, and seems a little obvious which makes me wonder why it hasn't been noticed before.
Do you think you could write a test in a PR to reproduce it? Then we could also try your suggestion of removing that check and seeing if any other tests break, which would be a good indication if it's the wrong change to make.
from aiohttp.
I think the code is expecting that the client will close the connection, but we can't always rely on that even if they say they're going to close it, they may not.
from aiohttp.
yeah, I forked aiohttp last night. I'll work on a small replication. I did try removing the call. This results in the next read request in close() failing with timeout error and then the socket does close but with a .. uh.. 1006 message I think.
I also started looking out how to pass message to close() so I could add a condition for the read statement. Didn't get very far but it was kind of late.
from aiohttp.
https://datatracker.ietf.org/doc/html/rfc6455#section-7
Once an endpoint has both sent and received a Close control frame, that endpoint SHOULD Close the WebSocket Connection
So, this is what it is trying to achieve when close is initiated by us.
As such, when a server is instructed to Close the WebSocket Connection it SHOULD initiate a TCP Close immediately, and when a client is instructed to do the same, it SHOULD wait for a TCP Close from the server.
Except as indicated above or as specified by the application layer (e.g., a script using the WebSocket API), clients SHOULD NOT close the connection.
I think we just need to tweak that code so that the server does not wait to receive a close code (as it has already received one), but it should continue to close the transport. i.e. Rather than removing that check we want to add self._set_code_close_transport(...)
in there (but, we might need to avoid calling it twice?).
from aiohttp.
so something like this instead of deleting? I looked through the code and it seems like _close_code is always set but i'm not sure if its safe to assume it is? Default is None.
if self._closing:
self._set_code_close_transport(self._close_code)
return True
from aiohttp.
but i'm not sure if its safe to assume it is?
Not sure, I'd have to look more closely. If we get the test up first, then we can see how it works.
from aiohttp.
Boiling this down has been harder then I expected. So far I'm not recreating the issue. More research and foul language will be required.
from aiohttp.
I'm pretty convinced there is a bug here where we don't close the transport if the client holds it open forever
from aiohttp.
@spikefishjohn Can you give #8200 a shot? I'm running it on my production HA systems without any unexpected side effects
I'll come up with a test for it if it fixes your issue
from aiohttp.
@bdraco yeah i'll give it a test. I've been trying to reproduce the issue with a smaller code base but haven't been able to so far which has been pretty frustrating.
I'll add this in today and see if it fixes the issue. If not i'll add a pdb trace of the accept to show what is happening if that helps.
from aiohttp.
Ok that seems to fix the issue. Here is the client I'm using to talk to gns3.
import asyncio
import base64
import json
import websockets
import logging
logger = logging.getLogger('websockets')
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
log = logging.getLogger(__name__)
# GNS3 WebSocket server violates RFC 6455 so we have to be active closer
# Lets give Websockets a chance to get data.
WS_CLOSE_TIMEOUT = 10
RECONNECT_TIMEOUT = 1.618
CONTROLLER_WS_API = '/v2/notifications/ws'
COMPUTE_WS = '/v2/notifications/ws'
SERVER = '127.0.0.1:3080'
USER = 'XXX'
PASS = 'XXX'
CREDS = f'{USER}:{PASS}'
ENCODED_CREDS = base64.b64encode(CREDS.encode()).decode()
CONTROLLER_URI = f'ws://{SERVER}{CONTROLLER_WS_API}'
COMPUTE_URI = f'ws://{SERVER}{COMPUTE_WS}'
async def main() -> None:
async with asyncio.TaskGroup() as tasks:
tasks.create_task(websocket_logger(CONTROLLER_URI))
async def websocket_logger(endpoint: str) -> None:
headers = {
'Authorization': f'Basic {ENCODED_CREDS}'
}
try:
async with websockets.connect(endpoint, close_timeout=WS_CLOSE_TIMEOUT, extra_headers=headers) as websocket:
print("Call close")
await websocket.close()
print("close complete")
except ConnectionRefusedError:
log.info(f'Connection to {endpoint!r} refused.')
await asyncio.sleep(RECONNECT_TIMEOUT)
if __name__ == '__main__':
asyncio.run(main())
This is what the client now reports.
john@compute01:~$ python3.11 ws-client.py
2024-03-02 11:40:39,775 - DEBUG - = connection is CONNECTING
2024-03-02 11:40:39,775 - DEBUG - > GET /v2/notifications/ws HTTP/1.1
2024-03-02 11:40:39,775 - DEBUG - > Host: 127.0.0.1:3080
2024-03-02 11:40:39,775 - DEBUG - > Upgrade: websocket
2024-03-02 11:40:39,775 - DEBUG - > Connection: Upgrade
2024-03-02 11:40:39,775 - DEBUG - > Sec-WebSocket-Key: XXX
2024-03-02 11:40:39,775 - DEBUG - > Sec-WebSocket-Version: 13
2024-03-02 11:40:39,775 - DEBUG - > Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
2024-03-02 11:40:39,776 - DEBUG - > Authorization: Basic XXX
2024-03-02 11:40:39,776 - DEBUG - > User-Agent: Python/3.11 websockets/12.0
2024-03-02 11:40:39,779 - DEBUG - < HTTP/1.1 101 Switching Protocols
2024-03-02 11:40:39,779 - DEBUG - < Upgrade: websocket
2024-03-02 11:40:39,779 - DEBUG - < Connection: upgrade
2024-03-02 11:40:39,779 - DEBUG - < Sec-WebSocket-Accept: XXX
2024-03-02 11:40:39,779 - DEBUG - < Sec-WebSocket-Extensions: permessage-deflate
2024-03-02 11:40:39,779 - DEBUG - < Date: Sat, 02 Mar 2024 16:40:39 GMT
2024-03-02 11:40:39,779 - DEBUG - < Server: Python/3.10 aiohttp/3.9.3
2024-03-02 11:40:39,779 - DEBUG - = connection is OPEN
Call close
2024-03-02 11:40:39,779 - DEBUG - = connection is CLOSING
2024-03-02 11:40:39,779 - DEBUG - > CLOSE 1000 (OK) [2 bytes]
2024-03-02 11:40:39,780 - DEBUG - < TEXT '{"action": "ping", "event": {"cpu_usage_percent...y_usage_percent": 3.4}}' [84 bytes]
2024-03-02 11:40:39,781 - DEBUG - < CLOSE 1000 (OK) [2 bytes]
2024-03-02 11:40:39,781 - DEBUG - = connection is CLOSED
close complete
john@compute01:~$
I'll pass this on the original poster of the bug and have them test as well.
from aiohttp.
I'll pass this on the original poster of the bug and have them test as well.
Thanks. Please keep us updated.
from aiohttp.
FYI the bug reporter indicated they won't be able to test for a week or so.
from aiohttp.
@spikefishjohn Was the reporter able to test the linked PR? Thanks
from aiohttp.
Thanks!
from aiohttp.
@bdraco The original poster of the GNS3 issues has indicated they will not be able to test this and asked that the original GNS3 bug be closed. Your patch fixed the client I made above for GNS3. I think that is as much as a reply as this will get.
That being said if you think there is something else I can do to help by all means let me know.
from aiohttp.
Related Issues (20)
- Please update llhttp to 9.2.1 HOT 7
- Using MultipartWriter.append_json breaks in 3.9.4 with AssertionError "assert CONTENT_DISPOSITION in payload.headers" HOT 8
- Exception occurred while requesting https URL using proxy aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host HOT 3
- Documentation mentions async_timeout as dependency HOT 2
- TimeoutError instead of 403 "Forbidden" in case of not corresponding content length HOT 4
- CONTRIB: easily-integrated minimal http server example HOT 1
- aiohttp ^C hangs when psycopg connection pool created HOT 1
- llhttp should be a separate, optional package HOT 2
- Error message not always propagated on 3.9.4 HOT 5
- ValueError: I/O operation on closed file on WSL HOT 2
- Security improvement: raise_for_status + ClientError prevent tokens from leaking HOT 5
- Broken HTTP request parsing: Upgrade: h2c header leads to discarded body HOT 8
- aiohttp does not support concurrent requests exceeding 500. HOT 2
- Termux aiohttp could not build wheels for aiohttp HOT 5
- aiohttp cannot make HTTPS (SSL) requests in a Windows container HOT 10
- DNS over HTTPS (DoH) HOT 1
- Unmonitored websocket task triggers false errors in logs HOT 3
- Documentation not working HOT 1
- https://docs.aiohttp.org/ has been defaced/squatted HOT 1
- aiohttp.org site is down HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from aiohttp.