DuckoNetДокументация 0.11.5Документация DuckoLab
Разделы

DuckoNet: HTTP/3 к сайту через MASQUE

HTTP/3 к сайту через MASQUE

MASQUE задаётся явно объектом MasqueProxy, импортируемым из duckonet:

MasqueProxy(endpoint, username="", password="", carrier="h2",
            uri_template="/.well-known/masque/udp/{target_host}/{target_port}/")

endpoint — HTTPS URL прокси, без пути (кроме /), query и fragment. Credentials передавайте отдельными полями, а не в endpoint. HTTP API нормализует имя хоста и добавляет порт 443, если он пропущен. Для учётных данных поддерживается Basic authentication. Имя пользователя/пароль скрыты из repr, но сами объекты и ответы не следует произвольно журналировать.

import os
from duckonet import HttpClient, MasqueProxy

proxy = MasqueProxy(
    "https://proxy.example:443",
    username=os.environ.get("MASQUE_USER", ""),
    password=os.environ.get("MASQUE_PASSWORD", ""),
)
with HttpClient(api_key=os.environ["DUCKONET_API_KEY"], browser="chrome",
                proxy=proxy, protocol="h3") as client:
    if not client.capabilities.http3_proxy:
        raise RuntimeError("Выбранный runtime/profile не предоставляет HTTP3 proxy")
    response = client.get("https://origin.example/data")
    response.raise_for_status()
    print(response.status_code, response.protocol)

Можно выбрать маршрут для одного запроса: client.get(url, proxy=proxy, protocol="h3"). Поддерживаются и AsyncHttpClient (await client.get(...)), и обычные sync/async stream() с теми же proxy и protocol. client.capabilities.http3_proxy и client.capabilities.proxy_carriers сообщают о возможности загруженной сессии; они не гарантируют доступность или пригодность конкретного сервера прокси.

Маршрут использует HTTP/2 поверх TLS к прокси, CONNECT-UDP с reliable capsules RFC9297 и строгий HTTP/3 к конечному HTTPS-серверу. Прокси обязан поддерживать этот способ передачи и канонический URI template. Другие carrier или uri_template отклоняются; HTTPS/3 carrier и datagram-only peer этим API не заявлены. Ответ response.protocol описывает протокол сайта, а не внешнее соединение к прокси.

Для MasqueProxy задайте protocol="h3": фасад выберет h3_only. Расширенный вариант выбора того же режима — application="h3_only" при создании клиента. AUTO и H1/H2 для этого маршрута не предоставляются. Ошибка туннеля не превращается в прямой запрос или понижение протокола. Для обычных HTTP/HTTPS/SOCKS5/SOCKS5H proxy URLs прежняя семантика сохраняется: они не становятся MASQUE и не дают H3-туннель. SOCKS5 UDP ASSOCIATE не реализован.

Hostname и цепочка TLS проверяются для прокси и сайта. Один ca_bundle клиента используется для обеих проверок; отдельных proxy CA настроек нет. Если нужен свой доверенный CA, передайте абсолютный локальный путь к bundle, который подходит обоим узлам. Учётные данные прокси не предназначены для origin. Адрес самого прокси может разрешаться локально; целевое имя передаётся в CONNECT-UDP с сохранением SNI и проверки сертификата конечного сайта.

При фатальном отказе транспорта туннеля текущее действие возвращает исходную ошибку; неисправное соединение исключается из повторного использования. Библиотека не повторяет запрос автоматически. Следующий запрос выполняется только явным вызовом приложения и может открыть новое соединение через тот же прокси; успех зависит от его доступности. Решение повторить операцию принимает приложение с учётом возможных побочных эффектов.

Параметры запроса/stream, cookies, HTTP сроки и HTTP исключения остаются параметрами существующего HTTP API. Неподдержанные сочетания маршрута/протокола/профиля отклоняются; для анализа HTTP-ошибок используйте действующие NativeError и describe_http_error. Отдельного публичного MasqueError нет. Доступ по API-ключу и выбранным подписанным профилям сохраняет обычные правила DuckoNet.

Асинхронный запрос через MASQUE

import asyncio
import os
from duckonet import AsyncHttpClient, MasqueProxy

async def main():
    proxy = MasqueProxy(
        os.environ["MASQUE_ENDPOINT"],
        username=os.environ.get("MASQUE_USER", ""),
        password=os.environ.get("MASQUE_PASSWORD", ""),
    )
    async with AsyncHttpClient(
        api_key=os.environ["DUCKONET_API_KEY"], browser="chrome",
        proxy=proxy, protocol="h3",
    ) as client:
        response = await client.get("https://origin.example/data")
        response.raise_for_status()
        print(response.status_code, response.protocol)

asyncio.run(main())

stream() открывается через with client.stream("GET", url, ...) или async with client.stream("GET", url, ...); содержимое читается через stream.iter_bytes() или stream.iter_bytes() в async for соответственно. Маршрут, проверка TLS и строгий H3 действуют и для потока.

