WebTransport

W3C 작업 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2025/WD-webtransport-20251217/
최신 공개 버전:
https://www.w3.org/TR/webtransport/
편집자 초안:
https://w3c.github.io/webtransport/
히스토리:
https://www.w3.org/standards/history/webtransport/
피드백:
public-webtransport@w3.org 제목에 “[webtransport] … 메시지 주제 …” 포함 (아카이브)
GitHub
명세 내 인라인
편집자:
Nidhi Jaju (Google)
Victor Vasiliev (Google)
Jan-Ivar Bruaroey (Mozilla)
이전 편집자:
Bernard Aboba (Microsoft Corporation)
Peter Thatcher (Google)
Robin Raymond (Optical Tone Ltd.)
Yutaka Hirano (Google)

요약

이 문서는 브라우저와 서버 간에 데이터를 보내고 받을 수 있도록 WebIDL에서 정의된 ECMAScript API 집합을 정의하며, [WEB-TRANSPORT-OVERVIEW]를 활용합니다. 이 명세는 IETF WEBTRANS 워킹 그룹에서 개발된 프로토콜 명세와 함께 개발되고 있습니다.

이 문서의 상태

이 섹션은 이 문서가 발행된 시점의 상태를 설명합니다. W3C의 최신 발행 목록과 최신 기술 보고서 개정판은 W3C 기술 보고서 색인에서 확인할 수 있습니다.

이 문서는 WebTransport 워킹 그룹에서 Recommendation track을 사용해 워킹 드래프트로 발행되었습니다. 이 문서는 W3C 권고안이 되는 것을 목표로 합니다.

이 문서에 대한 피드백과 의견을 환영합니다. 이슈를 등록 하거나, 이 문서의 GitHub 저장소를 이용해 주세요.

워킹 드래프트로 발행되었다고 해서 W3C 및 회원의 승인이나 지지를 의미하지는 않습니다. 이 문서는 초안이며 언제든 업데이트, 교체 또는 다른 문서에 의해 폐기될 수 있습니다. 이 문서를 진행 중인 작업 외의 용도로 인용하는 것은 적절하지 않습니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성되었습니다. W3C는 그룹의 산출물과 관련하여 이루어진 공개된 특허 리스트를 관리합니다. 해당 페이지에는 특허 공개 방법에 대한 안내도 포함되어 있습니다. 어떤 개인이 특정 특허가 필수 청구항을 포함한다고 생각하는 경우, W3C 특허 정책 6항에 따라 그 정보를 공개해야 합니다.

이 문서는 2025년 8월 18일 W3C 프로세스 문서의 적용을 받습니다.

1. 소개

이 섹션은 규범적인 내용이 아닙니다.

이 명세는 [WEB-TRANSPORT-OVERVIEW]를 사용하여 서버로 데이터를 보내고 받을 수 있습니다. 이는 WebSocket과 유사하게 사용할 수 있지만, 다중 스트림, 단방향 스트림, 순서가 뒤바뀐 전달, 그리고 신뢰성 있는 전송과 비신뢰성 전송을 모두 지원합니다.

참고: 이 명세에서 제공하는 API는 IETF WEBTRANS WG에서 진행 중인 작업을 바탕으로 한 예비 제안입니다. [WEB-TRANSPORT-HTTP3][WEB-TRANSPORT-HTTP2] 명세가 진행 중이므로 프로토콜과 API 모두 앞으로 상당히 변경될 수 있습니다.

2. 준수

비규범적으로 표시된 섹션뿐만 아니라, 이 명세의 모든 작성 지침, 도표, 예시, 참고 사항은 규범적인 내용이 아닙니다. 그 외의 모든 내용은 규범적입니다.

이 명세에서 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", "OPTIONAL"이라는 핵심 용어는 [RFC2119][RFC8174]에서 설명된 대로, 오직 대문자로 나타날 때만 해당 의미로 해석됩니다.

이 명세는 하나의 제품에 적용되는 준수 기준을 정의합니다: 이 명세에 포함된 인터페이스를 구현하는 사용자 에이전트입니다.

알고리즘이나 특정 단계로 표현된 준수 요구사항은 최종 결과가 동일하기만 하면 어떤 방식으로 구현해도 됩니다. (특히, 이 명세에서 정의된 알고리즘은 따라가기 쉽도록 설계된 것이며, 성능을 위한 것이 아닙니다.)

이 명세에서 정의된 API를 ECMAScript로 구현하는 경우, 반드시 Web IDL 명세 [WEBIDL]에 정의된 ECMAScript 바인딩과 용어에 따라 일관되게 구현해야 합니다. 이 명세는 해당 명세와 용어를 사용합니다.

3. 프로토콜 개념

WebTransport에는 두 가지 주요 프로토콜 개념이 있습니다: 세션과 스트림. 각 WebTransport 세션은 여러 개의 WebTransport 스트림을 포함할 수 있습니다.

이들은 프로토콜 이름과 혼동해서는 안 되며, 이는 애플리케이션 수준의 API 구조입니다.

3.1. WebTransport 세션

WebTransport 세션은 HTTP/3 또는 HTTP/2 하위 연결에서의 WebTransport 세션입니다. 풀링이 활성화되면 하나의 연결에 여러 WebTransport 세션이 있을 수 있습니다.

WebTransport 세션[WEB-TRANSPORT-OVERVIEW]에 정의된 다음 기능을 가집니다:

기능 정의
데이터그램 보내기 [WEB-TRANSPORT-OVERVIEW] 섹션 4.2
데이터그램 받기 [WEB-TRANSPORT-OVERVIEW] 섹션 4.2
단방향(송신) 스트림 생성 [WEB-TRANSPORT-OVERVIEW] 섹션 4.3
양방향 스트림 생성 [WEB-TRANSPORT-OVERVIEW] 섹션 4.3
단방향(수신) 스트림 받기 [WEB-TRANSPORT-OVERVIEW] 섹션 4.3
양방향 스트림 받기 [WEB-TRANSPORT-OVERVIEW] 섹션 4.3

WebTransport 세션 session드레이닝 중 상태가 됩니다. 이 때 CONNECT 스트림이 서버에 의해 정상적으로 종료되도록 요청받았을 때입니다. 자세한 내용은 [WEB-TRANSPORT-OVERVIEW] 섹션 4.1을 참고하세요.

옵션의 정수 code와 옵션의 바이트 시퀀스 reason과 함께 WebTransport 세션 session종료하려면 [WEB-TRANSPORT-OVERVIEW] 섹션 4.1의 절차를 따르세요.

WebTransport 세션 session은 선택적으로 정수 code바이트 시퀀스 reason과 함께 종료됨 상태가 됩니다. 이 때 CONNECT 스트림이 서버에 의해 종료됩니다. 자세한 내용은 [WEB-TRANSPORT-OVERVIEW] 섹션 4.1을 참고하세요.

3.2. WebTransport 스트림

WebTransport 스트림WebTransport 세션 내에서 신뢰성 있고 순서가 보장되는 바이트 스트림 개념으로, [WEB-TRANSPORT-OVERVIEW] 섹션 4.3에 설명되어 있습니다.

WebTransport 스트림단방향(수신), 단방향(송신) 또는 양방향 중 하나입니다.

WebTransport 스트림은 다음과 같은 기능을 가집니다:

기능 정의 수신 단방향 송신 단방향 양방향
바이트 전송 (FIN 포함 가능) [WEB-TRANSPORT-OVERVIEW] 섹션 4.3 아니오
바이트 수신 (FIN 포함 가능) [WEB-TRANSPORT-OVERVIEW] 섹션 4.3 아니오
수신 중단 WebTransport 스트림에서 [WEB-TRANSPORT-OVERVIEW] 섹션 4.3 아니오
송신 중단 WebTransport 스트림에서 [WEB-TRANSPORT-OVERVIEW] 섹션 4.3 아니오

WebTransport 스트림에는 다음과 같은 신호가 있습니다:

이벤트 정의 수신 단방향 송신 단방향 양방향
수신 중단됨 [WEB-TRANSPORT-OVERVIEW] 섹션 4.3 아니오
송신 중단됨 [WEB-TRANSPORT-OVERVIEW] 섹션 4.3 아니오
흐름 제어 [WEB-TRANSPORT-OVERVIEW] 섹션 4.3 아니오

4. WebTransportDatagramsWritable 인터페이스

WebTransportDatagramsWritableWritableStream으로, 데이터그램 보내기를 위한 송신 스트리밍 기능을 제공합니다.

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportDatagramsWritable : WritableStream {
  attribute WebTransportSendGroup? sendGroup;
  attribute long long sendOrder;
};

4.1. 내부 슬롯

WebTransportDatagramsWritable 객체는 다음 내부 슬롯을 가집니다.

내부 슬롯 설명 (규범적이지 않음)
[[OutgoingDatagramsQueue]] 내보내는 데이터그램, 타임스탬프 및 데이터그램이 전송되거나 폐기될 때 resolve되는 promise의 튜플 큐
[[Transport]] WebTransport를 소유하는 WebTransportDatagramsWritable
[[SendGroup]] 옵션의 WebTransportSendGroup 또는 null
[[SendOrder]] 옵션 전송 순서 번호, 기본값 0
생성WebTransportDatagramsWritable 을 주어진 WebTransport transportsendGroup, 그리고 sendOrder와 함께 다음 단계를 수행
  1. streamnew WebTransportDatagramsWritable로, 아래와 같이 생성:

    [[OutgoingDatagramsQueue]]

    빈 큐

    [[Transport]]

    transport

    [[SendGroup]]

    sendGroup

    [[SendOrder]]

    sendOrder

  2. writeDatagramsAlgorithmwriteDatagramstransportstream으로 실행하는 액션으로 설정

  3. Set up streamwriteAlgorithmwriteDatagramsAlgorithm으로 설정

  4. stream을 반환

4.2. 속성

sendGroup, 타입 WebTransportSendGroup, nullable

getter 단계:

  1. this[[SendGroup]]을 반환합니다.

setter 단계 (값 value 주어짐):

  1. value가 null이 아니고, value.[[Transport]]this.[[Transport]]와 다르면, InvalidStateError 예외를 throw합니다.

  2. this.[[SendGroup]]value로 설정합니다.

sendOrder, 타입 long long

getter 단계:

  1. this[[SendOrder]]을 반환합니다.

setter 단계 (값 value 주어짐):

  1. this.[[SendOrder]]value로 설정합니다.

4.3. 절차

writeDatagrams 알고리즘은 transportwritable을 매개변수로 하고, 입력으로 data를 받습니다. 다음 단계로 정의합니다:

  1. timestamp를 현재 시점을 나타내는 타임스탬프로 설정합니다.

  2. dataBufferSource 객체가 아니라면, TypeError로 거부된 프로미스를 반환합니다.

  3. datagramstransport.[[Datagrams]]로 설정합니다.

  4. datagrams.[[OutgoingMaxDatagramSize]]data의 [[ByteLength]]보다 작으면, undefined로 해결된 프로미스를 반환합니다.

  5. 새 프로미스 promise를 생성합니다.

  6. data가 나타내는 바이트를 복사하여 bytes로 설정합니다.

  7. chunkbytes, timestamp, promise의 튜플로 설정합니다.

  8. writable.[[OutgoingDatagramsQueue]]chunk를 큐에 추가합니다.

  9. writable.[[OutgoingDatagramsQueue]]의 길이가 datagrams.[[OutgoingDatagramsHighWaterMark]]보다 작으면, promise를 undefined로 resolve합니다.

  10. promise를 반환합니다.

참고: 관련 WritableStream은 해당 스트림에 대해 writeDatagrams로 반환된 모든 프로미스가 resolve된 후에만 writeDatagrams를 호출합니다. 따라서 타임스탬프와 만료 기간은 웹 개발자가 WritableStreamDefaultWriter.ready를 신경 쓸 때만 효과적으로 동작합니다.

sendDatagramsWebTransport 객체 transportWebTransportDatagramsWritable 객체 writable을 받아, 네트워크 작업을 큐에 추가하여 transport로 다음 절차를 실행합니다:

  1. queuewritable.[[OutgoingDatagramsQueue]]의 복사본으로 설정합니다.

    참고: 위 복사와 네트워크 작업 큐잉은 최적화할 수 있습니다.

  2. maxSizetransport.[[Datagrams]].[[OutgoingMaxDatagramSize]]로 설정합니다.

  3. durationtransport.[[Datagrams]].[[OutgoingDatagramsExpirationDuration]]로 설정합니다.

  4. duration이 null이면, duration구현 정의 값으로 설정합니다.

  5. 다음 단계를 병렬로 실행합니다:

    1. queue가 비어 있지 않은 동안:

      1. bytes, timestamp, promisequeue의 첫 번째 요소로 설정합니다.

      2. timestamp로부터 duration 밀리초 이상 경과했다면:

        1. queue의 첫 번째 요소를 제거합니다.

        2. 네트워크 작업을 큐에 추가하여 transportpromise를 undefined로 resolve합니다.

      3. 그렇지 않으면, 이 루프를 종료합니다.

    2. transport.[[State]]"connected"가 아니면 반환합니다.

    3. queue가 비어 있지 않은 동안:

      1. bytes, timestamp, promisequeue의 첫 번째 요소로 설정합니다.

      2. bytes 길이 ≤ maxSize이면:

        1. bytes를 즉시 네트워크에 보낼 수 없다면 이 루프를 종료합니다.

        2. 데이터그램 보내기transport.[[Session]]bytes로 실행합니다.

      3. queue의 첫 번째 요소를 제거합니다.

      4. 네트워크 작업을 큐에 추가하여 transportpromise를 undefined로 resolve합니다.

사용자 에이전트는 WebTransport 객체 중 [[State]]"connecting" 또는 "connected"인 경우, 관련 WebTransportDatagramsWritable 객체의 일부(송신 순서 규칙에 따라 결정됨)에 대해 sendDatagrams를 실행해야 하며, 알고리즘이 진행 가능할 때 최대한 빨리 실행하는 것이 바람직합니다.

송신 순서 규칙은, 일반적으로 송신은 이전에 큐에 추가된 스트림 및 데이터그램, 앞으로 큐에 추가될 스트림 및 데이터그램의 송신과 교차될 수 있지만, 송신은 동일한 [[SendGroup]] 및 더 높은 [[SendOrder]] 값을 가진, 에러나 에러 상태 또는 흐름 제어로 인해 블록되지 않은 모든 바이트가 송신될 때까지 대기해야 한다는 것입니다.

참고: 트랜스포트의 [[State]] 값이 "connecting"일 때 데이터그램 작성이 허용됩니다. 데이터그램은 [[OutgoingDatagramsQueue]]에 저장되고, "connected" 상태일 때와 동일한 방식으로 폐기될 수 있습니다. 트랜스포트의 [[State]]"connected"가 되면 큐에 있던 데이터그램 송신을 시작합니다.

5. WebTransportDatagramDuplexStream 인터페이스

WebTransportDatagramDuplexStream는 범용 이중 스트림입니다.

[Exposed=(Window,Worker), SecureContext]
interface WebTransportDatagramDuplexStream {
  WebTransportDatagramsWritable createWritable(
      optional WebTransportSendOptions options = {});
  readonly attribute ReadableStream readable;

  readonly attribute unsigned long maxDatagramSize;
  attribute unrestricted double? incomingMaxAge;
  attribute unrestricted double? outgoingMaxAge;
  attribute unrestricted double incomingHighWaterMark;
  attribute unrestricted double outgoingHighWaterMark;
};

5.1. 내부 슬롯

WebTransportDatagramDuplexStream 객체는 다음 내부 슬롯을 가집니다.

내부 슬롯 설명 (규범적이지 않음)
[[Transport]] WebTransport 를 소유하는 WebTransportDatagramDuplexStream
[[Readable]] 수신 데이터그램용 ReadableStream
[[ReadableType]] 수신 데이터그램에 사용되는 ReadableStreamType
[[Writables]] 순서가 지정된 집합WebTransportDatagramsWritable 스트림, 처음에는 비어 있음
[[IncomingDatagramsQueue]] 수신 데이터그램과 타임스탬프 쌍의 큐
[[IncomingDatagramsPullPromise]] pullDatagrams에 의해 설정되는 promise로, 수신 데이터그램을 대기함
[[IncomingDatagramsHighWaterMark]] unrestricted double로, 수신 데이터그램의 high water mark를 나타냄
[[IncomingDatagramsExpirationDuration]] unrestricted double 수신 데이터그램의 만료 지속 시간(밀리초)을 나타내며, null일 수 있음
[[OutgoingDatagramsHighWaterMark]] unrestricted double로, 송신 데이터그램의 high water mark를 나타냄
[[OutgoingDatagramsExpirationDuration]] unrestricted double 값으로, 송신 데이터그램의 만료 지속 시간(밀리초)을 나타내며, null일 수 있음
[[OutgoingMaxDatagramSize]] 송신 데이터그램의 최대 크기를 나타내는 정수
최대 데이터그램 크기는 사용 중인 프로토콜에 따라 다름 HTTP/3 [WEB-TRANSPORT-HTTP3]에서는 값이 경로 MTU의 추정치와 관련이 있고, 오버헤드를 고려하여 구현 정의 양만큼 감소됨. HTTP/2 [WEB-TRANSPORT-HTTP2]에는 해당 제한이 없음

데이터그램 처리는 전체 데이터그램을 메모리에 보관하는 경우가 많으므로, 구현에는 크기 제한이 있음. 향후 프로토콜 확장에서는 모든 프로토콜 변형에 대한 이러한 크기 제한 신호화가 가능할 수 있음.

사용자 에이전트는 [[OutgoingMaxDatagramSize]]WebTransport 객체의 [[State]]"connecting" 또는 "connected" 일 때 갱신할 수 있음.

생성 WebTransportDatagramDuplexStream 을 주어진 WebTransport transport, readablereadableType으로 아래 단계를 수행
  1. streamnew WebTransportDatagramDuplexStream로 생성하고, 다음과 같음:

    [[Transport]]

    transport

    [[Readable]]

    readable

    [[ReadableType]]

    readableType

    [[Writables]]

    비어 있는 순서가 지정된 집합

    [[IncomingDatagramsQueue]]

    빈 큐

    [[IncomingDatagramsPullPromise]]

    null

    [[IncomingDatagramsHighWaterMark]]

    구현 정의

    [[IncomingDatagramsExpirationDuration]]

    null

    [[OutgoingDatagramsHighWaterMark]]

    구현 정의

    이 구현 정의 값은 전송 데이터의 적시성이 저해되지 않는 선에서 적절한 처리량을 보장하도록 조율되어야 함.

    [[OutgoingDatagramsExpirationDuration]]

    null

    [[OutgoingMaxDatagramSize]]

    구현 정의 정수

  2. stream을 반환

5.2. 메서드

createWritable()

WebTransportDatagramsWritable을(를) 생성합니다.

