Skip to content

Commit 587a1cc

Browse files
vvanglroKludex
andauthored
fix: upgrade is not websocket and dependencies are installed, should not warning (#2360)
* fix: upgrade is not websocket, handle httptools with the same logic as h11 * test: add case * refactor: clearer judgment * Refactor(http): streamline upgrade warning logic * ruff * fix: simplify httptools_impl methods --------- Co-authored-by: Marcelo Trylesinski <[email protected]>
1 parent cee31a6 commit 587a1cc

File tree

3 files changed

+72
-18
lines changed

3 files changed

+72
-18
lines changed

tests/protocols/test_http.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,18 @@
159159
b"".join([b"x" * 32 * 1024 + b"\r\n", b"\r\n", b"\r\n"]),
160160
]
161161

162+
UPGRADE_REQUEST_ERROR_FIELD = b"\r\n".join(
163+
[
164+
b"GET / HTTP/1.1",
165+
b"Host: example.org",
166+
b"Connection: upgrade",
167+
b"Upgrade: not-websocket",
168+
b"Sec-WebSocket-Version: 11",
169+
b"",
170+
b"",
171+
]
172+
)
173+
162174

163175
class MockTransport:
164176
def __init__(self, sockname=None, peername=None, sslcontext=False):
@@ -1080,3 +1092,35 @@ async def app(scope: Scope, receive: ASGIReceiveCallable, send: ASGISendCallable
10801092
assert b"Hi!" in protocol.transport.buffer
10811093

10821094
assert not expected_states # consumed
1095+
1096+
1097+
async def test_header_upgrade_is_not_websocket_depend_installed(
1098+
caplog: pytest.LogCaptureFixture, http_protocol_cls: HTTPProtocol
1099+
):
1100+
caplog.set_level(logging.WARNING, logger="uvicorn.error")
1101+
app = Response("Hello, world", media_type="text/plain")
1102+
1103+
protocol = get_connected_protocol(app, http_protocol_cls)
1104+
protocol.data_received(UPGRADE_REQUEST_ERROR_FIELD)
1105+
await protocol.loop.run_one()
1106+
assert "Unsupported upgrade request." in caplog.text
1107+
msg = "No supported WebSocket library detected. Please use \"pip install 'uvicorn[standard]'\", or install 'websockets' or 'wsproto' manually." # noqa: E501
1108+
assert msg not in caplog.text
1109+
assert b"HTTP/1.1 200 OK" in protocol.transport.buffer
1110+
assert b"Hello, world" in protocol.transport.buffer
1111+
1112+
1113+
async def test_header_upgrade_is_websocket_depend_not_installed(
1114+
caplog: pytest.LogCaptureFixture, http_protocol_cls: HTTPProtocol
1115+
):
1116+
caplog.set_level(logging.WARNING, logger="uvicorn.error")
1117+
app = Response("Hello, world", media_type="text/plain")
1118+
1119+
protocol = get_connected_protocol(app, http_protocol_cls, ws="none")
1120+
protocol.data_received(UPGRADE_REQUEST_ERROR_FIELD)
1121+
await protocol.loop.run_one()
1122+
assert "Unsupported upgrade request." in caplog.text
1123+
msg = "No supported WebSocket library detected. Please use \"pip install 'uvicorn[standard]'\", or install 'websockets' or 'wsproto' manually." # noqa: E501
1124+
assert msg in caplog.text
1125+
assert b"HTTP/1.1 200 OK" in protocol.transport.buffer
1126+
assert b"Hello, world" in protocol.transport.buffer

uvicorn/protocols/http/h11_impl.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,24 @@ def _get_upgrade(self) -> bytes | None:
147147

148148
def _should_upgrade_to_ws(self) -> bool:
149149
if self.ws_protocol_class is None:
150-
if self.config.ws == "auto":
151-
msg = "Unsupported upgrade request."
152-
self.logger.warning(msg)
153-
msg = "No supported WebSocket library detected. Please use \"pip install 'uvicorn[standard]'\", or install 'websockets' or 'wsproto' manually." # noqa: E501
154-
self.logger.warning(msg)
155150
return False
156151
return True
157152

153+
def _unsupported_upgrade_warning(self) -> None:
154+
msg = "Unsupported upgrade request."
155+
self.logger.warning(msg)
156+
if not self._should_upgrade_to_ws():
157+
msg = "No supported WebSocket library detected. Please use \"pip install 'uvicorn[standard]'\", or install 'websockets' or 'wsproto' manually." # noqa: E501
158+
self.logger.warning(msg)
159+
160+
def _should_upgrade(self) -> bool:
161+
upgrade = self._get_upgrade()
162+
if upgrade == b"websocket" and self._should_upgrade_to_ws():
163+
return True
164+
if upgrade is not None:
165+
self._unsupported_upgrade_warning()
166+
return False
167+
158168
def data_received(self, data: bytes) -> None:
159169
self._unset_keepalive_if_required()
160170

@@ -206,9 +216,7 @@ def handle_events(self) -> None:
206216
"headers": self.headers,
207217
"state": self.app_state.copy(),
208218
}
209-
210-
upgrade = self._get_upgrade()
211-
if upgrade == b"websocket" and self._should_upgrade_to_ws():
219+
if self._should_upgrade():
212220
self.handle_websocket_upgrade(event)
213221
return
214222

uvicorn/protocols/http/httptools_impl.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,19 +141,20 @@ def _get_upgrade(self) -> bytes | None:
141141
return upgrade
142142
return None # pragma: full coverage
143143

144-
def _should_upgrade_to_ws(self, upgrade: bytes | None) -> bool:
145-
if upgrade == b"websocket" and self.ws_protocol_class is not None:
146-
return True
147-
if self.config.ws == "auto":
148-
msg = "Unsupported upgrade request."
149-
self.logger.warning(msg)
144+
def _should_upgrade_to_ws(self) -> bool:
145+
if self.ws_protocol_class is None:
146+
return False
147+
return True
148+
149+
def _unsupported_upgrade_warning(self) -> None:
150+
self.logger.warning("Unsupported upgrade request.")
151+
if not self._should_upgrade_to_ws():
150152
msg = "No supported WebSocket library detected. Please use \"pip install 'uvicorn[standard]'\", or install 'websockets' or 'wsproto' manually." # noqa: E501
151153
self.logger.warning(msg)
152-
return False
153154

154155
def _should_upgrade(self) -> bool:
155156
upgrade = self._get_upgrade()
156-
return self._should_upgrade_to_ws(upgrade)
157+
return upgrade == b"websocket" and self._should_upgrade_to_ws()
157158

158159
def data_received(self, data: bytes) -> None:
159160
self._unset_keepalive_if_required()
@@ -166,9 +167,10 @@ def data_received(self, data: bytes) -> None:
166167
self.send_400_response(msg)
167168
return
168169
except httptools.HttpParserUpgrade:
169-
upgrade = self._get_upgrade()
170-
if self._should_upgrade_to_ws(upgrade):
170+
if self._should_upgrade():
171171
self.handle_websocket_upgrade()
172+
else:
173+
self._unsupported_upgrade_warning()
172174

173175
def handle_websocket_upgrade(self) -> None:
174176
if self.logger.level <= TRACE_LOG_LEVEL:

0 commit comments

Comments
 (0)