SplitHTTP (H2, QUIC H3)
v1.8.16+Используется для загрузки с помощью HTTP-фрагментированной передачи, загрузка осуществляется с помощью нескольких HTTP POST-запросов.
Может использоваться через CDN, не поддерживающие WebSocket, но есть несколько требований:
- CDN должен поддерживать HTTP-фрагментированную передачу и потоковые ответы без буферизации. Ядро будет отправлять различную информацию, чтобы сообщить CDN об этом, но CDN должна ее соблюдать. Если промежуточный узел не поддерживает потоковые ответы и зависает, этот транспорт, скорее всего, не будет работать.
Цель та же, что и у V2fly Meek, но благодаря использованию фрагментированной загрузки скорость загрузки выше, а скорость отдачи оптимизирована, но все еще очень ограничена, поэтому к HTTP-прокси предъявляются более высокие требования (см. выше).
SplitHTTP
также принимает заголовок X-Forwarded-For
.
SplitHttpObject
SplitHttpObject
соответствует элементу splithttpSettings
в конфигурации транспорта.
{
"path": "/",
"host": "xray.com",
"headers": {
"key": "value"
},
"scMaxEachPostBytes": 1000000,
"scMaxConcurrentPosts": 100,
"scMinPostsIntervalMs": 30,
"noSSEHeader": false,
"xPaddingBytes": "100-1000",
"xmux": {
"maxConcurrency": 0,
"maxConnections": 0,
"cMaxReuseTimes": 0,
"cMaxLifetimeMs": 0
}
}
path
: string
Путь HTTP-протокола, используемый SplitHTTP. Значение по умолчанию — "/"
.
host
: string
Хост, отправляемый в HTTP-запросе SplitHTTP. Значение по умолчанию пустое. Если значение на сервере пустое, значение хоста, отправляемое клиентом, не проверяется.
Если значение указано на сервере или в headers
, оно будет сравниваться со значением хоста в запросе клиента.
Приоритет выбора хоста для отправки клиентом: host
> headers
> address
.
headers
: map {string: string}
Только для клиента. Пользовательские HTTP-заголовки. Пара «ключ-значение», где каждый ключ представляет собой имя HTTP-заголовка, а соответствующее значение — строка.
scMaxEachPostBytes
: int | string
Максимальный размер блока выгрузки в байтах. Значение по умолчанию — 1000000 (1 МБ).
Размер, установленный на клиенте, должен быть меньше этого значения, иначе запрос POST, размер которого превышает значение, установленное на сервере, будет отклонен.
Это значение должно быть меньше максимального размера тела запроса, разрешенного CDN или другим обратным прокси-сервером HTTP, иначе будет выдаваться ошибка HTTP 413.
Также может быть строкой в формате "500000-1000000", и ядро будет случайным образом выбирать значение из этого диапазона для уменьшения цифрового следа.
scMaxConcurrentPosts
: int | string
Максимальное количество одновременных запросов POST на одно соединение. Значение по умолчанию — 100.
Параллельная выгрузка также (и в основном) контролируется параметром scMinPostsIntervalMs
, поэтому это значение является лишь страховкой.
Фактическое количество запросов, отправляемых клиентом, должно быть меньше, чем на сервере. (На практике, поскольку указанного выше ограничения трудно достичь, клиент может фактически установить значение, превышающее значение на сервере, но это не рекомендуется).
Также может быть строкой в формате "50-100", и ядро будет случайным образом выбирать значение из этого диапазона для уменьшения цифрового следа.
scMinPostsIntervalMs
: int | string
Только для клиента. Минимальный интервал между запросами POST на выгрузку. Значение по умолчанию — 30.
Также может быть строкой в формате "10-50", и ядро будет случайным образом выбирать значение из этого диапазона для уменьшения цифрового следа.
noSSEHeader
: bool
Только для сервера. Не отправлять заголовок ответа Content-Type: text/event-stream
. Значение по умолчанию — false
(то есть заголовок будет отправлен).
xPaddingBytes
: int | string
Задает размер заполнения для запросов (исходящих) и ответов (входящих), используемый для уменьшения отпечатка запроса. Единица измерения: байты. Значение по умолчанию: "100-1000"
. При каждом запросе случайным образом выбирается число из этого диапазона. Тип: Int32Range
Значение -1
полностью отключает заполнение.
xmux
: XmuxObject
XmuxObject
v24.9.19+Только для клиента. Позволяет пользователю контролировать поведение многопоточности SplitHTTP в h2 и h3. Не используйте данную функцию вместе с mux.cool.
{
"maxConcurrency": "16-32",
"maxConnections": 0,
"cMaxReuseTimes": "64-128",
"cMaxLifetimeMs": 0
}
При установке всех значений в 0 или их отсутствии, ядро заполнит их значениями по умолчанию.
Объяснение терминов:
- Потоки будут мультиплексироваться в физические соединения, например: Соединение 1 (Поток 1, Поток 2, Поток 3) Соединение 2 (Поток 4, Поток 5, Поток 6) ... и так далее. В других источниках вы можете встретить описание "соединение-подключение", это то же самое.
- Все следующие поля имеют тип Int32Range:
maxConcurrency
: int/string
Значение по умолчанию — 0 (неограниченно). Максимальное количество потоков, мультиплексируемых в одном соединении. Когда количество потоков в соединении достигает этого значения, ядро создает дополнительные соединения для размещения новых потоков, аналогично параметру concurrency
в mux.cool.
maxConnections
: int/string
Значение по умолчанию — 0 (неограниченно). Максимальное количество открытых соединений. Ядро будет активно открывать новые соединения для каждого потока до тех пор, пока не будет достигнуто это значение. Затем ядро начнет мультиплексировать потоки в уже установленные соединения. Конфликтует с maxConcurrency
.
cMaxReuseTimes
: int/string
Значение по умолчанию — 0 (неограниченно). Максимальное количество раз, которое соединение может быть использовано повторно. По достижении этого значения ядро больше не будет назначать потоки этому соединению, и оно будет разорвано после закрытия последнего внутреннего потока.
cMaxLifetimeMs
: int/string
Значение по умолчанию — 0 (неограниченно). Максимальное время "жизни" соединения. По истечении этого времени ядро больше не будет назначать потоки этому соединению, и оно будет разорвано после закрытия последнего внутреннего потока.
Версия HTTP
Поведение клиента
По умолчанию клиент будет использовать http/1.1, если TLS не включен, и h2, если TLS включен.
Если TLS включен, можно указать конкретную версию HTTP (http/1.1, h2, h3) в массиве alpn
в настройках TLS (работает только в том случае, если массив содержит только один элемент, если указано несколько элементов, будет использоваться поведение по умолчанию).
Поведение сервера
По умолчанию сервер будет прослушивать TCP-порт и обрабатывать трафик http/1.1 и h2.
Если TLS включен, можно указать h3
в массиве alpn
в настройках TLS. В этом случае сервер будет прослушивать UDP-порт и обрабатывать трафик h3.
Советы
Поскольку этот протокол основан на стандартных HTTP-запросах, он нечувствителен к преобразованию версий HTTP, и различные промежуточные узлы могут преобразовывать версии HTTP.
Например, если вы хотите использовать h3 для подключения к Cloudflare, но Cloudflare не будет использовать h3 для обратного подключения, а будет использовать http/1.1 или h2, то на клиенте alpn
должен быть установлен в h3
, а на сервере — нет, поскольку запросы, отправляемые на сервер, не будут использовать h3.
Browser Dialer
При использовании HTTPS этот транспорт также поддерживает Browser Dialer.
Подробности протокола
Подробное обсуждение см. в #3412 и #3462. Ниже приведено краткое описание и требования к совместимости реализации:
- Загрузка начинается с запроса
GET /<UUID>
. Сервер немедленно отвечает200 OK
иTransfer Encoding:chunked
и сразу же отправляет двухбайтовую полезную нагрузку, чтобы заставить HTTP-промежуточные узлы сбросить заголовки.
На данный момент сервер отправляет следующие заголовки:
X-Accel-Buffering: no
— отключает буферизацию.Content-Type: text/event-stream
— отключает буферизацию на некоторых промежуточных узлах, можно отключить с помощью опции"noSSEHeader"
.Transfer-Encoding: chunked
— кодировка передачи данных, используется только в HTTP/1.1.Cache-Control: no-store
— отключает любое возможное кэширование ответов.
Выгрузка начинается с запроса
POST /<UUID>/<seq>
.seq
работает аналогично порядковому номеру TCP, начиная с 0. Пакеты данных могут отправляться одновременно, сервер должен пересобрать данные в соответствии с порядковым номером. Порядковый номер не должен сбрасываться.Клиент может открывать запросы на выгрузку и загрузку в любом порядке, любой из них может инициировать сеанс, но соединение
GET
должно быть открыто в течение 30 секунд, иначе сеанс будет разорван.Запрос
GET
будет оставаться открытым до тех пор, пока соединение не будет разорвано. Как сервер, так и клиент могут закрыть соединение. Конкретное поведение зависит от версии HTTP.
Рекомендации:
Не ожидайте, что CDN будет правильно передавать все заголовки. Цель этого протокола — обойти CDN, которые не поддерживают WS, а такие CDN обычно ведут себя не очень хорошо.
Следует предполагать, что все HTTP-соединения не поддерживают потоковые запросы, поэтому размер каждого пакета, отправляемого по исходящему соединению, должен основываться на задержке, пропускной способности и ограничениях самого промежуточного узла (аналогично MTU и алгоритму Нейгла в TCP).