createWritable() 메서드가 호출되면, 사용자 에이전트는 다음 단계를 반드시 실행해야 합니다:
  1. transportthis에 연관된 WebTransport 객체로 설정합니다.

  2. 만약 transport.[[State]]"closed" 또는 "failed"이면, throw InvalidStateError를 발생시킵니다.

  3. sendGroupoptionssendGroup으로 설정합니다.

  4. 만약 sendGroup이 null이 아니고, sendGroup.[[Transport]]this.[[Transport]]와 다르면, throw InvalidStateError를 발생시킵니다.

  5. sendOrderoptionssendOrder로 설정합니다.

  6. transport, sendGroup, sendOrder생성WebTransportDatagramsWritable을(를) 반환합니다.

5.3. 속성

readable, of type ReadableStream, readonly

getter 단계:

  1. this.[[Readable]]를 반환.

incomingMaxAge, of type unrestricted double, nullable

getter 단계:

  1. this.[[IncomingDatagramsExpirationDuration]]를 반환.

setter 단계: value가 주어지면,

  1. value가 음수이거나 NaN이면, throw RangeError.

  2. value0이면 value를 null로 설정.

  3. this.[[IncomingDatagramsExpirationDuration]]value로 설정.

maxDatagramSize, of type unsigned long, readonly

WebTransportDatagramsWritable에 전달할 수 있는 최대 데이터 크기. getter 단계는 this.[[OutgoingMaxDatagramSize]]를 반환.

outgoingMaxAge, of type unrestricted double, nullable

getter 단계:

  1. this[[OutgoingDatagramsExpirationDuration]]를 반환.

setter 단계: value가 주어지면,

  1. value가 음수이거나 NaN이면, throw RangeError.

  2. value0이면 value를 null로 설정.

  3. this.[[OutgoingDatagramsExpirationDuration]]value로 설정.

incomingHighWaterMark, of type unrestricted double

getter 단계:

  1. this.[[IncomingDatagramsHighWaterMark]]를 반환.

setter 단계: value가 주어지면,

  1. value가 음수이거나 NaN이면, throw RangeError.

  2. value1 미만이면 value1로 설정.

  3. this.[[IncomingDatagramsHighWaterMark]]value로 설정.

outgoingHighWaterMark, of type unrestricted double

getter 단계:

  1. this.[[OutgoingDatagramsHighWaterMark]]를 반환.

setter 단계: value가 주어지면,

  1. value가 음수이거나 NaN이면, throw RangeError.

  2. value1 미만이면 value1로 설정.

  3. this.[[OutgoingDatagramsHighWaterMark]]value로 설정.

5.4. 절차

pullDatagrams를 하려면, WebTransport 객체 transport가 주어졌을 때 다음 단계를 실행한다:

  1. datagramstransport.[[Datagrams]]로 한다.

  2. 단언: datagrams.[[IncomingDatagramsPullPromise]] 는 null이다.

  3. queuedatagrams.[[IncomingDatagramsQueue]]로 한다.

  4. queue가 비어 있으면,

    1. datagrams.[[IncomingDatagramsPullPromise]] 에 새 promise를 넣는다.

    2. datagrams.[[IncomingDatagramsPullPromise]]를 반환.

  5. datagramtimestampdequeuing queue의 결과로 한다.

  6. datagrams.[[ReadableType]]"bytes"이면:

    1. datagrams.[[Readable]]current BYOB request view가 null이 아니면,

      1. viewdatagrams.[[Readable]]current BYOB request view로 한다.

      2. viewbyte lengthdatagram의 크기보다 작으면, a promise rejected with RangeError를 반환한다.

      3. elementSizethe typed array constructors table에서 view.[[TypedArrayName]]에 해당하는 element size로 한다. view에 [[TypedArrayName]] 내부 슬롯이 없으면 (DataView인 경우) elementSize는 0으로 한다.

      4. elementSize가 1이 아니면, a promise rejected with TypeError를 반환한다.

    2. Pull from bytes datagramdatagrams.[[Readable]]에 넣는다.

  7. 그 밖의 경우:

    1. chunkdatagram을 나타내는 새로운 Uint8Array 객체로 한다.

    2. Enqueue chunktransport.[[Datagrams]].[[Readable]]로 넣는다.

  8. a promise resolved with undefined를 반환한다.

receiveDatagrams를 하려면, WebTransport 객체 transport가 주어졌을 때 다음 단계를 실행한다:

  1. timestamp를 현재 시점을 나타내는 타임스탬프로 한다.

  2. queuedatagrams.[[IncomingDatagramsQueue]]로 한다.

  3. durationdatagrams.[[IncomingDatagramsExpirationDuration]]로 한다.

  4. duration이 null이면 durationimplementation-defined 값으로 설정한다.

  5. sessiontransport.[[Session]]으로 한다.

  6. sessionavailable incoming datagrams가 있을 때 반복:

    1. datagramreceiving a datagramsession을 사용하여 구한다.

    2. timestamp를 현재 시점을 나타내는 타임스탬프로 한다.

    3. chunkdatagramtimestamp의 쌍으로 한다.

    4. Enqueue chunkqueue에 넣는다.

  7. toBeRemovedqueue의 길이에서 datagrams.[[IncomingDatagramsHighWaterMark]] 를 뺀 값으로 한다.

  8. toBeRemoved가 양수이면, dequeuing queuetoBeRemoved (내림 처리)번 반복한다.

  9. queue가 비어있지 않을 때 반복:

    1. bytes, timestampqueue의 첫 번째 요소로 한다.

    2. timestamp로부터 duration ms보다 오래 지났으면 dequeue queue.

    3. 아니면 break로 이 루프를 나간다.

  10. queue가 비어있지 않고 datagrams.[[IncomingDatagramsPullPromise]] 가 null이 아니면,

    1. bytes, timestampdequeuing queue의 결과로 한다.

    2. promisedatagrams.[[IncomingDatagramsPullPromise]]로 한다.

    3. datagrams.[[IncomingDatagramsPullPromise]] 를 null로 설정한다.

    4. Queue a network tasktransport로 다음 단계를 실행하게 한다:

      1. chunkbytes를 나타내는 새 Uint8Array 객체로 한다.

      2. Enqueue chunkdatagrams.[[Readable]]에 넣는다.

      3. Resolve promise를 undefined로 처리한다.

사용자 에이전트는 receiveDatagramsWebTransport 객체의 [[State]]"connected"일 때, 알고리즘이 진행될 수 있는 경우 가능한 한 빨리 실행해야 한다.

6. WebTransport 인터페이스

WebTransport[WEB-TRANSPORT-OVERVIEW]에 정의된 하위 전송 기능에 대한 API를 제공합니다.

[Exposed=(Window,Worker), SecureContext]
interface WebTransport {
  constructor(USVString url, optional WebTransportOptions options = {});

  Promise<WebTransportConnectionStats> getStats();
  [NewObject] Promise<ArrayBuffer> exportKeyingMaterial(BufferSource label, optional BufferSource context);
  readonly attribute Promise<undefined> ready;
  readonly attribute WebTransportReliabilityMode reliability;
  readonly attribute WebTransportCongestionControl congestionControl;
  [EnforceRange] attribute unsigned short? anticipatedConcurrentIncomingUnidirectionalStreams;
  [EnforceRange] attribute unsigned short? anticipatedConcurrentIncomingBidirectionalStreams;
  readonly attribute DOMString protocol;

  readonly attribute Promise<WebTransportCloseInfo> closed;
  readonly attribute Promise<undefined> draining;
  undefined close(optional WebTransportCloseInfo closeInfo = {});

  readonly attribute WebTransportDatagramDuplexStream datagrams;

  Promise<WebTransportBidirectionalStream> createBidirectionalStream(
      optional WebTransportSendStreamOptions options = {});
  /* a ReadableStream of WebTransportBidirectionalStream objects */
  readonly attribute ReadableStream incomingBidirectionalStreams;

  Promise<WebTransportSendStream> createUnidirectionalStream(
      optional WebTransportSendStreamOptions options = {});
  /* a ReadableStream of WebTransportReceiveStream objects */
  readonly attribute ReadableStream incomingUnidirectionalStreams;
  WebTransportSendGroup createSendGroup();

  static readonly attribute boolean supportsReliableOnly;
};

enum WebTransportReliabilityMode {
  "pending",
  "reliable-only",
  "supports-unreliable",
};

6.1. 내부 슬롯

WebTransport 객체는 다음과 같은 내부 슬롯을 가진다.

내부 슬롯 설명 (규범적이지 않음)
[[SendStreams]] 순서가 지정된 집합으로, 이 WebTransport에 의해 소유되는 WebTransportSendStream 객체들의 집합.
[[ReceiveStreams]] 순서가 지정된 집합으로, 이 WebTransport에 의해 소유되는 WebTransportReceiveStream 객체들의 집합.
[[IncomingBidirectionalStreams]] ReadableStream으로, WebTransportBidirectionalStream 객체로 구성됨.
[[IncomingUnidirectionalStreams]] ReadableStream으로, WebTransportReceiveStream 객체로 구성됨.
[[State]] 전송 상태를 나타내는 enum. "connecting", "connected", "draining", "closed", "failed" 중 하나.
[[Ready]] 관련 WebTransport session설정되면 완료되고, 설정 과정이 실패하면 reject되는 promise.
[[Reliability]] WebTransportReliabilityMode로, 첫 홉이 신뢰성 없는(UDP) 전송을 지원하는지 또는 신뢰성 있는(TCP 대체) 전송만 가능한지를 나타냄. 연결 전까지는 "pending" 반환.
[[CongestionControl]] WebTransportCongestionControl로, 애플리케이션이 처리량 또는 저지연에 최적화된 혼잡 제어 알고리즘을 선호하여 요청했는지, 또는 "default"인지를 나타냄.
[[AnticipatedConcurrentIncomingUnidirectionalStreams]] 애플리케이션이 서버가 생성할 것으로 예상하는 수신 단방향 스트림의 동시 개수 또는 null.
[[AnticipatedConcurrentIncomingBidirectionalStreams]] 애플리케이션이 서버가 생성할 것으로 예상하는 양방향 스트림의 동시 개수 또는 null.
[[Protocol]] 서버가 선택한 애플리케이션 레벨 프로토콜을 나타내는 문자열(있으면). 초기값은 빈 문자열.
[[Closed]] 관련 WebTransport 객체가 정상적으로 종료되면 완료되고, 비정상적으로 종료되거나 초기화에 실패하면 reject되는 promise.
[[Draining]] 관련 WebTransport sessiondrained되면 완료되는 promise.
[[Datagrams]] WebTransportDatagramDuplexStream.
[[Session]] WebTransport 객체의 WebTransport session 또는 null
[[NewConnection]] "no" 또는 "yes-and-dedicated" 중 하나.
[[RequireUnreliable]] UDP가 필수인지 여부를 나타내는 불리언.
[[ServerCertificateHashes]] 리스트로, 0개 이상의 WebTransportHash 객체.

6.2. 생성자

WebTransport() 생성자가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:
  1. baseURLthisrelevant settings objectAPI base URL로 한다.

  2. urlURL record로, parsing urlbaseURL의 결과로 한다.

  3. url이 failure라면, throw SyntaxError 예외를 발생시킨다.

  4. urlschemehttps가 아니면, throw SyntaxError 예외를 발생시킨다.

  5. urlfragment가 null이 아니면, throw SyntaxError 예외를 발생시킨다.

  6. allowPoolingoptionsallowPooling으로 한다.

  7. dedicatedallowPooling의 not 값으로 한다.

  8. serverCertificateHashesoptionsserverCertificateHashes로 한다.

  9. dedicated가 false이고 serverCertificateHashes비어있지 않으면, throw NotSupportedError 예외를 발생한다.

  10. newConnectiondedicated가 false면 "no", 아니면 "yes-and-dedicated"로 한다.

  11. requireUnreliableoptionsrequireUnreliable로 한다.

  12. congestionControloptionscongestionControl로 한다.

  13. congestionControl"default"가 아니고, 사용자 에이전트가 congestionControl에 최적화된 혼잡제어 알고리즘을 지원하지 않으면, congestionControl"default"로 설정.

  14. protocolsoptionsprotocols로 한다.

  15. protocols 내의 값 중 중복되거나, WebTransport 프로토콜의 애플리케이션 프로토콜 값 조건에 맞지 않거나, isomorphic encoded 길이가 0이거나 512를 초과하면 throw SyntaxError 예외를 발생.

  16. anticipatedConcurrentIncomingUnidirectionalStreamsoptionsanticipatedConcurrentIncomingUnidirectionalStreams로 한다.

  17. anticipatedConcurrentIncomingBidirectionalStreamsoptionsanticipatedConcurrentIncomingBidirectionalStreams로 한다.

  18. datagramsReadableTypeoptionsdatagramsReadableType로 한다.

  19. incomingDatagramsnew ReadableStream으로 한다.

  20. transport를 새로 생성한 WebTransport 객체로 한다. 다음과 같이 설정:

    [[SendStreams]]

    ordered set

    [[ReceiveStreams]]

    ordered set

    [[IncomingBidirectionalStreams]]

    ReadableStream

    [[IncomingUnidirectionalStreams]]

    ReadableStream

    [[State]]

    "connecting"

    [[Ready]]

    새 promise

    [[Reliability]]

    "pending"

    [[CongestionControl]]

    congestionControl

    [[AnticipatedConcurrentIncomingUnidirectionalStreams]]

    anticipatedConcurrentIncomingUnidirectionalStreams

    [[AnticipatedConcurrentIncomingBidirectionalStreams]]

    anticipatedConcurrentIncomingBidirectionalStreams

    [[Protocol]]

    빈 문자열

    [[Closed]]

    새 promise

    [[Draining]]

    새 promise

    [[Datagrams]]

    undefined

    [[Session]]

    null

    [[NewConnection]]

    newConnection

    [[RequireUnreliable]]

    requireUnreliable

    [[ServerCertificateHashes]]

    serverCertificateHashes

  21. transport.[[Datagrams]]creating WebTransportDatagramDuplexStream의 결과를 할당. 인자로는 transport, incomingDatagrams, datagramsReadableType 사용.

  22. pullDatagramsAlgorithmpullDatagramstransport로 실행하는 액션으로 한다.

    Note: 데이터그램에 64 kibibytes 버퍼를 사용할 것을 권고하며, WebTransport 데이터그램 frame 크기의 상한이 QUIC의 최대 데이터그램 프레임 크기(권장 64 kibibytes)이므로, 이를 초과하는 경우 스트림 오류 예방 목적임.

  23. datagramsReadableType"bytes"면, set up with byte reading support incomingDatagramspullAlgorithmpullDatagramsAlgorithm을 설정하고, highWaterMark 를 0으로 설정. 아니면, set up incomingDatagramspullAlgorithmpullDatagramsAlgorithm을, highWaterMark를 0으로 설정.

  24. pullBidirectionalStreamAlgorithmpullBidirectionalStreamtransport를 인자로 실행하는 액션으로 한다.

  25. Set up transport.[[IncomingBidirectionalStreams]]pullAlgorithmpullBidirectionalStreamAlgorithm을, highWaterMark에 0을 설정.

  26. pullUnidirectionalStreamAlgorithmpullUnidirectionalStreamtransport를 인자로 실행하는 액션으로 한다.

  27. Set up transport.[[IncomingUnidirectionalStreams]]pullAlgorithmpullUnidirectionalStreamAlgorithm을, highWaterMark에 0을 설정.

  28. clienttransportrelevant settings object로 한다.

  29. originclientorigin으로 한다.

  30. request를 새 request로, URLurl, clientclient, service-workers mode는 "none", referrer는 "no-referrer", mode는 "webtransport", credentials mode는 "omit", cache mode는 "no-store", policy containerclientpolicy container, destination은 "", originorigin, redirect mode는 "error"로 한다.

    Note: 리다이렉트는 따라가지 않는다. 네트워크 오류와 리다이렉션 오류는 구분불가. 교차 오리진 상황에서 CORS로 막을 정보를 노출하지 않기 위한 정책임. 동일 오리진일 때 handshake 남용 방지 목적도 있음.

  31. requestmethod를 "CONNECT"로 하고, :protocol pseudo-header"webtransport"로 한다.

  32. protocols가 비어있지 않으면, (WT-Available-Protocols, structured header liststructured header string 아이템을 protocols 순서대로 포함)로 set a structured field valuerequestheader list에 설정.

  33. Fetch requestuseParallelQueue를 true로, processResponse 에는 response를 받으면 다음 단계를 실행하는 것으로 설정:

    1. Process a WebTransport fetch responseresponse, origin, protocols, congestionControl로 호출.

  34. transport를 반환한다.

WebTransport connection을 얻는다: network partition key networkPartitionKeyrequest request가 주어졌을 때:
  1. transportWebTransport으로, request와 연관된 객체로 한다.

  2. urlrequestcurrent URL로 한다.

  3. newConnectiontransport.[[NewConnection]]로 한다.

  4. requireUnreliabletransport.[[RequireUnreliable]]로 한다.

  5. serverCertificateHashestransport.[[ServerCertificateHashes]]의 값들로 한다.

  6. connectionobtaining a connectionnetworkPartitionKey, url, false, newConnection, requireUnreliable를 인자로 호출한 결과로 한다. 이 때 serverCertificateHashes비어 있지 않으면 디폴트 인증서 검증 대신, custom certificate requirements를 만족하고, verifying the certificate hashserverCertificateHashes에 대해 true를 반환해야 유효한 것으로 간주. 둘 중 하나라도 만족하지 않으면 failure.

  7. connection이 failure면 failure 반환.

  8. connection이 첫 SETTINGS frame을 받을 때까지 기다리고, settings를 그 SETTINGS frame을 나타내는 딕셔너리로 한다.

  9. settingsSETTINGS_ENABLE_CONNECT_PROTOCOL (0x08, Section 3 of [RFC8441] for HTTP/2; 0x08, Section 3 of [RFC9220])의 값이 1이 아니면 failure 반환.

  10. settings가 서버의 WebTransport 지원을 나타내지 않으면 failure 반환. [WEB-TRANSPORT-OVERVIEW] Section 4.1.

    Note: SETTINGS_WT_MAX_SESSIONS는 IETF에서 변경 가능성이 있으며 SETTINGS_ENABLE_WEBTRANSPORT로 되돌릴 수 있음.

  11. connection을 반환.

