Обновление файла
This commit is contained in:
@@ -8,11 +8,12 @@
|
||||
- Cookie PVEAuthCookie — если заданы PVE_USERNAME + PVE_PASSWORD
|
||||
3. Проксирует бинарный VNC-поток между браузером клиента и Proxmox.
|
||||
|
||||
Особенности Proxmox:
|
||||
Особенности:
|
||||
- В Proxmox 8.x+ vncticket может содержать спецсимволы (#, /, %, :),
|
||||
которые ломают парсинг URL (RFC 3986). Кодируем их через quote().
|
||||
- PVE может вернуть HTTP redirect (302) на `https://...` вместо `wss://...`;
|
||||
перехватываем и переписываем scheme через process_redirect.
|
||||
которые ломают парсинг URL (RFC 3986). Кодируем через quote().
|
||||
- process_redirect в websockets не работает на uvloop (используется
|
||||
uvicorn[standard]), поэтому редиректы не обрабатываем — Proxmox
|
||||
обычно их и не делает при корректном URL.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -22,7 +23,6 @@ from urllib.parse import quote
|
||||
|
||||
import httpx
|
||||
import websockets
|
||||
from websockets.http11 import Response
|
||||
from fastapi import APIRouter, Query, WebSocket, WebSocketDisconnect
|
||||
|
||||
from ..config import settings
|
||||
@@ -32,23 +32,6 @@ logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/console", tags=["console"])
|
||||
|
||||
|
||||
def _process_redirect(request, response: Response) -> Optional[str]:
|
||||
"""Перехватывает HTTP-redirect от Proxmox и переписывает https://→wss://.
|
||||
|
||||
Proxmox иногда возвращает Location со схемой https:// (хотя для WebSocket
|
||||
положено wss://). Библиотека websockets в этом случае падает с
|
||||
InvalidURI("scheme isn't ws or wss"). Возвращаем исправленный URL.
|
||||
"""
|
||||
location = response.headers.get("Location", "")
|
||||
if not location:
|
||||
return None
|
||||
if location.startswith("https://"):
|
||||
return "wss://" + location[len("https://"):]
|
||||
if location.startswith("http://"):
|
||||
return "ws://" + location[len("http://"):]
|
||||
return location
|
||||
|
||||
|
||||
async def _get_pve_auth_cookie() -> Optional[Tuple[str, str]]:
|
||||
"""Аутентифицируется в Proxmox по логину/паролю и возвращает (cookie_header, csrf_token).
|
||||
|
||||
@@ -94,9 +77,8 @@ async def console_ws(
|
||||
|
||||
guest_path = "qemu" if guest_type == "vm" else "lxc"
|
||||
pve_host_only = settings.pve_host.replace("http://", "").replace("https://", "")
|
||||
# quote() экранирует спецсимволы в тикете и порте по правилам RFC 3986,
|
||||
# не затрагивая уже экранированные символы. Без этого в Proxmox 8.x+
|
||||
# vncticket может содержать # / % : которые ломают URL.
|
||||
# quote() экранирует спецсимволы в тикете и порте по правилам RFC 3986.
|
||||
# Без этого в Proxmox 8.x+ vncticket может содержать # / % : которые ломают URL.
|
||||
safe_ticket = quote(ticket, safe="")
|
||||
safe_port = quote(str(port), safe="")
|
||||
upstream_url = (
|
||||
@@ -129,7 +111,6 @@ async def console_ws(
|
||||
extra_headers=headers,
|
||||
subprotocols=["binary"],
|
||||
ssl=None if settings.pve_verify_ssl else False,
|
||||
process_redirect=_process_redirect,
|
||||
) as upstream:
|
||||
logger.info("console_ws: upstream connected")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user