Все параметры MasqueProxy

ПараметрЗначение по умолчанию и ограничения
endpointОбязателен. HTTPS URL с hostname; порт 443 по умолчанию, явный порт 1…65535. Только пустой путь или /, без query, fragment, пробелов, обратной косой черты и credentials в URL. Длина нормализованного endpoint — до 4096 UTF-8 байт.
username"". Строка до 1024 UTF-8 байт, без управляющих символов.
password"". Те же ограничения; передавайте отдельно от URL.
carrier"h2". Поддерживается только это значение: HTTP/2 поверх TLS к прокси.
uri_template"/.well-known/masque/udp/{target_host}/{target_port}/". Поддерживается только этот шаблон. Хост и порт назначения подставляет транспорт.

Объект описывает неизменяемый маршрут. Проверка аргументов выполняется при использовании в HTTP API; само создание MasqueProxy(...) не устанавливает соединение и не проверяет сервер. Пустые credentials означают работу без заданного имени и пароля; сервер может требовать авторизацию. Неверные параметры дают ValueError или TypeError; неподдержанный профиль или транспорт может дать NativeError. Отказы прокси, TLS, аутентификации и CONNECT-UDP проверяйте по HTTP диагностике describe_http_error(error). Успешное создание объекта и capability не заменяют успешного запроса.

Профиль, cookies и полный прогон

WebSocket и MASQUE используют существующую установку, каталог state_dir, API-ключ и подписанные профили DuckoNet. Для обновления программы сохраняйте прежний state_dir: в нём находятся идентичность установки и история доверия. Cookies живут в памяти клиента; для сохранения после закрытия приложения используйте export_data() и import_data(). Выбор доступных версий браузера по ключу остаётся общим для HTTP и WS.

Когда используется version="last", клиент подготавливает новые доступные поколения в фоне. Обрамляйте весь связанный прогон client.run(): HTTP, открываемые в нём WS и потоки используют закреплённое поколение до завершения своих операций. Следующий внешний run() выбирает уже подготовленное поколение; вложенный run() наследует текущий. Обновление не переключает профиль внутри открытого WS. При явно выбранной версии профиль остаётся закреплённым.

import os
from duckonet import HttpClient

with HttpClient(
    api_key=os.environ["DUCKONET_API_KEY"], browser="chrome", version="last",
) as client:
    with client.run():
        response = client.get("https://app.example/session")
        response.raise_for_status()
        with client.websocket("wss://app.example/events", origin="https://app.example") as ws:
            ws.send("start")
            print(ws.recv())
        print(client.browser_profile)

В асинхронном коде используются async with client.run() и async with client.websocket(...). Закрывайте WS и потоки внутри своего run(); сам выход из run() не является командой немедленно прервать уже открытое соединение. Без явного run() автоматические операции используют исходное поколение клиента. client.profile_update_status показывает состояние подготовки профиля, а client.browser_profile — фактический профиль выбранного прогона. Поколение не даёт бессрочное право на сетевую работу: действуют обычные проверки срока действия, отзыва и доступа по ключу, в том числе при обмене по WS.

Cookies принадлежат клиенту и сохраняют штатные domain/path/secure/SameSite правила. Они доступны HTTP и WS в пределах того же владельца и переживают штатную смену поколения. Для общего cookie-состояния переиспользуйте один клиент; два независимых клиента не становятся одним cookie jar только из-за одинакового адреса сервера. cookies= — разовое наложение, а постоянными cookies управляйте через client.cookies.

Поддерживаемые маршруты

СценарийПоддержка
ws:// / wss:// напрямуюHTTP/1.1 Upgrade; текст, binary и permessage-deflate по согласованию.
WS через обычный HTTP/HTTPS/SOCKS5/SOCKS5H proxyС учётом возможностей профиля и транспорта. socks5 использует локальное разрешение цели; socks5h передаёт имя прокси. Для wss сохраняется проверка TLS сайта.
HTTP/3 к HTTPS-сайту через MasqueProxyСтрогий H3 внутри CONNECT-UDP, внешний carrier H2 с reliable capsules.
WS поверх H2/H3, WS через MASQUEНе предоставляются.
H3 через обычную HTTP/HTTPS/SOCKS строкуНе предоставляется; SOCKS5 UDP ASSOCIATE отсутствует.
MASQUE AUTO, H1/H2 к сайту, внешний H1/H3 carrier или другой URI templateНе предоставляются в этом API.

Внешнее соединение с прокси и соединение с сайтом имеют разные назначения. response.protocol относится к сайту. Настройки браузерного профиля применяются к соединению с целевым сайтом. TLS-соединение с прокси устанавливается отдельно. Библиотека не гарантирует полное совпадение всех сетевых признаков WebSocket и TLS прокси с браузером.

Текст страницы