WebTransport fetch response 처리: responsecongestionControl이 주어지면 다음을 실행:
  1. responsenetwork error면, 남은 단계를 중단하고 queue a network tasktransport로 다음 단계를 실행:

    1. transport.[[State]]"closed" 또는 "failed"면 단계를 중단.

    2. error를 새로 생성한 WebTransportError로 하고, source"session"으로 한다.

    3. Cleanup transporterror로 한다.

  2. connectionresponse와 연관된 underlying connection으로 한다.

  3. [WEB-TRANSPORT-OVERVIEW] Section 4.1의 제한을 따라 WebTransport session 확립connection과 서버의 response로 진행.

  4. session을 위에서 확립WebTransport session으로 한다. 이때 생성되는 underlying transport stream을 session의 CONNECT stream이라 칭함.

    Note: 이 단계는 [QUIC-DATAGRAM] 명시된 파라미터 교환 마무리도 포함.

  5. 이전 단계가 실패하면 남은 단계를 중단하고 queue a network tasktransport로 다음 단계 실행:

    1. transport.[[State]]"closed" 또는 "failed"면 단계를 중단.

    2. error를 새로 생성한 WebTransportError로 하고, source"session"으로 한다.

    3. Cleanup transporterror로 한다.

  6. 사용자 에이전트가 혼잡제어 알고리즘을 여러 개 지원하면, 본 connection의 송신 데이터에 congestionControl에 맞는 것을 선택.

  7. Queue a network tasktransport로 다음 단계 실행:

    1. 단언: this[[Datagrams]][[OutgoingMaxDatagramSize]] 는 정수임.

    2. transport.[[State]]"connecting"이 아니면:

      1. in parallel로, terminate session

      2. 단계를 중단한다.

    3. transport.[[State]]"connected"로 한다.

    4. transport.[[Session]]session으로 설정.

    5. transport.[[Protocol]] 에, 협상된 애플리케이션 프로토콜의 문자열 값이 있으면 그 값, 아니면 ""로 설정.

    6. 연결이 HTTP/3이면 transport.[[Reliability]]"supports-unreliable"로 설정.

    7. 연결이 HTTP/2면 [WEB-TRANSPORT-HTTP2] transport[[Reliability]]"reliable-only"로 설정.

    8. Resolve transport.[[Ready]] 를 undefined로 처리.

pullBidirectionalStream: WebTransport 객체 transport가 주어졌을 때, 다음을 실행한다.
  1. transport.[[State]]"connecting"이면, transport.[[Ready]]가 fulfill될 때 다음 단계를 수행한 결과를 반환:

    1. pullBidirectionalStreamtransport로 호출한 결과를 반환.

  2. transport.[[State]]"connected"가 아니면, rejected promise를 InvalidStateError로 생성해 반환.

  3. sessiontransport.[[Session]]로 한다.

  4. p를 새 promise로 한다.

  5. 다음 단계를 in parallel로 실행:

    1. session에서 available incoming bidirectional stream이 될 때까지 대기

    2. internalStreamreceiving a bidirectional stream에서 session으로 얻는다.

    3. Queue a network tasktransport로 다음 단계 실행:

      1. streamcreating WebTransportBidirectionalStreaminternalStreamtransport를 이용해 생성

      2. Enqueue streamtransport.[[IncomingBidirectionalStreams]]에 추가

      3. Resolve p를 undefined로 처리.

  6. p를 반환.

pullUnidirectionalStream: WebTransport 객체 transport가 주어졌을 때 다음 단계 실행:
  1. transport.[[State]]"connecting"이면, transport.[[Ready]]가 fulfill되었을 때 다음 단계들을 실행한 결과를 반환:

    1. pullUnidirectionalStreamtransport로 호출한 결과 반환

  2. transport.[[State]]"connected"가 아니면, rejected promise를 InvalidStateError로 반환.

  3. sessiontransport.[[Session]]로 한다.

  4. p를 새 promise로 한다.

  5. 다음 단계를 in parallel로 실행:

    1. sessionavailable incoming unidirectional stream이 될 때까지 대기

    2. internalStreamreceiving an incoming unidirectional stream에서 session으로 얻는다.

    3. Queue a network tasktransport로 다음 단계를 실행:

      1. streamcreating WebTransportReceiveStreaminternalStreamtransport를 인자로 생성

      2. Enqueue streamtransport.[[IncomingUnidirectionalStreams]]에 추가

      3. Resolve p를 undefined로 한다.

  6. p를 반환.

6.3. 속성

ready, Promise<undefined> 타입, readonly

얻을 때 this[[Ready]]를 반환해야 한다.

closed, Promise<WebTransportCloseInfo> 타입, readonly

얻을 때 this[[Closed]]를 반환해야 한다.

draining, Promise<undefined> 타입, readonly

얻을 때 this[[Draining]]를 반환해야 한다.

datagrams, WebTransportDatagramDuplexStream 타입, readonly

이 세션을 통해 데이터그램을 송수신하는 단일 duplex 스트림. datagrams 속성의 getter 단계는 다음과 같다:

  1. this[[Datagrams]]를 반환.

incomingBidirectionalStreams, ReadableStream 타입, readonly

서버로부터 수신된 ReadableStreamWebTransportBidirectionalStream들의 목록을 반환함.

Note: 수신 스트림에 이미 데이터가 있는지는 서버 동작에 따라 다를 수 있음.

incomingBidirectionalStreams 속성 getter 단계:

  1. this[[IncomingBidirectionalStreams]]를 반환.

incomingUnidirectionalStreams, ReadableStream 타입, readonly

서버로부터 수신된 각 ReadableStream의 단방향 스트림 WebTransportReceiveStream로 이루어짐.

Note: 수신 스트림에 이미 데이터가 있는지는 서버 동작에 따라 다를 수 있음.

incomingUnidirectionalStreams 속성 getter 단계:

  1. this.[[IncomingUnidirectionalStreams]]를 반환.

reliability, WebTransportReliabilityMode 타입, readonly

연결이 신뢰성 없는(UDP) 전송을 지원하는지 또는 신뢰성 있는(TCP fallback) 전송만 지원하는지 여부. 연결이 설정될 때까지 "pending"을 반환. getter 단계는 this[[Reliability]]를 반환함.

congestionControl, WebTransportCongestionControl 타입, readonly

생성자에서 요청했고 사용자 에이전트가 충족시켜준 경우 처리량 최적화 또는 저지연 최적화 혼잡 제어 알고리즘에 대한 애플리케이션의 선호도. 요청했으나 충족되지 않은 경우 "default". getter 단계는 this[[CongestionControl]]를 반환.

supportsReliableOnly, boolean 타입, readonly

사용자 에이전트가 오직 신뢰할 수 있는 WebTransport 세션만 지원하는 연결을 지원하면 true, 아니면 false.

anticipatedConcurrentIncomingUnidirectionalStreams, unsigned short 타입, nullable

애플리케이션이 서버가 개설할 것으로 예상하는 동시에 열린 수신 단방향 스트림 수를 명시적으로 지정할 수 있음. null이 아니면, 사용자 에이전트는 서버와의 협상에서 [[AnticipatedConcurrentIncomingUnidirectionalStreams]]를 고려하여 향후 왕복시간을 줄이기 위해 노력해야 함.

getter 단계는 this[[AnticipatedConcurrentIncomingUnidirectionalStreams]]를 반환.

setter 단계는 value가 주어질 경우 this[[AnticipatedConcurrentIncomingUnidirectionalStreams]]value를 할당.

anticipatedConcurrentIncomingBidirectionalStreams, unsigned short 타입, nullable

애플리케이션이 서버가 개설할 것으로 예상하는 동시에 열린 양방향 스트림 수를 명시적으로 지정할 수 있음. null이 아니면 사용자 에이전트는 서버와의 협상에서 [[AnticipatedConcurrentIncomingBidirectionalStreams]]를 고려해야 함.

getter 단계는 this[[AnticipatedConcurrentIncomingBidirectionalStreams]]를 반환.

setter 단계는 value가 주어질 경우 this[[AnticipatedConcurrentIncomingBidirectionalStreams]]value를 할당.

Note: anticipatedConcurrentIncomingUnidirectionalStreams 또는 anticipatedConcurrentIncomingBidirectionalStreams를 설정해도 애플리케이션이 예상한 수 만큼 스트림을 반드시 수신할 것이라는 보장은 없음.

protocol, DOMString 타입, readonly

WebTransport 세션이 설정되고 protocols 생성자 옵션에서 비어 있지 않은 배열이 주어졌을 때, 서버가 선택한 애플리케이션 레벨 프로토콜(있는 경우)를 반환. 그렇지 않으면 빈 문자열을 반환. getter 단계는 this[[Protocol]]를 반환.

6.4. 메서드

close(closeInfo)

WebTransport 객체와 연관된 WebTransport session을 종료한다.

close가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. transportthis로 한다.

  2. transport.[[State]]"closed""failed"이면 단계를 중단한다.

  3. transport.[[State]]"connecting"이면:

    1. error를 새로 생성한 WebTransportError로 하고, source"session"을 사용한다.

    2. Cleanup transporterror와 함께 실행한다.

    3. 이 단계를 중단한다.

  4. sessiontransport.[[Session]]으로 한다.

  5. codecloseInfo.closeCode로 한다.

  6. reasonString을(를) 최대 code unit prefix로 하고, closeInfo.reason 값 중 UTF-8 인코드 prefix의 길이가 1024를 넘지 않는 경우로 한다.

  7. reasonreasonStringUTF-8 인코딩 값으로 한다.

  8. in parallel로, terminate sessioncodereason을 전달하여 실행한다.

    Note: 이는 sending 중단receiving 중단transport.[[SendStreams]][[ReceiveStreams]]에 포함된 WebTransport stream 모두에 대해 수행한다.

  9. Cleanup transportAbortErrorcloseInfo와 함께 호출한다.

getStats()

WebTransportunderlying connection 에 대한 통계를 비동기로 수집하고 결과를 제공한다.

getStats 호출 시, 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. transportthis로 한다.

  2. p를 새 promise로 한다.

  3. transport.[[State]]"failed"이면, reject p와 함께 InvalidStateError를 반환하고, 단계를 중단.

  4. 다음 단계를 in parallel로 실행:

    1. transport.[[State]]"connecting"이면, 변경될 때까지 대기한다.

    2. transport.[[State]]"failed"면, queue a network tasktransport에 대해 reject pInvalidStateError로 반환하고 단계를 중단한다.

    3. transport.[[State]]"closed"면, queue a network tasktransport에 대해 resolve p을 해당 connection에서 수집된 최신 통계로 반환한다. 통계 수집 시점은 구현정의이다.

    4. gatheredStatslist로, underlying connection에서 WebTransportConnectionStatsWebTransportDatagramStats의 딕셔너리 멤버를 정확히 채우기에 필요한 통계 항목으로 한다.

    5. queue a network tasktransport에 대해 다음 단계 실행:

      1. statsnew WebTransportConnectionStats 객체로 한다.

      2. datagramStatsnew WebTransportDatagramStats 객체로 한다.

      3. stats["datagrams"] 에 datagramStats를 할당.

      4. statsdatagramStats의 각 member 중 노출하고 싶은 값에 대해, set membergatheredStatsentry에서 얻은 값으로 할당한다.

      5. Resolve pstats를 할당.

  5. p를 반환한다.

exportKeyingMaterial(BufferSource label, optional BufferSource context)

WebTransportTLS Keying Material Exporter로부터 TLS 세션에 고유하게 연관된 underlying connection 에서 keying material을 추출한다.

exportKeyingMaterial이 호출되면, 사용자 에이전트는 다음을 실행해야 한다:

  1. transportthis로 한다.

  2. labelLengthlabelbyte length로 한다.

  3. labelLength가 255를 초과하면 a promise rejected with RangeError를 반환.

  4. contextLength를 0으로 한다.

  5. context가 주어졌으면 contextLengthcontextbyte length로 한다.

  6. contextLength가 255를 초과하면 a promise rejected with RangeError를 반환.

  7. p를 새 promise로 한다.

  8. 다음 단계를 in parallel로 실행하되, abort when transport[[State]]"closed""failed"가 되면, 대신 queue a network tasktransportreject pInvalidStateError로 반환한다:

    1. keyingMaterial[WEB-TRANSPORT-OVERVIEW] Section 4.1에 정의된 대로 labelLength, label, contextLengthcontext로 TLS keying material을 export한 결과로 한다.

    2. queue a network tasktransport와, resolve pkeyingMaterial로 한다.

  9. p를 반환한다.

createBidirectionalStream()

출력용 양방향 스트림을 위한 WebTransportBidirectionalStream 객체를 생성한다. 스트림을 생성해도 피어가 즉시 이를 인지하지 않으며, 실제 데이터가 전송되어야 인지할 수도 있다.

Note: 스트림이 생성되어도 실제 데이터가 보내지기 전까지 서버에서 인지하지 못할 수 있다.

createBidirectionalStream 호출 시, 사용자 에이전트는 다음 단계를 실행해야 한다:
  1. this.[[State]]"closed""failed"rejected promise를 InvalidStateError로 반환.

  2. sendGroupoptionssendGroup으로 한다.

  3. sendGroup이 null이 아니고 sendGroup.[[Transport]]this와 다르면, throw InvalidStateError.

  4. sendOrderoptionssendOrder로 한다.

  5. waitUntilAvailableoptionswaitUntilAvailable로 한다.

  6. p를 새 promise로 한다.

  7. transportthis로 한다.

  8. 다음 단계를 in parallel로 실행(단, abort when transport.[[State]]"closed""failed"가 되면 queue a network tasktransport와, reject pInvalidStateError로 반환한다):

    1. streamIdtransport.[[Session]]에서 사용 가능한 새 스트림 ID(중복/불가용 시 아래 참고)에 할당. 할당 불가 시,waitUntilAvailable이 true면 대기, 아니면 queue a network taskreject pQuotaExceededError로 반환.

    2. internalStreamcreating a bidirectional stream에서 transport.[[Session]]streamId로 얻는다.

    3. queue a network tasktransport에 대해 다음 실행:

      1. transport.[[State]]"closed""failed"면, reject pInvalidStateError로 반환, 단계 중단.

      2. streamcreating WebTransportBidirectionalStream에서 internalStream, transport, sendGroup, sendOrder로 새로 생성.

      3. Resolve pstream 할당함.

  9. p를 반환한다.

createUnidirectionalStream()

출력용 단방향 스트림을 위한 WebTransportSendStream을 생성한다. 스트림을 생성해도 서버가 인지하지 못하며 실제 데이터가 전송되어야 인지할 수 있다.

Note: 스트림이 생성되어도 실제 데이터가 보내지기 전까지 서버가 인지하지 못할 수 있다.

createUnidirectionalStream() 호출 시, 사용자 에이전트는 다음 단계를 실행해야 한다:
  1. this.[[State]]"closed""failed"rejected promise를 InvalidStateError로 반환.

  2. sendGroupoptionssendGroup으로 한다.

  3. sendGroup이 null이 아니고 sendGroup.[[Transport]]this와 다르면, throw InvalidStateError.

  4. sendOrderoptionssendOrder로 한다.

  5. waitUntilAvailableoptionswaitUntilAvailable로 한다.

  6. p를 새 promise로 한다.

  7. transportthis로 한다.

  8. 다음 단계를 in parallel로 실행(단, abort when transport.[[State]]"closed""failed"가 되면 queue a network tasktransport와, reject pInvalidStateError로 반환한다):

    1. streamIdtransport.[[Session]]에서 사용할 수 있는 새 스트림 ID로 (불가 시 아래 참조), waitUntilAvailable이 true면 대기, 아니면 queue a network taskreject pQuotaExceededError로 반환.

    2. internalStreamcreating an outgoing unidirectional stream에서 transport.[[Session]]streamId로 얻는다.

    3. queue a network tasktransport에 대해 다음 실행:

      1. transport.[[State]]"closed""failed"면, reject pInvalidStateError로 반환, 단계 중단.

      2. streamcreating WebTransportSendStream에서 internalStream, transport, sendGroup, sendOrder로 새로 생성.

      3. Resolve pstream 할당함.

  9. p를 반환한다.

createSendGroup()

WebTransportSendGroup 을 생성한다.

createSendGroup()가 호출되면 사용자 에이전트는 다음을 실행해야 한다:
  1. this.[[State]]"closed""failed"throw InvalidStateError.

  2. creating WebTransportSendGroupthis로 생성한 결과를 반환한다.

6.5. 절차

cleanupWebTransport transporterror 그리고 선택적으로 closeInfo로 수행하려면, 다음 단계를 실행:
  1. sendStreamstransport.[[SendStreams]]의 복사본으로 설정.

  2. receiveStreamstransport.[[ReceiveStreams]]의 복사본으로 설정.

  3. outgoingDatagramWritablestransport.[[Datagrams]].[[Writables]]로 설정.

  4. incomingDatagramstransport.[[Datagrams]].[[Readable]]로 설정.

  5. readytransport.[[Ready]]로 설정.

  6. closedtransport.[[Closed]]로 설정.

  7. incomingBidirectionalStreamstransport.[[IncomingBidirectionalStreams]]로 설정.

  8. incomingUnidirectionalStreamstransport.[[IncomingUnidirectionalStreams]]로 설정.

  9. transport.[[SendStreams]] 를 빈 set으로 설정.

  10. transport.[[ReceiveStreams]] 를 빈 set으로 설정.

  11. transport.[[Datagrams]].[[OutgoingDatagramsQueue]] 를 빈 queue로 설정.

  12. transport.[[Datagrams]].[[IncomingDatagramsQueue]] 를 빈 queue로 설정.

  13. closeInfo가 주어지면, transport.[[State]]"closed"로, 아니면 transport.[[State]]"failed"로 설정.

  14. For each stream in sendStreams에 대해 다음 수행:

    1. stream.[[PendingOperation]] 가 null이 아니면 stream.[[PendingOperation]]error로 reject.

    2. Error streamerror로 처리.

  15. For each stream in receiveStreams: error streamerror로 처리.

    Note: 스크립트 작성자가 Promise resolve에서 동기적으로 코드를 주입할 수 있기 때문에, 여기서 transport의 값은 예측할 수 없이 변할 수도 있어, 이후로는 transport를 조작하지 않는다. 이 동작을 호출하는 로직에서도 마찬가지 주의가 필요하다.

  16. closeInfo가 주어지면 다음을 실행:

    1. Resolve closedcloseInfo를 할당.

    2. Assert: readysettled임을 보장.

    3. Close incomingBidirectionalStreams를 처리.

    4. Close incomingUnidirectionalStreams를 처리.

    5. writable in outgoingDatagramWritables에 대해 close writable 처리.

    6. Close incomingDatagrams을 처리.

  17. 그 외에는,

    1. Reject closederror로.

    2. closed.[[PromiseIsHandled]]를 true로 설정.

    3. Reject readyerror로.

    4. ready.[[PromiseIsHandled]]를 true로 설정.

    5. Error incomingBidirectionalStreamserror로.

    6. Error incomingUnidirectionalStreamserror로.

    7. writable in outgoingDatagramWritables에 대해 error writableerror로 처리.

    8. Error incomingDatagramserror로.

queue a network taskWebTransport transport와 일련의 단계 steps로 실행하려면 다음을 수행:

  1. Queue a global tasknetwork task source에 넣고, transportrelevant global object에서 steps를 실행.

6.6. 클라이언트가 시작하지 않은 세션 종료

WebTransport transport와 연결된 WebTransport session종료될 때, 선택적으로 codereasonBytes와 함께 다음 단계를 실행한다:
  1. Queue a network tasktransport에 대해 다음 단계 실행:

    1. transport.[[State]]"closed" 또는 "failed"면 이 단계를 중단한다.

    2. error를 새로 생성한 WebTransportError로, source"session"로 한다.

    3. closeInfonew WebTransportCloseInfo로 생성한다.

    4. code가 주어진 경우, closeInfocloseCodecode를 설정한다.

    5. reasonBytes가 주어진 경우, closeInforeasonreasonBytesUTF-8 해독값을 할당한다.

      Note: reasonBytes에는 언어나 방향 정보가 없다. First-strong 규칙으로 표시 방향을 추론할 수 있다.

    6. Cleanup transporterrorcloseInfo와 함께 처리한다.

WebTransport transportunderlying connection에 연결 오류가 발생할 때 다음 단계를 실행:
  1. Queue a network tasktransport로 다음 단계 실행:

    1. transport.[[State]]"closed" 또는 "failed"면 이 단계를 중단한다.

    2. error를 새로 생성한 WebTransportError로, source"session"로 한다.

    3. Cleanup transporterror와 함께 처리한다.

6.7. 컨텍스트 정리 절차

이 명세서는 context cleanup steps를 다음과 같이 정의한다. 단, WebTransport transport가 주어진다:

  1. transport.[[State]]"connected"이면, 다음을 수행한다:

    1. transport.[[State]]"failed"로 설정한다.

    2. 병렬로(In parallel), terminate를 수행하여 transport.[[Session]]을 종료한다.

    3. 네트워크 작업을 큐에 넣어 transport로 다음 단계를 실행한다:

      1. error를 새로 생성된 WebTransportError로 두되, 그 source"session"으로 한다.

      2. Cleanuptransporterror로 수행한다.

  2. transport.[[State]]"connecting"이면, transport.[[State]]"failed"로 설정한다.

    이는 워커에서도 수행되어야 한다. 다음을 참조: #127whatwg/html#6731.

6.8. 가비지 컬렉션(Garbage Collection)

WebTransport 객체의 [[State]]"connecting"일 때는, [[IncomingBidirectionalStreams]], [[IncomingUnidirectionalStreams]], 어떤 WebTransportReceiveStream, 또는 [[Datagrams]].[[Readable]]locked 상태이거나, ready, draining, closed 프로미스가 관찰 중인 경우에는 garbage collection 대상이 되어서는 안 된다.

WebTransport 객체의 [[State]]"connected"일 때는, [[IncomingBidirectionalStreams]], [[IncomingUnidirectionalStreams]], 어떤 WebTransportReceiveStream, 또는 [[Datagrams]].[[Readable]]locked 상태이거나, draining 또는 closed 프로미스가 관찰 중인 경우에는 garbage collection 대상이 되어서는 안 된다.

WebTransport 객체의 [[State]]"draining"일 때는, [[IncomingBidirectionalStreams]], [[IncomingUnidirectionalStreams]], 어떤 WebTransportReceiveStream, 또는 [[Datagrams]].[[Readable]]locked 상태이거나, closed 프로미스가 관찰 중인 경우에는 garbage collection 대상이 되어서는 안 된다.

establishedWebTransport session이 있고 네트워크 전송 대기 중인 데이터가 있는 WebTransport 객체(여기에는 [[Datagrams]].[[OutgoingDatagramsQueue]] 에 포함된 데이터그램이 포함됨)는 garbage collection 대상이 되어서는 안 된다.

WebTransport 객체가 garbage collection의 대상이 되었는데 underlying connection 이 아직 열려 있는 경우, 사용자 에이전트는 반드시 Application Error Code 0 및 Application Error Message ""로 WebTransport session을 종료 해야 한다.

6.9. 구성(Configuration)

dictionary WebTransportHash {
  required DOMString algorithm;
  required BufferSource value;
};

dictionary WebTransportOptions {
  boolean allowPooling = false;
  boolean requireUnreliable = false;
  sequence<WebTransportHash> serverCertificateHashes = [];
  WebTransportCongestionControl congestionControl = "default";
  [EnforceRange] unsigned short? anticipatedConcurrentIncomingUnidirectionalStreams = null;
  [EnforceRange] unsigned short? anticipatedConcurrentIncomingBidirectionalStreams = null;
  sequence<DOMString> protocols = [];
  ReadableStreamType datagramsReadableType;
};

enum WebTransportCongestionControl {
  "default",
  "throughput",
  "low-latency",
};

WebTransportOptions는 매개변수의 사전으로, WebTransport session이 어떻게 설정되고 사용되는지를 결정한다.

allowPooling, of type boolean, defaulting to false

true로 설정하면, WebTransport 세션이 풀링될 수 있다. 즉, 해당 세션의 underlying connection 을(를) 다른 WebTransport 세션과 공유할 수 있다.

requireUnreliable, of type boolean, defaulting to false

true로 설정하면, WebTransport 세션은 HTTP/2 연결에서는 설정될 수 없으며, 반드시 HTTP/3 연결이 가능해야 한다.

serverCertificateHashes, of type sequence<WebTransportHash>, defaulting to []

이 옵션은 dedicated 연결을 사용하는 트랜스포트에서만 지원된다. 이 기능을 지원하지 않는 트랜스포트 프로토콜에서 이 필드가 비어 있지 않으면, NotSupportedError 예외가 발생해야 한다.

지원되고 비어 있지 않으면, user agent는 서버 인증서가 certificate hash 검증에 성공하고 serverCertificateHashescustom certificate requirements를 모두 만족할 때에만 신뢰해야 한다. user agent는 알 수 없는 algorithm 해시를 무시해야 한다. 비어 있으면, user agent는 일반 fetch 요청에서 사용하는 인증서 검증을 사용해야 한다.

이 옵션은 allowPooling 과 함께 사용할 수 없다.

congestionControl, of type WebTransportCongestionControl, defaulting to "default"

애플리케이션이 처리량 또는 저지연에 특화된 혼잡 제어 알고리즘을 사용할 것을 선호하는 경우 설정할 수 있다. 이 값은 user agent에게 힌트를 제공한다.

이 구성 옵션은 브라우저에서 저지연 최적화 혼잡 제어 알골리즘 구현이 아직 없어 "at risk"로 간주된다.

anticipatedConcurrentIncomingUnidirectionalStreams, of type unsigned short, nullable, defaulting to null

애플리케이션이 서버가 개설할 것으로 예상하는 동시에 열린 수신 단방향 스트림 수를 지정할 수 있다. user agent는 서버에서 최소 100개의 수신 단방향 스트림을 허용해야 한다. null이 아니면, user agent는 [[AnticipatedConcurrentIncomingUnidirectionalStreams]] 값을 서버와의 협상에 반영해서 왕복 횟수 감소를 시도해야 한다.

anticipatedConcurrentIncomingBidirectionalStreams, of type unsigned short, nullable, defaulting to null

애플리케이션이 서버가 개설할 것으로 예상하는 동시에 열린 양방향 스트림 수를 지정할 수 있다. user agent는 서버에서 최소 100개의 양방향 스트림 생성을 허용해야 한다. null이 아니면, user agent는 [[AnticipatedConcurrentIncomingBidirectionalStreams]] 값을 서버와 협상에 반영해서 왕복 횟수 감소를 시도해야 한다.

protocols, of type sequence<DOMString>, defaulting to []

애플리케이션 레벨의 protocol names 배열을 선택적으로 제공한다. 선호하는 애플리케이션 프로토콜을 선택하고 클라이언트에 통보하는 것은 서버에서 옵션이다. 적합한 프로토콜이 제공되지 않으면 서버에서 요청을 거절할 수 있다.

datagramsReadableType, of type ReadableStreamType

수신 데이터그램에 대해 readable byte stream을 사용하고자 하는 애플리케이션의 선호를 명시적으로 지정 가능하다. 지정하지 않으면 기본 readable stream이 사용된다.

Note: readable stream은 데이터그램 의미와 호환되지만, readable byte stream은 호환되지 않는다. 데이터그램은 0바이트 이상의 독립 메시지이며 순서가 보장되지 않고 도착할 수 있다(단순 바이트 시퀀스가 아님). 빈 데이터그램은 손실되고, min 사용 시 메시지 구분이 불가하다.

compute a certificate hash를 수행하기 위해, certificate가 주어졌을 때 다음 단계를 수행한다:

  1. certcertificate로 두되, [RFC5280]에 정의된 Certificate 메시지의 DER 인코딩으로 표현한다.

  2. cert의 SHA-256 해시를 계산하고 계산된 값을 반환한다.

verify a certificate hash를 수행하기 위해, certificate chain과 해시 배열 hashes가 주어졌을 때, 다음 단계를 수행한다:

  1. certificatecertificate chain의 첫 번째 인증서(리프 인증서)로 둔다.

  2. referenceHashcomputing a certificate hashcertificate로 수행한 결과로 둔다.

  3. hashes의 각 해시 hash에 대해:

    1. hash.value 가 null이 아니고 hash.algorithm 이 "sha-256"과 ASCII 대소문자 구분 없는 일치이면:

      1. hashValuehash.value 가 나타내는 바이트 시퀀스로 둔다.

      2. hashValuereferenceHash와 같으면 true를 반환한다.

  4. false를 반환한다.

custom certificate requirements는 다음과 같다: 인증서는 [RFC5280]에 정의된 X.509v3 인증서여야 하며, Subject Public Key 필드에서 사용되는 키는 allowed public key algorithms 중 하나여야 하고, 현재 시간은 [RFC5280]의 섹션 4.1.2.5에 정의된 인증서의 유효 기간 내에 있어야 하며 유효 기간의 총 길이는 2주를 초과해서는 안 된다. 사용자 에이전트는 인증서에 대해 추가적인 implementation-defined 요구사항을 부과할 수 있다.

Subject Public Key Info 필드(그리고 그 결과로 TLS CertificateVerify 메시지)에서 사용되는 allowed public key algorithms의 정확한 목록은 implementation-defined이다. 그러나 상호 운용 가능한 기본값을 제공하기 위해 secp256r1 (NIST P-256) named group([RFC3279], Section 2.3.5; [RFC8422])을 사용하는 ECDSA를 포함해야 한다. RSA 키([RFC3279], Section 2.3.1)는 포함되어서는 안 된다.

6.10. WebTransportCloseInfo 딕셔너리

WebTransportCloseInfo 사전은 종료WebTransport 세션의 에러 코드와 사유를 설정하는 데 사용되는 정보를 포함합니다.

dictionary WebTransportCloseInfo {
  unsigned long closeCode = 0;
  USVString reason = "";
};

이 사전은 다음 속성들을 가져야 합니다:

closeCode, 타입 unsigned long, 기본값 0

피어에게 전달되는 에러 코드입니다.

reason, 타입 USVString, 기본값 ""

WebTransport의 종료 사유입니다.

6.11. WebTransportSendOptions 딕셔너리

WebTransportSendOptionscreateUnidirectionalStream, createBidirectionalStream, createWritable 메서드의 동작을 제어하는 기본 매개변수 딕셔너리입니다.

dictionary WebTransportSendOptions {
  WebTransportSendGroup? sendGroup = null;
  long long sendOrder = 0;
};

이 딕셔너리는 다음 속성을 가집니다:

sendGroup, 타입 WebTransportSendGroup, nullable, 기본값 null

생성된 스트림을 그룹(group)으로 묶기 위한 선택적 WebTransportSendGroup 또는 null입니다.

sendOrder, 타입 long long, 기본값 0

send order 번호를 지정하면 생성된 스트림이 엄격한 순서(strict ordering)에 참여합니다. 현재 엄격 순서(strictly ordered) 스트림에 대기 중인 바이트는 send order 번호가 더 낮은 엄격 순서(strictly ordered) 스트림에 대기 중인 바이트보다 먼저 전송됩니다.

send order 번호를 지정하지 않으면, 해당 스트림에서 바이트를 다른 스트림에 비해 언제 전송할지는 구현 정의입니다. 하지만, 사용자 에이전트는 send order 번호가 낮은 스트림에 bandwidth가 부족하지 않은 한 모든 스트림 간에 대역폭을 공평하게 분배하는 것이 권장됩니다.

참고: 이는 송신 측 데이터 우선순위화로, 수신 순서를 보장하지 않습니다.

6.12. WebTransportSendStreamOptions 딕셔너리

WebTransportSendStreamOptionsWebTransportSendStreamcreateUnidirectionalStream 또는 createBidirectionalStream 에 의해 생성될 때의 동작을 제어하는 매개변수 딕셔너리입니다.

dictionary WebTransportSendStreamOptions : WebTransportSendOptions {
  boolean waitUntilAvailable = false;
};

이 딕셔너리는 다음 속성을 가집니다:

waitUntilAvailable, 타입 boolean, 기본값 false

true일 때, createUnidirectionalStream 또는 createBidirectionalStream 호출의 프로미스는 이행(settled)되지 않습니다. 기저 연결에 스트림을 생성할 충분한 플로우 컨트롤 크레딧이 생기거나, 연결에서 더 이상 송신 스트림을 생성할 수 없는 상태가 될 때까지 대기합니다. false일 때는, 호출 시 플로우 컨트롤 윈도우가 없다면 프로미스가 reject됩니다.

6.13. WebTransportConnectionStats 딕셔너리

WebTransportConnectionStats 사전은 WebTransport sessionunderlying connection에 대한 WebTransport 특화 통계 정보를 포함한다.

Note: 풀링이 사용되는 경우, 동일한 WebTransport sessions이 동일한 connection에 풀링되면 모두 동일한 정보를 받는다. 즉, 동일한 network partition key를 보유한 풀링된 sessions 간에 정보가 공개된다.

Note: 사용 불가능한 통계는 WebTransportConnectionStats 사전에서 absent 상태가 된다.

dictionary WebTransportConnectionStats {
  unsigned long long bytesSent;
  unsigned long long bytesSentOverhead;
  unsigned long long bytesAcknowledged;
  unsigned long long packetsSent;
  unsigned long long bytesLost;
  unsigned long long packetsLost;
  unsigned long long bytesReceived;
  unsigned long long packetsReceived;
  DOMHighResTimeStamp smoothedRtt;
  DOMHighResTimeStamp rttVariation;
  DOMHighResTimeStamp minRtt;
  required WebTransportDatagramStats datagrams;
  unsigned long long? estimatedSendRate = null;
  boolean atSendCapacity = false;
};

이 사전에는 다음 속성들이 있어야 한다:

bytesSent, 타입 unsigned long long

underlying connection을 통해 전송된 payload 바이트 수 (프레이밍 오버헤드, 재전송 제외)

bytesSentOverhead, 타입 unsigned long long

bytesSent만큼의 payload 바이트를 underlying connection 에서 전송할 때 소요된 프레이밍 및 재전송 오버헤드 (바이트 단위)

bytesAcknowledged, 타입 unsigned long long

서버가 QUIC ACK 메커니즘을 통해 수신을 인지한 payload 바이트 수 (underlying connection, 프레이밍은 포함하지 않음)

Note: 일반적으로 bytesSent 보다 작으며 패킷 손실로 인해 영구적으로 작을 수도 있음.

bytesAcknowledged 은(는) 구현 가능성 문제로 Working Group이 위험요소로 지정함.
packetsSent, 타입 unsigned long long

underlying connection 에서 전송된 전체 패킷 수 (손실된 패킷 포함)

bytesLost, 타입 unsigned long long

underlying connection 에서 손실된 바이트 수 (단조 증가하지 않음, 손실로 선언했던 패킷이 뒤늦게 수신될 수 있음). UDP 등 외부 프레이밍 포함 않음.

packetsLost, 타입 unsigned long long

underlying connection 에서 손실된 패킷 수 (단조 증가하지 않음, 손실로 선언했던 패킷이 뒤늦게 수신될 수 있음)

bytesReceived, 타입 unsigned long long

underlying connection 에서 수신된 전체 바이트 수(스트림 중복 데이터 포함, UDP 등 외부 프레이밍 제외)

packetsReceived, 타입 unsigned long long

underlying connection 에서 수신된 전체 패킷 수(처리 불가 패킷도 포함)

smoothedRtt, 타입 DOMHighResTimeStamp

현재 해당 연결에서 관찰되는 smoothed RTT. [RFC9002] Section 5.3 참조.

rttVariation, 타입 DOMHighResTimeStamp

현재 연결에서 관찰되는 RTT 샘플의 평균 변동값. [RFC9002] Section 5.3 참조.

minRtt, 타입 DOMHighResTimeStamp

전체 연결에서 관찰된 최소 RTT. [RFC9002] Section 5.2 참조.

estimatedSendRate, 타입 unsigned long long, nullable, 기본값 null

user agent가 큐에 쌓인 데이터를 초당 몇 비트로 전송할지 추정치(모든 스트림/데이터그램에 적용). 해당 WebTransport session에 공유되는 모든 데이터에 적용되며, 혼잡 제어 알고리즘(congestionControl으로 선택 가능)이 산출한다. 프레이밍 오버헤드는 미포함, 애플리케이션 payload의 전송 가능 속도를 의미. user agent가 추정치를 제공하지 않으면 null. 이전 결과가 null이 아니었어도 null이 될 수 있음.

atSendCapacity, 타입 boolean, 기본값 false

false면 estimatedSendRate 가 애플리케이션 때문에 제한되어 있을 수 있음(애플리케이션에서 혼잡제어로 허용되는 양보다 훨씬 적게 보냄). 이때 혼잡제어 알고리즘에서 네트워크 용량 추정이 부정확할 수 있음.

true면 애플리케이션이 네트워크 용량만큼 전송하며 estimatedSendRate 가 네트워크 용량을 반영.

atSendCapacitytrueestimatedSendRate 는 상한치에 해당함. 애플리케이션 전송 속도가 유지되면 estimatedSendRate 는 네트워크 상황에 맞게 조정됨. 단, atSendCapacity 가 true여도 estimatedSendRatenull일 수 있음.

6.14. WebTransportDatagramStats 딕셔너리

WebTransportDatagramStats 사전은 underlying connection을 통한 데이터그램 전송 통계를 포함한다.

dictionary WebTransportDatagramStats {
  unsigned long long droppedIncoming;
  unsigned long long expiredIncoming;
  unsigned long long expiredOutgoing;
  unsigned long long lostOutgoing;
};

이 사전에는 다음 속성이 포함되어야 한다:

droppedIncoming, 타입 unsigned long long

애플리케이션이 datagramsreadable 에서 새 데이터그램이 수신 큐를 초과하기 전에 읽지 않아 드롭된 수신 데이터그램 수

expiredIncoming, 타입 unsigned long long

incomingMaxAge 보다 오래되어 datagramsreadable 에서 읽히기 전에 드롭된 수신 데이터그램 수

expiredOutgoing, 타입 unsigned long long

전송 대기 중 outgoingMaxAge 보다 오래되어 전송되기 전에 드롭된 데이터그램 수

lostOutgoing, 타입 unsigned long long

전송된 데이터그램 중 [RFC9002] Section 6.1에 정의된 대로 손실로 선언된 데이터그램 수

7. 인터페이스 WebTransportSendStream

WebTransportSendStreamWritableStream 으로, 송신 단방향 또는 양방향 WebTransport 스트림을 통해 데이터를 스트리밍할 수 있는 기능을 제공합니다.

이 객체는 WritableStream 타입의 Uint8Array 데이터로 서버에 데이터를 전송하기 위해 쓸 수 있습니다.

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportSendStream : WritableStream {
  attribute WebTransportSendGroup? sendGroup;
  attribute long long sendOrder;
  Promise<WebTransportSendStreamStats> getStats();
  WebTransportWriter getWriter();
};

WebTransportSendStream 은 항상 create 절차에 의해 생성됩니다.

WebTransportSendStream전송 단계전송-수신 단계WritableStream의 WritableStream의 단계와 동일합니다.

7.1. 속성

sendGroup, 타입 WebTransportSendGroup, nullable

getter 단계:

  1. this[[SendGroup]]를 반환.

setter 단계에서 value가 주어지면:

  1. value가 null이 아니고, value.[[Transport]]this.[[Transport]]와 다르면, throw InvalidStateError 예외를 발생한다.

  2. this.[[SendGroup]]value로 설정.

sendOrder, 타입 long long

getter 단계:

  1. this[[SendOrder]]를 반환.

setter 단계에서 value가 주어지면:

  1. this.[[SendOrder]]value를 설정.

7.2. 메서드

getStats()

WebTransportSendStream의 성능에 대한 통계를 수집하고, 결과를 비동기로 보고합니다.

getStats가 호출되면, 사용자 에이전트는 다음 단계를 실행해야 합니다:

  1. p를 새 promise로 한다.

  2. 다음 단계를 in parallel로 실행:

    1. gatheredStatslist로, this WebTransportSendStream 에 특화된 통계를 WebTransportSendStreamStats의 딕셔너리 멤버에 정확히 할당하게 준비합니다.

    2. Queue a network tasktransport로 다음 단계를 실행:

      1. statsnew WebTransportSendStreamStats 객체로 한다.

      2. user agent가 노출하고자 하는 stats의 각 member member마다, set membergatheredStats의 해당 entry 값으로 설정.

      3. Resolve pstats로 처리.

  3. p를 반환.

getWriter()

이 메서드는 getWriter와 동일한 방법으로 구현해야 하며, 단 WritableStream에서 상속되는 대신 WritableStreamDefaultWriter를 생성하는 것이 아니라, WebTransportWriterWebTransportWriterthis와 함께 생성해야 합니다.

7.3. 내부 슬롯

WebTransportSendStream 객체는 다음과 같은 내부 슬롯을 가진다.

내부 슬롯 설명 (비규범적)
[[InternalStream]] outgoing unidirectional 또는 bidirectional WebTransport 스트림
[[PendingOperation]] 진행 중인 쓰기 또는 닫기 작업을 나타내는 프라미스, 또는 null
[[Transport]] WebTransport 객체가 소유한 WebTransportSendStream.
[[SendGroup]] 선택적 WebTransportSendGroup, 또는 null
[[SendOrder]] 옵션 전달 순서 번호, 기본값은 0
[[AtomicWriteRequests]] 순서가 지정된 집합의 프라미스 모음으로, underlying sink에 큐잉된 요청 중 atomic 처리가 필요한 쓰기 요청들을 추적
[[BytesWritten]] 스트림에 기록된 바이트 수
[[CommittedOffset]] 스트림에서 피어에게 전달될 바이트 수를 기록하는 오프셋. 스트림이 sending 중단 상태여도 값을 유지함; 참조: [RELIABLE-RESET]

7.4. 절차

생성하려면 WebTransportSendStream 을, 송신 단방향 또는 양방향 WebTransport 스트림 internalStream, WebTransport transport, sendGroup, sendOrder와 함께 다음 단계를 수행한다:

  1. streamnew WebTransportSendStream로 생성합니다. 다음과 같이 초기화됩니다:

    [[InternalStream]]

    internalStream

    [[PendingOperation]]

    null

    [[Transport]]

    transport

    [[SendGroup]]

    sendGroup

    [[SendOrder]]

    sendOrder

    [[AtomicWriteRequests]]

    비어 있는 ordered set의 promise 집합

    [[BytesWritten]]

    0

    [[CommittedOffset]]

    0

  2. writeAlgorithmchunkstream쓰기 위한 동작으로 둡니다.

  3. closeAlgorithmstream닫기 위한 동작으로 둡니다.

  4. abortAlgorithmreason과 함께 stream중단하는 동작으로 둡니다.

  5. Set up streamwriteAlgorithmwriteAlgorithm으로, closeAlgorithmcloseAlgorithm으로, abortAlgorithmabortAlgorithm으로 설정합니다.

  6. abortSignalstream의 [[controller]].[[abortController]].[[signal]]로 둡니다.

  7. 다음 단계abortSignal에 추가합니다.

    1. pendingOperationstream.[[PendingOperation]]로 둡니다.

    2. pendingOperation이 null이면, 이 단계들을 중단합니다.

    3. stream.[[PendingOperation]]를 null로 설정합니다.

    4. reasonabortSignalabort reason으로 둡니다.

    5. promise중단 stream with reason의 결과로 둡니다.

    6. Upon fulfillment of promise, reject pendingOperationreason으로 거절합니다.

  8. Append streamtransport.[[SendStreams]]에 추가합니다.

  9. stream을 반환합니다.

write chunk을(를) WebTransportSendStream stream에 쓰기 위해, 다음 단계를 수행한다:
  1. transportstream.[[Transport]]를 할당한다.

  2. chunkBufferSource가 아니라면, TypeError로 거부된 promise를 반환한다.

  3. promise에 새로운 promise를 할당한다.

  4. byteschunk가 나타내는 바이트 시퀀스의 복사본을 할당한다.

  5. stream.[[PendingOperation]]promise를 할당한다.

  6. inFlightWriteRequeststream.inFlightWriteRequest를 할당한다.

  7. atomicstream.[[AtomicWriteRequests]]inFlightWriteRequest를 포함하고 있다면 true, 아니면 false를 할당한다.

  8. 다음 단계를 병렬로 실행한다:

    1. atomic이 true이고 현재 플로우 제어 윈도우가 bytes 전체를 전송하기에 너무 작으면 남은 단계를 중단하고 네트워크 작업 큐에서 transport로 다음 하위 단계를 실행한다:

      1. stream.[[PendingOperation]] 을 null로 설정한다.

      2. 모든 atomic write 요청 중단stream에 대해 실행한다.

    2. 그렇지 않으면, send bytes을(를) stream.[[InternalStream]]에서 전송하고 그 작업이 완료될 때까지 기다린다. 이 전송은 이전에 대기 중이었던 스트림, 데이터그램 및 앞으로 대기할 스트림/데이터그램 전송과 섞여 동작할 수 있다.

      사용자 에이전트는 성능 향상을 위해 버퍼를 사용할 수 있다. 이 버퍼는 고정된 상한을 두어, WebTransportSendStream 사용자가 backpressure 정보를 알 수 있도록 해야 한다.

      이 전송은 [[SendGroup]] 이 같고 [[SendOrder]] 가 더 높은(더 우선순위가 높은) 스트림들 중 에러가 아니고 플로우 제어에 막혀있지 않은 모든 바이트가 먼저 전송될 때까지 block되어야 한다.

      stream.[[SendOrder]] 는 이 병렬 동작 내에서 접근한다.

      사용자 에이전트는 이러한 값이 전송 도중 라이브업데이트되는 것에도 동적으로 반응해야 하나, 구체적인 방식은 구현 정의이다.

      Note: 재전송 순서에 대한 정의는 구현 정의이다. 그러나 데이터가 높은 [[SendOrder]] 값을 가질수록 우선적으로 재전송되어야 한다.

      이 전송은 플로우 제어 또는 에러 이외에는 starvation이 발생해서는 안 된다.

      사용자 에이전트는 starvation이 아닌 모든 스트림에 대역폭을 공정하게 할당해야 한다.

      Note: 여기서 공정성의 정의는 구현 정의이다.

    3. 이전 단계가 네트워크 오류로 실패했다면, 남은 단계를 중단한다.

      Note: 여기에서 promise를 거부하지 않는데, 네트워크 오류는 별도 경로로 처리되며 해당 단계에서 stream.[[PendingOperation]] 이 reject된다.

    4. 그 외의 경우, 네트워크 작업 큐에서 transport로 아래 단계를 실행한다:

      1. stream.[[PendingOperation]] 을 null로 설정한다.

      2. bytes의 길이를 stream.[[BytesWritten]]에 더한다.

      3. stream.[[AtomicWriteRequests]]inFlightWriteRequest를 포함한다면, 해당 요청 삭제를 수행한다.

      4. Resolve promise를 undefined로 해결한다.

  9. promise를 반환한다.

Note: 이 알고리즘(혹은, write(chunk)) 에서 반환된 promise의 이행은, 해당 chunk가 서버에 ack되었다는 의미가 아님에 유의해야 한다. 단지 해당 chunk가 버퍼에 추가되었음을 의미할 수 있다. 서버에 도달했는지 확인하려면, 서버에서 응용 레벨의 ack 메시지를 보내야 한다.

close WebTransportSendStream stream을 닫으려면, 다음 단계를 수행한다:
  1. transportstream.[[Transport]]를 할당한다.

  2. promise에 새로운 promise를 할당한다.

  3. streamtransport.[[SendStreams]]에서 제거한다.

  4. stream.[[PendingOperation]]promise를 할당한다.

  5. 다음 단계를 병렬로 실행한다:

    1. Send FIN을 stream.[[InternalStream]]에 전송하고, 완료될 때까지 기다린다.

    2. stream.[[InternalStream]]이 "all data committed" 상태가 될 때까지 기다린다. [QUIC]

    3. 네트워크 작업 큐에서 transport에 대해 아래 단계를 수행한다:

      1. stream.[[PendingOperation]] 을 null로 설정한다.

      2. Resolve promise를 undefined로 완료한다.

  6. promise를 반환한다.

abort WebTransportSendStream stream을(를) reason과 함께 중단하려면, 다음 단계를 수행한다:
  1. transportstream.[[Transport]]를 할당한다.

  2. promise에 새로운 promise를 할당한다.

  3. code에 0을 할당한다.

  4. streamtransport.[[SendStreams]]에서 제거한다.

  5. reasonWebTransportError이고, reason.[[StreamErrorCode]] 가 null이 아니면, codereason.[[StreamErrorCode]] 값을 할당한다.

  6. code < 0이면, code에 0을 할당한다.

  7. code가 4294967295를 초과하면, code에 4294967295를 할당한다.

  8. committedOffsetstream.[[CommittedOffset]]을 할당한다.

    Note: code의 유효 범위는 0~4294967295이다. 기본 연결 이 HTTP/3을 사용하는 경우, 이 코드는 [WEB-TRANSPORT-HTTP3] 에서 정의한 [0x52e4a40fa8db, 0x52e5ac983162] 범위로 인코딩된다.

  9. 다음 단계를 병렬로 실행한다:

    1. 중단stream.[[InternalStream]]codecommittedOffset을 인자로 호출한다.

    2. 네트워크 작업 큐에서 transportpromise를 undefined로 해결한다.

  10. promise를 반환한다.

abort all atomic write requestsWebTransportSendStream stream에 대해 수행하려면 다음 단계를 실행한다:
  1. writeRequestsstream.writeRequests를 할당한다.

  2. requestsToAbortstream.[[AtomicWriteRequests]]를 할당한다.

  3. writeRequestsrequestsToAbort에 속하지 않는 promise를 포함한다면, streamAbortError 에러를 전달하고, 이 단계를 중단한다.

  4. stream.[[AtomicWriteRequests]]를 비운다.

  5. requestsToAbort의 각 promise에 대해, AbortError로 reject 한다.

  6. 병렬로, requestsToAbort의 각 promise에 대해 해당 promise와 연관된 바이트의 전송을 중단한다.

7.5. 서버로부터 수신 중단 신호 받기

WebTransport streamWebTransportSendStream stream과 연관되어 있고 서버로부터 receiving aborted 신호를 받으면, 다음 단계를 수행한다:

  1. transportstream.[[Transport]]로 둔다.

  2. codereceiving aborted 신호에 첨부된 애플리케이션 프로토콜 오류 코드로 둔다.

    Note: code의 유효 값은 0부터 4294967295(포함)까지이다. underlying connection이 HTTP/3을 사용 중인 경우, 해당 코드는 [WEB-TRANSPORT-HTTP3]에 서술된 대로 [0x52e4a40fa8db, 0x52e5ac983162] 범위의 숫자로 인코딩된다.

  3. Queue a network tasktransport로 수행하여 다음 단계를 실행한다:

    1. transport.[[State]]"closed" 또는 "failed"이면, 이 단계들을 중단한다.

    2. Remove를 수행하여 streamtransport.[[SendStreams]]에서 제거한다.

    3. error를 새로 createdWebTransportError로 두되, 그 source"stream"이고 streamErrorCodecode로 한다.

    4. stream.[[PendingOperation]] 이 null이 아니면, stream.[[PendingOperation]]error로 reject한다.

    5. Error를 수행하여 streamerror로 에러 상태로 만든다.

7.6. WebTransportSendStreamStats 사전

WebTransportSendStreamStats 사전은 하나의 WebTransportSendStream에 특화된 통계 정보를 포함합니다.

dictionary WebTransportSendStreamStats {
  unsigned long long bytesWritten;
  unsigned long long bytesSent;
  unsigned long long bytesAcknowledged;
};

이 사전에는 다음 속성이 포함되어야 한다:

bytesWritten, 타입 unsigned long long

애플리케이션이 이 WebTransportSendStream 에 성공적으로 기록한 총 바이트 수. 이 숫자는 증가만 한다.

bytesSent, 타입 unsigned long long

애플리케이션이 이 WebTransportSendStream 에 쓴 바이트 중 최소 한 번 이상 전송된 바이트 수 표시. 이 값은 증가만 하며 항상 bytesWritten 이하이다.

Note: 이것은 단일 스트림에서의 앱 데이터 전송 진행률일 뿐이며 네트워크 오버헤드는 포함하지 않는다.

bytesAcknowledged, 타입 unsigned long long

애플리케이션이 이 WebTransportSendStream 에 쓴 바이트 중 QUIC의 ACK 메커니즘에 의해 서버가 수신 확인을 한(acknowledged) 순차 바이트 수. 첫 번째 미acknowledged 바이트 전까지의 모든 바이트만 포함. 이 숫자는 증가만 하며 bytesSent 이하이다.

Note: 연결이 HTTP/2일 때는 이 값이 bytesSent 과 일치한다.

8. 인터페이스 WebTransportSendGroup

WebTransportSendGroup 은 여러 개의 개별 (일반적으로 엄격하게 순서화된) WebTransportSendStream에 걸쳐 분산된 데이터 전송을 추적하는 선택적 조직 객체입니다.

WebTransportSendStream은 생성 시 또는 sendGroup 속성 할당을 통해, 언제든지 최대 하나의 그룹(grouped) WebTransportSendGroup에 속할 수 있습니다. 기본적으로 이들은 그룹에 속하지 않음(ungrouped) 상태입니다.

유저 에이전트는 WebTransportSendGroup들에 대해 WebTransportSendStream 전송을 위한 대역폭 할당 시 동등하게 간주합니다. 각 WebTransportSendGroupsendOrder 평가를 위한 독립적인 번호 공간도 제공합니다.

[Exposed=(Window,Worker), SecureContext]
interface WebTransportSendGroup {
  Promise<WebTransportSendStreamStats> getStats();
};

WebTransportSendGroup 은 항상 create 절차에 의해 생성됩니다.

8.1. 메서드

getStats()

이 sendGroup 하위에 WebTransportSendStreamgrouped된 모든 스트림의 통계를 집계하여 비동기적으로 결과를 보고한다.

getStats가 호출되면 사용자 에이전트는 다음 단계를 실행해야 한다:

  1. p를 새 promise로 한다.

  2. streamsWebTransportSendStream[[SendGroup]]이 this인 모든 스트림으로 한다.

  3. 다음 단계를 in parallel로 실행:

    1. gatheredStatsstreams 내 모든 스트림의 집계 통계(WebTransportSendStreamStats의 딕셔너리 멤버에 정확히 할당 가능한 값) 리스트로 한다.

    2. Queue a network tasktransport와 함께 다음 단계 실행:

      1. statsnew WebTransportSendStreamStats 객체로 한다.

      2. user agent가 노출하고 싶은 stats의 각 member member에 대해, set membergatheredStats의 해당 entry 값으로 설정한다.

      3. Resolve pstats로 처리.

  4. p를 반환.

8.2. 내부 슬롯

WebTransportSendGroup 객체는 다음과 같은 내부 슬롯을 가진다.

내부 슬롯 설명 (비규범적)
[[Transport]] WebTransport 객체가 소유하고 있는 WebTransportSendGroup.

8.3. 절차

생성을 하려면, WebTransportSendGroupWebTransport transport와 함께, 다음 단계를 실행한다:

  1. sendGroupnew WebTransportSendGroup으로, 다음과 같이 생성한다:

    [[Transport]]

    transport

  2. sendGroup을 반환한다.

9. 인터페이스 WebTransportReceiveStream

WebTransportReceiveStreamReadableStream 으로, 수신 단방향 또는 양방향 WebTransport 스트림을 통해 서버로부터 데이터를 스트리밍 받을 수 있는 기능을 제공합니다.

이 객체는 ReadableStream 타입의 Uint8Array 데이터로, 서버에서 수신한 데이터를 읽어서 소비할 수 있습니다. WebTransportReceiveStreamreadable byte stream이기 때문에 소비자는 BYOB reader기본 리더(default reader) 모두 사용할 수 있습니다.

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportReceiveStream : ReadableStream {
  Promise<WebTransportReceiveStreamStats> getStats();
};

WebTransportReceiveStream 은 항상 create 절차에 의해 생성됩니다.

WebTransportReceiveStream전송 단계전송-수신 단계ReadableStream의 단계와 동일합니다.

9.1. 메서드

getStats()

WebTransportReceiveStream의 성능에 특화된 통계를 수집하고, 그 결과를 비동기적으로 보고한다.

getStats가 호출되면, 사용자 에이전트는 다음 단계를 반드시 수행해야 한다:

  1. p를 새로운 promise로 둔다.

  2. 다음 단계를 병렬로(In parallel) 수행한다:

    1. gatheredStats를, list 형태의 통계로 두되 this WebTransportReceiveStream에 특화된 값으로서, WebTransportReceiveStreamStatsdictionary members를 정확히 채우는 데 필요하다.

    2. Queue a network tasktransport로 수행하여 다음 단계를 실행한다:

      1. statsnew로 생성한 WebTransportReceiveStreamStats 객체로 둔다.

      2. 사용자 에이전트가 노출하려는 stats의 각 member member에 대해, set을 수행하여 membergatheredStats의 해당 entry로 설정한다.

      3. Resolve를 수행하여 pstats로 해결한다.

  3. p를 반환한다.

9.2. 내부 슬롯

WebTransportReceiveStream 객체는 다음과 같은 내부 슬롯을 가지고 있습니다.

내부 슬롯 설명 (비규범적)
[[InternalStream]] 수신 단방향 또는 양방향 WebTransport 스트림.
[[Transport]] WebTransport 객체가 WebTransportReceiveStream을 소유합니다.

9.3. 절차

create를 수행하여 WebTransportReceiveStream을 만들고, incoming unidirectional 또는 bidirectional WebTransport stream internalStreamWebTransport transport가 주어졌을 때 다음 단계를 수행한다:

  1. streamnew로 생성한 WebTransportReceiveStream으로 두고, 다음과 같이 설정한다:

    [[InternalStream]]

    internalStream

    [[Transport]]

    transport

  2. pullAlgorithm을, pulls bytes를 통해 stream에서 바이트를 끌어오는 동작으로 둔다.

  3. cancelAlgorithm을, cancels를 사용해 reason을 주어 stream을 취소하는 동작으로 둔다.

  4. Set up with byte reading supportstream에 대해 수행하되, pullAlgorithmpullAlgorithm으로, cancelAlgorithmcancelAlgorithm으로 설정한다.

  5. Append를 수행하여 streamtransport[[ReceiveStreams]]에 추가한다.

  6. stream을 반환한다.

WebTransportReceiveStream stream에서 pull bytes를 수행하려면, 다음 단계를 실행한다.

  1. transportstream.[[Transport]]로 둔다.

  2. internalStreamstream.[[InternalStream]]로 둔다.

  3. promise를 새로운 promise로 둔다.

  4. buffer, offset, maxBytes를 null로 둔다.

  5. streamcurrent BYOB request view가 null이 아니면:

    1. offsetstreamcurrent BYOB request view.[[ByteOffset]]으로 설정한다.

    2. maxBytesstreamcurrent BYOB request viewbyte length로 설정한다.

    3. bufferstreamcurrent BYOB request viewunderlying buffer로 설정한다.

  6. 그 외의 경우:

    1. offset을 0으로 설정한다.

    2. maxBytesimplementation-defined 크기로 설정한다.

    3. buffernew ArrayBuffer로, 크기를 maxBytes로 하여 생성한다. 만약 ArrayBuffer 할당에 실패하면, a promise rejected with를 통해 RangeError를 반환한다.

  7. 다음 단계를 In parallel로 수행한다:

    1. Write를 수행하여, read된 바이트를 internalStream에서 bufferoffset 위치부터 최대 maxBytes 바이트까지 기록한다. 최소 한 바이트가 읽히거나 FIN이 수신될 때까지 대기한다. read를 읽힌 바이트 수로, hasReceivedFIN을 FIN이 동반되었는지 여부로 둔다.

      사용자 에이전트는 전송 성능을 개선하기 위한 버퍼를 가질 수 있다. 이러한 버퍼는 서버로의 역압(backpressure) 정보를 전달하기 위해 고정된 상한을 가져야 한다(SHOULD).

      Note: 이 동작은 buffer를 전부 채우기 전에 반환될 수 있다.

    2. 이전 단계가 실패하면, 남은 단계를 중단한다.

      Note: 여기서는 promise를 reject하지 않는다. 네트워크 오류는 다른 곳에서 처리되며, 그 단계들은 error를 통해 stream을 에러 상태로 만들고, 이 pull을 대기 중인 모든 읽기 요청을 reject한다.

    3. Queue a network tasktransport로 수행하여 다음 단계를 실행한다:

      Note: 위에서 설명한 버퍼가 이 절차가 실행되는 event loop에서 사용 가능하면, 다음 단계는 즉시 실행될 수 있다.

      1. 만약 read > 0이면:

        1. view를 새로운 Uint8Array로, buffer, offset, read를 사용하여 설정한다.

        2. Enqueue를 수행하여 viewstream에 넣는다.

      2. hasReceivedFIN이 true이면:

        1. Remove를 수행하여 streamtransport[[ReceiveStreams]]에서 제거한다.

        2. Close를 수행하여 stream을 닫는다.

      3. Resolve를 수행하여 promise를 undefined로 해결한다.

  8. promise를 반환한다.

WebTransportReceiveStream streamreason과 함께 취소(cancel)하려면, 다음 단계를 수행한다.

  1. transportstream.[[Transport]]로 둔다.

  2. internalStreamstream.[[InternalStream]]로 둔다.

  3. promise를 새로운 promise로 둔다.

  4. code를 0으로 둔다.

  5. 만약 reasonWebTransportError이고 reason.[[StreamErrorCode]]가 null이 아니면, codereason.[[StreamErrorCode]]로 설정한다.

  6. 만약 code < 0이면, code를 0으로 설정한다.

  7. 만약 code > 4294967295이면, code를 4294967295로 설정한다.

    Note: code의 유효 값은 0부터 4294967295(포함)까지이다. underlying connection이 HTTP/3를 사용 중인 경우, 해당 코드는 [WEB-TRANSPORT-HTTP3]에 서술된 대로 [0x52e4a40fa8db, 0x52e5ac983162] 범위의 숫자로 인코딩된다.

  8. Remove를 수행하여 streamtransport[[SendStreams]]에서 제거한다.

  9. 다음 단계를 In parallel로 수행한다:

    1. Abort receivinginternalStream에 대해 code로 수행한다.

    2. Queue a network tasktransport로 수행하여 다음 단계를 실행한다:

      Note: 위에서 설명한 버퍼가 이 절차가 실행되는 event loop에서 사용 가능하면, 다음 단계는 즉시 실행될 수 있다.

      1. Remove를 수행하여 streamtransport[[ReceiveStreams]]에서 제거한다.

      2. Resolve를 수행하여 promise를 undefined로 해결한다.

  10. promise를 반환한다.

9.4. 서버로부터 송신 중단 신호 받기

서버로부터 sending aborted 신호를 받을 때, WebTransportReceiveStream stream과 연관된 WebTransport stream에 대해 다음 단계를 수행한다:
  1. transportstream.[[Transport]]로 둔다.

  2. codesending aborted 신호에 첨부된 애플리케이션 프로토콜 오류 코드로 둔다.

    Note: code의 유효 값은 0부터 4294967295(포함)까지이다. underlying connection이 HTTP/3를 사용 중인 경우, 해당 코드는 [WEB-TRANSPORT-HTTP3]에 설명된 대로 [0x52e4a40fa8db, 0x52e5ac983162] 범위의 숫자로 인코딩된다.

  3. Queue a network tasktransport로 수행하여 다음 단계를 실행한다:

    1. transport.[[State]]"closed" 또는 "failed"이면, 이 단계들을 중단한다.

    2. Remove를 수행하여 streamtransport[[ReceiveStreams]]에서 제거한다.

    3. error를 새로 createdWebTransportError로 두되, 그 source"stream"이고 streamErrorCodecode로 한다.

    4. Error를 수행하여 streamerror로 에러 상태로 만든다.

9.5. WebTransportReceiveStreamStats 사전

WebTransportReceiveStreamStats 사전은 하나의 WebTransportReceiveStream에 특화된 통계 정보를 포함합니다.

dictionary WebTransportReceiveStreamStats {
  unsigned long long bytesReceived;
  unsigned long long bytesRead;
};

해당 사전은 다음 속성을 가집니다:

bytesReceived, 타입 unsigned long long

WebTransportReceiveStream을(를) 위해 서버 애플리케이션이 전송한 바이트 중 지금까지 수신된 바이트의 진행 상황을 나타낸다. 누락된 첫 바이트 전까지의 순차 바이트만 포함하며, 이 숫자는 증가만 한다.

Note: 이는 단일 스트림에서 받은 앱 데이터의 진행률만 나타내며, 네트워크 오버헤드는 포함하지 않는다.

bytesRead, 타입 unsigned long long

애플리케이션이 이 WebTransportReceiveStream에서 성공적으로 읽은 총 바이트 수. 이 값은 증가만 하며, 항상 bytesReceived 이하이다.

10. 인터페이스 WebTransportBidirectionalStream

[Exposed=(Window,Worker), SecureContext]
interface WebTransportBidirectionalStream {
  readonly attribute WebTransportReceiveStream readable;
  readonly attribute WebTransportSendStream writable;
};

10.1. 내부 슬롯

WebTransportBidirectionalStream 은 다음의 내부 슬롯을 가집니다.

내부 슬롯 설명 (비규범적)
[[Readable]] WebTransportReceiveStream입니다.
[[Writable]] WebTransportSendStream입니다.
[[Transport]] WebTransport 객체가 해당 WebTransportBidirectionalStream를 소유합니다.

10.2. 속성

readable, 타입 WebTransportReceiveStream, readonly

getter 단계: this[[Readable]]를 반환한다.

writable, 타입 WebTransportSendStream, readonly

getter 단계: this[[Writable]]를 반환한다.

10.3. 절차

create를 수행하여 WebTransportBidirectionalStream을 생성하기 위해, bidirectional WebTransport stream internalStream, WebTransport 객체 transport, 그리고 sendOrder가 주어졌을 때 다음 단계를 수행한다.

  1. readablecreating을 통해 얻은 WebTransportReceiveStream의 결과로 두되, internalStreamtransport를 사용한다.

  2. writablecreating을 통해 얻은 WebTransportSendStream의 결과로 두되, internalStream, transport, 그리고 sendOrder를 사용한다.

  3. streamnew로 생성한 WebTransportBidirectionalStream으로 두며, 다음과 같이 한다:

    [[Readable]]

    readable

    [[Writable]]

    writable

    [[Transport]]

    transport

  4. stream을 반환한다.

11. WebTransportWriter 인터페이스

WebTransportWriterWritableStreamDefaultWriter 의 하위 클래스로, 두 가지 메서드가 추가됩니다.

WebTransportWriter 는 항상 생성 절차에 의해 생성됩니다.

[Exposed=*, SecureContext]
interface WebTransportWriter : WritableStreamDefaultWriter {
  Promise<undefined> atomicWrite(optional any chunk);
  undefined commit();
};

11.1. 메서드

atomicWrite(chunk)

atomicWrite 메서드는 전달된 chunk가 전송 시점의 흐름 제어 윈도우 내에서 전체가 전송될 수 없다면 거절됩니다. 이 동작은 흐름 제어 교착 상태에 민감한 특수 트랜잭션 기반 응용을 만족시키기 위해 설계되었습니다 ([RFC9308] Section 4.4 참고).

참고: atomicWrite 는 일부 데이터를 전송한 후에도 거절될 수 있습니다. 흐름 제어 관점에서만 원자성을 제공하며, 다른 오류가 발생할 수 있습니다. atomicWrite 는 데이터가 패킷 사이에서 분할되거나 다른 데이터와 interleaved되는 것을 방지하지 않습니다. 단지 송신자만 atomicWrite 가 흐름 제어 크레딧 부족으로 실패한 것을 알 수 있습니다.

참고: 원자적 쓰기는 비원자적 쓰기 뒤에 큐에 있을 경우 여전히 블록될 수 있습니다. 만약 원자적 쓰기가 거절되면, 그 시점 이후 큐에 있는 모든 요청도 거절됩니다. 이렇게 거절된 비원자적 쓰기는 스트림 에러를 발생시킵니다. 따라서 응용에서는 항상 atomicWrite를 await하는 것이 권장됩니다.

atomicWrite 가 호출되면, 유저 에이전트는 다음 단계를 실행해야 합니다:

  1. pwrite(chunk)WritableStreamDefaultWriterchunk를 사용해 호출한 결과로 둡니다.

  2. Append pstream.[[AtomicWriteRequests]]에 추가합니다.

  3. promise가 settle 될 때 반응하는 결과를 반환하며, 다음 단계를 실행합니다:

    1. stream.[[AtomicWriteRequests]]p를 포함하면, p를 제거합니다.

    2. pr 이유로 거절되면, 거절된 promiser로 반환합니다.

    3. undefined를 반환합니다.

commit()

commit 메서드는 스트림의 [[CommittedOffset]] 값을 해당 스트림에 기록된 바이트 수([[BytesWritten]])로 갱신합니다. 이렇게 하면 쓰기가 중단(abort)되어 스트림이 송신 중단(abort sending)되더라도 해당 바이트가 피어에게 신뢰성 있게 전달됨을 보장합니다. 이 동작은 [RELIABLE-RESET]에서 설명된 메커니즘을 사용합니다.

참고: 이 메서드는 연결이 실패한 경우에는 전달을 보장하지 않으며, 스트림이 송신 중단(abort sending)된 경우에만 전달이 보장됩니다.

commitstream에 대해 호출되면, 유저 에이전트는 다음 단계를 실행해야 합니다:

  1. transportstream.[[Transport]]로 둡니다.

  2. stream.[[CommittedOffset]]stream.[[BytesWritten]] 값으로 설정합니다.

11.2. 절차

create를 수행하여 WebTransportWriter를 만들고, WebTransportSendStream stream이 주어졌을 때 다음 단계를 실행한다:

  1. writernew로 생성한 WebTransportWriter로 둔다.

  2. new WritableStreamDefaultWriter(stream) 생성자 단계를 실행하되 writer를 this로, stream을 생성자 인자로 전달한다.

  3. writer를 반환한다.

12. WebTransportError 인터페이스

WebTransportErrorDOMException 의 하위 클래스입니다.

[Exposed=(Window,Worker), Serializable, SecureContext]
interface WebTransportError : DOMException {
  constructor(optional DOMString message = "", optional WebTransportErrorOptions options = {});

  readonly attribute WebTransportErrorSource source;
  readonly attribute unsigned long? streamErrorCode;
};

dictionary WebTransportErrorOptions {
  WebTransportErrorSource source = "stream";
  [Clamp] unsigned long? streamErrorCode = null;
};

enum WebTransportErrorSource {
  "stream",
  "session",
};

12.1. 내부 슬롯

WebTransportError 은 다음 내부 슬롯을 가집니다.

내부 슬롯 설명 (비규범적)
[[Source]] WebTransportErrorSource로, 이 오류의 원인을 나타냅니다.
[[StreamErrorCode]] 이 오류에 대한 응용 프로토콜 오류 코드, 또는 null.

12.2. 생성자

new WebTransportError(message, options) 생성자 단계는 다음과 같다:

  1. thisname"WebTransportError"로 설정한다.

  2. thismessagemessage로 설정한다.

  3. this의 내부 슬롯을 다음과 같이 설정한다:

    [[Source]]

    options.source

    [[StreamErrorCode]]

    options.streamErrorCode

    Note: 이 name은 레거시 코드에 대한 매핑이 없으므로 thiscode 는 0이다.

12.3. 속성

source, 타입 WebTransportErrorSource, 읽기 전용

getter 단계는 this[[Source]]를 반환하는 것이다.

streamErrorCode, 타입 unsigned long, 읽기 전용, null 허용

getter 단계는 this[[StreamErrorCode]]를 반환하는 것이다.

12.4. 직렬화

WebTransportError 객체는 직렬화 가능한 객체입니다. 해당 직렬화 단계(valueserialized가 주어짐)는 다음과 같습니다:

  1. DOMException 직렬화 단계valueserialized로 실행합니다.

  2. serialized.[[Source]]value.[[Source]]를 설정합니다.

  3. serialized.[[StreamErrorCode]]value.[[StreamErrorCode]]를 설정합니다.

해당 역직렬화 단계(serializedvalue가 주어짐)는 다음과 같습니다:

  1. DOMException 역직렬화 단계serializedvalue로 실행합니다.

  2. value.[[Source]]serialized.[[Source]]로 설정합니다.

  3. value.[[StreamErrorCode]]serialized.[[StreamErrorCode]]로 설정합니다.

13. 프로토콜 매핑

이 섹션은 비규범적입니다.

이 섹션에서는 [WEB-TRANSPORT-OVERVIEW]를 활용하여, 이 명세에 정의된 메서드의 기저 프로토콜 동작을 설명합니다. 버퍼링으로 인해 인과관계가 즉각적이지 않을 수 있습니다.

WebTransport 프로토콜 동작 API 효과
세션 drained await wt.draining

기저 연결이 HTTP/3를 사용하는 경우, [WEB-TRANSPORT-HTTP3]의 다음 프로토콜 동작이 적용됩니다.

WebTransportError 오류에서 application streamErrorCode 값은 httpErrorCode로 변환되며, 반대도 마찬가지입니다. 자세한 내용은 [WEB-TRANSPORT-HTTP3] Section 4.3을 참고하세요.

API 메서드 QUIC 프로토콜 동작
writable.abort(error) STREAM 송신 중단(aborts sending) - httpErrorCode와 [[CommittedOffset]] 오프셋, 그리고 스트림 헤더 포함; stream 기준. [RELIABLE-RESET] 참고
writable.close() STREAM 송신(streams) - FIN 비트 설정됨
writable.getWriter().write(chunk)() STREAM 송신(streams)
writable.getWriter().close() STREAM 송신(streams) - FIN 비트 설정됨
writable.getWriter().abort(error) STREAM 송신 중단(aborts sending) - httpErrorCode와 [[CommittedOffset]] 오프셋, 그리고 스트림 헤더 포함; stream 기준. [RELIABLE-RESET] 참고
readable.cancel(error) STREAM 수신 중단(aborts receiving) - httpErrorCode
readable.getReader().cancel(error) STREAM 수신 중단(aborts receiving) - httpErrorCode
wt.close(closeInfo) 세션 종료(terminate) - closeInfo
QUIC 프로토콜 동작 API 효과
received STOP_SENDING with httpErrorCode errors writable with streamErrorCode
STREAM 수신(received) (await readable.getReader().read()).value
STREAM 수신(received) - FIN 비트 설정됨 (await readable.getReader().read()).done
received RESET_STREAM with httpErrorCode errors readable with streamErrorCode
세션 정상 종료(terminated) - closeInfo
(await wt.closed).closeInfo, 그리고 errors 열린 스트림들
네트워크 오류
(await wt.closed) reject됨, 그리고 errors 열린 스트림들

참고: [QUIC] RFC9000 3.2장에서 논의된 바와 같이, RESET_STREAM 프레임이나 RESET_STREAM_AT 프레임([RELIABLE-RESET])의 수신은 항상 애플리케이션에 바로 표시되는 것은 아닙니다. 리셋 수신 신호는 즉시 전달될 수 있으며, 스트림 데이터 전달이 중단되고 소비되지 않은 데이터는 폐기될 수 있습니다. 하지만 즉시 신호 전달이 반드시 필요한 것은 아닙니다. 특히 RESET_STREAM_AT 프레임의 Reliable Size 필드에 표시된 데이터 전달을 허용하기 위해 신호가 지연될 수 있습니다. 스트림 데이터가 완전히 수신되었지만 애플리케이션에서 아직 읽지 않은 경우에는 송신 중단 신호가 생략될 수 있습니다. WebTransport는 항상 스트림 헤더의 신뢰성 전달을 보장하기 위해 RESET_STREAM_AT 프레임을 사용합니다; 자세한 내용은 HTTP/3 4.1장HTTP/3 4.2장 그리고 [WEB-TRANSPORT-HTTP3] 참고.

HTTP/3 프로토콜 동작 API 효과
세션 drained await wt.draining

만약 기본 연결이 HTTP/2를 사용한다면 [WEB-TRANSPORT-HTTP2]의 다음 프로토콜 동작이 적용됩니다. HTTP/3과 달리, 스트림 에러 코드를 HTTP 에러 코드로 변환할 필요는 없습니다.

API 메서드 HTTP/2 프로토콜 동작
writable.abort(error) WT_STREAM 송신 중단(aborts sending) - error
writable.close() WT_STREAM 송신(streams) - FIN 비트 설정됨
writable.getWriter().write() WT_STREAM 송신(streams)
writable.getWriter().close() WT_STREAM 송신(streams) - FIN 비트 설정됨
writable.getWriter().abort(error) WT_STREAM 송신 중단(aborts sending) - error
readable.cancel(error) WT_STREAM 수신 중단(aborts receiving) - error
readable.getReader().cancel(error) WT_STREAM 수신 중단(aborts receiving) - error
wt.close(closeInfo) 세션 종료(terminate) - closeInfo
HTTP/2 프로토콜 동작 API 효과
received WT_STOP_SENDING - error errors writable with streamErrorCode
WT_STREAM 수신(received) (await readable.getReader().read()).value
WT_STREAM 수신(received) - FIN 비트 설정됨 (await readable.getReader().read()).done
received WT_RESET_STREAM - error errors readable with streamErrorCode
세션 정상 종료(terminated) - closeInfo
(await wt.closed).closeInfo, 그리고 errors 열린 스트림들
네트워크 오류
(await wt.closed) reject됨, 그리고 errors 열린 스트림들
세션 drained await wt.draining

14. 프라이버시 및 보안 고려사항

이 섹션은 비규범적입니다. 새로운 동작을 지정하지 않으며, 명세의 다른 부분에 이미 존재하는 정보를 요약합니다.

14.1. 통신의 기밀성

네트워크를 관찰할 수 있는 공격자는 통신이 이루어지고 있다는 사실을 숨길 수 없습니다. 이는 공개 정보로 간주되어야 합니다.

이 문서에서 설명하는 모든 전송 프로토콜은 TLS [RFC8446] 또는 의미적으로 동등한 프로토콜을 사용하므로, TLS의 모든 보안 속성(트래픽의 기밀성 및 무결성 포함)을 제공합니다. HTTP를 통한 WebTransport는 아웃바운드 HTTP 요청과 동일한 인증서 검증 메커니즘을 사용하므로, 원격 서버 인증을 위한 동일한 공개키 인프라에 의존합니다. WebTransport에서는 인증서 검증 오류가 치명적이며, 인증서 검증을 우회할 수 있는 중간 경유(interstitial)는 제공되지 않습니다.

14.2. 상태 지속성

WebTransport는 고유 식별자나 새로운 상태 지속 방법을 자체적으로 생성하지 않으며, 기존의 지속 상태를 서버에 자동으로 노출하지도 않습니다. 예를 들어, [WEB-TRANSPORT-HTTP3][WEB-TRANSPORT-HTTP2]는 쿠키를 전송하거나 HTTP 인증 또는 캐싱 무효화 메커니즘을 지원하지 않습니다. TLS를 사용하기 때문에 TLS 세션 티켓 등 TLS의 지속 상태는 상속받으며, 이는 수동적 네트워크 관찰자에게는 보이지 않지만 서버가 동일 클라이언트의 여러 연결을 연관시키는 데 사용할 수 있습니다.

14.3. 프로토콜 보안

WebTransport는 [WEB-TRANSPORT-OVERVIEW]에서 설명된 요구사항을 부과합니다. 예:

  1. 원격 서버가 WebTransport 프로토콜이 사용 중임을 인지하도록 하고, 원격 서버가 WebTransport 프로토콜 사용에 동의함을 확인한다. [WEB-TRANSPORT-HTTP3]는 ALPN [RFC7301], HTTP/3 설정, 그리고 WebTransport 프로토콜을 식별하기 위한 :protocol pseudo-header의 조합을 사용한다. [WEB-TRANSPORT-HTTP2]는 ALPN, HTTP/2 설정, 그리고 WebTransport 프로토콜을 식별하기 위한 :protocol pseudo-header의 조합을 사용한다.

  2. 전송 세션을 시작한 리소스의 오리진에 기반하여 서버가 연결을 필터링할 수 있도록 허용한다. 세션 설정 요청의 Origin 헤더 필드가 이 정보를 담는다.

프로토콜 보안 관련 고려사항은 보안 고려사항(Security Considerations) 섹션에서 설명되어 있습니다. [WEB-TRANSPORT-OVERVIEW] 섹션 6, [WEB-TRANSPORT-HTTP3] 섹션 8, 그리고 [WEB-TRANSPORT-HTTP2] 섹션 9에서 확인할 수 있습니다.

네트워킹 API는 일반적으로 로컬 네트워크의 사용 가능한 호스트를 스캔하는 데 사용될 수 있으므로, 지문 채취(fingerprinting) 및 기타 공격에 활용될 수 있습니다. WebTransport는 WebSocket 방식을 따릅니다: 특정 연결 오류는 WebTransport 엔드포인트임이 확인될 때까지 반환되지 않습니다. 따라서 웹 애플리케이션은 존재하지 않는 엔드포인트와 Web에서 연결을 받아들이지 않는 엔드포인트를 구분할 수 없습니다.

14.4. 인증서 해시를 통한 인증

일반적으로, 유저 에이전트는 TLS 서버 인증서의 유효성을 URL의 서버 이름에 대해 검증함으로써 TLS 연결을 인증합니다 [RFC9525]. 이는 유저 에이전트가 유지하는 신뢰 앵커로 서버 인증서를 체인 연결하는 방식입니다; 신뢰 앵커는 인증서의 서버 이름을 인증합니다. 이 시스템을 Web PKI라 부릅니다.

이 API는 웹 애플리케이션이 서버 이름 대신 특정 서버 인증서로 인증된 원격 네트워크 엔드포인트에 연결할 수 있게 합니다. 이 메커니즘은 장기 인증서 취득이 어려운 엔드포인트(예: 단명 VM, 공개 라우팅이 안 되는 호스트)와의 연결을 가능하게 합니다. 이 메커니즘이 개별 연결에 대해 Web PKI 기반 인증을 대체하므로, 두 보안 특성을 비교해야 합니다.

원격 서버가 TLS 핸드셰이크에 성공하려면 인증서의 공개키에 해당하는 개인키를 반드시 소유해야 합니다. API는 인증서를 해시값으로 식별합니다. 해시 함수가 두 번째 프리이미지 저항성을 갖는 한만 안전합니다. 이 문서에서 정의된 함수는 SHA-256뿐이며, API는 여러 알고리즘-해시 쌍 지정으로 새로운 해시 함수를 도입할 수 있습니다.

Web PKI는 서버 이름에 대한 신뢰 체인을 구축하는 것 외에도 추가 보안 메커니즘을 제공합니다. 예를 들어, 인증서 폐기 처리가 있습니다. 인증서가 단명인 경우에는 불필요하지만, 그 외에는 인증서 해시가 제공되는 방식(예: HTTP 캐시 자원)이 중요합니다. 인증서가 손상으로 교체되었다면 캐시를 무효화해야 합니다. Web PKI는 취약한 키 생성 등 문제를 방지하기 위한 추가 기능도 제공합니다. 이 명세는 구체적 지침을 제공하지 않지만, 브라우저는 구현 정의에 따라 취약한 키 인증서를 거부할 수 있습니다.

Web PKI는 인증서의 만료 기간을 강제합니다. 이는 키 손상 범위를 제한하고, 서버 운영자가 키 교체를 지원/실행하도록 유도합니다. 이러한 이유로 WebTransport도 유사한 만료 기간을 부과합니다; 인증서는 단명 또는 단기 사용이 예상되므로, 만료 기간은 2주로 제한됩니다. 2주 제한은 키 손상 결과를 최소화하기 위해 가능한 한 낮게 설정하면서, 기기 간 시계 오차와 클라이언트-서버 간 인증서 동기화 비용을 낮추기 위한 균형입니다.

WebTransport API는 애플리케이션이 여러 인증서 해시를 한 번에 지정할 수 있게 하여, 새 인증서가 롤아웃되는 기간 동안 클라이언트가 여러 인증서를 허용할 수 있게 합니다.

WebRTC의 유사 메커니즘과 달리, WebTransport의 서버 인증서 해시 API는 클라이언트 인증 수단을 제공하지 않습니다; 클라이언트가 서버 인증서를 알고 있거나 접속 방법을 아는 것만으로는 충분하지 않습니다. 필요하다면 애플리케이션이 인증을 인밴드로 직접 처리해야 합니다.

14.5. 지문 채취 및 추적

이 API는 사이트가 네트워크 활동을 생성하고, 그 효과를 세밀하게 관찰할 수 있게 합니다. 이런 방식으로 얻은 정보는 식별 정보가 될 수 있습니다.

매우 유사한 네트워킹 기능이 다른 웹 플랫폼 API(예: fetch, [webrtc])에도 있으므로, WebTransport 추가로 인한 프라이버시 악영향은 최소입니다. 이 섹션의 고려사항은 다른 네트워킹 기능에도 똑같이 적용됩니다.

네트워크 특성 측정은 네트워크를 실제로 사용하고, 그 사용의 효과를 측정해야 하며, 이 둘 모두 이 API로 가능합니다. WebTransport는 사이트가 원하는 서버로 네트워크 활동을 생성하고 효과를 관찰할 수 있게 합니다. 네트워크 경로의 안정적 속성과 동적 사용 효과 모두 관찰이 가능합니다.

네트워크 정보는 서버에 직접 네트워킹 스택을 통해, 혹은 클라이언트의 데이터 소비/전송 속도, 또는 API에서 제공하는 통계 (§ 6.13 WebTransportConnectionStats Dictionary)로 제공됩니다. 따라서 사용자 에이전트의 정보 제한만으로 프라이버시 위험을 관리할 수 없습니다.

14.5.1. 정적 관찰

사이트는 사용자 에이전트와 선택한 서버 간의 네트워크 용량 또는 왕복 시간(RTT)을 관찰할 수 있습니다. 이 정보는 다른 추적 벡터와 결합되면 식별 정보가 될 수 있습니다. RTT는 여러 측정이 여러 관찰 지점에서 이루어질 경우, 사용자 에이전트의 물리적 위치도 일부 드러낼 수 있습니다.

네트워킹은 공유되지만, 네트워크 사용은 종종 산발적이기 때문에, 사이트는 종종 경쟁이 없거나 거의 없는 네트워크 경로의 용량과 RTT를 관찰할 수 있습니다. 이러한 특성은 네트워크 위치와 병목 위치가 고정된 사용자에게는 안정적입니다.

14.5.2. 공유 네트워킹

경쟁이 있는 링크는 사이트에 사이트 간 인식을 활성화할 기회를 제공합니다. 이는 무단 추적에 활용될 수 있습니다 [UNSANCTIONED-TRACKING]. 네트워크 용량은 한정된 공유 자원이므로, 사용자 에이전트가 여러 사이트에 동시에 접근하면 각 사이트에 제시되는 신원 간의 연결이 드러날 수 있습니다.

한 사이트의 네트워킹 기능 사용은 다른 사이트에서 사용할 수 있는 용량을 감소시키며, 이는 네트워킹 API를 통해 관찰될 수 있습니다. 네트워크 사용과 지표는 동적으로 변할 수 있으므로, 모든 변화가 실시간으로 관찰 가능합니다. 이를 통해 사이트는 서로 다른 사이트의 활동이 동일 사용자에서 비롯된 것임을 더욱 확신할 수 있습니다.

사용자 에이전트는 비활성 또는 포커스가 없는 사이트에 대해 통계 (§ 6.13 WebTransportConnectionStats Dictionary)와 같은 피드백 메커니즘 접근을 제한하거나 저하시킬 수 있습니다 (HTML § 6.6 포커스). 단, 서버가 네트워크 변화 관찰을 막을 수는 없습니다.

14.5.3. 풀링된 세션

공유 네트워킹 시나리오와 유사하게, 여러 세션이 하나의 연결에 풀링될 때, 한 세션의 정보가 다른 세션의 활동에 의해 영향을 받습니다. 한 세션은 다른 세션의 데이터 전송 속도 등 활동 정보를 추론할 수 있습니다.

공유 연결 사용만으로도 서버가 세션을 연관지을 수 있습니다. 네트워크 파티션 키를 사용하면, 공유 세션으로 인해 원치 않는 사이트 간 인식이 활성화되는 것을 방지할 수 있습니다.

15. 예시

15.1. 데이터그램 버퍼 전송

이 섹션은 비규범적입니다.

데이터그램 버퍼 전송은 datagramscreateWritable 메서드와, 결과 스트림의 writer를 사용하여 달성할 수 있습니다. 아래 예시에서는 트랜스포트가 전송 준비가 되었을 때만 데이터그램을 전송합니다.

async function sendDatagrams(url, datagrams) {
  const wt = new WebTransport(url);
  const writable = wt.datagrams.createWritable();
  const writer = writable.getWriter();
  for (const bytes of datagrams) {
    await writer.ready;
    writer.write(bytes).catch(() => {});
  }
  await writer.close();
}

15.2. 고정 간격으로 데이터그램 전송

이 섹션은 비규범적입니다.

트랜스포트가 전송 준비가 되었는지 여부와 상관없이 고정 간격으로 데이터그램을 전송하려면, datagramscreateWritable 메서드와 결과 스트림의 writer를 사용하되, ready 속성을 await하지 않으면 됩니다.

// 100ms마다 데이터그램 전송
async function sendFixedRate(url, createDatagram, ms = 100) {
  const wt = new WebTransport(url);
  const writable = wt.datagrams.createWritable();
  const writer = writable.getWriter();
  const bytes = createDatagram();
  setInterval(() => writer.write(bytes).catch(() => {}), ms);
}

15.3. 데이터그램 수신

이 섹션은 비규범적입니다.

데이터그램은 transport.datagrams.readable 속성을 읽어서 받을 수 있습니다. null 값은 패킷 처리가 충분히 빠르지 않음을 나타낼 수 있습니다.

async function receiveDatagrams(url) {
  const wt = new WebTransport(url);
  for await (const datagram of wt.datagrams.readable) {
    // 데이터그램 처리
  }
}

15.4. BYOB 리더로 데이터그램 수신

이 섹션은 비규범적입니다.

datagrams읽을 수 있는 바이트 스트림이므로, BYOB(Bring Your Own Buffer 리더)를 사용할 수 있습니다. BYOB 리더를 사용하면 버퍼 할당을 더욱 정밀하게 제어할 수 있어 복사를 방지할 수 있습니다. 이 예제에서는 64 kibibytes 메모리 버퍼에 데이터그램을 읽어옵니다.

const wt = new WebTransport(url);

for await (const datagram of wt.datagrams.readable) {
  const reader = datagram.getReader({ mode: "byob" });

  let array_buffer = new ArrayBuffer(65536);
  const buffer = await readInto(array_buffer);
}

async function readInto(buffer) {
  let offset = 0;

  while (offset < buffer.byteLength) {
    const {value: view, done} = await reader.read(
        new Uint8Array(buffer, offset, buffer.byteLength - offset));
    buffer = view.buffer;
    if (done) {
      break;
    }
    offset += view.byteLength;
  }

  return buffer;
}

15.5. 스트림 전송

이 섹션은 비규범적입니다.

데이터를 단방향 스트림으로 전송하려면, createUnidirectionalStream 함수와 결과 스트림의 writer를 사용합니다.

작성된 청크 경계는 수신 시 유지되지 않을 수 있으며, 바이트가 전송 중에 합쳐질 수 있습니다. 따라서 응용에서는 자체 프레이밍을 제공하는 것이 좋습니다.

async function sendData(url, ...data) {
  const wt = new WebTransport(url);
  const writable = await wt.createUnidirectionalStream();
  const writer = writable.getWriter();
  for (const bytes of data) {
    await writer.ready;
    writer.write(bytes).catch(() => {});
  }
  await writer.close();
}

Streams 명세는 write()의 promise를 await하지 않는 것 을 권장하지 않습니다.

인코딩은 ReadableStream에서 파이프를 통해서도 할 수 있습니다. 예를 들어 TextEncoderStream 을 사용할 수 있습니다.

async function sendText(url, readableStreamOfTextData) {
  const wt = new WebTransport(url);
  const writable = await wt.createUnidirectionalStream();
  await readableStreamOfTextData
    .pipeThrough(new TextEncoderStream("utf-8"))
    .pipeTo(writable);
}

15.6. 수신 스트림 받기

이 섹션은 비규범적입니다.

수신 스트림 읽기는 incomingUnidirectionalStreams 속성을 반복하고, 각 WebTransportReceiveStream 을 반복하여 청크를 소비하면 됩니다.

청크는 송신자가 아닌, 사용자 에이전트에 의해 결정됩니다.

async function receiveData(url, processTheData) {
  const wt = new WebTransport(url);
  for await (const readable of wt.incomingUnidirectionalStreams) {
    // 각각의 스트림을 IIFE로 소비, 스트림별 에러 보고
    ((async () => {
      try {
        for await (const bytes of readable) {
          processTheData(bytes);
        }
      } catch (e) {
        console.error(e);
      }
    })());
  }
}

디코딩은 새 WritableStream으로 파이프를 통해서도 할 수 있습니다. 예를 들어 TextDecoderStream 을 사용할 수 있습니다. 이 예시는 텍스트 출력이 interleave되지 않아야 한다고 가정하여, 한 번에 하나의 스트림만 읽습니다.

async function receiveText(url, createWritableStreamForTextData) {
  const wt = new WebTransport(url);
  for await (const readable of wt.incomingUnidirectionalStreams) {
    // 출력이 interleave되지 않도록 순차적으로 소비, 스트림별 에러 보고
    try {
      await readable
       .pipeThrough(new TextDecoderStream("utf-8"))
       .pipeTo(createWritableStreamForTextData());
    } catch (e) {
      console.error(e);
    }
  }
}

15.7. BYOB 리더로 스트림 수신

이 섹션은 비규범적입니다.

WebTransportReceiveStream읽기 가능한 바이트 스트림(readable byte streams)이므로, BYOB 리더(reader)를 사용할 수 있습니다. BYOB 리더를 사용하면 버퍼 할당을 더 정밀하게 제어할 수 있어 복사 과정을 피할 수 있습니다. 아래 예제는 WebTransportReceiveStream에서 처음 1024 바이트를 하나의 메모리 버퍼로 읽습니다.

const wt = new WebTransport(url);

const reader = wt.incomingUnidirectionalStreams.getReader();
const { value: recv_stream, done } = await reader.read();
const byob_reader = recv_stream.getReader({ mode: "byob" });

let array_buffer = new ArrayBuffer(1024);
const buffer = await readInto(array_buffer);

async function readInto(buffer) {
  let offset = 0;

  while (offset < buffer.byteLength) {
    const {value: view, done} = await reader.read(
        new Uint8Array(buffer, offset, buffer.byteLength - offset));
    buffer = view.buffer;
    if (done) {
      break;
    }
    offset += view.byteLength;
  }

  return buffer;
}

15.8. 트랜잭션성 청크 스트림 전송

이 섹션은 비규범적입니다.

단방향 스트림에서 트랜잭션 데이터 조각을, 흐름 제어로 블록되지 않고 전체 전송이 가능할 때만 보내려면, getWriter 함수와 결과 writer를 사용하면 됩니다.

async function sendTransactionalData(wt, bytes) {
  const writable = await wt.createUnidirectionalStream();
  const writer = writable.getWriter();
  await writer.ready;
  try {
    await writer.atomicWrite(bytes);
  } catch (e) {
    if (e.name != "AbortError") throw e;
    // 흐름 제어 블록 방지로 거절됨
    // 비원자적 쓰기가 pending이 아니라면 writable은 에러 상태가 되지 않음
  } finally {
    writer.releaseLock();
  }
}

15.9. 서버 인증서 해시 사용

이 섹션은 비규범적입니다.

WebTransport 세션은 클라이언트의 기본 신뢰 평가 대신, 서버에 제공된 인증서의 해시값을 검사하여 신뢰성을 평가하도록 할 수 있습니다. 아래 예시에서 hashValueBufferSource 타입으로, 서버 인증서의 SHA-256 해시를 담고 있으며, 기저 연결이 이를 유효로 간주해야 합니다.

const wt = new WebTransport(url, {
  serverCertificateHashes: [
    {
      algorithm: "sha-256",
      value: hashValue,
    }
  ]
});
await wt.ready;

15.10. 전체 예시

이 섹션은 비규범적입니다.

이 예시는 closed, ready promise 활용, 클라이언트/서버의 단방향 및 양방향 스트림 열기, 데이터그램 송수신 등을 보여줍니다.

transport의 writable 속성은 datagrams 에 과거 존재했으나, 아래처럼 간단히 polyfill할 수 있습니다:
wt.datagrams.writable ||= wt.datagrams.createWritable();
// 페이지의 이벤트 로그에 항목을 추가하며, 선택적으로 지정된 CSS 클래스를 적용함.
// CSS 클래스.

let wt, streamNumber, datagramWriter;

connect.onclick = async () => {
  try {
    const url = document.getElementById('url').value;

    wt = new WebTransport(url);
    wt.datagrams.writable ||= wt.datagrams.createWritable();
    addToEventLog('연결 시작 중...');
    await wt.ready;
    addToEventLog(`${(wt.reliability == "reliable-only")? "TCP" : "UDP"} ` +
                  `연결 준비 완료.`);
    wt.closed
      .then(() => addToEventLog('연결 정상적으로 종료됨.'))
      .catch(() => addToEventLog('연결 비정상적으로 종료됨.', 'error'));

    streamNumber = 1;
    datagramWriter = wt.datagrams.writable.getWriter();

    readDatagrams();
    acceptUnidirectionalStreams();
    document.forms.sending.elements.send.disabled = false;
    document.getElementById('connect').disabled = true;
  } catch (e) {
    addToEventLog(`연결 실패. ${e}`, 'error');
  }
}

sendData.onclick = async () => {
  const form = document.forms.sending.elements;
  const data = sending.data.value;
  const bytes = new TextEncoder('utf-8').encode(data);
  try {
    switch (form.sendtype.value) {
      case 'datagram': {
        await datagramWriter.ready;
        datagramWriter.write(bytes).catch(() => {});
        addToEventLog(`데이터그램 전송: ${data}`);
        break;
      }
      case 'unidi': {
        const writable = await wt.createUnidirectionalStream();
        const writer = writable.getWriter();
        writer.write(bytes).catch(() => {});
        await writer.close();
        addToEventLog(`단방향 스트림으로 데이터 전송: ${data}`);
        break;
      }
      case 'bidi': {
        const duplexStream = await wt.createBidirectionalStream();
        const n = streamNumber++;
        readFromIncomingStream(duplexStream.readable, n);

        const writer = duplexStream.writable.getWriter();
        writer.write(bytes).catch(() => {});
        await writer.close();
        addToEventLog(`양방향 스트림 #${n}에 데이터 전송: ${data}`);
        break;
      }
    }
  } catch (e) {
    addToEventLog(`데이터 전송 중 오류: ${e}`, 'error');
  }
}

// 데이터그램을 EOF까지 이벤트 로그로 읽음
async function readDatagrams() {
  try {
    const decoder = new TextDecoderStream('utf-8');

    for await (const data of wt.datagrams.readable.pipeThrough(decoder)) {
      addToEventLog(`데이터그램 수신: ${data}`);
    }
    addToEventLog('데이터그램 읽기 완료!');
  } catch (e) {
    addToEventLog(`데이터그램 읽기 중 오류: ${e}`, 'error');
  }
}

async function acceptUnidirectionalStreams() {
  try {
    for await (const readable of wt.incomingUnidirectionalStreams) {
      const number = streamNumber++;
      addToEventLog(`새 단방향 스트림 #${number}`);
      readFromIncomingStream(readable, number);
    }
    addToEventLog('단방향 스트림 수락 완료!');
  } catch (e) {
    addToEventLog(`스트림 수락 중 오류 ${e}`, 'error');
  }
}

async function readFromIncomingStream(readable, number) {
  try {
    const decoder = new TextDecoderStream('utf-8');
    for await (const data of readable.pipeThrough(decoder)) {
      addToEventLog(`스트림 #${number}에서 데이터 수신: ${data}`);
    }
    addToEventLog(`스트림 #${number} 종료됨`);
  } catch (e) {
    addToEventLog(`스트림 #${number}에서 읽기 중 오류: ${e}`, 'error');
    addToEventLog(`    ${e.message}`);
  }
}

function addToEventLog(text, severity = 'info') {
  const log = document.getElementById('event-log');
  const previous = log.lastElementChild;
  const entry = document.createElement('li');
  entry.innerText = text;
  entry.className = `log-${severity}`;
  log.appendChild(entry);

  // 이전 로그 항목이 보이면, 새 요소로 스크롤
  if (previous &&
      previous.getBoundingClientRect().top < log.getBoundingClientRect().bottom) {
    entry.scrollIntoView();
  }
}

16. 감사의 글

편집자들은 워킹 그룹 의장들과 팀 연락 담당자인 Jan-Ivar Bruaroey, Will Law, Yves Lafon에게 그들의 지원에 감사의 뜻을 전합니다.

WebTransport 인터페이스는 QuicTransport 인터페이스를 기반으로 하며, 이는 W3C ORTC CG에서 처음 기술되었습니다. 이 명세서에 맞게 적용되었습니다.

색인

이 명세서에서 정의된 용어

참조로 정의된 용어

참고문헌

규범적 참고문헌

[CSP3]
Mike West; Antonio Sartori. 콘텐츠 보안 정책 레벨 3. 2025년 11월 6일. WD. URL: https://www.w3.org/TR/CSP3/
[DOM]
Anne van Kesteren. DOM 표준. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT-6.0]
Allen Wirfs-Brock. ECMA-262 6판, ECMAScript 2015 언어 명세. 2015년 6월. 표준. URL: http://www.ecma-international.org/ecma-262/6.0/index.html
[ENCODING]
Anne van Kesteren. 인코딩 표준. Living Standard. URL: https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch 표준. Living Standard. URL: https://fetch.spec.whatwg.org/
[HR-TIME-3]
Yoav Weiss. 고해상도 시간. 2024년 11월 7일. WD. URL: https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren; et al. HTML 표준. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 표준. Living Standard. URL: https://infra.spec.whatwg.org/
[QUIC]
Jana Iyengar; Martin Thomson. QUIC: UDP 기반 다중화 및 안전한 전송. 제안된 표준. URL: https://www.rfc-editor.org/rfc/rfc9000
[QUIC-DATAGRAM]
Tommy Pauly; Eric Kinnear; David Schinazi. QUIC을 위한 신뢰하지 않는 데이터그램 확장. 제안된 표준. URL: https://www.rfc-editor.org/rfc/rfc9221
[RFC2119]
S. Bradner. 요구 사항 수준을 표시하기 위한 RFC 키워드. 1997년 3월. 현재 최선의 규범. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC3279]
L. Bassham; W. Polk; R. Housley. 인터넷 X.509 공개 키 인프라 인증서 및 인증서 폐기 목록(CRL) 프로필을 위한 알고리즘 및 식별자. 2002년 4월. 제안된 표준. URL: https://www.rfc-editor.org/rfc/rfc3279
[RFC5280]
D. Cooper; et al. 인터넷 X.509 공개 키 인프라 인증서 및 인증서 폐기 목록(CRL) 프로필. 2008년 5월. 제안된 표준. URL: https://www.rfc-editor.org/rfc/rfc5280
[RFC8174]
B. Leiba. RFC 2119 키워드에서 대문자와 소문자의 모호성. 2017년 5월. 현재 최선의 규범. URL: https://www.rfc-editor.org/rfc/rfc8174
[RFC8422]
Y. Nir; S. Josefsson; M. Pegourie-Gonnard. 전송 계층 보안(TLS) 버전 1.2 및 이전 버전을 위한 타원 곡선 암호(ECC) 암호 제품군. 2018년 8월. 제안된 표준. URL: https://www.rfc-editor.org/rfc/rfc8422
[RFC8441]
P. McManus. HTTP/2로 WebSockets 부트스트래핑. 2018년 9월. 제안된 표준. URL: https://httpwg.org/specs/rfc8441.html
[RFC9002]
J. Iyengar, Ed.; I. Swett, Ed.. QUIC 손실 감지 및 혼잡 제어. 2021년 5월. 제안된 표준. URL: https://www.rfc-editor.org/rfc/rfc9002
[RFC9220]
R. Hamilton. HTTP/3로 WebSockets 부트스트래핑. 2022년 6월. 제안된 표준. URL: https://httpwg.org/specs/rfc9220.html
[RFC9525]
P. Saint-Andre; R. Salz. TLS의 서비스 아이덴티티. 2023년 11월. 제안된 표준. URL: https://www.rfc-editor.org/rfc/rfc9525
[STREAMS]
Adam Rice; et al. Streams 표준. Living Standard. URL: https://streams.spec.whatwg.org/
[URL]
Anne van Kesteren. URL 표준. Living Standard. URL: https://url.spec.whatwg.org/
[WEB-TRANSPORT-HTTP2]
Alan Frindell; et al. HTTP/2 상의 WebTransport. 인터넷-드래프트. URL: https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-http2
[WEB-TRANSPORT-HTTP3]
Alan Frindell; Eric Kinnear; Victor Vasiliev. HTTP/3 상의 WebTransport. 인터넷-드래프트. URL: https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-http3
[WEB-TRANSPORT-OVERVIEW]
Victor Vasiliev. WebTransport 프로토콜 프레임워크. 인터넷-드래프트. URL: https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-overview
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 표준. Living Standard. URL: https://webidl.spec.whatwg.org/

참고용 참고문헌

[RELIABLE-RESET]
Marten Seemann; 奥一穂. 부분 전송이 포함된 QUIC 스트림 리셋(QUIC Stream Resets with Partial Delivery). 인터넷-드래프트. URL: https://datatracker.ietf.org/doc/html/draft-ietf-quic-reliable-stream-reset
[RFC7301]
S. Friedl; et al. TLS 애플리케이션-계층 프로토콜 협상 확장(Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension). 2014년 7월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc7301
[RFC8446]
E. Rescorla. TLS 프로토콜 버전 1.3(The Transport Layer Security (TLS) Protocol Version 1.3). 2018년 8월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc8446
[RFC9308]
M. Kühlewind; B. Trammell. QUIC 전송 프로토콜의 적용(Applicability of the QUIC Transport Protocol). 2022년 9월. 정보성 문서. URL: https://www.rfc-editor.org/rfc/rfc9308
[UNSANCTIONED-TRACKING]
Mark Nottingham. 무단 웹 추적(Unsanctioned Web Tracking). 2015년 7월 17일. TAG Finding. URL: https://www.w3.org/2001/tag/doc/unsanctioned-tracking/
[WEBRTC]
Cullen Jennings; et al. 브라우저 실시간 통신(WebRTC: Real-Time Communication in Browsers). 2025년 3월 13일. REC. URL: https://www.w3.org/TR/webrtc/

IDL 색인

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportDatagramsWritable : WritableStream {
  attribute WebTransportSendGroup? sendGroup;
  attribute long long sendOrder;
};

[Exposed=(Window,Worker), SecureContext]
interface WebTransportDatagramDuplexStream {
  WebTransportDatagramsWritable createWritable(
      optional WebTransportSendOptions options = {});
  readonly attribute ReadableStream readable;

  readonly attribute unsigned long maxDatagramSize;
  attribute unrestricted double? incomingMaxAge;
  attribute unrestricted double? outgoingMaxAge;
  attribute unrestricted double incomingHighWaterMark;
  attribute unrestricted double outgoingHighWaterMark;
};

[Exposed=(Window,Worker), SecureContext]
interface WebTransport {
  constructor(USVString url, optional WebTransportOptions options = {});

  Promise<WebTransportConnectionStats> getStats();
  [NewObject] Promise<ArrayBuffer> exportKeyingMaterial(BufferSource label, optional BufferSource context);
  readonly attribute Promise<undefined> ready;
  readonly attribute WebTransportReliabilityMode reliability;
  readonly attribute WebTransportCongestionControl congestionControl;
  [EnforceRange] attribute unsigned short? anticipatedConcurrentIncomingUnidirectionalStreams;
  [EnforceRange] attribute unsigned short? anticipatedConcurrentIncomingBidirectionalStreams;
  readonly attribute DOMString protocol;

  readonly attribute Promise<WebTransportCloseInfo> closed;
  readonly attribute Promise<undefined> draining;
  undefined close(optional WebTransportCloseInfo closeInfo = {});

  readonly attribute WebTransportDatagramDuplexStream datagrams;

  Promise<WebTransportBidirectionalStream> createBidirectionalStream(
      optional WebTransportSendStreamOptions options = {});
  /* a ReadableStream of WebTransportBidirectionalStream objects */
  readonly attribute ReadableStream incomingBidirectionalStreams;

  Promise<WebTransportSendStream> createUnidirectionalStream(
      optional WebTransportSendStreamOptions options = {});
  /* a ReadableStream of WebTransportReceiveStream objects */
  readonly attribute ReadableStream incomingUnidirectionalStreams;
  WebTransportSendGroup createSendGroup();

  static readonly attribute boolean supportsReliableOnly;
};

enum WebTransportReliabilityMode {
  "pending",
  "reliable-only",
  "supports-unreliable",
};

dictionary WebTransportHash {
  required DOMString algorithm;
  required BufferSource value;
};

dictionary WebTransportOptions {
  boolean allowPooling = false;
  boolean requireUnreliable = false;
  sequence<WebTransportHash> serverCertificateHashes = [];
  WebTransportCongestionControl congestionControl = "default";
  [EnforceRange] unsigned short? anticipatedConcurrentIncomingUnidirectionalStreams = null;
  [EnforceRange] unsigned short? anticipatedConcurrentIncomingBidirectionalStreams = null;
  sequence<DOMString> protocols = [];
  ReadableStreamType datagramsReadableType;
};

enum WebTransportCongestionControl {
  "default",
  "throughput",
  "low-latency",
};

dictionary WebTransportCloseInfo {
  unsigned long closeCode = 0;
  USVString reason = "";
};

dictionary WebTransportSendOptions {
  WebTransportSendGroup? sendGroup = null;
  long long sendOrder = 0;
};

dictionary WebTransportSendStreamOptions : WebTransportSendOptions {
  boolean waitUntilAvailable = false;
};

dictionary WebTransportConnectionStats {
  unsigned long long bytesSent;
  unsigned long long bytesSentOverhead;
  unsigned long long bytesAcknowledged;
  unsigned long long packetsSent;
  unsigned long long bytesLost;
  unsigned long long packetsLost;
  unsigned long long bytesReceived;
  unsigned long long packetsReceived;
  DOMHighResTimeStamp smoothedRtt;
  DOMHighResTimeStamp rttVariation;
  DOMHighResTimeStamp minRtt;
  required WebTransportDatagramStats datagrams;
  unsigned long long? estimatedSendRate = null;
  boolean atSendCapacity = false;
};

dictionary WebTransportDatagramStats {
  unsigned long long droppedIncoming;
  unsigned long long expiredIncoming;
  unsigned long long expiredOutgoing;
  unsigned long long lostOutgoing;
};

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportSendStream : WritableStream {
  attribute WebTransportSendGroup? sendGroup;
  attribute long long sendOrder;
  Promise<WebTransportSendStreamStats> getStats();
  WebTransportWriter getWriter();
};

dictionary WebTransportSendStreamStats {
  unsigned long long bytesWritten;
  unsigned long long bytesSent;
  unsigned long long bytesAcknowledged;
};

[Exposed=(Window,Worker), SecureContext]
interface WebTransportSendGroup {
  Promise<WebTransportSendStreamStats> getStats();
};

[Exposed=(Window,Worker), SecureContext, Transferable]
interface WebTransportReceiveStream : ReadableStream {
  Promise<WebTransportReceiveStreamStats> getStats();
};

dictionary WebTransportReceiveStreamStats {
  unsigned long long bytesReceived;
  unsigned long long bytesRead;
};

[Exposed=(Window,Worker), SecureContext]
interface WebTransportBidirectionalStream {
  readonly attribute WebTransportReceiveStream readable;
  readonly attribute WebTransportSendStream writable;
};

[Exposed=*, SecureContext]
interface WebTransportWriter : WritableStreamDefaultWriter {
  Promise<undefined> atomicWrite(optional any chunk);
  undefined commit();
};

[Exposed=(Window,Worker), Serializable, SecureContext]
interface WebTransportError : DOMException {
  constructor(optional DOMString message = "", optional WebTransportErrorOptions options = {});

  readonly attribute WebTransportErrorSource source;
  readonly attribute unsigned long? streamErrorCode;
};

dictionary WebTransportErrorOptions {
  WebTransportErrorSource source = "stream";
  [Clamp] unsigned long? streamErrorCode = null;
};

enum WebTransportErrorSource {
  "stream",
  "session",
};

이슈 색인

이것은 워커에서도 처리되어야 합니다. 참고: #127whatwg/html#6731.

이 구성 옵션은 저지연 최적화 혼잡 제어 알고리즘이 브라우저에 구현되지 않았기 때문에 기능 위험(atrisk)으로 간주됩니다. 작성 시점 기준입니다.

bytesAcknowledged on WebTransportConnectionStats 는 구현 가능성 문제로 워킹 그룹에 의해 위험(feature at risk) 항목으로 지정되었습니다.