* Introduction

''This section is non-normative.''

[907] This document is an implementation of Web transport protocols.

* Fetch and connections

[908] The [[request]]'s [DFN[[F[current server url]]][request's current server url]]
is a [[URL record]].  Once a value is set, the [F[current server url][request's server url]]
is that value.  Otherwise, the [F[current server url][request's current server url]]
is same as its [F[current url][request's current url]].

;; This field can be used to implement a [[reverse proxy]].

[1303] In the [[basic fetch]], when [VAR[request]]'s [F[current url][request's current url]]'s
[F[scheme][URL scheme]] is [CODE[ftp][ftp:]],
return the result of performing an [[HTTP fetch]] using [VAR[request]].

[896] To modify [VAR[request]]'s [F[header list][request's header list]] per HTTP
in [[HTTP-network-or-cache fetch]], run these steps:
[FIG(steps)[
= [898] Append [CODE[Accept-Encoding]] header, if necessary.
==
@@ REQUIRED for Web compat [SEE[ [[docs.github.com]] ]]
= [897] Append [CODE[DNT]] header, if necessary.
= [899] Append [CODE[Upgrade-Insecure-Requests]] header, if necessary.
]FIG]

[1304] In the steps to [[obtain a connection]], to choose a connection
for [[origin]] [VAR[origin]] from the [[user agent]]'s [F[connection pool]], run these steps:
[FIG(steps)[
= [1305] If [VAR[origin]]'s [F[scheme][URL scheme]] is [CODE[ftp][ftp:]]:
== [1306] Return [[null]].
= [1307] Otherwise:
== [1308] Return a [[connection]] whose
[F[to be closed]] is [[false]],
[F[状態]] is 「初期」 or 「要求待ち」, and
[F[WebSocket接続の状態]] is [[null]] in the [[user agent]]'s [F[connection pool]],
if any, or [[null]].
]FIG]

[1325] In the steps to [[obtain a connection]], just before establishing an HTTP connection,
run these steps:
[FIG(steps)[
= [1326] Wait until implementation dependent constraints on the number of relevant
connections in the [[user agent]]'s [F[connection pool]] is small enough.
If the [[user agent]] detects an idle connection in its [F[connection pool]],
it may choose to abort that connection.
]FIG]

[822] In the steps to [[obtain a connection]], to establish an HTTP connection,
run these steps:
[FIG(steps)[
= [808] Let [VAR[transport]] be the result of
[[establishing a transport][establish a transport]].
[FIG(list members)[

: [VAR[request url]] : the request's [F[current url][request's current url]]
: [VAR[server url]] : the request's [F[current server url][request's current server url]]
: [VAR[credentials]] : [[true]]
: [VAR[[CODE[acceptSslCerts]]]] : the request's [F[[CODE[acceptSslCerts]]]] flag
: [VAR[user agent]] : the [[user agent]]
: [VAR[skip DNS cache]] : whether the request's [F[cache mode]]
is either one of [CODE[no-cache]], [CODE[reload]], and [CODE[no-store]], or not

]FIG]
= [823] If [VAR[transport]] is a [[failure]]:
== [824] Return a [[failure]].
= [1296] Otherwise, if [VAR[transport]]'s [F[http protocol][transport's http protocol]]
is [CODE[http2]]:
==
@@
= [932] Otherwise, if [VAR[transport]]'s [F[http protocol][transport's http protocol]]
is [CODE[ftp]]:
== [934] If the [[HTTP-network-or-cache fetch]] steps set credentials to the request:
=== [935] Set [VAR[username]] and [VAR[password]] to the appropriate values.
== [1285] Otherwise:
=== [1286] Set [VAR[username]] to [CODE[anonymous]].
=== [1287] Set [VAR[password]] to [CODE[User@]].
== [933] Let [VAR[connection]] be the result of 
[[initiating an FTP connection][initiate an FTP connection]]
with [VAR[transport]], [VAR[username]], and [VAR[password]].
== [1291] Wait until [VAR[connection]]'s [F[established promise][FTP connection's established promise]]
is resolved or rejected.
== [1292] If [VAR[connection]]'s [F[established promise][FTP connection's established promise]]
is resolved:
=== [1293] Return [VAR[ftp]].
== [1294] Otherwise:
=== [1295] Return a [[failure]].
= [825] Otherwise:
== [826] Return an [[HTTP connection]]:
[FIG(list members)[
[FIGCAPTION[
[[HTTP connection]]
]FIGCAPTION]
: [F[endpoint type][connection's endpoint type]] : [CODE[client]]
: [F[transport][connection's transport]] : [VAR[transport]]
]FIG]
]FIG]

[809] To [[obtain a WebSocket connection]] for [VAR[url]], run these steps:
[FIG(steps)[
= [821] Let [VAR[transport]] be the result of
[[establishing a transport][establish a transport]].
[FIG(list members)[

: [VAR[request url]] : [VAR[url]]
: [VAR[server url]] : [VAR[url]]
: [VAR[[CODE[acceptSslCerts]]]] : the request's [F[[CODE[acceptSslCerts]]]] flag
: [VAR[user agent]] : the [[user agent]]
: [VAR[ws]] : [[true]]
: [VAR[skip DNS cache]] :whether the request's [F[cache mode]]
is either one of [CODE[no-cache]], [CODE[reload]], and [CODE[no-store]], or not

]FIG]
= [827] If [VAR[transport]] is a [[failure]]:
== [828] Return a [[failure]].
= [829] Otherwise:
== [830] Return an [[HTTP connection]]:
[FIG(list members)[
[FIGCAPTION[
[[HTTP connection]]
]FIGCAPTION]
: [F[endpoint type][connection's endpoint type]] : [CODE[client]]
: [F[transport][connection's transport]] : [F[transport]]
]FIG]
]FIG]

[607] To [DFN[wait for other connections]] of [VAR[host]], [VAR[port]], and [VAR[ws]]
in [VAR[user agent]], run these steps:
[FIG(steps)[
= [1324] If [VAR[ws]] is [[false]], abort these steps.
= [831] If [VAR[host]] is a [[domain]]:
== [832] Let [VAR[n]] be an implementation dependent small number.
= [833] Otherwise:
== [834] Let [VAR[n]] be [N[1]].
= [835] Wait while the number of [[connections][connection]] with the following 
conditions is ''not'' less than [VAR[n]]:
[FIG(list)[
- It is in [VAR[user agent]]'s [F[connection pool]].
-
@@ Its [F[remote host][transport's remote host]] is [VAR[host]].
-
@@ Its [F[remote port][transport's remote port]] is [VAR[port]].
- Its [F[WebSocket接続の状態]] is [CODE[CONNECTING]].
]FIG]

]FIG]

[1336] To [[establish a WebSocket connection]], given a [VAR[url]], 
[VAR[protocols]], and [VAR[client]], run these steps:
[FIG(steps)[
= [1337] Let [VAR[requestURL]] be a copy of [VAR[url]], with its 
[F[scheme][URL scheme]] set to "[CODE[http][http:]]", if [VAR[url]]'s [F[scheme][URL scheme]]
is "[CODE[ws][ws:]]", and to "[CODE[https][https:]]" otherwise.
= [1338] Let [VAR[request]] be a [[request]]:
[FIG(list members middle)[
[FIGCAPTION[
[[Request][request]]
]FIGCAPTION]
: [F[url][request's url]] : [VAR[url]]
: [F[client][request's client]] : [VAR[client]]
: [F[skip-service-worker flag]] : [[true]]
: [F[synchronous flag]] : [[true]]
: [F[mode][request mode]] : [CODE[websocket]]
: [F[credentials mode]] : [CODE[include]]
: [F[cache mode]] : [CODE[no-store]]
: [F[redirect mode]] : [CODE[error]]
: [F[WebSocket subprotocols]] : [VAR[protocols]]
]FIG]
= [1339] [[Fetch][fetch]] [VAR[request]] with [VAR[[[process response]]]] >>1348
and [VAR[[[process response done]]]] >>1342.
]FIG]

[1348] The [[process response]] with [VAR[response]] is as follows:
[FIG(steps)[
= [1340] If [VAR[response]] is not a [[network error]] and
[VAR[response]]'s [F[WebSocket connection established]] is [[true]]:
== [1346] [[The WebSocket Connection is Established]] with:
[FIG(list members)[
: [VAR[[[Extensions In Use]]]] :
[VAR[response]]'s [F[header list][response's header list]]'s
`[CODE[Sec-WebSocket-Extensions]]` header's value, if any, or [CODE[null]]
: [VAR[[[Subprotocol In Use]]]] :
[VAR[response]]'s [F[header list][response's header list]]'s
`[CODE[Sec-WebSocket-Protocol]]` header's value, if any, or [CODE[null]]
]FIG]
]FIG]

[1342] The [[process response done]] with [VAR[response]] is as follows:
[FIG(steps)[
= [1345] Let [VAR[exit status]] be [VAR[response]]'s [F[exit status][response's exit status]].
= [1350] If [VAR[exit status]] is [CODE[null]]:
== [1351] Set [VAR[exit status]] to an [[exit status]] whose [F[失敗]] is [[false]].
= [1343] [[The WebSocket Connection Is Closed]] with:
[FIG(list members)[
: [VAR[[[Fail The WebSocket Connection]]]] : [VAR[exit status]]'s [F[失敗]]
: [VAR[cleanly]] : [VAR[exit status]]'s [F[WebSocket cleanly]] is [[true]]
: [VAR[[[The WebSocket Connection Close Code]]]] : [VAR[exit status]]'s [F[WebSocket状態符号]]
: [VAR[[[The WebSocket Connection Close Reason]]]] : [VAR[exit status]]'s [F[WebSocket理由文字列]]
]FIG]
]FIG]

[838] To make an HTTP request over [VAR[connection]] using [VAR[request]]
in [[HTTP-network fetch]], 
with [VAR[credentials]] flag and optional [VAR[not retryable]] flag,
run these steps:
[FIG(steps)[
= [1344] Configure [VAR[connection]] such that any notification is handled by >>839,
which uses [VAR[websocket data type]] and [VAR[websocket data]].
= [837] If [VAR[connection]]'s [F[transport][connection's transport]]'s
[F[http protocol][transport's http protocol]] is [CODE[http2]]:
== 
@@
= [930] If [VAR[connection]]'s [F[transport][connection's transport]]'s
[F[http protocol][transport's http protocol]] is [CODE[ftp]]:
== [1289] [[Send an FTP request][send an FTP request]] [VAR[request]] over [VAR[connection]].
= [931] Otherwise:
== [541] If [VAR[connection]]'s [F[transport][connection's transport]]'s
[F[request mode]] is ''HTTP proxy'':
=== [845] Let [VAR[target]] be [VAR[request]]'s [F[originpathquery]].
== [843] Otherwise:
=== [844] Let [VAR[target]] be [VAR[request]]'s [F[current url][request's current url]]'s [F[pathquery]].
== [901] Let [VAR[host header]] be [VAR[request]]'s [F[current url][request's current url]]'s [F[hostport]].
== [900] Append [CODE[Host]]/[VAR[host header]] to [VAR[request]]'s [F[header list][request's header list]].
== [905] Append [CODE[Connection]]/[CODE[keep-alive]] to [VAR[request]]'s
[F[header list][request's header list]].
== [840] Send an [[HTTP request]] over [VAR[connection]].
[FIG(list members)[
[FIGCAPTION[
[[HTTP request]]
]FIGCAPTION]
: [F[要求メソッド]] : [VAR[request]]'s [F[method][request method]]
: [F[要求対象]] : [VAR[target]]
: [F[ヘッダーリスト]] : [VAR[request]]'s [F[header list][request's header list]]
: [F[本体]] : [VAR[request]]'s [F[body][request body]]
: [F[mode][request mode]] : [VAR[request]]'s [F[mode][request mode]]
]FIG]
]FIG]

[839] Any notification [VAR[msg]] from [VAR[connection]] is processed as follows,
switched by [VAR[msg]]'s type:
[FIG(switch)[
: 要求の本体の一部の送信の通知 : Process [VAR[transmitted]] as follows:
[FIG(steps)[
= 
@@ Increase [VAR[request]]'s [F[body][request body]] stream's transmitted bytes
]FIG]
: 要求の送信完了の通知 :
[FIG(steps)[
= 
@@ Set [VAR[request]]'s [F[body][request body]] stream's done flag
]FIG]
: 応答のヘッダー受信完了の通知 : Process [VAR[http response]] and
[VAR[WebSocket connection established]] as follows:
[FIG(steps)[
= [856] If [VAR[connection]]'s [F[transport][connection's transport]]'s
[F[request mode]] is ''not'' ''HTTP proxy'' and
[VAR[http response]]'s [F[状態符号]] is [CODE[407]]:
== [857] Set [VAR[response]] to a [[network error]].
= [858] Otherwise:
== [841] Set [VAR[response]] to a [[response]]:
[FIG(list members)[
[FIGCAPTION[
[[Response][response]]
]FIGCAPTION]
: [F[status][status code]] : [VAR[http response]]'s [F[状態符号]]
: [F[status message]] : [VAR[http response]]'s [F[理由句]]
: [F[header list][response's header list]] : [VAR[http response]]'s [F[ヘッダーリスト]]
: [F[HTTPS state]] : [VAR[connection]]'s [F[transport][connection's transport]]'s
[F[HTTPS state][connection's HTTPS state]]
: [F[WebSocket connection established]] : [VAR[WebSocket connection established]]
]FIG]
== [892] If [VAR[connection]]'s [F[transport][connection's transport]]'s
[F[protocol][transport's protocol]] is 
[CODE[tls]] and [VAR[connection]]'s [F[transport][connection's transport]]'s
[F[has alert]] is [[false]]:
=== [893] Process the HSTS header of [VAR[response]], if any.
=== [894] Process the PKP headers of [VAR[response]], if any.
= [842] Now ''headers are transmitted''.  Return [VAR[response]].
]FIG]
: [CODE[datastart]] の通知 : Process [VAR[data type]] as follows:
[FIG(steps)[
= [537] If [VAR[request]]'s [F[mode][request mode]] is [CODE[websocket]]:
== [1360] Set [VAR[websocket data type]] to [VAR[data type]].
== [1349] If [VAR[data type]] is [[Text]]:
=== [538] Set [VAR[websocket data]] to the [[empty string]].
== [1352] Otherwise:
=== [1353] Set [VAR[websocket data]] to the [[empty byte string]].
]FIG]
: [CODE[data]] の通知 : Process [VAR[data]] as follows:
[FIG(steps)[
= [1354] If [VAR[request]]'s [F[mode][request mode]] is [CODE[websocket]]:
== [1356] Append [VAR[data]] to [VAR[websocket data]].
= [1355] Otherwise:
== 
@@ Write [VAR[data]] to [VAR[response]]'s [F[body][response body]] stream
]FIG]
: [CODE[dataend]] の通知 :
[FIG(steps)[
= [1357] If [VAR[request]]'s [F[mode][request mode]] is [CODE[websocket]]:
== [1359] [[A WebSocket Message Has Been Received]] with:
[FIG(list members)[
: [VAR[type]] : [VAR[websocket data type]]
: [VAR[data]] : [VAR[websocket data]]
]FIG]
= [1358] Otherwise:
== 
@@ Set [VAR[response]]'s [F[body][response body]] stream's done flag
]FIG]
: [CODE[wsclosing]] の通知 :
[[The WebSocket Closing Handshake Is Started]].
: 完了の通知 : Process [VAR[http response]] and [VAR[exit status]] as follows:
[FIG(steps)[
= [851] If [VAR[exit status]]'s [F[失敗]] is true:
== [852] If ''headers are transmitted'':
=== [855] Mutate [VAR[response]] into a [[network error]] whose
[F[exit status][response's exit status]] is [VAR[exit status]].
== [257] Otherwise, if [VAR[not retryable]] is [[false]],
[VAR[exit status]]'s [F[can retry][exit's can retry]] is [[true]], and
the [[user agent]] wants to retry the request:
=== [882] Let [VAR[connection]] be the result of 
[[obtaining a connection][obtain a connection]], given [VAR[request]]'s 
[F[current url][request's current url]]'s [F[origin]] and [VAR[credentials]].
=== [883] If [VAR[connection]] is a [[failure]], return a [[network error]]
and abort these steps.
=== [884] Return the result of recursively making an HTTP request
over [VAR[connection]] using [VAR[request]],
with [VAR[credentials]] flag, with [VAR[not retryable]] flag set.
== [854] Otherwise:
=== [853] Return a [[network error]] whose [F[exit status][response's exit status]]
is [VAR[exit status]].
]FIG]
]FIG]

[NOTE[
[247] The [[user agent]] might not want to retry the request because, e.g.,
there is a request body specified as a [CODE[ReadableStream]].
]NOTE]

@@ TLS client certificate dialog

@@
[357] [[HTTP]] [CODE(HTTP)[[[CONNECT]]]] プロキシからの応答の受信
- [CODE(HTTP)[[[407]]]] なら、...
- その他非 [CODE(HTTP)[[[200]]]] なら、[[ネットワークエラー]]

@@
[539] [[WebSocket]] server steps

[1375] A [[request]] has following additional field:
[FIG(list members)[
: [DFN[[F[[CODE[acceptSslCerts]]]]]] : A [[boolean]].  Initially, [[false]].
]FIG]

[1347] A [[response]] has following additional fields:
[FIG(list members)[
: [DFN[[F[exit status][response's exit status]]]] :
An [[exit status]] or [CODE[null]].  Initially, [CODE[null]].
: [DFN[[F[incomplete message][response's incomplete message]]]] flag :
A [[boolean]].  Initially, [[false]].
: [DFN[[F[WebSocket connection established]]]] flag :
A [[boolean]].  Initially, [[false]].
]FIG]

* Hosts and ports

[323] An [DFN[IP address]] is an [[IPv4 address]] or [[IPv6 address]].

[365] A [DFN[port]] is a 16-bit unsigned integer.

** Name resolution

[1278] A [[user agent]] has [DFN[[F[DNS cache]]]], which is a map from
a [[domain]] to a [[pair]] of ([F[address]] ([[IP address]] or [[failure]]),
[F[expires]] ([[number]])).

[1328] The [F[DNS cache]] has an associated [F[monotonic clock]],
which is an implementation dependent [[monotonic clock]].

[1281] The [DFN[[VAR[DNS cache timeout]]]] is [N[60]] seconds.

[369] The underlying [[platform]] is expected to provide the way to
[DFN[resolve a name]], which receives a string [VAR[host string]]
and a [[boolean]] [VAR[skip DNS cache]] and returns a [[IP address]] or [[failure]].
If the platform does not support a feature equivalent to
[VAR[skip DNS cache]], it [MAY[MUST]] be ignored.

;; [509] It asynchronously returns.

[615] The [[user agent]] [VAR[user agent]]'s [DFN[name resolution steps]]
for [[host]] [VAR[host]] and optional [[boolean]] [VAR[skip DNS cache]] (whose
default is [[false]]) are:

[FIG(steps)[
= [616] If [VAR[host]] is a [[domain]]:
== [1309] If [VAR[skip DNS cache]] is [[false]]:
=== [1283] Let [VAR[cached]] be [VAR[user agent]]'s [F[DNS cache]] [ [VAR[host]] ].
== [1310] Otherwise:
=== [1311] Let [VAR[cached]] be [CODE[null]].
== [1280] Let [VAR[now]] be the current value of [VAR[user agent]]'s [F[DNS cache]]'s [F[monotonic clock]].
== [1284] If [VAR[cached]] is [CODE[null]] or [VAR[cached]]'s [F[expires]] is a time after
[VAR[now]]:
=== [402] Let [VAR[host string]] be the result of [[serializing][host serializer]] [VAR[host]].
=== [617] Let [VAR[addr]] be the result of [[resolving][resolve a name]]
[VAR[host string]] with [VAR[skip DNS cache]].
=== [1377] If [VAR[addr]] is an [[IPv4 address]] in the range [CODE[[[0.0.0.0]]/8]]:
==== [1380] Set [VAR[addr]] to a [[failure]].
=== [1279] Set [VAR[user agent]]'s [F[DNS cache]] [ [VAR[host]] ]
to ([VAR[addr]], [VAR[DNS cache timeout]] after [VAR[now]]).
=== [1282] Return [VAR[addr]].
== [1312] Otherwise:
=== [1313] Return [VAR[cached]]'s [F[address]].
= [618] Otherwise:
== [619] Return [VAR[host]].
]FIG]

;; [508] These steps asynchronously return an [[IP address]] or [[failure]].

** Verification of service identity

[943] The [DFN[service identity verification steps]] for [VAR[host]] and
[VAR[certificate]] are these steps:
[FIG(steps)[
= [947] Let [VAR[domains]] be a list of the [CODE[dNSName]] values in [VAR[certificate]]'s 
[CODE[subjectAltName]] [[extension][TLS extension]], if any.
= [948] Let [VAR[addresses]] be a list of the [CODE[iPAddress]] values in [VAR[certificate]]'s 
[CODE[subjectAltName]] [[extension][TLS extension]], if any.
= [949] If all of these conditions are [[true]]:
[FIG(list)[
- [964] [VAR[domains]] is empty
- [965] [VAR[addresses]] is empty
- [966] [VAR[certificate]]'s [CODE[subject]] field has any [CODE[CN]] value
]FIG]
== [967] Let [VAR[cn]] be [VAR[certificate]]'s [CODE[subject]] field has 
the first [CODE[CN]] value.
= [968] Otherwise:
== [969] Let [VAR[cn]] be [[null]].
= [944] If [VAR[host]] is a [[domain]]:
== [958] For each [VAR[domain]] in [VAR[domains]]:
=== [957] If [VAR[host]] [[certificate-domain-pattern matches][certificate-domain-pattern match]] [VAR[domain]]:
==== [959] Return [[true]] and abort these steps.
== [970] If [VAR[cn]] is not [[null]] and
[VAR[host]] [[certificate-domain-pattern matches][certificate-domain-pattern match]] [VAR[cn]]:
=== [971] Return [[true]] and abort these steps.
= [945] Otherwise, if [VAR[host]] is an [[IPv4 address]]:
== [954] For each [VAR[address]] in [VAR[addresses]]:
=== [955] If [VAR[address]] represents the same [[IPv4 address]] as [VAR[host]]:
==== [956] Return [[true]] and abort these steps.
== [963] If [VAR[cn]] is the result of applying [[IPv4 serializer]] to [VAR[host]]:
=== [972] Return [[true]] and abort these steps.
= [946] Otherwise, if [VAR[host]] is an [[IPv6 address]]:
== [950] For each [VAR[address]] in [VAR[addresses]]:
=== [951] If [VAR[address]] represents the same [[IPv6 address]] as [VAR[host]]:
==== [952] Return [[true]] and abort these steps.
= [953] Return [[false]].
]FIG]

[960] Whether a [[domain]] [VAR[domain]] [DFN[certificate-domain-pattern matches][certificate-domain-pattern match]]
a string [VAR[pattern]] or not is the value returned by the following steps:
[FIG(steps)[
= [962] If the last character of [VAR[pattern]], if any, is a [CODE[.]] character:
== [973] Return [[false]] and abort these steps.
= [975] Let [VAR[canonicalized pattern]] be [VAR[pattern]], [[converted to ASCII lowercase]].
= [974] If [VAR[domain]] is [VAR[canonicalized pattern]], optionally followed by
a [CODE[.]] character:
== [976] Return [[true]] and abort these steps.
= [977] If the first two characters of [VAR[canonicalized pattern]], if any, is [CODE[*.]]:
== [979] Remove the first two characters from [VAR[canonicalized pattern]].
== [980] If [VAR[canonicalized pattern]] does not contain any [CODE[.]] character,
or [VAR[canonicalized pattern]] is an [[ICANN public suffix]]:
=== [982] Return [[false]] and abort these steps.
== [983] If [VAR[domain]] is one or more characters,
followed by [VAR[canonicalized pattern]], optionally followed by a [CODE[.]] character:
=== [984] Return [[true]] and abort these steps.
= [978] Return [[false]].
]FIG]

[1327] A string [VAR[string]] is an [DFN[ICANN public suffix]] if
the [[public suffix]] of [VAR[string]] is [VAR[string]]
when only [[ICANN domains]] are taken into account.

* URLs

[1058] The [DFN[[F[hostport]]]] of a [[URL record]] [VAR[url]] is the concatenation of:
[FIG(list)[
= [1059] [F[host]]
= [902] If [VAR[url]]'s [F[port]] is not [[null]]:
== [903] [CODE[:]]
== [904] [VAR[url]]'s [F[port]], [[serialized][serialize an integer]]
]FIG]

[622] The [DFN[effective port]] of [VAR[url]] is the value returned by these steps:
[FIG(steps)[
= [623] Let [VAR[port]] be [VAR[url]]'s [F[port][URL's port]].
= [624] If [VAR[port]] is [[null]]:
== [625] Set [VAR[port]] to the value determined by the [VAR[url]]'s [F[scheme][URL scheme]]:
[FIG(switch)[
: [CODE(URI)@en[ftp]] : [[21]]
: [CODE(URI)@en[http]] : [[80]]
: [CODE(URI)@en[https]] : [[443]]
]FIG]
= [626] Return [VAR[port]].
]FIG]

[1057] The [DFN[[F[pathquery]]]] of a [[URL record]] [VAR[url]] is the concatenation of:
[FIG(list)[
= [846] [CODE[/]]
= [847] The strings in [VAR[url]]'s [F[path]], separated from each other by [CODE[/]]
= [848] If [VAR[url]]'s [F[query]] is not [[null]]:
== [849] [CODE[?]]
== [850] [VAR[url]]'s [F[query]]
]FIG]

[1299] The [DFN[[F[originpathquery]]]] of a [[URL record]] [VAR[url]] is the
value returned by these steps:
[FIG(steps)[
= [1300] Set [VAR[clone]] be a copy of [VAR[url]].
= [1301] [[Strip [VAR[clone]] for use as a referrer][Strip [VAR[url]] for use as a referrer]].
= [1302] Return the result of applying the [[URL serializer]] to [VAR[clone]].
]FIG]

[1056] The [DFN[proxy environment variable parser]] for string [VAR[value]]
[MUST[MUST]] run these steps:
[FIG(steps)[
= [1028] If [VAR[value]] does not begin with a [[scheme][URL scheme (syntax)]]
followed by [CODE[://]]:
== [1316] prepend [CODE[http://]] to [VAR[value]].
= [1029] Return the result of applying the [[URL parser]] to [VAR[value]].
]FIG]

;; [1318] These steps can return a [[URL record]] or a [[failure]].

* Proxies

[1314] A [[user agent]] [VAR[user agent]] has [DFN[[F[get proxies]]]] steps,
which are invoked with [VAR[user agent]] and [[URL record]] [VAR[url]].
The [F[get proxies]] steps must return a list of zero or more [[proxy configuration]]
objects.

;; [1052] [VAR[url]]'s [F[scheme][URL scheme]] has to be a [[network scheme]].

[612] A [DFN[proxy configuration]] has [DFN[[F[protocol][proxy's protocol]]]], which is one of:
[CODE[tcp]],
[CODE[unix]],
[CODE[http]],
[CODE[https]],
[CODE[socks4]], and
[CODE[socks5]].

;; [1017] The value [CODE[tcp]] represents direct access (i.e. no proxy).

[613] A [[proxy configuration]] whose [F[protocol][proxy's protocol]] is
[CODE[http]], [CODE[https]], [CODE[socks4]], or [CODE[socks5]] has
[DFN[[F[host][proxy's host]]]], whose value is a [[host]], and
[DFN[[F[port][proxy's port]]]], whose value is an [[integer]] or [[null]].
The initial value of the [F[port][proxy's port]] is [[null]].

[543] A [[proxy configuration]] whose [F[protocol][proxy's protocol]] is
[CODE[http]] or [CODE[https]] has [DFN[[F[username][proxy's username]]]],
whose value is a [[string]],
and [DFN[[F[password][proxy's password]]]], whose value is a [[string]] or [[null]].
The initial value of the [F[username][proxy's username]] is the [[empty string]].
The initial value of the [F[password]] is [[null]].

[614] A [[proxy configuration]] whose [F[protocol][proxy's protocol]] is
[CODE[unix]] has [DFN[[F[path][proxy's path]]]], whose value is a [[byte string]].

[1315] The [F[get proxies]] steps are implementation dependent.  Following
subsections include examples of such steps.

** Proxy configurations from environment variables

[1043] This subsection applies to a [[user agent]] that supports [[environment variable]]
based proxy configurations.

[1317] A [[user agent]] has following states:
[FIG(list members)[
: [DFN[[F[HTTP proxy]]]] : A [[proxy configuration]] or [[null]].
: [DFN[[F[HTTPS proxy]]]] : A [[proxy configuration]] or [[null]].
: [DFN[[F[FTP proxy]]]] : A [[proxy configuration]] or [[null]].
: [DFN[[F[no proxy hosts]]]] : A list of [[host]]s.
]FIG]

[836] Upon initialization, a [[user agent]] [MUST[MUST]] run these steps:
[FIG(steps)[
= [1021] Set [VAR[user agent]]'s [F[HTTP proxy]] to the result of
[[parsing environment variable][parse an environment variable]] [CODE[http_proxy]].
= [1022] Set [VAR[user agent]]'s [F[HTTPS proxy]] to the result of
[[parsing environment variable][parse an environment variable]] [CODE[https_proxy]].
= [1023] Set [VAR[user agent]]'s [F[FTP proxy]] to the result of
[[parsing environment variable][parse an environment variable]] [CODE[ftp_proxy]].
= [1037] Let [VAR[no_proxy]] be the result of
[[getting the environment variable][get an environment variable]] [CODE[no_proxy]].
= [1038] If [VAR[no_proxy value]] is not [[null]] and is not the [[empty string]]:
== [1039] For each substring [VAR[value]] obtained by splitting [VAR[no_proxy value]]
by a [CODE[,]] character:
=== [1040] Remove any leading and trailing [[C0 controls and space]] characters
from [VAR[value]].
=== [1041] Let [VAR[host]] be the result of applying the [[host parser]] to [VAR[value]].
=== [1042] If [VAR[host]] is not an error,
append [VAR[host]] to [VAR[user agent]]'s [F[no proxy hosts]].
]FIG]

[1024] To [DFN[parse an environment variable]] whose name is [VAR[name]],
run these steps:
[FIG(steps)[
= [1025] Let [VAR[value]] be the result of 
[[getting the environment variable][get an environment variable]] [VAR[name]].
= [1026] If [VAR[value]] is [[null]] or the [[empty string]]:
== [1027] Return [[null]] and abort these steps.
= [1055] Let [VAR[url]] be the result of applying the [[proxy environment variable parser]]
to [VAR[value]].
= [1030] If [VAR[url]]'s [F[scheme][URL scheme]] is [CODE[http][http:]]
or [CODE[https][https:]]:
== [1031] Return a [[proxy configuration]].
[FIG(list members)[
[FIGCAPTION[
[[Proxy configuration][proxy configuration]]
]FIGCAPTION]
: [F[protocol][proxy's protocol]] : [VAR[url]]'s [F[scheme][URL scheme]]
: [F[host][proxy's host]] : [VAR[url]]'s [F[host][URL's host]]
: [F[port][proxy's port]] : [VAR[url]]'s [F[port][URL's port]]
: [F[username][proxy's username]] : [VAR[url]]'s [F[username][URL's username]]
: [F[password][proxy's password]] : [VAR[url]]'s [F[password][URL's password]]
]FIG]
= [1032] Otherwise, if [VAR[url]]'s [F[scheme][URL scheme]] is [CODE[socks4][socks4:]]
or [CODE[socks5][socks5:]] and [CODE[url]]'s [F[host][URL's host]] is not [[null]]:
== [1033] Return a [[proxy configuration]].
[FIG(list members)[
[FIGCAPTION[
[[Proxy configuration][proxy configuration]]
]FIGCAPTION]
: [F[protocol][proxy's protocol]] : [VAR[url]]'s [F[scheme][URL scheme]]
: [F[host][proxy's host]] : [VAR[url]]'s [F[host][URL's host]]
: [F[port][proxy's port]] : [VAR[url]]'s [F[port][URL's port]]
]FIG]
= [1034] Otherwise:
== [1035] The [[user agent]] [MAY[MAY]] report an error and [MAY[MAY]]
terminate the [[user agent]].
== [1036] Return [[null]].
]FIG]

[1045] To [DFN[get an environment variable]] with string [VAR[name]], run these steps:
[FIG(steps)[
= [1047] Let [VAR[value]] be the value of the [[user agent]]'s [[process]]'s
[[environment variable]] whose name is [VAR[name]], if any, or the [[empty string]].
= [1290] Let [VAR[uc name]] be [VAR[name]], [[converted to ASCII uppercase]].
= [1373] Let [VAR[uc value]] be the value of the [[user agent]]'s [[process]]'s
[[environment variable]] whose name is [VAR[uc name]], if any, or the [[empty string]].
= [1046] If [VAR[value]] is not the [[empty string]] and [VAR[value]] is not [VAR[uc value]]:
== [1049] Let [VAR[encoding]] be the [[encoding]] of the [[platform]].
== [1048] Return the result of [[decoding][decode]] [VAR[value]] in [VAR[encoding]].
= [1050] Otherwise:
== [1051] Return [CODE[null]].
]FIG]

[FIG(important)[
[1374] For security, uppercase environment variable [CODE[HTTP_PROXY]]
cannot be used.
]FIG]

[1000] The [F[get proxies]] steps for [VAR[url]] are these steps:
[FIG(steps)[
= [1018] For each [[host]] [VAR[host]] in [VAR[user agent]]'s [F[no proxy hosts]]:
== [1019] If [VAR[host]] [[equals][host equivalence]] [VAR[url]]'s [F[host]]:
=== [1020] Return a list whose only member is a [[proxy configuration]]
whose [F[protocol][proxy's protocol]] is [CODE[tcp]] and abort these steps.
= [611] If [VAR[url]]'s [F[scheme][URL scheme]] is [CODE[http][http:]] and 
[VAR[user agent]]'s [F[HTTP proxy]] is not [[null]]:
== [1012] Return a list whose only member is [VAR[user agent]]'s [F[HTTP proxy]]
and abort these steps.
= [1013] If [VAR[url]]'s [F[scheme][URL scheme]] is [CODE[https][https:]] and 
[VAR[user agent]]'s [F[HTTPS proxy]] is not [[null]]:
== [1014] Return a list whose only member is [VAR[user agent]]'s [F[HTTPS proxy]]
and abort these steps.
= [1015] If [VAR[url]]'s [F[scheme][URL scheme]] is [CODE[ftp][ftp:]] and 
[VAR[user agent]]'s [F[FTP proxy]] is not [[null]]:
== [1016] Return a list whose only member is [VAR[user agent]]'s [F[FTP proxy]]
and abort these steps.
= [546] Return a list whose only member is a [[proxy configuration]]
whose [F[protocol][proxy's protocol]] is [CODE[tcp]].
]FIG]

** Proxy configurations from ProxyRules

@@
[609] <https://developer.chrome.com/extensions/proxy#type-ProxyRules>

** Proxy configurations from WebDriver

@@

** Proxy configurations from PAC

[1319] This subsection applies to a [[user agent]] which is configured to
use a [[PAC]] script to choose appropriate proxies.

[1320] A [[user agent]] has following states, whose values can be configured by
the [[user]]:
[FIG(list members)[
: [DFN[[F[[[PAC]] [[URL]]]]  : A [[URL record]] or [[null]].
: [DFN[[F[use [[WPAD]] flag]]]] : A [[boolean]].
]FIG]

[1004] A [[user agent]] has a [F[[[PAC]] script]], which is initially [[null]].

[1001] The [[user agent]] [MUST[MUST]] send appropriate [[WPAD]] request
if its [F[use [[WPAD]] flag]] is [[true]].

[1003] If a [[PAC]] [[URL]] is provided by [[WPAD]] processing,
the [[user agent]] [MUST[MUST]] [[fetch]] the [[PAC]] file.
Otherwise, if [F[[[PAC]] [[URL]]]] is not [[null]],
the [[user agent]] [MUST[MUST]] [[fetch]] the [F[[[PAC]] [[URL]]]].
When a [[PAC]] script file is [[fetch]]ed, the [[user agent]]'s
[F[[[PAC]] script]] [MUST[MUST]] be set to the file.

[1321] The [F[get proxies]] steps for [VAR[url]] are these steps:
[FIG(steps)[
= [544] If [VAR[user agent]]'s [F[[[PAC]] script]] is not [[null]]:
== [545] Process [VAR[user agent]]'s [F[[[PAC]] script]] with [VAR[url]].
== [1011] Return the result of the previous step and abort these steps.
= [1322] Return a list whose only member is a [[proxy configuration]]
whose [F[protocol][proxy's protocol]] is [CODE[tcp]].
]FIG]

* Transports

[640] A [DFN[transport]] has following states:

[FIG(list members)[ [408] [[Transport][transport]]

: [DFN[[F[protocol]]][transport's protocol]] :
One of 
[CODE[tcp]],
[CODE[unix]],
[CODE[http1connect]],
[CODE[http2connect]],
[CODE[tls]],
[CODE[socks4]], and
[CODE[socks5]].
: [DFN[[F[endpoint type][transport's endpoint type]]]] :
Either [CODE[client]] or [CODE[server]].
: [DFN[[F[http protocol][transport's http protocol]]]] :
Either [CODE[http1]], [CODE[http2]], or [CODE[ftp]].
The default is [CODE[http1]].
: [DFN[[F[proxy configuration][transport's proxy configuration]]]] : A [[proxy configuration]].
:[VAR[送信閉じ済みフラグ]]:初期状態では未設定。
:[VAR[受信閉じ済みフラグ]]:初期状態では未設定。
:[VAR[送信待ちバッファー]]:初期状態では空のリスト。
: [DFN[[F[request mode]]]] :
The value is either ''default'' or ''HTTP proxy''.
If the [F[request mode]] of a [[transport]] is ''HTTP proxy'',
a [[request]] has to be sent over the [[transport]] as an [[HTTP request]]
whose [[request target]] is an [[absolute URL]].
: [DFN[[F[HTTPS state]]][transport's HTTPS state]] :
An [[HTTPS state]] value.  Either [CODE[none]], [CODE[deprecated]], or [CODE[modern]].
The default is [CODE[none]].
]FIG]

;; [819] There are also [F[protocol][transport's protocol]] dependent 
additional states.

[38] An [DFN[exit status]] has following states:

[FIG(list members)[ [469] [[Exit status][exit status]]

:リセット:[[真]]か[[偽]]。既定値は[[偽]]。
:失敗:[[真]]か[[偽]]。
:[[WebSocket]] cleanly:[[真]]か[[偽]]か null。既定値は null。
:[[WebSocket]] [[状態符号]]:[[整数]]か null。既定値は null。
:[[WebSocket]] 理由:[[文字列]]か null。既定値は null。
: [DFN[[F[can retry][exit's can retry]]]] : A [[boolean]].  The default is [[false]].
]FIG]

[1054] To [DFN[create a transport for a proxy configuration]] [VAR[proxy]]
with a [[URL record]] [VAR[url]] and optional [VAR[ws]] and [VAR[skip DNS cache]]
flags in [VAR[user agent]],
run rhese steps:
[FIG(steps)[
= [549] If [VAR[user agent]] does not support [VAR[proxy]]'s [F[protocol]]:
== [550] Return a [[failure]] and abort these steps.
= [551] Switch by [VAR[proxy]]'s [F[protocol]]:
[FIG(switch)[
: [CODE[tcp]] :
[FIG(steps)[
= [552] Set [VAR[effective port]] be the [[effective port]] of [VAR[url]].
= [553] Set [VAR[addr]] to the result of applying [[name resolution steps]] 
to [VAR[url]]'s [F[host][URL's host]] with [VAR[skip DNS cache]] in [VAR[user agent]].
= [554] If [VAR[addr]] is an [[error]]:
== [555] Return a [[failure]] and abort these steps.
= [557] [[Wait for other connections][wait for other connections]] of
[VAR[addr]], [VAR[port]], and [VAR[ws]] in [VAR[user agent]] in [VAR[user agent]].
= [558] Return the result of 
[[establishing a TCP transport][establish a TCP transport]]
to [VAR[addr]] and [VAR[effective port]].
]FIG]
: [CODE[unix]] :
[FIG(steps)[
= [559] Return the result of
[[establishing a UNIX socket domain transport][establish a UNIX socket domain transport]]
with [VAR[proxy]]'s [F[path][proxy's path]], [VAR[url]]'s [F[host][URL's host]],
and [VAR[url]]'s [[effective port]].
]FIG]
: [CODE[http]] or [CODE[https]] :
[FIG(steps)[
= [560] [[Wait for other connections][wait for other connections]] of
[VAR[url]]'s [F[host][URL host]], [VAR[port]], and [VAR[ws]] in [VAR[user agent]].
= [561] Let [VAR[proxy port]] be [VAR[proxy]]'s [F[port]].
= [562] If [VAR[proxy port]] is [[null]]:
== [563] If [VAR[proxy]]'s [F[protocol]] is [CODE[http]], set [VAR[proxy port]] to [N[80]].
== [564] If [VAR[proxy]]'s [F[protocol]] is [CODE[https]], set [VAR[proxy port]] to [N[443]].
= [565] Let [VAR[proxy addr]] be the result of applying [[name resolution steps]] 
to [VAR[proxy]]'s [F[host]] in [VAR[user agent]].
= [566] If [VAR[proxy addr]] is an [[error]]:
== [567] Return a [[failure]] and abort these steps.
= [568] Let [VAR[transport]] be the result of 
[[establishing a TCP transport][establish a TCP transport]]
to [VAR[proxy addr]] and [VAR[proxy port]].
= [570] If [VAR[proxy]]'s [F[protocol]] is [CODE[https]]:
== [571] Set [VAR[transport]] to the result of running the [[TLS steps]] for
[VAR[transport]] and [VAR[proxy]]'s [F[host]].
= [556] If [VAR[transport]] is a [[failure]]:
== [569] Return a [[failure]] and abort these steps.
= [572] If [VAR[url]]'s [F[scheme][URL scheme]] is [CODE(URI)@en[https]]:
== [577] Let [VAR[http]] be an [[HTTP connection]]:
[FIG(list members)[
[FIGCAPTION[
[[HTTP connection]]
]FIGCAPTION]
: [F[endpoint type][connection's endpoint type]] : [CODE[client]]
: [F[transport][connection's transport]] : [VAR[transport]]
]FIG]
== [578] Set [VAR[transport]] to the result of
[[establishing an HTTP [CODE(HTTP)[CONNECT]] transport][establish an HTTP [CODE(HTTP)@en[CONNECT]] transport]]
with [VAR[http]] and [VAR[url]].
@@ [VAR[credentials]] flag and proxy credentials
== [579] If [VAR[transport]] is a [[failure]] whose HTTP response's [F[status]] is
[CODE[407]]:
=== 
@@ Show proxy auth dialog
= [580] Otherwise:
== [581] Set [VAR[transport]]'s [F[request mode]] to ''HTTP proxy''.
= [548] Return [VAR[transport]].
]FIG]
: [CODE[socks4]] :
[FIG(steps)[
= [582] Let [VAR[effective port]] be the [[effective port]] of [VAR[url]].
= [583] Set [VAR[addr]] to the result of applying [[name resolution steps]] 
to [VAR[url]]'s [F[host]] with [VAR[skip DNS cache]] in [VAR[user agent]].
= [584] If [VAR[addr]] is ''not'' an [[IPv4 address]]:
== [585] Return a [[failure]] and abort these steps.
= [587] [[Wait for other connections][wait for other connections]] of
[VAR[addr]], [VAR[port]], and [VAR[ws]] in [VAR[user agent]].
= [588] Let [VAR[proxy port]] be [VAR[proxy]]'s [F[port]].
= [589] If [VAR[proxy port]] is [[null]], set [VAR[proxy port]] to [N[1080]].
= [590] Let [VAR[proxy addr]] be the result of applying [[name resolution steps]] 
to [VAR[proxy]]'s [F[host]] in [VAR[user agent]].
= [591] Let [VAR[transport]] be the result of 
[[establishing a TCP connection][establish a TCP connection]]
to [VAR[proxy addr]] and [VAR[proxy port]].
= [592] Return the result of
[[establishing a SOCKS4 connection][establish a SOCKS4 connection]]
with [VAR[transport]], [VAR[addr]], and [VAR[effective port]].
]FIG]
: [CODE[socks5]] :
[FIG(steps)[
= [593] Let [VAR[effective port]] be the [[effective port]] of [VAR[url]].
= [594] [[Wait for other connections][wait for other connections]] of
[VAR[url]]'s [F[host][URL host]], [VAR[port]], and [VAR[ws]] in [VAR[user agent]].
= [595] Let [VAR[proxy port]] be [VAR[proxy]]'s [F[port]].
= [597] If [VAR[proxy port]] is [[null]], set [VAR[proxy port]] to [N[1080]].
= [596] Let [VAR[proxy addr]] be the result of applying [[name resolution steps]] 
to [VAR[proxy]]'s [F[host]] in [VAR[user agent]].
= [598] Let [VAR[transport]] be the result of 
[[establishing a TCP transport][establish a TCP transport]]
to [VAR[proxy addr]] and [VAR[proxy port]].
= [599] Return the result of
[[establishing a SOCKS5 transport][establish a SOCKS5 transport]]
with [VAR[transport]], [VAR[url]]'s [F[host]], and [VAR[effective port]].
]FIG]
]FIG]

]FIG]

;; [634] These steps asynchronously return.

[542] To [DFN[establish a transport]] for [[URL record]]s [VAR[request url]] and
[VAR[server url]]
and a [[user agent]] [VAR[user agent]], optionally with [VAR[credentials]], [VAR[ws]],
[VAR[[CODE[acceptSslCerts]]]],
and [VAR[skip DNS cache]] flags, run these steps:

[FIG(steps)[
= [936] Assert: [VAR[request url]]'s [F[scheme][URL scheme]] is a [[network scheme]].
= [909] Assert: Either [VAR[server url]]'s [F[scheme][URL scheme]] is [CODE[http][http:]]
or [VAR[server url]] is [VAR[request url]].
= [1009] Let [VAR[proxies]] be the result of [[getting proxies][get proxies]] for 
[VAR[server url]] in [VAR[user agent]].
= [547] For each [VAR[proxy]] in [VAR[proxies]], in order, run these substeps:
== [1053] Set [VAR[transport]] to the result of 
[[creating a transport for proxy][create a transport for a proxy configuration]]
[VAR[proxy]] with [VAR[server url]], [VAR[ws]], and [VAR[skip DNS cache]].
== [600] If [VAR[transport]] is not a [[failure]]:
=== [601] If [VAR[request url]]'s [F[scheme][URL scheme]] is [CODE(URI)@en[https][https:]]:
==== [602] Set [VAR[transport]] to the result of running the [[TLS steps]] for
[VAR[transport]], [VAR[request url]]'s [F[host]], [VAR[credentials]] flag, [VAR[ws]] flag,
and [VAR[[CODE[acceptSslCerts]]]] flag, in [VAR[user agent]].
=== [603] Otherwise, if [VAR[transport]]'s [F[request mode]] is '''not''' ''HTTP proxy'' and
[VAR[request url]]'s [F[scheme][URL scheme]] is [CODE(URI)@en[ftp][ftp:]]:
==== [929] Set [VAR[transport]]'s [F[http protocol][transport's http protocol]] to [CODE[ftp]].
== [927] If [VAR[transport]] is not a [[failure]]:
=== [1182] Set [VAR[transport]]'s [F[proxy configuration][transport's proxy configuration]]
to [VAR[proxy]].
=== [605] Return [VAR[transport]] and abort these steps.
= [606] Return a [[failure]].
]FIG]

;; [507] These steps asynchronously return.

-*-*-

[642] [[アプリケーション]]は、 [[transport]] に次の指示を行えます。
[FIG(list)[
- [[バイト]]の送信の指示
- 正常終了の送信の指示
- 中断の指示
- credentials の送信の指示
]FIG]

[643] [[バイト]]の送信の指示は、送信する[[バイト]] (0-255 のいずれかの値)と、
[[緊急データ]]か否かのフラグ (既定値は未設定。)
を[[引数]]とし、次のように処理します。
[FIG(steps)[
= [644] [VAR[送信閉じ済みフラグ]]が設定されていれば、[[例外]]を投げて停止します。
= [645] [VAR[送信待ちバッファー]]が満杯なら、[[例外]]を投げて停止します。
= [646] [[緊急データ]]フラグが設定されていて、
[[transport]] の種類が[[緊急データ]]に対応していないものなら、
[[例外]]を投げて停止します。
= [647] [VAR[送信待ちバッファー]]の末尾に、
引数の[[バイト]]、
引数の[[緊急データ]]か否かのフラグ、
[[約束]]の組を追加します。
= [648] 追加した[[約束]]を返します。
]FIG]

;; [649] 返された[[約束]]は、[[バイト]]が送信された際に[[解決]]されます。

[650] [[バイト列]]を送信するとは、当該[[バイト列]]について先頭の[[バイト]]から順に[[バイト]]の送信の指示を行い、最後の[[バイト]]が返した[[約束]]を返す
(空バイト列なら[[解決]]済みの[[約束]]を返す) ことをいいます。

[651] 正常終了の送信の指示は、次のように処理します。
[FIG(steps)[
= [652] [VAR[送信閉じ済みフラグ]]が設定されていれば、[[例外]]を投げて停止します。
= [653] [VAR[送信閉じ済みフラグ]]を設定します。
= [654] [[transport]]の種類に応じた処理を行います。
]FIG]

[655] 中断の指示は、次のように処理します。
[FIG(steps)[
= [656] [VAR[送信閉じ済みフラグ]]と[VAR[受信閉じ済みフラグ]]の両方が設定されていれば、
[[例外]]を投げて停止します。
= [657] [VAR[送信閉じ済みフラグ]]を設定します。
= [658] [VAR[受信閉じ済みフラグ]]を設定します。
= [659] [VAR[送信待ちバッファー]]の先頭の項目から順に、
[[約束]]を[[拒絶]]していきます。
= [660] [[transport]]の種類に応じた処理を行います。
= [661] 中断の通知を行います。リセットフラグを設定します。
]FIG]

[662] [[credentials]] の送信の指示は、
[[transport]]の種類に応じた処理を実行します。そのようなものがなければ、
[[例外]]を投げます。
なお引数として、[[transport]]の種類に応じた [[credentials]] を受け取ります。

[663] [[transport]]は、[[アプリケーション]]に対して次の通知を行います。
[FIG(list)[
- [664] [[バイト]]の受信の通知
[FIG(list members)[
:[[バイト]]:受信した[[バイト]]。 0-255 のいずれかの値。
:[[緊急データ]]フラグ: [[TCP]] [[緊急データ]]か否か。既定値は[[偽]]。
]FIG]
- [665] 正常終了の受信の通知
- [666] 中断の通知
[FIG(list members)[
:[[リセット]]フラグ:[[TCP]] [CODE[[[RST]]]] 相当のものであるか否か。既定値は[[偽]]。
]FIG]
- [667] 警告の通知
- [668] challenge の受信の通知
[FIG(list members)[
: [VAR[transport]] :認証を行う [[transport]]。
:[[challenge]]:プロトコル依存の [[challenge]] データ。
]FIG]
]FIG]

[669] [[transport]]の種類に依存した方法で次の[[バイト]]を送信可能であると判断したら、
次のようにします。
[FIG(steps)[
= [670] [VAR[送信待ちバッファー]]が空なら、ここで停止します。
= [671] [VAR[送信待ちバッファー]]の先頭の項目を取得し、バッファーからは削除します。
= [672] [[transport]]の種類に依存した方法で取得した項目の[[バイト]]を送信します。
(あれば) [[緊急データ]]フラグを引渡します。
= [673] 取得した項目の[[約束]]を[[解決]]します。
]FIG]

** TCP

[1435] A [[transport]] whose [F[protocol][transport's protocol]] is
[CODE[tcp]] has following additional states:

[FIG(list members)[

: [DFN[[F[[[remote host]]][transport's remote host]]]] :  A [[host]].
: [DFN[[F[[[remote port]]][transport's remote port]]]] :  A [[port]].
: [DFN[[F[[[local host]]][transport's local host]] :      A [[host]].
: [DFN[[F[[[local port]]][transport's local port]] :      A [[port]].
: [DFN[[F[[[tcp connection]]][transport's tcp connection]] : A [[TCP connection]].

]FIG]

[742] To [DFN[TCP connect]] to [[host]] [VAR[host]] and [[port]] [VAR[port]],
establish a connection to [VAR[host]] and [VAR[port]] as described in TCP
specifications and asynchronously returns a new [[TCP connection]]
representing the connection if the connection is established,
or [[failure]] if the connection cannot be established.
A [DFN[TCP connection]] has 
[DFN[[F[[[local address]]][TCP connection's local address]]]], which is an [[IP address]],
and [DFN[[F[[[local port]]][TCP connection's local port]]]], which is a [[port]].

[1437] To [DFN[set TCP options]] of [[TCP connection]] [VAR[tcp]],
run these steps:

[FIG(steps)[
= [420] Disable the [CODE[SO_OOBINLINE]] option of [VAR[tcp]].
= [424] Enable the [CODE[SO_NODELAY]] option of [VAR[tcp]].
= [437] Run the implementation dependent steps for setting [[TCP keep alive]] options, e.g.:
== [635] Enable the [CODE[SO_KEEPALIVE]] option of [VAR[tcp]].
== [636] Set [CODE[TCP_KEEPIDLE]] option of [VAR[tcp]] to [N[45]] seconds.
== [637] Set [CODE[TCP_KEEPINTVL]] option of [VAR[tcp]] to [N[45]] seconds.
]FIG]


[627] To [DFN[establish a TCP transport]] to [[IP address]] [VAR[addr]] and 
[[port]] [VAR[port]], run these steps:

[FIG(steps)[
= [1416] If [VAR[addr]] is [CODE[127.0.53.53]]:
== [1417] Return a [[failure]] and abort these steps.
= [628] Let [VAR[tcp]] be the result of invoking
[[TCP connect]] with [VAR[addr]] and [VAR[port]].
= [629] If [VAR[tcp]] is [[failure]]:
== [782] Return [[failure]] and abort these steps.
= [674] Let [VAR[transport]] be a new [[transport]]:
[FIG(list members)[ [406] [[Transport][transport]]

: [F[protocol][transport's protocol]] : [CODE[tcp]]
: [F[endpoint type][transport's endpoint type]] : [CODE[client]]
: [F[remote host][transport's remote host]] : [VAR[addr]]
: [F[remote port][transport's remote port]] : [VAR[port]]
: [F[local host][transport's local host]] : [VAR[tcp]]'s [F[local address]]
: [F[local port][transport's local port]] : [VAR[tcp]]'s [F[local port]]
: [F[tcp connection][transport's tcp connection]] : [VAR[tcp]]

]FIG]
= [641] [[Set TCP options][set TCP options]] of [VAR[tcp]].
= [818] Return [VAR[transport]].
]FIG]

;; [510] These steps asynchronously return.

[411] Whenever it accepts a [[TCP connection]] [VAR[tcp]] from
[[IP address]] [VAR[remote addr]] and [[port]] [VAR[remote port]],
a TCP server listening [[IP address]] [VAR[addr]] and [[port]] [VAR[port]]
[MUST[MUST]] run the [[TCP after accept steps]] with
[VAR[tcp]],
[VAR[addr]], [VAR[port]], [VAR[remote addr]], and [VAR[remote port]].

[524] The [DFN[TCP after accept steps]] with 
[[TCP connection]] [VAR[tcp]],
[[IP address]] [VAR[addr]],
[[port]] [VAR[port]],
[[IP address]] [VAR[remote addr]], and
[[port]] [VAR[remote port]] are:

[FIG(steps)[
= [414] Let [VAR[transport]] be a new [[transport]] representing the
[[TCP connection]], with following states:
[FIG(list members)[ [417] [[Transport][transport]]

: [F[protocol][transport's protocol]] : [CODE[tcp]]
: [F[endpoint type][transport's endpoint type]] : [CODE[server]]
: [F[remote host][transport's remote host]] : [VAR[remote addr]]
: [F[remote port][transport's remote port]] : [VAR[remote port]]
: [F[local host][transport's local host]] : [VAR[addr]]
: [F[local port][transport's local port]] : [VAR[port]]
: [F[tcp connection][transport's tcp connection]] : [VAR[tcp]]

]FIG]
= [1436] [[Set TCP options][set TCP options]] of [VAR[tcp]].
= [460] Optionally, run implementation dependent steps (e.g. [[DoS]] protection).
= [446] Return [VAR[transport]].
]FIG]

-*-*-

[676] [[TCP]] の[[セグメント]]を受信したら、次のようにします。
[FIG(steps)[
= [677] [[TCP]] に従い処理し、不適切と判断すればここで停止します。
= [678] [CODE[[[RST]]]] フラグが設定されていれば、
== [679] [VAR[送信閉じ済みフラグ]]を設定します。
== [680] [VAR[受信閉じ済みフラグ]]を設定します。
== [681] 中断を通知します。リセットフラグを設定します。
= [682] データの各[[バイト]]について、順に、
== [683] [[バイト]]の受信を通知します。当該[[バイト]]の値を渡します。
[[緊急ポインター]]が本[[バイト]]を指していれば、[[緊急データ]]フラグも設定します。
= [684] [CODE[[[FIN]]]] フラグが設定されていれば、
== [685] [VAR[受信閉じ済みフラグ]]を設定します。
== [686] 正常終了の受信を通知します。
]FIG]

[687] [[タイムアウト]]その他の理由で[[transport]]が利用できないことを検知したら、
次のようにします。
[FIG(steps)[
= [688] [VAR[送信閉じ済みフラグ]]を設定します。
= [689] [VAR[受信閉じ済みフラグ]]を設定します。
= [690] 中断を通知します。
]FIG]

[691] [[バイト]]を送信できるかどうかは、[[フロー制御]]、[[輻輳制御]]その他の状況により決定します。

[692] [[バイト]]の送信は、次のようにします。
[FIG(steps)[
= [693] [[緊急データ]]フラグが設定されていれば、
== [694] 指定された[[バイト]]をデータとして含み、[[緊急ポインター]]が当該[[バイト]]を指す[[セグメント]]を送信することにします。
= [695] それ以外なら、
== [696] 指定された[[バイト]]をデータとして含む[[セグメント]]を送信することにします。
]FIG]

;; [697] 実際の送信時には、前後の[[バイト]]とまとめた[[セグメント]]で送信されたり、
必要に応じて[[再送]]されたりします。

[698] [[緊急データ]]に対応しています。

[699] 正常終了の送信の指示があれば、次のようにします。
[FIG(steps)[
= [700] [CODE[[[FIN]]]] フラグが設定された[[セグメント]]を送信することにします。
]FIG]

[701] 中断の指示があれば、次のようにします。
[FIG(steps)[
= [702] 必要に応じて [CODE[[[FIN]]]] フラグが設定された[[セグメント]]を送信することにします。
= [703] [[TCP]] で受信したデータの処理を以後行わないことにします。
]FIG]

** HTTP [CODE(HTTP)@en[CONNECT]]

[633] A [[transport]] whose [F[protocol][transport's protocol]] is
[CODE[http1connect]] or [CODE[http2connect]] has following additional states:

[FIG(list members)[
: [DFN[[F[http][transport's http]]]] : An [[HTTP connection]].
: [DFN[[F[established][transport's established]]]] :  A [[boolean]].  Initially, [[false]].
]FIG]

[739] To [DFN[establish an HTTP [CODE(HTTP)@en[CONNECT]] transport]]
with [[HTTP connection]] [VAR[http]] and [[URL record]] [VAR[url]], run these steps:
[FIG(steps)[
= [740] Let [VAR[transport]] be a [[transport]]:
[FIG(list members)[ [632] [[Transport][transport]]

: [F[protocol][transport's protocol]] :
If [VAR[http]]'s [F[protocol][connection's protocol]] is [CODE[http2]], [CODE[http2connect]].
Otherwise, [CODE[http1connect]].
: [F[endpoint type][transport's endpoint type]] : [CODE[client]]
: [F[http][transport's http]] : [VAR[http]]

]FIG]
= [766] Send an [[HTTP request]] over [VAR[http]]:
[FIG(list members)[
: [F[method][request method]] : [CODE[CONNECT]]
: [F[request target]] : [VAR[url]]'s [F[hostport]]
: [F[header list]] :
[FIG(list members)[
: [CODE[Host]] : [VAR[url]]'s [F[hostport]]
: [CODE[Proxy-Connection]] : [CODE[keep-alive]]
: [CODE[User-Agent]] : [[default `[CODE[User-Agent]]` value]]
]FIG]
]FIG]
= [741] If failed, return a [[failure]] and abort these steps.
= [817] Process notifications from [VAR[http]] as follows:
[FIG(switch)[
: [744] [[要求]]のヘッダー受信完了の通知 :
[FIG(steps)[
= [745] 応答の状態符号が [CODE(HTTP)[[[200]]]] なら、
== [746] Set [VAR[transport]]'s [F[established][transport's established]] to [[true]].
== [747] Return [VAR[transport]].
= [748] Otherwise:
== [749] Return a [[failure]].
]FIG]
: [750] [[要求]]の [CODE[data]] の通知 :
[FIG(steps)[
= [751] If [VAR[transport]]'s [F[established][transport's established]] is [[true]]:
-= [752] データの各バイトについて、順に、
-== [753] バイトの受信を通知します。当該バイトの値を渡します。
]FIG]
: [754] [[要求]]の [CODE[dataend]] の通知 :
[FIG(steps)[
= [755] If [VAR[transport]]'s [F[established][transport's established]] is [[true]]:
-= [756] [VAR[受信閉じ済みフラグ]]を設定します。
-= [757] 正常終了の受信を通知します。
]FIG]
: [758] [[要求]]の完了の通知 :
[FIG(steps)[
= [759] If [VAR[connection]]'s [F[exit status][connection's exit status]]'s [F[失敗]] is [[true]]:
== [760] If [VAR[transport]]'s [F[established][transport's established]] is [[true]]:
=== [761] [VAR[送信閉じ済みフラグ]]を設定します。
=== [762] [VAR[受信閉じ済みフラグ]]を設定します。
=== [763] 中断を通知します。
== [764] Otherwise:
=== [765] Return a [[failure]].
]FIG]
]FIG]
]FIG]

@@ [738] XXX server accept steps

[767] バイトは常に送信可能とします。

[768] バイトの送信は、次のようにします。
[FIG(steps)[
= [769] [VAR[transport]]'s [F[http][transport's http]] でトンネルに指定されたバイトを送信します。
]FIG]

[770] 正常終了の送信の指示があれば、次のようにします。
[FIG(steps)[
= [771] [VAR[transport]]'s [F[http][transport's http]] に接続の正常終了を指示します。
]FIG]

[772] 中断の指示があれば、次のようにします。
[FIG(steps)[
= [773] [VAR[transport]]'s [F[http][transport's http]] に中断を指示します。
]FIG]

*** HTTP/2

@@

** SOCKS4

[743] A [[transport]] whose [F[protocol][transport's protocol]] is
[CODE[socks4]] has following additional state:

[FIG(list members)[
: [DFN[[F[transport][socks4 transport's transport]]]] : A [[transport]].
]FIG]

[774] To [DFN[establish a SOCKS4 transport]]
to [[IPv4 address]] [VAR[address]] and [[port]] [VAR[port]] over 
[[transport]] [VAR[transport]], run these steps:

[FIG(steps)[

= [776] [VAR[transport]]で 0x04 0x01 [VAR[p[SUB[1]]]] [VAR[p[SUB[2]]]] [VAR[a[SUB[1]]]] [VAR[a[SUB[2]]]]
[VAR[a[SUB[3]]]] [VAR[a[SUB[4]]]] 0x00 を送信します。
=- [VAR[p[SUB[1]]]] [VAR[p[SUB[2]]]] は[VAR[port]]を[[16ビット符号無し整数]]
([[ネットワークバイト順]]) としたものです。
=- [VAR[a[SUB[1]]]] [VAR[a[SUB[2]]]] [VAR[a[SUB[3]]]] [VAR[a[SUB[4]]]]
は[VAR[address]]を[[32ビット符号無し整数]] ([[ネットワークバイト順]]) としたものです。
= [777] [VAR[transport]]から8バイト受信するのを最大30s待ちます。
= [778] 受信した最初の2バイトが 0x00 0x5A でなければ、
== [779] [VAR[transport]]の中断を指示します。
== [780] Return a [[failure]] and abort these steps.
= [781] Return a new [[transport]]:
[FIG(list members)[ [630] [[Transport][transport]]

: [F[protocol][transport's protocol]] : [CODE[socks4]]
: [F[endpoint type][transport's endpoint type]] : [CODE[client]]
: [F[transport][socks4 transport's transport]] : [VAR[transport]]

]FIG]

]FIG]

;; [511] These steps asynchronously return.

[783] 接続確立後は、指示は[VAR[transport]]への指示とし、
[VAR[transport]]からの通知があればそれを通知します。

** SOCKS5

[775] A [[transport]] whose [F[protocol][transport's protocol]] is
[CODE[socks5]] has following additional state:

[FIG(list members)[
: [DFN[[F[transport][socks5 transport's transport]]]] : A [[transport]].
]FIG]

[784] To [DFN[establish a SOCKS5 transport]]
to destination [VAR[host]] and [[port]] [VAR[port]] over [[transport]] [VAR[transport]],
run these steps:

[FIG(steps)[

= [785] If [VAR[host]] is a [[domain]] whose length is greater than [N[255]]:
== [803] Return a [[failure]] and abort these steps.
= [786] [VAR[transport]]で 0x05 0x01 0x00 を送信します。
= [787] [VAR[transport]]から2バイト受信するのを最大30s待ちます。
= [788] 受信したのが 0x05 0x00 でなければ、
== [789] [VAR[transport]]の中断を指示します。
== [790] Return a [[failure]] and abort these steps.
= [791] [VAR[transport]]で 0x05 0x01 0x00 [VAR[A]] [VAR[p[SUB[1]]]] [VAR[p[SUB[2]]]]
を送信します。
=- [VAR[A]] は、
=-= [VAR[host]]が[[ドメイン名]]の場合、[VAR[host]]を [[UTF-8]] に変換したものの前に
[VAR[host]] を [[UTF-8]] に変換したもののバイト数を[[8ビット符号無し整数]]としたものを置いたものです。
=-= [VAR[host]]が[[IPv4アドレス]]の場合、[VAR[host]]を[[32ビット符号無し整数]] ([[ネットワークバイト順]]) としたものです。
=-= [VAR[host]]が[[IPv6アドレス]]の場合、[VAR[host]]を16バイトのバイト列としたものです。
=- [VAR[p[SUB[1]]]] [VAR[p[SUB[2]]]] は[VAR[port]]を[[16ビット符号無し整数]]
([[ネットワークバイト順]]) としたものです。
= [792] [VAR[transport]]から5バイト受信するのを最大30s待ちます。
= [793] 受信した最初の3バイトが 0x05 0x00 0x00 でないか、
第4バイトが 0x01, 0x03, 0x04 のいずれでもないか、
5バイトに満たなければ、
== [794] [VAR[transport]]の中断を指示します。
== [795] Return a [[failure]] and abort these steps.
= [796] 第4バイトが 0x01 なら、[VAR[transport]]から5バイト受信するのを最大30s待ちます。
= [797] 第4バイトが 0x03 なら、第5バイトを[[8ビット符号無し整数]]として解釈し、
[VAR[transport]]からそのバイト数 + 2 バイト分受信するのを最大30s待ちます。
= [798] 第4バイトが 0x04 なら、[VAR[transport]]から17バイト受信するのを最大30s待ちます。
= [799] 得られたのが指定のバイト数に満たなければ、
== [800] [VAR[transport]]の中断を指示します。
== [801] Return a [[failure]] and abort these steps.
= [802] Return a [[transport]]:
[FIG(list members)[ [576] [[Transport][transport]]

: [F[protocol][transport's protocol]] : [CODE[socks5]]
: [F[endpoint type][transport's endpoint type]] : [CODE[client]]
: [F[transport][socks5 transport's transport]] : [VAR[transport]]

]FIG]
]FIG]

;; [520] These steps asynchronously return.


[804] 接続確立後は、指示は[VAR[transport]]への指示とし、
[VAR[transport]]からの通知があればそれを通知します。

** Unix domain sockets

[805] To [DFN[establish a Unix domain socket connection]] for [[byte string]] [VAR[path]]
with [[host]] [VAR[host]] and [[integer]] [VAR[port]], run these steps:

[FIG(steps)[
= [807] [[ソケットAPI]]を使って新たに接続します。
[FIG(list members)[
: [[アドレス族]] :[CODE[[[AF_UNIX]]]]
: [[パス名]] : [VAR[path]]
: [[ソケット型]] : [CODE[[[SOCK_STREAM]]]]
]FIG]
= [806] If failed, return a [[failure]] and abort these steps.
= [820] Return a new [[transport]] representing the socket,
with following states:
[FIG(list members)[ [631] [[Transport][transport]]

: [F[protocol][transport's protocol]] : [CODE[unix]]
: [F[endpoint type][transport's endpoint type]] : [CODE[client]]

]FIG]

]FIG]

;; [522] These steps asynchronously return.

[604] A Unix domain socket server, whenever it accepts a connection,
[MUST[MUST]] run the [[Unix domain socket after accept steps]].

[586] The [DFN[Unix domain socket after accept steps]] are:

[FIG(steps)[
= [608] Let [VAR[transport]] be a new [[transport]] representing the
Unix domain socket connection, with following states:
[FIG(list members)[ [620] [[Transport][transport]]

: [F[protocol][transport's protocol]] : [CODE[unix]]
: [F[endpoint type][transport's endpoint type]] : [CODE[server]]

]FIG]
= [675] Return [VAR[transport]].
]FIG]

-*-*-

[810] バイトが送信可能かどうかは、 [CODE[[[send]]]] によりバイト列を送信できるかどうかとします。

[811] バイトの送信は、 [CODE[[[send]]]] によります。

[812] 正常終了の送信の指示があれば、 [CODE[[[shutdown]]]] [CODE[[[SHUT_WR]]]] を実行します。

[813] 中断の指示があれば、 [CODE[[[shutdown]]]] [CODE[[[SHUT_RDWR]]]] を実行します。

[814]  [CODE[[[recv]]]] によりバイト列を受信したら、
各バイトを順に、バイトの受信を通知します。

[815] [CODE[[[recv]]]] で何も受信しなくなれば、
[VAR[送信閉じ済みフラグ]]を設定し、正常終了の受信を通知します。

[816] [CODE[[[send]]]] や [CODE[[[recv]]]] でエラーが発生したら、
[VAR[送信閉じ済みフラグ]]と[VAR[受信閉じ済みフラグ]]を設定し、
中断を通知します。

** TLS

[877] A [[transport]] whose [F[protocol][transport's protocol]] is
[CODE[tls]] has following additional states:
[FIG(list members)[
: [F[is ev]] : A [[boolean]].
The default is [[false]].
: [F[remote certificates]] : A list of [[certificates][certificate]].
: [F[has alert]] : A [[boolean]].
The default is [[false]].
]FIG]

[638] The [DFN[TLS steps]] for [VAR[transport]], [VAR[url]], and [VAR[credentials]],
with optional [VAR[ws]] and [VAR[[CODE[acceptSslCerts]]]] flags,
in [VAR[user agent]] are as follows:
[FIG(steps)[
= 
@@ credentials
= [878] If [VAR[ws]] is true:
== [879] Set [VAR[alpn protocols]] to ([CODE[http/1.1]]).
= [880] Otherwise:
== [881] Set [VAR[alpn protocols]] to ([CODE[h2]], [CODE[http/1.1]]).
==
@@ If switched from HTTP/2 to HTTP/1.1
= [356] Initiate [[TLS handshake]].
[FIG(list members)[
: Minimum TLS version : [CODE[1.0]]
: Underlying transport : [VAR[transport]]
: Compression : Disabled
: [[TLS session]] cache : [VAR[user agent]]'s [F[[[TLS session]] cache]]
: [[SNI]] host : 
If [VAR[url]]'s [F[host]] is a [[domain]], [VAR[url]]'s [F[host]].
Otherwise, [[null]].
: Use [[OCSP stapling]] request : [[true]]
: [[ALPN protocol names][ALPN protocol name]] : [VAR[alpn protocols]]
: Certificate database : [VAR[user agent]]'s [F[certificate database]]
: Additional verification for server certificate [VAR[cert]] :
Return the result of running the [[service identity verification steps]] with
[VAR[url]]'s [F[host]] and [VAR[cert]].
]FIG]
= [861] If failed, return a [[failure]] and abort these steps.
= [865] Let [VAR[alpn]] be the [[ALPN protocol name]] obtained by the TLS handshake.
= [872] Let [VAR[version]] be the [[TLS]] protocol version in use.
= [873] Let [VAR[cipher]] be the [[cipher suite]] and parameters in use.
= [866] If [VAR[alpn]] is [[null]] or [CODE[http/1.1]]:
== [867] Set [VAR[protocol]] to [CODE[http1]].
= [868] Otherwise, if [VAR[alpn]] is [CODE[h2]]:
== [869] Set [VAR[protocol]] to [CODE[http2]].
== [885] If one of the following conditions is met:
[FIG(list)[
- [887] [VAR[version]] is [CODE[1.0]] or [CODE[1.1]]
- [888] [VAR[cipher]]'s [[cipher suite]] is blacklisted by the [[HTTP/2]] specification
- [890] [VAR[cipher]]'s parameter is disallowed by the [[HTTP/2]] specification
]FIG]
===
@@ connection error [CODE[INADEQUATE_SECURITY]]
=== [886] Return a [[failure]] and abort these steps.
= [870] Otherwise:
== [871] Return a [[failure]] and abort these steps.
= [874] Let [VAR[certs]] be the received [[certificates][certificate]].
= [876] Let [VAR[ev]] be whether [VAR[certs]] contain a valid [[EV certificate]] or not.
= [985] Let [VAR[ocsp]] be the [[OCSP stapling]] response, if any, or [[null]].
= [993] For each [VAR[cert]] in [VAR[certs]]'s [[CA certificates][CA certificate]]:
== [994] If the result of running the [[certificate revocation verification steps]]
with [VAR[certificate]] set to [VAR[cert]], [VAR[certificate type]] set to ''CA certificate'',
and [VAR[ocsp]] set to [[null]], is [[false]]:
== [704] Return a [[failure]] and abort these steps.
= [862] If the result of running the [[certificate revocation verification steps]]
with [VAR[certificate]] set to [VAR[certs]]'s [[end entity certificate]],
[VAR[certificate type]] set to ''end entity'', and [VAR[ocsp]], is [[false]]:
== [704] Return a [[failure]] and abort these steps.
= [705] Apply [[PKP]] verification for [VAR[certs]] and [VAR[url]]'s [F[host]]
in [VAR[user agent]].
= [860] Let [VAR[tls transport]] be a new [[transport]] that represents the [[TLS connection]],
with following states:
[FIG(list members)[ [1423] [[Transport][transport]]

: [F[protocol][transport's protocol]] : [CODE[tls]]
: [F[endpoint type][transport's endpoint type]] : [CODE[client]]
: [F[http protocol][transport's http protocol]] : [VAR[protocol]]
: [F[is ev]] : [VAR[ev]]
: [F[remote certificates]] : [VAR[certs]]

]FIG]
= [859] Set [VAR[tls transport]]'s [F[HTTPS state][transport's HTTPS state]]
to [CODE[modern]] or [CODE[deprecated]], as determined by an implementation dependent
algorithm whose inputs are [VAR[version]], [VAR[cipher]], [VAR[certs]],
and whether there are TLS warnings or not.
= [906] Return [VAR[tls transport]].
]FIG]

@@ [1376] If [VAR[[CODE[acceptSslCerts]]]] flag is set, ignore verification errors.

;; [941] When [[SNI]] host is [[null]], the [[TLS]] client is not expected to
send any [[SNI]] [[extension][TLS extension]] in the handshake.

[895] The [DFN[certificate revocation verification steps]] for
[VAR[certificate]] (a [[certificate]]),
[VAR[certificate type]] (''CA certificate'' or ''end entity certificate''), and
[VAR[ocsp]] (an [[OCSP response]] or [[null]]) are these steps:
[FIG(steps)[
= [864] If the [[user agent]]'s [F[certificate database]] knows whether
[VAR[cert]] has been revoked or not:
== [875] Return [[true]] if [VAR[cert]] has been revoked,
or [[false]] otherwise, and abort these steps.
= [937] If [VAR[ocsp]] is a valid [[OCSP]] response:
== [999] Return [[true]] if [VAR[cert]] has been revoked according to [VAR[ocsp]],
or [[false]] otherwise, and abort these steps.
= [989] Otherwise, if [VAR[cert]] has the [[OCSP must-staple]] option enabled:
== [940] Return [[false]] and abort these steps.
= [990] Let [VAR[duration]] be [VAR[cert]]'s [F[[CODE[notAfter]]]] timestamp - 
[VAR[cert]]'s [F[[CODE[notBefore]]]] timestamp.
= [991] If [VAR[duration]] is less than 10 days (i.e. [VAR[cert]] is a [[short-lived certificate]]):
== [992] Return [[true]] and abort these steps.
= [863] Let [VAR[ocsp url]] be [VAR[cert]]'s [[OCSP]] [[URL]].
= [995] If [VAR[ocsp url]] is not [[null]],
the implementation [MAY[MAY]] run these substeps:
== [996] Send an [[OCSP]] request for [VAR[cert]] to [VAR[ocsp url]].
Set [VAR[ocsp]] to the result.
== [997] If [VAR[ocsp]] is a valid [[OCSP]] response:
=== [986] Let [VAR[result]] be [[true]] if [VAR[cert]] has been revoked according to [VAR[ocsp]],
or [[false]] otherwise.
=== [998] [MAY[Optionally]], save [VAR[result]] to the [[user agent]]'s 
[F[certificate database]] as the cached verification result for [VAR[cert]].
=== [988] Return [VAR[result]] and abort these steps.
=
@@ unset EV flag (and set HTTPS state to deprecated?)
= [987] Return [[true]].
]FIG]

;; [523] These steps asynchronously return.

@@ [938] [[HTTPS state]] steps

@@ [939] is EV flag

[384] A [[user agent]] has [F[[[TLS session]] cache]] and
[F[certificate database]].

-*-*-

[923] A TLS server, whenever its underlying transport accepts a connection,
[MUST[MUST]] run these steps:

[FIG(steps)[
= [928] Assert: The underlying transport protocol is 
TCP or Unix domain socket.
= [925] Let [VAR[transport]] be the result of running
[[TCP after accept steps]], if the underlying transport protocol is TCP, or
[[Unix domain socket after accept steps]], otherwise.
= [1424] Start TLS over [VAR[transport]].
=- [706] Optionally, perform implementation dependent verification of the client certificates.
=-
@@ OCSP stapling
=
@@ If failed, ...
= [1433] Let [VAR[protocol]] be [CODE[http/1.1]].
=
@@ ALPN: H2
= [1431] Let [VAR[certs]] be the received [[certificates][certificate]].
= [1426] Let [VAR[tls transport]] be a new [[transport]] that represents the 
[[TLS connection]], with following states:
[FIG(list members)[ [1430] [[Transport][transport]]

: [F[protocol][transport's protocol]] : [CODE[tls]]
: [F[endpoint type][transport's endpoint type]] : [CODE[server]]
: [F[http protocol][transport's http protocol]] : [VAR[protocol]]
: [F[remote certificates]] : [VAR[certs]]

@@
- [[TLS]] の版
- 選択された [[cipher suite]] と引数
- [[SNI]] ホスト名
]FIG]
=
@@ Verify TLS version and cipher suites.
= [1434] Return [VAR[transport]].
]FIG]

;; [1427] These steps asynchronously return.

-*-*-

[707] [VAR[transport]]からバイトを受信したら、[[バイト]]と[[緊急データ]]フラグを [[TLS]] に従い処理します。

[708] [[closure alert]] を受信したら、次のようにします。
[FIG(steps)[
= [709] 正常終了の受信を通知します。
]FIG]

[710] [[error alert]] を受信したら、次のようにします。
[FIG(steps)[
= [891] Set [VAR[connection]]'s [F[has alert]] to [[true]].
= [711] [[alert level]] が[[警告]] and [VAR[user agent]] does not have
[[HSTS policy]] or pin for [VAR[url]]'s [F[host]]:
== [712] 警告を通知します。
= [713] それ以外なら、
== [714] [VAR[送信閉じ済みフラグ]]を設定します。
== [715] [VAR[受信閉じ済みフラグ]]を設定します。
== [716] 中断を通知します。リセットフラグを設定します。
]FIG]

[717] [VAR[transport]]から正常終了を受信したら、次のようにします。
[FIG(steps)[
= [718] [VAR[受信閉じ済みフラグ]]が設定されていなければ、
== [719] [VAR[受信閉じ済みフラグ]]を設定します。
== [720] 正常終了の受信を通知します。
]FIG]

[721] [VAR[transport]]から中断を受信したら、次のようにします。
[FIG(steps)[
= [722] [VAR[受信閉じ済みフラグ]]と[VAR[送信閉じ済みフラグ]]のどちらかが未設定なら、
== [723] [VAR[送信閉じ済みフラグ]]を設定します。
== [724] [VAR[受信閉じ済みフラグ]]を設定します。
== [725] 中断を通知します。
]FIG]

[726] バイトの送信は、 [[TLS]] に従い処理します。

[727] バイトを送信できるかどうかは、新たなバイトを入力として [[TLS]]
で処理できるかどうかとします。

[728] 正常終了の送信の指示があれば、次のようにします。
[FIG(steps)[
= [729] [[closure alert]] を送信します。
= [730] [VAR[transport]]に正常終了の送信を指示します。
]FIG]

[731] 中断の指示があれば、[VAR[transport]]に中断を指示します。

[732] [[TLS]] の処理によりバイト列を送信するべきときは、
[VAR[transport]]で指定されたバイト列を送信します。

@@
[889] TLS renegotiation:
If protocol is http2 and after preface, connection error PROTOCOL_ERROR

[733] [[TLS]] の最初の [[handshake]] 
または[[再折衝]]により[[クライアント証明書]]を要求された時は、
次のようにします。
[FIG(steps)[
= [734] challenge の受信を通知します。
[FIG(list members)[
: [VAR[transport]] : [VAR[transport]]
:challenge:(サーバーなら) [CODE(HTTP)@en[[[ClientHello]]]]
や (クライアントなら) [CODE(HTTP)@en[[[CertificateRequest]]]]
に含まれる情報のうち必要なもの。
]FIG]
]FIG]

[735] credentials の送信は、次のようにします。
[FIG(steps)[
= [736] [[TLS]] が [[credentials]] を受け付ける状態でなければ、例外を投げて停止します。
= [737] そうでなければ、与えられた [[credentials]] を [[TLS]] の処理に引渡します。
]FIG]

* HTTP/1

[355] An [DFN[HTTP connection]] has following states:
[FIG(list members)[
: [DFN[[F[endpoint type][connection's endpoint type]]]] : [CODE[client]] or [CODE[server]].
: [DFN[[F[transport][connection's transport]]]] : A [[transport]].
]FIG]

[34] An [[HTTP connection]] whose [F[protocol][connection's protocol]] is [CODE[http1]]
has following additional states:

[FIG(list members)[
:[VAR[状態]]:後述の状態遷移における状態のいずれか。初期値は「初期」。
: [F[write mode]] : 
One of [CODE[null]], "raw", "websocket", or "sent".  Initially, [CODE[null]].
: [F[to be closed]] :
A [[boolean]].  Initially, [[false]].
:[VAR[要求]]:[[要求]]か null。初期値は null です。
:[VAR[応答]]:[[応答]]か null。初期値は null です。
:[VAR[一時バッファー]]:バイト列。初期値は空。
:[VAR[最後のヘッダー]]:ヘッダーか null
:[VAR[残り長さ]]:[[非負整数]]か null か「chunked」かエラー。
: [F[response received][connection's response received]] :
A [[boolean]].  Initially, '''[[true]]'''.
:[VAR[要求の転送済]]:[[非負整数]]。初期値は 0。
:[VAR[要求の処理完了]]:[[Promise]] か null。初期値は null。
: [DFN[[F[WebSocket key]]]] : A byte string or [CODE[null]].  Initially, [CODE[null]].
:[VAR[WebSocket接続の状態]]:[CODE[CONNECTING]]、[CODE[OPEN]]、
[CODE[CLOSING]]、null のいずれか。初期値は null。
:[VAR[フレーム]]:[[WebSocketフレーム]]または null。初期値は null。
: [F[WebSocket data type]] : [[Text]], [[Binary]], or [CODE[null]].
Initially, [CODE[null]].
: [F[decoder][connection's decoder]] : A [CODE(DOMi)@en[TextDecoder]] or [CODE[null]]. 
Initially, [CODE[null]].
: [F[exit status][connection's exit status]] :  An [[exit status]] or [[null]].
Initially, [[null]].
:[VAR[切断タイマー]]:タイマー。
: [DFN[[F[stream request method]]]] : A byte string or [CODE[null]].  Initially, [CODE[null]].
: [DFN[[F[stream WebSocket subprotocols]]]] : An [[ordered set]] of zero or more byte strings.
Initially, an [[empty][list empty]] set.
: [DFN[[F[stream received]]]] : A [[boolean]].  Initially, [[false]].
: [DFN[[F[stream sent]]]] : A [[boolean]].  Initially, [[false]].
]FIG]

[314] タイマーは、初期状態では動作していません。時間と動作が設定されると、
指定時間経過後に指定の動作が実行されます。既に設定された動作は取り消され、実行されません。

[62] [[要求]]は、次のようなデータ構造です。
[FIG(list members)[
[FIGCAPTION[
[[要求]]
]FIGCAPTION]
:[[要求メソッド]]:バイト列。
:[[要求対象]]:バイト列。
:[[プロトコルの版]]:[CODE[1.1]]。
:[[ヘッダーリスト]]:0個以上の[[ヘッダー]]のリスト。
:[[本体]]:バイト列。初期値は空。
: [F[mode][request mode]] : A [[mode][request mode]] value.
: [DFN[[F[WebSocket subprotocols]]]] : An [[ordered set]] of zero or more byte strings.
Initially, an [[empty][list empty]] list.
]FIG]

[63] [[応答]]は、次のようなデータ構造です。
[FIG(list members)[
[FIGCAPTION[
[[応答]]
]FIGCAPTION]
:[[プロトコルの版]]:[CODE[0.9]], [CODE[1.0]], [CODE[1.1]] のいずれか。初期値は [CODE[0.9]]。
:[[状態符号]]:[[非負整数]]。初期値は [CODE[200]]。
:[[理由句]]:[[バイト列]]。初期値は [CODE[OK]]。
:[[ヘッダーリスト]]:0個以上の[[ヘッダー]]のリスト。初期値は空。
: [DFN[[F[incomplete message][response's incomplete message]]]] :
A [[boolean]].  Initially, [[false]].
]FIG]

** アプリケーションからの指示

[42] 要求の送信は、次のようにします。この処理は、
[VAR[connection]] and [[要求]]である[VAR[送信する要求]]を入力として受け取ります。

[FIG(steps)[
= [90] Assert: The following conditions have to be [[true]]:
[FIG(list)[
- [93] [VAR[送信する要求]]'s [[要求メソッド]]が空ではない。
- [94] [VAR[送信する要求]]'s [[要求メソッド]]に 0x09, 0x0A, 0x0D, 0x20 が含まれない。
- [95] [VAR[送信する要求]]'s [[要求対象]]が空ではない。
- [96] [VAR[送信する要求]]'s [[要求対象]]に 0x0A, 0x0D が含まれない。
- [97] [VAR[送信する要求]]'s [[要求対象]]の先頭と末尾が 0x09, 0x20 でない。
- [99] [VAR[送信する要求]]'s すべての[[ヘッダー]]について、
-- [100] 名前に 0x3A が含まれない。
-- [101] 名前が空ではない。
-- [103] 名前に 0x0A, 0x0D が含まれない。
-- [102] 名前の先頭と末尾が 0x09, 0x20 でない。
-- [104] 値に 0x0A, 0x0D が含まれない。
-- [105] 値の先頭と末尾が 0x09, 0x20 でない。
- [298] [VAR[送信する要求]]'s [CODE(HTTP)@en[[[Transfer-Encoding:]]]] [[ヘッダー]]がない。
- [91] If [VAR[送信する要求]]'s [F[mode][request mode]] is [CODE[websocket]]:
-- [92] [VAR[送信する要求]]'s [[本体]] is empty.
- [1334] For each [VAR[protocol]] in [VAR[送信する要求]]'s [F[WebSocket subprotocols]]:
-- [1335] [VAR[protocol]] does not contain [N[0x09]], [N[0x0A]], [N[0x0D]], or [N[0x20]].
- [261] [VAR[送信する要求]]'s [[本体]]が空の場合、
-- [262] [VAR[送信する要求]]'s [CODE(HTTP)@en[[[Content-Length:]]]] [[ヘッダー]]がないか、値が [CODE[0]] である。
- [267] [VAR[送信する要求]]'s [[本体]]が空でない場合、
-- [263] [VAR[送信する要求]]'s [CODE(HTTP)@en[[[Content-Length:]]]] [[ヘッダー]]があって、値が[[本体]]のバイト数である。
- [251] [VAR[connection]]'s [F[endpoint type]] is [CODE[client]].
- [74] [VAR[connection]]'s [F[to be closed]] flag is [[true]].
- [58] [VAR[状態]]が「初期」か「要求待ち」.
]FIG]
= [61] [VAR[要求]]を、[VAR[送信する要求]]に設定します。
= [135] Set [VAR[connection]]'s [F[stream request method]] to [VAR[送信する要求]]'s [F[要求メソッド]].
= [64] [VAR[応答]]を、新しい[[応答]]に設定します。
= [60] [VAR[一時バッファー]]を、空バイト列に設定します。
= [59] [VAR[状態]]を、「応答前」に設定します。
= [77] [VAR[要求]]に [CODE(HTTP)@en[[[Connection:]]]] [[ヘッダー]]があって
[CODE(HTTP)@en[[[close]]]] ([[ASCII大文字・小文字不区別]]) [[接続オプション]]が指定されていれば、
== [78] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
= [98] If [VAR[要求]]'s [F[mode][request mode]] is [CODE[websocket]]:
== [258] Set [VAR[connection]]'s [VAR[WebSocket接続の状態]] to [CODE[CONNECTING]].
== [1331] Set [VAR[connection]]'s [F[WebSocket key]] be a nonce consisting of a randomly selected 16-byte value that has been [[forgiving-base64 encode]]d.
== [265] [[Append][append (header list)]] 
`[CODE[Sec-WebSocket-Key]]`/[VAR[connection]]'s [F[WebSocket key]]
to [VAR[要求]]'s [F[header list][request's header list]].
== [266] [[Append][append (header list)]] `[CODE[Sec-WebSocket-Version]]`/`[CODE[13]]` 
to [VAR[要求]]'s [F[header list][request's header list]].
== [1332] For each [VAR[protocol]] in [VAR[要求]]'s [F[WebSocket subprotocols]],
[[combine][combine (header list)]] `[CODE[Sec-WebSocket-Protocol]]`/[VAR[protocol]]
in [VAR[要求]]'s [F[header list][request's header list]].
== [264] 
@@ Let [VAR[permessageDeflate]] be a user-agent defined "[CODE[permessage-deflate]]"
extension header value.
== [1333] [[Append][append (header list)]] 
`[CODE[Sec-WebSocket-Extensions]]`/[VAR[permessageDeflate]] to 
[VAR[要求]]'s [F[header list][request's header list]].
== [57] Set [VAR[connection]]'s [F[write mode]] to "websocket".
== [241] Set [VAR[connection]]'s [F[stream WebSocket subprotocols]] to [VAR[要求]]'s
[F[WebSocket subprotocols]].
= [491] Otherwise, if [VAR[connection]]'s [F[stream request method]] is [CODE[CONNECT]]:
== [498] Set [VAR[connection]]'s [F[write mode]] to "before tunnel data".
= [35] Otherwise:
== [57] Set [VAR[connection]]'s [F[write mode]] to "raw".
= [45] [VAR[要求の処理完了]]を、新しい [[Promise]] に設定します。
= [48] [VAR[要求の処理完了]]を返します。
= [46] [[並列に]]、[VAR[要求]]のバイト列の送信を行います。
]FIG]

[25] ここで[VAR[要求]]のバイト列の送信は、次のようにします。

[FIG(steps)[
= [47] [[HTTP/1.1]] に従い[VAR[要求]]の[[ヘッダー部]] (空行の [CODE[CRLF]] まで)
を表す[[バイト列]]の各[[バイト]]を順に、
== [VAR[connection]]'s [F[transport][connection's transport]] で[[バイト]]の送信を指示します。
== エラーが返されたら、ここで停止します。
= [1] [VAR[要求]]の[[メッセージ本体]]が存在する場合、各[[バイト]]を順に、
== [VAR[connection]]'s [F[transport][connection's transport]] で[[バイト]]の送信を指示します。
== エラーが返されたら、ここで停止します。
== [VAR[要求の転送済]]を、1だけ大きな値に設定します。
== [VAR[要求]]について要求の本体の一部の送信を通知して構いません。
= [75] Run the [[sent steps]] for [VAR[connection]].
]FIG]

[259] [[WebSocket]] メッセージ送信は、次のようにします。
この処理は、[[バイト列]]である[VAR[データ]]と、[[テキスト]]または[[バイナリー]]のいずれかの[VAR[種別]]を引数として受け取ります。
[FIG(steps)[
= [278] 前提として、次の条件を満たす必要があります。
[FIG(list)[
- [289] [VAR[データ]]の長さは 2[SUP[63]] [[未満]]かつ実装の扱える範囲内である
]FIG]
= [271] [VAR[WebSocket接続の状態]]が [CODE[[[OPEN]]]] でなければ、
エラーを返して停止します。
= [268] [[WebSocketフレーム]]を作成します。
[FIG(list members)[
:[[FIN]]:1
:[[RSV1]]:0
:[[RSV2]]:0
:[[RSV3]]:0
:[[opcode]]:[VAR[種別]]がテキストなら 1、バイナリーなら 2
:[[mask]]:1
:[[長さ]]:[VAR[データ]]のバイト数
:[[マスクキー]]:無作為に決定した4バイトのバイト列
:データ:[VAR[データ]]
]FIG]
= [269] 作成した [[WebSocketフレーム]]のデータの各[[バイト]]について、
先頭から [VAR[i]] バイト目 (先頭が0バイト) であれば、
[[マスクキー]]の [VAR[i]] [[mod]] 4 バイト目 (先頭が0バイト)
と [[XOR]] した結果に差し替えます。
= [270] [VAR[connection]]'s [F[transport][connection's transport]] で [[WebSocketフレーム]]のバイト列を送信することとします。
]FIG]

[260] ping 送信は、次のようにします。
この処理は、バイト列である[VAR[データ]]と、[VAR[応答]]フラグを受け取ります。
[FIG(steps)[
= [287] 前提として、次の条件を満たす必要があります。
[FIG(list)[
- [288] [VAR[データ]]の長さは 2[SUP[63]] [[未満]]かつ実装の扱える範囲内である
]FIG]
= [272] [VAR[WebSocket接続の状態]]が [CODE[[[OPEN]]]] でなければ、
エラーを返して停止します。
= [273] [[WebSocketフレーム]]を作成します。
[FIG(list members)[
:[[FIN]]:1
:[[RSV1]]:0
:[[RSV2]]:0
:[[RSV3]]:0
:[[opcode]]:[VAR[応答]]フラグが設定されていれば 10、されていなければ 9
:[[mask]]:1
:[[長さ]]:データのバイト数
:[[マスクキー]]:無作為に決定した4バイトのバイト列
:データ:指定されたバイト列
]FIG]
= [274] 作成した [[WebSocketフレーム]]のデータの各[[バイト]]について、
先頭から [VAR[i]] バイト目 (先頭が0バイト) であれば、
[[マスクキー]]の [VAR[i]] [[mod]] 4 バイト目 (先頭が0バイト)
と [[XOR]] した結果に差し替えます。
= [275] [VAR[connection]]'s [F[transport][connection's transport]] で [[WebSocketフレーム]]のバイト列を送信することとします。
]FIG]

[107] If a request whose [F[method]] is [CODE[CONNECT]] has been sent and
a response whose [F[status]] is [CODE[200]] has been received, and
the connection is not yet closed,
one or more bytes can be sent over the connection.
That is, to send a byte string [VAR[bytes]] over [[tunnel]] connection [VAR[connection]],
run these steps:

[FIG(steps)[
= [335] Assert:
@@ In CONNECT mode
= [109] [VAR[connection]]'s [F[transport][connection's transport]] で
[VAR[bytes]] の送信を指示します。
= [110] エラーが返されたら、ここで停止します。
]FIG]

[1443] To close a [[tunnel]] connection [VAR[connection]], run these steps:

[FIG(steps)[
= [1444] Run the [[sent steps]] for [VAR[connection]] with [VAR[close]] flag set to [[true]].
]FIG]

[50] WebSocket connection の正常終了は、次のようにします。引数として[[非負整数]]または null
である[VAR[状態符号]]と、
[[バイト列]]である[VAR[理由]]を受け取ります。

[FIG(steps)[
= [286] Assert:
[FIG(list)[
- [321] [VAR[WebSocket接続の状態]]が [CODE[OPEN]] or [CODE[CLOSING]]
- [285] [VAR[状態符号]]は2[SUP[16]] [[以下]]
- [283] [VAR[理由]]の長さは 2[SUP[63]] [[未満]]かつ実装の扱える範囲内である
- [276] [VAR[状態符号]]が null なら、[VAR[理由]]は空である
]FIG]
= [49] If [VAR[WebSocket接続の状態]] is [CODE[CLOSING]]:
== [277] Abort these steps.
= [281] [[WebSocketフレーム]]を作成します。
[FIG(list members)[
:[[FIN]]:1
:[[RSV1]]:0
:[[RSV2]]:0
:[[RSV3]]:0
:[[opcode]]:8
:[[mask]]:1
:[[長さ]]:データのバイト数
:[[マスクキー]]:無作為に決定した4バイトのバイト列
:データ:[VAR[状態符号]]が null なら空、
そうでなければ、[VAR[状態符号]]を表す[[16ビット符号無し整数]] ([[ネットワークバイト順]]) と、
それに続けて[VAR[理由]]
]FIG]
= [282] 作成した [[WebSocketフレーム]]のデータの各[[バイト]]について、
先頭から [VAR[i]] バイト目 (先頭が0バイト) であれば、
[[マスクキー]]の [VAR[i]] [[mod]] 4 バイト目 (先頭が0バイト)
と [[XOR]] した結果に差し替えます。
= [297] [VAR[WebSocket接続の状態]]を、 [CODE[[[CLOSING]]]] に設定します。
= [174] [VAR[要求]]について、 [CODE[wsclosing]] を通知します。
= [284] [VAR[connection]]'s [F[transport][connection's transport]] で、作成した [[WebSocketフレーム]]のバイト列を送信することとします。
= [315] [VAR[切断タイマー]]により20s後に次の要求に進むことにします。
]FIG]

[73] To close connection [VAR[connection]], run these steps:

[FIG(steps)[
= [108] Assert: 
@@ Not sending a body, CONNECT, or WS mode
= [72] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
= [66] [VAR[状態]]が「初期」か「要求待ち」なら、
== [55] [VAR[connection]]'s [F[transport][connection's transport]] で正常終了の送信を指示します。
]FIG]

[52] [[接続]]の中断は、次のようにします。

[FIG(steps)[
= [39] Set the [VAR[connection]]'s [F[exit status][connection's exit status]] to a new
[[exit status]] whose [F[失敗]] is [[true]].
= 
@@ Abort the writable stream
= [44] Run the [[sent steps]] for [VAR[connection]] with [VAR[close]] flag set to [[true]].
=
@@ Cancel the readable stream
]FIG]

** アプリケーションへの通知

[11] [[状態機械]]は、[[要求]]について次の通知を行います。
それぞれ、次に示す[[引数]] (あれば) 付きで通知されます。
[FIG(list)[
- 要求の本体の一部の送信の通知
[FIG(list members)[
:[[転送済]]:[VAR[要求の転送済]]。
]FIG]
- [526] 要求の送信完了の通知
-- [527] [[要求]]全体の送信が完了したことの通知です。
[[WebSocket]] や [CODE(HTTP)@en[[[CONNECT]]]] [[要求]]では、
[[要求ヘッダー]]後の[[空行]]まで送信した時点で発火されます。
- 応答のヘッダー受信完了の通知
[FIG(list members)[
:[[応答]]:[VAR[応答]]。
: [VAR[WebSocket connection established]] : A [[boolean]].  Initially, [[false]].
]FIG]
- [377] [CODE[datastart]] の通知
[FIG(list members)[
: [VAR[data type]] : [[Text]] or [[Binary]].  Initially, [[Text]].
]FIG]
-- [535] When a [[response body]] is started, [[tunnel]] has opened,
or a [[WebSocket message]] is started.
- [528] [CODE[data]] の通知
[FIG(list members)[
: [VAR[data]] : A [[string]] or a [[byte string]].
]FIG]
-- [529] When a chunk of data is received as part of [[response body]],
[[tunnel]], or [[WebSocket message]].
- [378] [CODE[dataend]] の通知
-- [536] When a [[response body]] is ended, [[tunnel]] has closed,
or a [[WebSocket message]] is ended.
- [250] ping の通知
[FIG(list members)[
:返答:[[真]]か[[偽]]。既定値は[[偽]]。
:データ:[[バイト列]]。既定値は空。
]FIG]
- [329] [CODE[wsclosing]] の通知
-- [317] When a [[WebSocket]] [[Close frame]] is sent or received for the first time.
- [358] 完了の通知
[FIG(list members)[
:[[応答]]:[VAR[応答]]。
: [VAR[exit status]] : A [[exit status]].
]FIG]
]FIG]

[15] 各[[要求]]について、2種類の送信の通知と3種類の受信の通知をそれぞれこの順序で行うか、
その途中で失敗の通知で中断するかのいずれかです。
送信の通知と受信の通知はどちらもそれぞれ進行し、相互の順序は不定です。
送信の完了は通知されないことがあります (失敗の場合)。
[CODE[data]] の通知は、0回以上の任意の回数行います。
[CODE[data]] の通知のかわりに 0回以上の ping の通知がある場合があります。
[[トンネル]]では最初に [CODE[datastart]] の通知、最後に [CODE[dataend]] の通知があります。
完了の通知の前に、 [CODE[wsclosing]] の通知があるかもしれません。

[FIG(flow)[
:initial:要求の送信
:v:
:>>:3
:->:reqbody
:->:reqeof
:->:headers
:->:rerror
:->:reset

:reqbody:本体一部送信
:->:reqbody
:->:reqeof
:v:
:>>:2
:->:rerror
:->:reset

:reqeof:送信完了
:v:
:>>:1
:->:reset

:headers:ヘッダー受信
:v:
:>>:3
:->:body
:->:complete
:->:reset

:body:受信
:v:
:>>:4
:->:complete
:->:body
:->:reset

:complete:完了 (成功)
:v:
:>>:3

:reset:完了 (失敗)
:>>:5

]FIG]

;; [253] 図の「受信」は、 [CODE[data]] 、ping の受信、 [CODE[wsclosing]],
[CODE[datastart]], [CODE[dataend]] を表します。

** The state machine

[68] [[クライアント]]は[[状態機械]]を持ちます。

[53] [VAR[connection]]'s [F[transport][connection's transport]] の[[バイト]]受信の通知があると、次のようにします。
ただし、[VAR[状態]]が「初期」なら、[VAR[状態]]が変化するまで待ってから実行します。
[FIG(steps)[
= [14] [[緊急データ]]フラグが設定されていなければ、
== [37] [VAR[状態]]により決まる処理を行います。
]FIG]

[40] 正常終了の受信の通知があると、次のようにします。
[FIG(steps)[
= [54] [VAR[状態]]により決まる正常終了処理を行います。
]FIG]

[13] 中断の通知があると、次のようにします。
[FIG(steps)[
= [359] リセットフラグが設定されていれば、
== [328] [[Connection error][connection error]] [VAR[connection]] with a new
[[exit status]] whose [F[リセット]] and [F[失敗]] are [[true]].
= [41] Otherwise:
== [525] [VAR[状態]]により決まる中断処理を行います。
]FIG]

[252] [[WebSocketフレーム]]は、次のようなデータ構造です。
[FIG(list members)[
[FIGCAPTION[
[[WebSocketフレーム]]
]FIGCAPTION]
:[[FIN]]:0 か 1。
:[[RSV1]]:0 か 1。
:[[RSV2]]:0 か 1。
:[[RSV3]]:0 か 1。
:[[opcode]]:0-15 の[[整数]]。
:[[mask]]:0 か 1。
:長さ:[[非負整数]]。
:マスクキー:4バイトの[[バイト列]]または null。
:データ:[[バイト列]]または[[文字列]]。
]FIG]

*** 「初期」状態

[69] 正常終了か中断を受信したら、
[FIG(steps)[
= [366] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
whose [F[失敗]] is 中断.
]FIG]

*** 「要求待ち」状態

[2] バイトを受信したら、何もせずに無視します。

[33] 正常終了か中断を受信したら、
[FIG(steps)[
= [326] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
whose [F[失敗]] is 中断.
]FIG]

*** 「要求送信中」状態

[56] バイトを受信したら、何もせずに無視します。

[67] 正常終了 or 中断を受信したら、
[FIG(steps)[
= [360] If 失敗:
== [76] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
= [361] Otherwise:
== [368] 次の要求に進みます。
]FIG]

*** 「応答前」状態

[24] バイトを受信したら、
[FIG(steps)[
= [130] Set [VAR[connection]]'s [F[response received][connection's response received]] to [[true]].
= [26] 受信したバイトを、[VAR[一時バッファー]]の末尾に連結します。
= [27] [VAR[一時バッファー]]の末尾4バイトが [CODE(HTTP)[HTTP]]
([[ASCII大文字・小文字不区別]]) なら、
== [VAR[応答]]の[[プロトコルの版]]を 1.0 に設定します。
== [VAR[状態]]を、「応答ヘッダー」に設定します。
== [VAR[一時バッファー]]を、空に設定します。
= [28] それ以外で、[VAR[一時バッファー]]の長さが8バイトなら、
== [236] If [VAR[connection]]'s [F[stream request method]] is [CODE[PUT]] or
[CODE[CONNECT]]:
=== [320] [[Connection error][connection error]] [VAR[connection]].
== [237] Otherwise:
=== [367] [VAR[要求]]について [CODE[datastart]] を通知します。
=== [922] [VAR[要求]]について [CODE[data]] を通知します。[VAR[一時バッファー]]を引渡します。
=== [452] [VAR[残り長さ]]を、 null に設定します。
=== [485] [VAR[状態]]を、「応答本体」に設定します。
]FIG]

[8] 正常終了か中断を受信したら、
[FIG(steps)[
= [132] [VAR[一時バッファー]]が[[空文字列]]なら、
== [133] Let [VAR[exit status]] be a new [[exit status]] whose [F[失敗]] is [[true]].
== [434] If not 中断 and [VAR[connection]]'s [F[response received][connection's response received]] is [[false]]:
=== [915] Set [VAR[exit status]]'s [F[can retry][exit's can retry]] to [[true]].
== [136] [[Connection error]] [VAR[connection]] with [VAR[exit status]].
= [240] If [VAR[connection]]'s [F[stream request method]] is [CODE[PUT]] or
[CODE[CONNECT]]:
== [363] [[Connection error][connection error]] [VAR[connection]].
= [924] Otherwise:
== [280] Run the [[headers received steps]] for [VAR[connection]].
== [920] [VAR[要求]]について [CODE[datastart]] を通知します。
== [530] [VAR[要求]]について [CODE[data]] を通知します。[VAR[一時バッファー]]を引渡します。
== [918] 中断なら、
=== [919] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
== [921] [VAR[要求]]について [CODE[dataend]] を通知します。
== [141] If 中断:
=== [142] [[Connection error][connection error]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
== [322] Otherwise:
=== [926] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
=== [438] 次の要求に進みます。
]FIG]

*** 「応答ヘッダー」状態

[36] バイトを受信したら、
[FIG(steps)[
= [VAR[一時バッファー]]の末尾に受信したバイトを追加します。
= [VAR[一時バッファー]]の末尾が 0x0A 0x0A または 0x0A 0x0D 0x0A なら、
== [137] ヘッダーの処理 (>>138) を行います。
= それ以外で、 [VAR[一時バッファー]]の長さが 2[SUP[18]]‐1 なら、
== [364] [[Connection error][connection error]] [VAR[connection]].
]FIG]

[12] 正常終了か中断を受信したら、
[FIG(steps)[
= [139] [[Connection error][connection error]] [VAR[connection]] with 
a new [[exit status]] whose [F[失敗]] is [[true]].
]FIG]

[138] ヘッダーの処理は、次のようにします。
[FIG(steps)[
= [140] [VAR[一時バッファー]]をヘッダー群として構文解析します。
= [113] [VAR[応答]]の[[プロトコルの版]]が [CODE[1.1]] で、
[CODE(HTTP)@en[[[Transfer-Encoding:]]]] [[ヘッダー]]があって、
[CODE(HTTP)@en[[[chunked]]]] ([[ASCII大文字・小文字不区別]]) が[[転送符号化]]として指定されていれば、
== [114] [VAR[残り長さ]]を、「chunked」に設定します。
= [115] それ以外なら、
== [32] [VAR[残り長さ]]を、[VAR[応答]]の [CODE(HTTP)@en[[[Content-Length:]]]] [[ヘッダー]]の処理の結果とします。
= [448] [VAR[残り長さ]]がエラーなら:
== [449] [[Connection error][connection error]] [VAR[connection]].
= [540] Otherwise, if [VAR[connection]]'s [F[stream request method]] is [CODE[CONNECT]] and
[VAR[応答]]の[[状態符号]]が [CODE(HTTP)[[[200]]]] なら、
== [290] Run the [[headers received steps]] for [VAR[connection]],
with [VAR[tunnel]] flag set to [[true]].
== [374] [VAR[要求]]について [CODE[datastart]] を通知します。
== [375] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
== [376] [VAR[状態]]を、「トンネル」に設定します。
== [362] Set [VAR[残り長さ]] to [CODE[null]].
= [143] それ以外で、[VAR[WebSocket接続の状態]]が [CODE[CONNECTING]] で、
[VAR[応答]]の[[状態符号]]が [CODE(HTTP)[101]] なら、
== [144] If one of following conditions are true:
[FIG(list)[
- [299] [VAR[応答]]に [CODE(HTTP)@en[[[Upgrade:]]]] [[ヘッダー]]が無いか、 
[CODE(HTTP)@en[[[websocket]]]] ([[ASCII大文字・小文字不区別]]) が含まれていない
- [300] [VAR[応答]]に [CODE(HTTP)@en[[[Connection:]]]] [[ヘッダー]]が無いか、 
[CODE(HTTP)@en[[[Upgrade]]]] ([[ASCII大文字・小文字不区別]]) が含まれていない
- [301] [VAR[応答]]に [CODE(HTTP)@en[[[Sec-WebSocket-Accept:]]]] [[ヘッダー]]が無いか、 
値が[VAR[要求]]の [CODE(HTTP)@en[[[Sec-WebSocket-Key:]]]] の値に 
[CODE(HTTP)[[[258EAFA5-E914-47DA-95CA-C5AB0DC85B11]]]] を連結した値の 
[[SHA-1]], [[forgiving-base64 encode]]d でない
- [302] [VAR[応答]]の [CODE(HTTP)@en[[[Sec-WebSocket-Extensions:]]]] 
[[ヘッダー]]が存在する
- [303] 
[VAR[応答]]'s [F[header list][response's header list]] has a
`[CODE(HTTP)@en[Sec-WebSocket-Protocol]]` header and
[VAR[connection]]'s [F[stream WebSocket subprotocols]] does not [[contain][list contain]]
[VAR[応答]]'s [F[header list][response's header list]] has a
`[CODE(HTTP)@en[Sec-WebSocket-Protocol]]` header's value
- [1329] 
[VAR[connection]]'s [F[stream WebSocket subprotocols]] is not [[empty][list empty]] and
[[parsing][parse a header]] `[CODE(HTTP)@en[Sec-WebSocket-Protocol]]`
in [VAR[応答]]'s [F[header list][response's header list]] results in [CODE[null]], 
[[failure]], or the empty byte sequence
]FIG]
... then run these substeps:
=== [294] Run the [[headers received steps]] for [VAR[connection]].
=== [248] Let [VAR[exit status]] be a new [[exit status]]:
[FIG(list members)[
[FIGCAPTION[
[[Exit status][exit status]]
]FIGCAPTION]
:失敗:[[真]]。
:cleanly:[[偽]]。
:[[状態符号]]:[CODE[[[1006]]]]。
:理由:[[空文字列]]。
]FIG]
=== [245] [[Connection error][connection error]] [VAR[connection]] with [VAR[exit status]].
== [146] それ以外なら、
=== [291] [VAR[WebSocket接続の状態]]を、 [CODE[OPEN]] に設定します。
=== [296] Run the [[headers received steps]] for [VAR[connection]],
with [VAR[WebSocket]] flag set to [[true]].
=== [292] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
=== [293] [VAR[状態]]を、「WebSocketフレーム前」に設定します。
=== [147] [VAR[一時バッファー]]を、空に設定します。
= [106] それ以外で、 [VAR[応答]]の[[状態符号]]が [CODE(HTTP)[[[1xx]]]] なら、
== [337] If [VAR[connection]]'s [F[stream request method]] is [CODE[CONNECT]] or
[VAR[WebSocket接続の状態]]が [CODE[CONNECTING]] なら、
=== [224] [[Connection error][connection error]] [VAR[connection]].
== [341] それ以外なら、
=== [342] [VAR[応答]]の[[プロトコルの版]]、[[状態符号]]、[[理由句]]、[[ヘッダーリスト]]を初期値に設定します。
=== [382] [VAR[状態]]を、「応答前」に設定します。
=== [383] [VAR[一時バッファー]]を、空バイト列に設定します。
= [344] それ以外なら、
=== [316] Run the [[headers received steps]] for [VAR[connection]].
== [385] [VAR[要求]]について [CODE[datastart]] を通知します。
== [346] 
[FIG(list)[
- [348] [VAR[応答]]の[[状態符号]]が [CODE(HTTP)[[[204]]]], [CODE(HTTP)[[[205]]]],
[CODE(HTTP)[[[304]]]] のいずれかの場合か、
- [349] [VAR[connection]]'s [F[stream request method]] is [CODE[HEAD]]
]FIG]
... のいずれかの場合、
=== [347] [VAR[残り長さ]]を、0に設定します。
== [87] [VAR[残り長さ]]が 0 なら、
=== [79] [VAR[応答]]に [CODE(HTTP)@en[[[Connection:]]]] [[ヘッダー]]があって
[CODE(HTTP)@en[[[close]]]] ([[ASCII大文字・小文字不区別]]) [[接続オプション]]が指定されていれば、
==== [80] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
=== [81] それ以外で、[VAR[応答]]の[[プロトコルの版]]が [CODE[1.0]] で、
[CODE(HTTP)@en[[[keep-alive]]]] ([[ASCII大文字・小文字不区別]]) [[接続オプション]]が指定された
[CODE(HTTP)@en[[[Connection:]]]] [[ヘッダー]]がなければ、
==== [82] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
=== [343] 次の要求に進みます。
== [116] それ以外で、 [VAR[残り長さ]]が「chunked」なら、
=== [117] [VAR[状態]]を、「塊前」に設定します。
== [88] それ以外なら、
=== [16] [VAR[状態]]を、「応答本体」に設定します。
]FIG]

[295] The [DFN[headers received steps]] for [VAR[connection]], with
optional [VAR[WebSocket]] and [VAR[tunnel]] flags (both defaulted to [[false]])
are these steps:

[FIG(steps)[
= [319] If [VAR[connection]]'s [F[write mode]] is "before tunnel data":
== [256] If [VAR[tunnel]] is [[true]]:
=== [345] Set [VAR[connection]]'s [F[write mode]] to "raw".
== [373] Otherwise:
=== [490] Run the [[sent steps]] for [VAR[connection]].
= [145] [VAR[要求]]について[[応答]]のヘッダー受信完了を通知,
with [VAR[WebSocket connection established]] set to [VAR[WebSocket]].
]FIG]

*** 「応答本体」状態

[6] バイトを受信したら、
[FIG(steps)[
= [451] [VAR[要求]]について [CODE[data]] を通知します。受信したバイトを引渡します。
= [453] [VAR[残り長さ]]が[[正]]なら、
== [454] [VAR[残り長さ]]を1減らします。
== [386] [VAR[残り長さ]]が0なら、
=== [387] [VAR[要求]]について [CODE[dataend]] を通知します。
=== [83] [VAR[応答]]に [CODE(HTTP)@en[[[Connection:]]]] [[ヘッダー]]があって
[CODE(HTTP)@en[[[close]]]] ([[ASCII大文字・小文字不区別]]) [[接続オプション]]が指定されていれば、
==== [84] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
=== [85] それ以外で、[VAR[応答]]の[[プロトコルの版]]が [CODE[1.0]] で、
[CODE(HTTP)@en[[[keep-alive]]]] ([[ASCII大文字・小文字不区別]]) [[接続オプション]]が指定された
[CODE(HTTP)@en[[[Connection:]]]] [[ヘッダー]]がなければ、
==== [86] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
=== [244] 次の要求に進みます。
]FIG]

[7] 正常終了か中断を受信したら、
[FIG(steps)[
= [388] [VAR[残り長さ]]が[[正]]なら、
== [389] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
== [395] [VAR[要求]]について [CODE[dataend]] を通知します。
== [455] Let [VAR[exit status]] be a new [[exit status]].
== [391] [VAR[応答]]の[[プロトコルの版]]が [CODE[1.1]] or 中断:
=== [392] Set [VAR[exit status]]'s [F[失敗]] to [[true]].
== [134] [[Connection error][connection error]] [VAR[connection]] with [VAR[exit status]].
= [390] Otherwise, [VAR[残り長さ is [N[0]]:
== [441] [VAR[要求]]について [CODE[dataend]] を通知します。
== [442] If 中断:
=== [444] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
== [445] Otherwise:
=== [470] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
=== [477] 次の要求に進みます。
= [400] Otherwise:
== [396] If 中断:
=== [916] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
== [401] [VAR[要求]]について [CODE[dataend]] を通知します。
== [397] If 中断:
=== [398] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
== [399] Otherwise:
=== [403] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
=== [404] 次の要求に進みます。
]FIG]

*** 「塊前」状態

[118] バイトを受信したら、
[FIG(steps)[
= [394] [[ASCII十六進数字]]なら、
== [456] [VAR[一時バッファー]]を、指定されたバイトに設定します。
== [457] [VAR[状態]]を、「塊サイズ」に設定します。
= [458] それ以外なら、
== [917] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
== [405] [VAR[要求]]について [CODE[dataend]] を通知します。
== [246] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

[119] 正常終了か中断を受信したら、
[FIG(steps)[
= [459] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
= [407] [VAR[要求]]について [CODE[dataend]] を通知します。
= [254] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

*** 「塊サイズ」状態

[120] バイトを受信したら、
[FIG(steps)[
= [462] [[ASCII十六進数字]]なら、
== [463] [VAR[一時バッファー]]に、指定されたバイトを追加します。
= [464] それ以外なら、
== [465] [VAR[一時バッファー]]を、[[十六進数]]として解釈します。
== [466] [VAR[残り長さ]]を、得られた値に設定します。
== [467] [VAR[残り長さ]]がエラー ([[桁溢れ]]) なら、
=== [468] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
=== [410] [VAR[要求]]について [CODE[dataend]] を通知します。
=== [393] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
== [428] それ以外で、[VAR[残り長さ]]が 0 なら、
=== [431] [VAR[要求]]について [CODE[dataend]] を通知します。
=== [429] [VAR[状態]]を、「trailer 前」に設定します。
=== [430] [VAR[一時バッファー]]を、空に設定します。
== [471] それ以外なら、
=== [472] バイトが 0x0A なら、
==== [473] [VAR[状態]]を、「塊」に設定します。
=== [474] それ以外なら、
==== [475] [VAR[状態]]を、「塊拡張」に設定します。
]FIG]

[122] 正常終了か中断を受信したら、
[FIG(steps)[
= [476] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
= [413] [VAR[要求]]について [CODE[dataend]] を通知します。
= [409] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

*** 「塊拡張」状態

[121] バイトを受信したら、
[FIG(steps)[
= [479] 0x0A なら、
== [480] [VAR[状態]]を、「塊」に設定します。
]FIG]

[123] 正常終了か中断を受信したら、
[FIG(steps)[
= [481] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
= [416] [VAR[要求]]について [CODE[dataend]] を通知します。
= [412] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

*** 「塊」状態

[124] バイトを受信したら、
[FIG(steps)[
= [249] [VAR[要求]]について [CODE[data]] を通知します。受信したバイトを引渡します。
= [486] [VAR[残り長さ]]を1減らします。
= [487] [VAR[残り長さ]]が0なら、
== [488] [VAR[状態]]を、「塊後」に設定します。
]FIG]

[125] 正常終了か中断を受信したら、
[FIG(steps)[
= [489] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
= [419] [VAR[要求]]について [CODE[dataend]] を通知します。
= [415] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

*** 「塊後」状態

[126] バイトを受信したら、
[FIG(steps)[
= [492] 0x0D なら、
== [493] Set [VAR[状態]] to "after chunk CR".
= [494] 0x0A なら、
== [495] [VAR[状態]]を、「塊前」に設定します。
= [496] それ以外なら、
== [497] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
== [422] [VAR[要求]]について [CODE[dataend]] を通知します。
== [418] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

[127] 正常終了か中断を受信したら、
[FIG(steps)[
= [500] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
= [425] [VAR[要求]]について [CODE[dataend]] を通知します。
= [423] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

*** "after chunk CR" state

[1418] When [VAR[byte]] is received:

[FIG(steps)[
= [1419] If [VAR[byte]] is [N[0x0A]]:
== [1420] Set [VAR[状態]] to "塊前".
= [1421] Otherwise:
== [1422] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
== [1425] [VAR[要求]]について [CODE[dataend]] を通知します。
== [427] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

[1428] 正常終了か中断を受信したら、

[FIG(steps)[
= [1429] Set [VAR[connection]]'s [F[response][connection's response]]'s
[F[incomplete message][response's incomplete message]] flag to [[true]].
= [1432] [VAR[要求]]について [CODE[dataend]] を通知します。
= [447] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

*** 「trailer 前」状態

[128] バイトを受信したら、
[FIG(steps)[
= [VAR[一時バッファー]]の末尾に受信したバイトを追加します。
= [VAR[一時バッファー]]の末尾が 0x0A 0x0A または 0x0A 0x0D 0x0A なら、
== [VAR[応答]]に [CODE(HTTP)@en[[[Connection:]]]] [[ヘッダー]]があって
[CODE(HTTP)@en[[[close]]]] ([[ASCII大文字・小文字不区別]]) [[接続オプション]]が指定されていれば、
=== [193] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
== [503] [VAR[終了]]を、新しい終了に設定します。
== [504] 次の要求に進みます。
= それ以外で、 [VAR[一時バッファー]]の長さが 2[SUP[18]]‐1 なら、
== [450] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

[129] 正常終了か中断を受信したら、
[FIG(steps)[
= [461] [[Connection error][connection error]] [VAR[connection]] with a new [[exit status]]
(whose [F[失敗]] is [[false]]).
]FIG]

*** 「WebSocket フレーム前」状態

[148] バイトを受信したら、
[FIG(steps)[
= [VAR[一時バッファー]]の末尾に、受信したバイトを追加します。
= [VAR[一時バッファー]]の長さが2未満なら、ここで停止します。
= [VAR[フレーム]]を、次のような新しい[[WebSocketフレーム]]に設定します。
[FIG(list members)[
:[[FIN]]:[VAR[一時バッファー]]の第1バイトの最上位ビット
:[[RSV1]]:[VAR[一時バッファー]]の第1バイトの上位から第2ビット目
:[[RSV2]]:[VAR[一時バッファー]]の第1バイトの上位から第3ビット目
:[[RSV3]]:[VAR[一時バッファー]]の第1バイトの上位から第4ビット目
:[[opcode]]:[VAR[一時バッファー]]の第1バイトの下位4ビットを[[整数]]としたもの
:[[mask]]:[VAR[一時バッファー]]の第2バイトの最上位ビット
:[[長さ]]:[VAR[一時バッファー]]の第2バイトの下位7ビットを[[整数]]としたもの
]FIG]
= [VAR[フレーム]]の[[長さ]]が126か127で、[[opcode]] が 8 [[以上]]なら、
== 失敗とします。ここで停止します。
= [VAR[フレーム]]の[[長さ]]が126なら、
== [VAR[一時バッファー]]の長さが4以上でなければ、ここで停止します。
== [VAR[フレーム]]の[[長さ]]を、[VAR[一時バッファー]]の第3、第4バイトを[[ネットワークバイト順]]の[[16ビット符号無し整数]]とした値に設定します。
== [VAR[フレーム]]の[[長さ]]が126未満なら、
=== 失敗とします。ここで停止します。
= [VAR[フレーム]]の[[長さ]]が127なら、
== [VAR[一時バッファー]]の長さが10以上でなければ、ここで停止します。
== [VAR[一時バッファー]]の第3バイトの最上位ビットが 1 なら、
=== 失敗とします。ここで停止します。
== [VAR[フレーム]]の[[長さ]]を、[VAR[一時バッファー]]の第3-8バイトを[[ネットワークバイト順]]の[[64ビット符号無し整数]]とした値に設定します。
== [VAR[フレーム]]の[[長さ]]が2[SUP[16]]未満なら、
=== 失敗とします。ここで停止します。
= [VAR[フレーム]]の[[長さ]]が実装の扱える範囲を超えていれば、
== 失敗とします。ここで停止します。
= [VAR[フレーム]]の[[mask]]が設定されていれば、
== [VAR[一時バッファー]]に次の4バイトがなければ、ここで停止します。
== [VAR[フレーム]]の[[マスクキー]]を、[VAR[一時バッファー]]のその4バイトに設定します。
= [150] If [VAR[connection]]'s [F[endpoint type][connection's endpoint type]] is [CODE[server]]
and [VAR[フレーム]]の [[mask]] が 0 なら、
== [153] 理由 [CODE[WebSocket Protocol Error]] で失敗とします。ここで停止します。
= [151] If [VAR[connection]]'s [F[endpoint type][connection's endpoint type]] is [CODE[client]]
and [VAR[フレーム]]の [[mask]] が 1 なら、
== [152] 理由 [CODE[Masked frame from server]] で失敗とします。ここで停止します。
= [154] [VAR[フレーム]]の FIN が 0 で [[opcode]] が 8, 9, 10 なら、
== [155] 失敗とします。ここで停止します。
= [156] [VAR[フレーム]]の RSV1, RSV2, RSV3 のいずれかでも 1 なら、
== [157] 理由 [CODE[Invalid reserved bit]] で失敗とします。ここで停止します。
= [158] [VAR[フレーム]]の [[opcode]] が 3-7, 11-15 なら、
== [159] 理由 [CODE[Unknown opcode]] で失敗とします。ここで停止します。
= [170] If [VAR[connection]]'s [F[WebSocket data type]] is [CODE[null]] and 
[VAR[フレーム]]の [[opcode]] が 0 なら、
== [171] 理由 [CODE[Unexpected continuation]] で失敗とします。ここで停止します。
= [172] If [VAR[connection]]'s [F[WebSocket data type]] is not [CODE[null]] and
[VAR[フレーム]]の [[opcode]] が 1 か 2 なら、
== [173] 理由 [CODE[Previous data frame unfinished]] で失敗とします。ここで停止します。
= [175] If [VAR[フレーム]]'s [F[FIN]] is [N[0]] and [VAR[フレーム]]'s [F[opcode]] is [N[1]]:
== [176] Set [VAR[connection]]'s [F[WebSocket data type]] to [[Text]].
= [181] If [VAR[フレーム]]'s [F[FIN]] is [N[0]] and [VAR[フレーム]]'s [F[opcode]] is [N[2]]:
== [183] Set [VAR[connection]]'s [F[WebSocket data type]] to [[Binary]].
= [195] [VAR[一時バッファー]]を、空に設定します。
= [160] [VAR[フレーム]]の長さが0なら、
== [190] Let [VAR[result]] be result of [[processing a WebSocket frame][process a WebSocket frame]].
== [1361] If [VAR[result]] is [[false]], abort these steps.
== [192] [VAR[フレーム]]を、 null に設定します。
== [191] [VAR[状態]]を、「WebSocket フレーム前」に設定します。
= [161] それ以外なら、
== [196] [VAR[状態]]を、「WebSocket データ」に設定します。
]FIG]

[149] 正常終了か中断を受信したら、
[FIG(steps)[
= [226] [VAR[WebSocket接続の状態]]を、[CODE[CLOSING]] に設定します。
= [227] Set [VAR[connection]]'s [F[exit status][connection's exit status]] to an
[[exit status]]:
[FIG(list members)[
[FIGCAPTION[
[[Exit status][exit status]]
]FIGCAPTION]
:失敗:[[真]]
:cleanly:[[偽]]
:状態符号:[CODE[[[1006]]]]
:理由:[[空文字列]]
]FIG]
= [330] 次の要求に進みます。
]FIG]

*** 「WebSocket データ」状態

[163] バイトを受信したら、
[FIG(steps)[
= [164] [VAR[一時バッファー]]の末尾に、受信したバイトを追加します。
= [165] [VAR[フレーム]]の [[mask]] が1なら、
== [166] [VAR[フレーム]]のマスクキーの先頭から第
(([VAR[一時バッファー]]の長さ - 1) mod 4) バイト (先頭が第0バイトとして数えた時。)
を使って[VAR[一時バッファー]]の末尾のバイトを [[XOR]] したものに置き換えます。
= [167] [VAR[一時バッファー]]の[[長さ]]が[VAR[フレーム]]の[[長さ]]と等しくなければ、
ここで停止します。
= [188] Let [VAR[result]] be result of [[processing a WebSocket frame][process a WebSocket frame]].
= [1362] If [VAR[result]] is [[false]], abort these steps.
= [184] [VAR[フレーム]]を、 null に設定します。
= [185] [VAR[状態]]を、「WebSocket フレーム前」に設定します。
= [186] [VAR[一時バッファー]]を、空に設定します。
]FIG]

@@ permessage-deflate

[162] 正常終了か中断を受信したら、
[FIG(steps)[
= [212] [VAR[WebSocket接続の状態]]を、[CODE[CLOSING]] に設定します。
= [215] Set [VAR[connection]]'s [F[exit status][connection's exit status]] to an
[[exit status]]:
[FIG(list members)[
[FIGCAPTION[
[[Exit status][exit status]]
]FIGCAPTION]
:失敗:[[真]]
:cleanly:[[偽]]
:状態符号:[CODE[[[1006]]]]
:理由:[[空文字列]]
]FIG]
= [331] 次の要求に進みます。
]FIG]

*** 「WebSocket 切断待ち」状態

[217] 「WebSocket フレーム前」状態、「WebSocket データ」状態で失敗するという時、
次のようにします。
[FIG(steps)[
= [229] [VAR[WebSocket接続の状態]]を、[CODE[CLOSING]] に設定します。
= [230] Let [VAR[exit status]] be a new [[exit status]]:
[FIG(list members)[ [440] [[Exit status][exit status]]

:失敗:[[真]]
:cleanly:[[偽]]
:状態符号:[CODE[[[1002]]]]
:理由:指定された理由。指定がなければ [CODE[WebSocket Protocol Error]]。

@@ API exposed status and reason

]FIG]
= [231] [[WebSocketフレーム]]を作成します。
[FIG(list members)[
:[[FIN]]:1
:[[RSV1]]:0
:[[RSV2]]:0
:[[RSV3]]:0
:[[opcode]]:8
:[[mask]]:1
:[[長さ]]:データのバイト数
:[[マスクキー]]:無作為に決定した4バイトのバイト列
:データ: 
[VAR[exit status]]'s [F[状態符号]]を表す[[16ビット符号無し整数]] ([[ネットワークバイト順]]),
followed by [VAR[exit status]]'s [F[理由]] encoded in UTF-8
]FIG]
= [305] 作成した [[WebSocketフレーム]]のデータの各[[バイト]]について、
先頭から [VAR[i]] バイト目 (先頭が0バイト) であれば、
[[マスクキー]]の [VAR[i]] [[mod]] 4 バイト目 (先頭が0バイト)
と [[XOR]] した結果に差し替えます。
= [306] [VAR[connection]]'s [F[transport][connection's transport]] で、作成した[[WebSocketフレーム]]を送信することにします。
= [232] [VAR[状態]]を、「WebSocket切断待ち」に設定します。
= [233] [[Connection error][connection error]] [VAR[connection]] with [VAR[exit status]].
]FIG]

[214] バイトを受信したら、
[FIG(steps)[
= [234] If [VAR[connection]]'s [F[exit status][connection's exit status]]'s [F[失敗]] is
[CODE[null]]:
== [235] Set [VAR[connection]]'s [F[exit status][connection's exit status]] to a new
[[exit status]] whose [F[失敗]] is [[true]],
[[状態符号]] is [CODE[[[1006]]]], and
理由 is [[空文字列]].
]FIG]

[220] 正常終了か中断を受信したら、

[FIG(steps)[
= [239] If 中断 and [VAR[connection]]'s [F[exit status][connection's exit status]]'s
[[失敗]] is [CODE[null]]:
== [89] Set [VAR[connection]]'s [F[exit status][connection's exit status]] to a new
[[exit status]] whose [F[失敗]] is [[true]],
[[状態符号]] is [CODE[[[1006]]]], and
理由 is [[空文字列]].
= [332] 次の要求に進みます。
]FIG]

*** 「トンネル」状態

[111] バイトを受信したら、
[FIG(steps)[
= [484] [VAR[要求]]について [CODE[data]] を通知します。受信したバイトを引渡します。
]FIG]

[112] 正常終了か中断を受信したら、
[FIG(steps)[
= [371] [VAR[要求]]について [CODE[dataend]] を通知します。
= [478] If 中断:
== [482] [[Connection error][connection error]] [VAR[connection]].
= [483] Otherwise:
== [324] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
== [327] 次の要求に進みます。
]FIG]

*** 「停止済み」状態

[318] To [DFN[connection error]] [VAR[connection]] with an optional [VAR[exit status]],
run these steps:

[FIG(steps)[
= [436] If [VAR[exit status]] is not specified:
== [439] Set [VAR[exit status]] to a new [[exit status]] whose [F[失敗]] is [[true]].
= [131] Set [VAR[connection]]'s [F[exit status][connection's exit status]] to [VAR[exit status]].
= [435] Run the [[sent steps]] for [VAR[connection]] with the [VAR[close]] flag set to [[true]].
= [338] 次の要求に進みます。
]FIG]

[372] The [DFN[sent steps]] for [VAR[connection]] with optional [VAR[close]]
flag ([[false]] if omitted) are these steps:

[FIG(steps)[
= [238] If [VAR[close]] is [[true]]:
== [51] Set [VAR[connection]]'s [F[to be closed]] flag to [[true]].
== 
@@ If [VAR[connection]]'s transport writable stream is not yet closed,
close the writer.
= [340] Set [VAR[connection]]'s [F[write mode]] to "sent".
= [279] 
@@ [VAR[要求]]について要求の送信完了を通知します。
= [499] Set [VAR[connection]]'s [F[stream sent]] flag to [[true]].
= [433] If [VAR[connection]]'s [F[stream received]] flag is [[true]]:
== [432] Run the [[end of stream steps]] for [VAR[connection]].
]FIG]

[43] 次の要求に進むとは、次のようにします。
[FIG(steps)[
= [243] [VAR[状態]]が「停止済み」なら、ここで停止します。
= [336] [VAR[切断タイマー]]を停止させます。
= [379] If [VAR[connection]]'s [F[write mode]] is not [CODE[null]] and is not "sent":
== [380] [VAR[状態]]を、「要求送信中」に設定します。
= [501] Set [VAR[connection]]'s [F[stream received]] flag to [[true]].
= [381] If [VAR[connection]]'s [F[stream sent]] flag is [[true]]:
== [325] Run the [[end of stream steps]] for [VAR[connection]].
]FIG]

[370] The [DFN[end of stream steps]] for [VAR[connection]] are these steps:

[FIG(steps)[
= [512] [VAR[要求]]が null ではなく:
== [513] [VAR[要求]]について完了を通知します。[VAR[connection]]'s [F[exit status][connection's exit status]]
(which might be [CODE[null]])
を引渡します。
= [333] [VAR[要求]]を、 null に設定します。
= [334] [VAR[応答]]を、 null に設定します。
= [514] Set [VAR[connection]]'s [F[write mode]] to [CODE[null]].
= [515] [VAR[要求の処理完了]]が null でなければ、
== [516] [VAR[要求の処理完了]]を[[解決]]します。
== [517] [VAR[要求の処理完了]]を null に設定します。
= [502] Set [VAR[connection]]'s [F[stream received]] flag to [[false]].
= [505] Set [VAR[connection]]'s [F[stream sent]] flag to [[false]].
= [506] Set [VAR[connection]]'s [F[exit status]] to [CODE[null]].
= [518] If [VAR[connection]]'s [F[to be closed]] flag is [[true]]:
== [339]
@@ If [VAR[connection]]'s underlying writable stream is not yet closed:
=== [351] [VAR[connection]]'s [F[transport][connection's transport]] の正常終了の送信を指示します。
=== [350] これ以後 [VAR[connection]]'s [F[transport][connection's transport]] の受信終了を指示して構いません。
== [352] [VAR[状態]]を、「停止済み」に設定します。
= [519] Otherwise:
== [353] [VAR[状態]]を、「要求待ち」に設定します。
]FIG]

[70] バイトを受信したら、何もしません。

[71] 正常終了や中断を受信したら、何もしません。

** ヘッダー群として構文解析

[17] 入力を、 0x0D や 0x0A で区切られた[[行]]に分割します。
[[行]]には区切りの 0x0D, 0x0A は含めません。

[3] 最初の行を (あれば) 次のようにします。

[FIG(steps)[
= 先頭が [CODE[/]] なら、
== その次が[[ASCII数字]]列なら、これを[[十進整数]]として解釈します。
ただし[[先導0]]があるときは、 0 とみなします。
== その次が [CODE[.]] なら、
=== その次が [[ASCII数字]]列なら、これを[[十進整数]]として解釈します。
=== [19] 最初の[[整数]]が2[[以上]]か、
最初の[[整数]]が1と等しく次の[[整数]]が1[[以上]]なら、
==== [VAR[応答]]の[[プロトコルの版]]を、 1.1 に設定します。
== 次が1個以上の [CODE(charname)@en[[[SP]]]] であれば、すべて無視します。
== [21] 次に[[ASCII数字]]列があれば、[VAR[応答]]の[[状態符号]]をその[[十進整数]]値に設定します。
== [9] 次の1個以上の [CODE(charname)@en[[[SP]]]] があれば、
=== [4] [VAR[応答]]の[[理由句]]を、[[行]]のそれより後の部分に設定します。
== [5] それ以外なら、
=== [31] [VAR[応答]]の[[理由句]]を、[[空文字列]]に設定します。
= 先頭が1個[[以上]]の [CODE(charname)@en[[[SP]]]] 列なら、
== [20] 次に[[ASCII数字]]列があれば、[VAR[応答]]の[[状態符号]]をその[[十進整数]]値に設定します。
== [10] 次の1個以上の [CODE(charname)@en[[[SP]]]] があれば、
=== [22] [VAR[応答]]の[[理由句]]を、[[行]]のそれより後の部分に設定します。
== [29] それ以外なら、
=== [30] [VAR[応答]]の[[理由句]]を、[[空文字列]]に設定します。
]FIG]

[23] 更に、次のようにします。
[FIG(steps)[
= [VAR[最後のヘッダー]]を、 null に設定します。
= 残りの各行について順番に、
== 先頭の文字が 0x20 か 0x09 なら、
=== [VAR[最後のヘッダー]]が null 以外なら、
==== 行の先頭から 0x20 と 0x09 をすべて除去します。
==== [VAR[最後のヘッダー]]の値の末尾に、 0x20 と行の内容を追加します。
== 先頭の文字が 0x3A でなく、 0x3A が含まれるなら、
=== [VAR[最後のヘッダー]]を、 0x3A より前の部分を名前、 0x3A より後の部分を値とするヘッダーに設定します。
=== [VAR[応答]]の[[ヘッダーリスト]]の末尾に、[VAR[最後のヘッダー]]を追加します。
== それ以外なら、
=== [VAR[最後のヘッダー]]を、 null に設定します。
= [VAR[応答]]の[[ヘッダーリスト]]の各ヘッダーについて、
== 名前の末尾から 0x20 と 0x09 をすべて除去します。
== 値の先頭から 0x20 と 0x09 をすべて除去します。
== 値の末尾から 0x20 と 0x09 をすべて除去します。
]FIG]

** WebSocket frames

[189] To [DFN[process a WebSocket frame]], switch by [VAR[connection]]'s 
[F[frame][connection's frame]]'s [F[opcode]]:

[FIG(switch)[
: [N[0]], [N[1]], or [N[2]] :
[FIG(steps)[
= [194] If [VAR[connection]]'s [F[frame][connection's frame]]'s [F[opcode]] is [N[1]]:
== [197] Set [VAR[connection]]'s [F[WebSocket data type]] to [[Text]].
== [179] [VAR[要求]]について、 [CODE[datastart]] を通知 with [[Text]].
== [168] Set [VAR[connection]]'s [F[decoder][connection's decoder]] to a 
[CODE(DOMi)@en[TextDecoder]] with:
[FIG(list members middle)[
[FIGCAPTION[
[1363] [CODE(DOMi)@en[TextDecoder]]
]FIGCAPTION]
: [F[encoding][TextDecoder's encoding]] : [[UTF-8]]
: [F[error mode][TextDecoder's error mode]] : [CODE[fatal]]
: [F[ignore BOM flag][TextDecoder's ignore BOM flag]] : [[true]]
]FIG]
= [198] Otherwise, if [VAR[connection]]'s [F[frame][connection's frame]]'s [F[opcode]] is [N[2]]:
== [1364] Set [VAR[connection]]'s [F[WebSocket data type]] to [[Binary]].
== [178] [VAR[要求]]について、 [CODE[datastart]] を通知 with [[Binary]].
= [182] If [VAR[connection]]'s [F[WebSocket data type]] is [[Text]]:
== [180] Let [VAR[output]] be the result of invoking
[VAR[decoder]]'s [CODE(DOMm)@en[decode][TextDecoder's decode]] method with:
[FIG(list members)[
: [VAR[input]] : [VAR[connection]]'s [F[一時バッファー]]
: [VAR[options]] :
[FIG(list members)[
[FIGCAPTION[
[534] [CODE(DOMi)@en[TextDecodeOptions]]
]FIGCAPTION]
: [CODE(DOMa)@en[stream]] : 
If [VAR[connection]]'s [F[frame][connection's frame]]'s [F[opcode]] is [N[0]], [[true]].
Otherwise, [[false]].
]FIG]
]FIG]
If an [[exception]] is thrown,
理由 [CODE[Invalid UTF-8 in text frame]] で失敗とし,
return [[false]], and abort these steps.
== [531] [VAR[要求]]について、 [CODE[data]] を通知 with [VAR[output]].
= [169] Otherwise:
== [177] [VAR[要求]]について、 [CODE[data]] を通知 with [VAR[connection]]'s [F[一時バッファー]].
= [533] If [VAR[connection]]'s [F[frame][connection's frame]]'s [F[FIN]] is [N[1]]:
== [532] [VAR[要求]]について、 [CODE[dataend]] を通知します。
== [187] Set [VAR[connection]]'s [F[WebSocket data type]] to [CODE[null]].
= [1369] Return [[true]].
]FIG]
: [N[8]] :
[FIG(steps)[
= [199] [VAR[一時バッファー]]の長さが1なら、
== [201] 理由[[空文字列]]で失敗とします。
== [1365] Return [[false]] and abort these steps.
= [202] [VAR[一時バッファー]]が空でないなら、
== [203] [VAR[フレーム]]の[[状態符号]]を、
[VAR[一時バッファー]]の先頭2バイトを[[ネットワークバイト順]]の[[符号無し16ビット整数]]として解釈した値とします。
== [206] [VAR[フレーム]]の[[状態符号]]が [CODE[[[1005]]]] か [CODE[[[1006]]]] なら、
=== [207] 理由[[空文字列]]で失敗とします。
=== [1366] Return [[false]] and abort these steps.
== [208] [VAR[フレーム]]の[[理由]]を、[VAR[一時バッファー]]から先頭2バイトを除いたものを入力として
[[utf-8復号器]]をエラーモード致死的で実行した出力とします。
== [209] 失敗の場合は、
=== [1368] 理由 [CODE[Invalid UTF-8 in Close frame]] で失敗とします。
=== [1367] Return [[false]] and abort these steps.
= [213] [VAR[WebSocket接続の状態]]が [CODE[CLOSING]] でなければ、
== [210] [VAR[WebSocket接続の状態]]を、 [CODE[CLOSING]] に設定します。
== [211] [VAR[要求]]について、 [CODE[wsclosing]] を通知します。
== [216] [[WebSocketフレーム]]を作成します。
[FIG(list members)[
:[[FIN]]:1
:[[RSV1]]:0
:[[RSV2]]:0
:[[RSV3]]:0
:[[opcode]]:8
:[[mask]]:1
:[[長さ]]:データのバイト数
:[[マスクキー]]:無作為に決定した4バイトのバイト列
:データ:[VAR[フレーム]]に[[状態符号]]がなければ空。そうでなければ、
[VAR[フレーム]]の[[状態符号]]を表す[[16ビット符号無し整数]] ([[ネットワークバイト順]]) と、
それに続けて理由
]FIG]
== [307] 作成した [[WebSocketフレーム]]のデータの各[[バイト]]について、
先頭から [VAR[i]] バイト目 (先頭が0バイト) であれば、
[[マスクキー]]の [VAR[i]] [[mod]] 4 バイト目 (先頭が0バイト)
と [[XOR]] した結果に差し替えます。
== [308] [VAR[connection]]'s [F[transport][connection's transport]] で、作成した[[WebSocketフレーム]]を送信することにします
@@ after completion of any ongoing transmission of frames.
== [225] Run the [[sent steps]] for [VAR[connection]] with [VAR[close]] flag set to
[[true]].
= [218] [VAR[状態]]を、「WebSocket切断待ち」に設定します。
= [228] Set [VAR[connection]]'s [F[exit status][connection's exit status]] to an
[[exit status]]:
[FIG(list members)[
[FIGCAPTION[
[[Exit status][exit status]]
]FIGCAPTION]
:失敗:[[偽]]
:cleanly:[[真]]
:状態符号:[VAR[フレーム]]の[[状態符号]] (なければ [CODE[1005]])
:理由:[VAR[フレーム]]の理由 (なければ[[空文字列]])
]FIG]
= [219] [VAR[connection]]'s [F[endpoint type][connection's endpoint type]] is [CODE[server]]:
== [311] 次の要求に進みます。
= [312] それ以外なら、
== [313] [VAR[切断タイマー]]で、 1s 後に次の要求に進むことにします。
= [1372] Return [[true]].
]FIG]
: [N[9]] :
[FIG(steps)[
= [222] [VAR[要求]]について、 ping を通知します。[VAR[一時バッファー]]をデータとして引き渡します。
= [223] [[WebSocketフレーム]]を作成します。
[FIG(list members)[
:[[FIN]]:1
:[[RSV1]]:0
:[[RSV2]]:0
:[[RSV3]]:0
:[[opcode]]:10
:[[mask]]:1
:[[長さ]]:データのバイト数
:[[マスクキー]]:無作為に決定した4バイトのバイト列
:データ:[VAR[一時バッファー]]
]FIG]
= [309] 作成した [[WebSocketフレーム]]のデータの各[[バイト]]について、
先頭から [VAR[i]] バイト目 (先頭が0バイト) であれば、
[[マスクキー]]の [VAR[i]] [[mod]] 4 バイト目 (先頭が0バイト)
と [[XOR]] した結果に差し替えます。
= [310] [VAR[connection]]'s [F[transport][connection's transport]] で、作成した[[WebSocketフレーム]]を送信することにします
@@ after completion of any ongoing transmission of frames.
= [1371] Return [[true]].
]FIG]
: [N[10]] :
[FIG(steps)[
= [221] [VAR[要求]]について、 ping を通知します。返答フラグを設定し、
[VAR[一時バッファー]]をデータとして引き渡します。
= [1370] Return [[true]].
]FIG]
]FIG]

* HTTP/2

@@

@@ server push

* FTP

@@ FTP support is to be removed from the Web.

[639] An [DFN[FTP connection]] has following states:
[FIG(list members)[
: [DFN[[F[endpoint type][FTP connection's endpoint type]]]] : [CODE[client]]
: [DFN[[F[transport][FTP connection's transport]]]] : A [[transport]].
: [DFN[[F[read buffer][FTP connection's read buffer]]]] : A [[byte string]].
Initially, an empty [[byte string]].
: [DFN[[F[state][FTP connection's state]]]] : Initially, ''connected state''.
: [DFN[[F[username][FTP connection's username]]]] : A [[string]].
: [DFN[[F[password][FTP connection's password]]]] : A [[string]].
: [DFN[[F[established promise][FTP connection's established promise]]]] : A [[promise]].
Initially, an unresolved [[promise]].
: [DFN[[F[path][FTP connection's path]]]] : A [[byte string]] or [[null]].
Initially, [[null]].
: [DFN[[F[object type][FTP connection's object type]]]] : Either ''unknown'',
''file'', or ''directory''.  Initially, ''unknown''.
: [DFN[[F[file length][FTP connection's file length]]]] : Either an [[integer]] or
[[null]].  Initially, [[null]].
: [DFN[[F[data length][FTP connection's data length]]]] : An [[integer]].
: [DFN[[F[data transport][FTP connection's data transport]]]] : A [[transport]] or [[null]].
Initially, [[null]].
: [DFN[[F[data state][FTP connection's data state]]]] : 
Either ''initial state'', ''data state'', or ''exit state''.
: [DFN[[F[data connected promise][FTP connection's data connected promise]]]] : A [[promise]].
: [DFN[[F[is unauthorized][FTP connection's is unauthorized]]]] : A [[boolean]].
Initially, [[false]].
]FIG]

[1227] An [[FTP connection]] has similar notification hooks as [[HTTP connection]].

** Control connections

[573] To [DFN[initiate an FTP connection]] with
a [[transport]] [VAR[transport]],
a [[string]] [VAR[username]], and a [[string]] [VAR[password]],
run these steps:
[FIG(steps)[
= [575] Let [VAR[ftp]] be a [[FTP connection]].
[FIG(list members)[
[FIGCAPTION[
[[FTP connection]]
]FIGCAPTION]
: [F[endpoint type][FTP connection's endpoint type]] : [CODE[client]]
: [F[transport][FTP connection's transport]] : [VAR[transport]]
: [F[username][FTP connection's username]] : [VAR[username]]
: [F[password][FTP connection's password]] : [VAR[password]]
]FIG]
= [1067] Let [VAR[current code]] be [[null]].
= [1066] Let [VAR[current text]] be an empty [[byte string]].
= [911] Configure [VAR[transport]] to run these substeps whenever
it notifies of [[バイト]]の受信 with [VAR[byte]] and [VAR[urgent data flag]]:
[FIG(steps)[
= [912] If [VAR[urgent data flag]] is set, abort these substeps.
= [1062] Append [VAR[byte]] to [VAR[ftp]]'s [F[read buffer][FTP connection's read buffer]].
= [1094] Optionally, abort these substeps.
= [1063] If [VAR[byte]] contains a [CODE[0x0A]] byte:
== [1064] Split [VAR[ftp]]'s [F[read buffer][FTP connection's read buffer]]
into two substrings at the first [CODE[0x0A]] byte.
Set [VAR[line]] to the first substring and [VAR[ftp]]'s 
[F[read buffer][FTP connection's read buffer]] to the second substring,
not including the [CODE[0x0A]] separator.
== [1065] Remove the [CODE[0x0D]] byte at the end of [VAR[line]], if any.
== [1075] If [VAR[line]] has three [CODE[0x30]]-[CODE[0x39]] bytes followed by
a [CODE[0x20]] or [CODE[0x2D]] byte at the beginning:
=== [1076] Let [VAR[code]] be the first three bytes of [VAR[line]].
=== [1069] Let [VAR[continue]] be whether the fourth byte of [VAR[line]] is [CODE[0x2D]] or not.
=== [1077] Remove first four bytes from [VAR[line]].
=== [1078] If [VAR[current code]] is [[null]]:
==== [1079] Set [VAR[current code]] to [VAR[code]].
==== [1081] Set [VAR[current text]] to [VAR[line]] followed by [CODE[0x0D]] [CODE[0x0A]].
=== [1082] Otherwise, [VAR[current code]] is [VAR[code]]:
==== [1083] Append [VAR[line]] followed by [CODE[0x0D]] [CODE[0x0A]] to [VAR[current text]].
=== [1084] Otherwise:
==== [1085] Set [VAR[current code]] to an [[error]].
=== [1086] If [VAR[current code]] is not an [[error]]:
==== [1087] Let [VAR[reply]] be an [[FTP reply]]:
[FIG(list members)[
: [F[code][FTP reply's code]] : A string obtained by replacing bytes
in [VAR[current code]] by [[code point]]s with same values.
: [F[text][FTP reply's text]] : [VAR[current text]]
]FIG]
==== [1091] Run the [[FTP client state machine]] with [VAR[ftp]] and [VAR[reply]].
== [1070] Otherwise:
=== [1072] Set [VAR[current code]] be [[null]].
=== [1071] Set [VAR[current text]] be an empty [[byte string]].
]FIG]
= [913] Configure [VAR[transport]] to run these substeps whenever
it notifies of 正常終了の受信 or 中断 with [VAR[reset flag]]:
[FIG(steps)[
= [1060] Set [VAR[is abort]] be whether the notification is about 中断 or not.
= [1090] Let [VAR[exit]] be
@@
= [1272] Run the [[FTP client state machine]] with [VAR[ftp]] and [[null]].
]FIG]
= [1088] Return [VAR[ftp]].
]FIG]

[1104] To [DFN[send FTP command]] [VAR[command]] with argument [VAR[text]] over [VAR[ftp]],
run these steps:
[FIG(steps)[
= [1105] If [VAR[text]] is [[null]]:
== [1106] Send [VAR[text]] followed by [CODE[0x0D]] [CODE[0x0A]] over [VAR[ftp]].
= [1107] Otherwise:
== [1108] Send [VAR[text]] followed by [VAR[text]] followed by [CODE[0x0D]] [CODE[0x0A]]
over [VAR[ftp]].
]FIG]

[1244] To [DFN[switch to passive mode]] with [VAR[ftp]], run these steps:
[FIG(steps)[
= [1137] 
@@ If [VAR[ftp]]'s [F[transport][FTP connection's transport]]
is IPv6:
== [1140] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''[CODE[PASV]] reply state''.
== [1138] [[Send FTP command][send FTP command]] `[CODE[EPSV]]` with [CODE[null]]
over [VAR[ftp]].
= [1139] Otherwise:
== [1132] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''[CODE[EPSV]] reply state''.
== [1136] [[Send FTP command][send FTP command]] `[CODE[PASV]]` with [CODE[null]]
over [VAR[ftp]].
]FIG]

[1068] An [DFN[FTP reply]] has following states:
[FIG(list members)[
[FIGCAPTION[
[[FTP reply]]
]FIGCAPTION]

: [DFN[[F[code][FTP reply's code]]]] : A [[string]].
: [DFN[[F[text][FTP reply's text]]]] : A [[byte string]].
]FIG]

[1110] The [[FTP reply]]'s [DFN[[F[first code]]]] is its [F[code][FTP reply's code]]'s
first character.

[1061] To [DFN[set FTP state]] of [[FTP connection]] [VAR[ftp]] to [VAR[state]],
run these steps:
[FIG(steps)[
= [1096] If [VAR[ftp]]'s [F[read buffer][FTP connection's read buffer]] is not empty:
== [1097] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
= [1098] Otherwise:
== [1095] Set [VAR[ftp]]'s [F[state][FTP connection's state]] to [VAR[state]].
]FIG]

[1092] The [DFN[FTP client state machine]] of [[FTP connection]] [VAR[ftp]]
run these steps with [[FTP reply]] [VAR[reply]],
switched by [VAR[ftp]]'s [F[state][FTP connection's state]]:
[FIG(switch)[
: ''Connected state'' : 
[FIG(steps)[
= [1099] If [VAR[reply]] is not [[null]]:
== [1209] If [VAR[reply]]'s [F[code][FTP reply's code]] is [CODE[421]] or [CODE[521]]:
=== [1253] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
== [1254] Otherwise:
=== [1100] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''[CODE[USER]] reply state''.
=== [1103] [[Send FTP command][send FTP command]] `[CODE[USER]]` and
[[UTF-8 encoded][UTF-8 encode]] [VAR[ftp]]'s [F[username][FTP connection's username]]
over [VAR[ftp]].
= [1101] Otherwise:
== [1102] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
]FIG]
: ''[CODE[USER]] reply state'' :
[FIG(steps)[
= [1109] If [VAR[reply]] is not [[null]]:
== [1111] If [VAR[reply]]'s [F[first code]] is [CODE[2]]:
=== [1157] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''authenticated state''.
=== [1126] Resolve [VAR[ftp]]'s [F[established promise][FTP connection's established promise]].
== [1112] Otherwise, [VAR[reply]]'s [F[first code]] is [CODE[3]]:
=== [1118] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''before [CODE[PASS]] reply state''.
=== [1119] [[Send FTP command][send FTP command]] `[CODE[PASS]]` with
[[UTF-8 encoded][UTF-8 encode]] [VAR[ftp]]'s [F[password][FTP connection's password]]
over [VAR[ftp]].
== [1113] Otherwise:
=== [1116] [[Request FTP authentication][request FTP authentication]] for [VAR[ftp]].
= [1114] Otherwise:
== [1115] [[Request FTP authentication][request FTP authentication]] for [VAR[ftp]].
]FIG]
: ''[CODE[PASS]] reply state'' :
[FIG(steps)[
= [1120] If [VAR[reply]] is not [[null]]:
== [1121] If [VAR[reply]]'s [F[first code]] is [CODE[2]]:
=== [1127] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''authenticated state''.
=== [1158] Resolve [VAR[ftp]]'s [F[established promise][FTP connection's established promise]].
== [1122] Otherwise:
=== [1123] [[Request FTP authentication][request FTP authentication]] for [VAR[ftp]].
= [1124] Otherwise:
== [1125] [[Request FTP authentication][request FTP authentication]] for [VAR[ftp]].
]FIG]
: ''[CODE[TYPE]] reply state'' :
[FIG(steps)[
= [1130] If [VAR[reply]] is not [[null]] and
[VAR[reply]]'s [F[first code]] is [CODE[2]]:
== [1073] [[Switch to passive mode][switch to passive mode]] with [VAR[ftp]].
= [1134] Otherwise:
== [1135] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
]FIG]
: ''[CODE[PASV]] reply state'' :
[FIG(steps)[
= [1141] If [VAR[reply]] is not [[null]] and
[VAR[reply]]'s [F[first code]] is [CODE[2]] :
== [1131] If [VAR[reply]]'s [F[text]] matches to the pattern
[CODE[0x28 [VAR[digits]] 0x2C [VAR[digits]] 0x2C [VAR[digits]] 0x2C [VAR[digits]] 0x2C [VAR[digits]] 0x2C [VAR[digits]] 0x29]],
where [VAR[digits]] represents one or more bytes in range [0x30, 0x39]:
=== [1133] Let [VAR[p1]] and [VAR[p2]] be the first such match's last two
[VAR[digits]] substrings, respectively, interpreted as decimal integers encoded in [[UTF-8]].
=== [1143] Let [VAR[port]] be [VAR[p1]] × 256 + [VAR[p2]].
=== [1144] 
[[Establish an FTP data connection][establish an FTP data connection]] for [VAR[ftp]] and
and [VAR[port]].
== [1154] Otherwise:
=== [1155] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
= [1142] Otherwise:
== [1145] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
]FIG]
: ''[CODE[EPSV]] reply state'' :
[FIG(steps)[
= [1146] If [VAR[reply]] is not [[null]] and
[VAR[reply]]'s [F[first code]] is [CODE[2]] :
== [1147] If [VAR[reply]]'s [F[text]] matches to the pattern
[CODE[0x28 0x7C 0x7C 0x7C [VAR[digits]] 0x7C 0x29]],
where [VAR[digits]] represents one or more bytes in range [0x30, 0x39]:
=== [1148] Let [VAR[port]] be the first such match's [VAR[digits]] substring,
interpreted as a decimal integer encoded in [[UTF-8]].
=== [1149] 
[[Establish an FTP data connection][establish an FTP data connection]] for
[VAR[ftp]] and [VAR[port]].
== [1152] Otherwise:
=== [1153] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
= [1150] Otherwise:
== [1151] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
]FIG]
: ''Authenticated state'' :
[[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
: ''[CODE[TYPE]] reply state'' :
[FIG(steps)[
= [1172] If [VAR[reply]] is not [[null]] and
[VAR[reply]]'s [F[first code]] is [CODE[2]]:
== [1175] If [VAR[ftp]]'s [F[object type][FTP connection's object type]] is ''directory'':
=== [1214] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''[CODE[CWD]] reply state''.
=== [1215] [[Send FTP command][send FTP command]] `[CODE[CWD]]` with [VAR[ftp]]'s
[F[path][FTP connection's path]] over [VAR[ftp]].
== [1176] Otherwise:
=== [1177] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''[CODE[SIZE]] reply state''.
=== [1178] [[Send FTP command][send FTP command]] `[CODE[SIZE]]` with [VAR[ftp]]'s
[F[path][FTP connection's path]] over [VAR[ftp]].
= [1173] Otherwise:
== [1174] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
]FIG]
: ''[CODE[SIZE]] reply state'' :
[FIG(steps)[
= [1170] If [VAR[reply]]'s [F[first code]] is [CODE[2]] and
[VAR[reply]]'s [F[text][FTP reply's text]] is one or more bytes in range [0x30, 0x39]:
== [1171] Set [VAR[ftp]]'s [F[file length][FTP connection's file length]] to 
[VAR[reply]]'s [F[text][FTP reply's text]], interpreted as a decimal integer
encoded in [[UTF-8]].
= [1179] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''[CODE[RETR]] reply state''.
= [1206] If [VAR[ftp]]'s [F[data connection][FTP connection's data connection]] is [[null]] or
[VAR[ftp]]'s [F[data state][FTP connection's data state]] is not ''initial state'':
== [1207] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
= [1208] Otherwise:
== [1228] Schedule to run the [VAR[data connected steps]] with [VAR[ftp]] when [VAR[ftp]]'s 
[F[data connected promise][FTP connection's data connected promise]] is resolved.
== [1180] [[Send FTP command][send FTP command]] `[CODE[RETR]]` with [VAR[ftp]]'s
[F[path][FTP connection's path]] over [VAR[ftp]].
]FIG]
: ''[CODE[RETR]] reply state'' :
[FIG(steps)[
= [1181] If [VAR[reply]]'s [F[first code]] is not [CODE[1]] or [CODE[2]]:
== [1246] If [VAR[reply]]'s [F[code][FTP reply's code]] is [CODE[421]], [CODE[425]],
or [CODE[426]],
or if [VAR[ftp]]'s [F[object type][FTP connection's object type]] is ''file'':
=== [1183] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
== [1210] Otherwise:
=== [1245] If [VAR[ftp]]'s [F[data transport][FTP connection's data transport]] is not [[null]]:
==== [1251] [VAR[ftp]]'s [F[data transport][FTP connection's data transport]]'s 中断の指示.
==== [1252] Set [VAR[ftp]]'s [F[data transport][FTP connection's data transport]] to [[null]].
==== [1248] Set [VAR[ftp]]'s [F[object type][FTP connection's object type]] to ''directory''.
==== [1247] [[Switch to passive mode][switch to passive mode]] with [VAR[ftp]].
=== [1249] Otherwise:
==== [1213] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''[CODE[CWD]] reply state''.
==== [1212] [[Send FTP command][send FTP command]] `[CODE[CWD]]` with [VAR[ftp]]'s
[F[path][FTP connection's path]] over [VAR[ftp]].
]FIG]
: ''[CODE[CWD]] reply state'' :
[FIG(steps)[
= [1216] If [VAR[reply]] is not [[null]] and
[VAR[reply]]'s [F[first code]] is [CODE[2]]:
== [1257] Set [VAR[ftp]]'s [F[file length][FTP connection's file length]] to [[null]].
== [1258] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''[CODE[LIST]] reply state''.
== [1219] If [VAR[ftp]]'s [F[data connection][FTP connection's data connection]] is [[null]] or
[VAR[ftp]]'s [F[data state][FTP connection's data state]] is not ''initial state'':
=== [1259] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
== [1260] Otherwise:
=== [1261] Schedule to run the [VAR[data connected steps]] with [VAR[ftp]] when [VAR[ftp]]'s 
[F[data connected promise][FTP connection's data connected promise]] is resolved.
=== [1262] [[Send FTP command][send FTP command]] `[CODE[LIST]]` with [[null]].
= [1217] Otherwise:
== [1218] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
]FIG]
: ''[CODE[RETR]] reply state'' :
[FIG(steps)[
= [1225] If [VAR[reply]]'s [F[first code]] is not [CODE[1]] or [CODE[2]]:
== [1226] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
]FIG]
]FIG]

[1074] To [DFN[send an FTP request]] [VAR[request]] over [VAR[ftp]],
run these steps:
[FIG(steps)[
= [1288] If [VAR[ftp]]'s [F[is unauthorized][FTP connection's is unauthorized]] is [[true]]:
== Return a [[response]] and abort these steps:
[FIG(list members)[
[FIGCAPTION[
[[Response][response]]
]FIGCAPTION]
: [F[status][status code]] : [CODE[401]]
: [F[status text][reason phrase]] : [CODE[Unauthorized]]
: [F[header list]] :
[FIG(list members)[
: [CODE[WWW-Authenticate]] : [CODE[[[Basic]] [[realm]]=""]]
]FIG]
]FIG]
= [1159] Assertion: [VAR[ftp]]'s [F[state][FTP connection's state]] has to be
''authenticated state''.
= [1165] Let [VAR[type]] be `[CODE[I]]`.
= [1160] Let [VAR[path]] be concatenation of [VAR[request]]'s [F[url][request's url]]'s 
[F[path]]'s items, separated with [CODE[/]], in order.  This can be the [[empty string]].
= [1161] If [VAR[path]] contains a [CODE[;]] character:
== [1162] Let [VAR[param]] be the first [CODE[;]] character and the following characters
in [VAR[path]].  Remove them from [VAR[path]].
== [1163] Switch by [VAR[param]]:
[FIG(switch)[
: [CODE[;type=a]] :
Set [VAR[ftp]]'s [F[object type][FTP connection's object type]] to ''file''.
Set [VAR[type]] to `[CODE[A]]`.
: [CODE[;type=i]] :
Set [VAR[ftp]]'s [F[object type][FTP connection's object type]] to ''file''.
: [CODE[;type=d]] :
Set [VAR[ftp]]'s [F[object type][FTP connection's object type]] to ''directory''.
]FIG]
= [1166] Set [VAR[path]] be the result of applying [[UTF-8 encode]] to [VAR[path]].
= [1167] Set [VAR[path]] be the result of applying [[percent decode]] to [VAR[path]].
= [1168] If the last byte of [VAR[path]], if any, is 0x2F:
== [1169] Set [VAR[ftp]]'s [F[object type][FTP connection's object type]] to ''directory''.
= [1164] Set [VAR[ftp]]'s [F[path][FTP connection's path]] to [VAR[path]].
= [1128] [[Set FTP state][set FTP state]] of [VAR[ftp]] to ''[CODE[TYPE]] reply state''.
= [1129] [[Send FTP command][send FTP command]] `[CODE[TYPE]]` with [VAR[type]] over 
[VAR[ftp]].
]FIG]

** Data connections

[910] To [DFN[establish an FTP data connection]] for [VAR[ftp]] and [VAR[port]],
run these steps:
[FIG(steps)[
= [1243] Set [VAR[ftp]]'s [F[data connected promise][FTP connection's data connected promise]]
to an unresolved [[promise]].
= [1188] If [VAR[port]] is less than [N[1024]], is greater than [N[65535]],
or is one of [[bad ports]]:
== [1189] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
= [1184] Let [VAR[host]] be [VAR[ftp]]'s [F[transport][FTP connection's transport]]'s
@@ remote host.
= [1185] Let [VAR[proxy]] be [VAR[ftp]]'s [F[transport][FTP connection's transport]]'s
[F[proxy configuration][transport's proxy configuration]].
= [1187] Let [VAR[url]] be a [[URL record]] whose [F[scheme][URL scheme]] is [CODE[ftp][ftp:]],
[F[host][URL's host]] is [VAR[host]], and [F[port][URL's port]] is [VAR[port]].
= [1186] Let [VAR[transport]] be the result of 
[[creating a transport for proxy][create a transport for a proxy configuration]]
[VAR[proxy]] with [VAR[url]].
= [1156] If [VAR[transport]] is a [[failure]]:
== [1190] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
= [1191] Set [VAR[ftp]]'s [F[data transport][FTP connection's data transport]] to
[VAR[transport]].
= [1201] Set [VAR[ftp]]'s [F[data state][FTP connection's data state]] to ''initial state''.
= [1195] Configure [VAR[transport]] to run these substeps whenever
it notifies of [[バイト]]の受信 with [VAR[byte]] and [VAR[urgent data flag]]:
[FIG(steps)[
= [1196] If [VAR[urgent data flag]] is set, abort these steps.
= [1200] If [VAR[ftp]]'s [F[data state][FTP connection's data state]] is ''initial state'':
== [1255] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
= [1256] Otherwise:
== [1222] Increment [VAR[ftp]]'s [F[data length][FTP connection's data length]].
== [1233] [VAR[ftp]]'s [CODE[data]] の通知 with [VAR[byte]].
== [1220] If [VAR[ftp]]'s [F[file length][FTP connection's file length]] is not [[null]] and
[VAR[ftp]]'s [F[file length][FTP connection's file length]] is
[VAR[ftp]]'s [F[data length][FTP connection's data length]]:
=== [1223] Set [F[data state][FTP connection's data state]] to ''exit state''.
=== [1224] [VAR[ftp]]'s [CODE[dataend]] の通知.
=== [1269] [VAR[ftp]]'s [F[data transport][FTP connection's data transport]]'s
正常終了の送信の指示.
=== [1270] Set [VAR[ftp]]'s [F[data transport][FTP connection's data transport]] to [[null]].
]FIG]
= [1197] Configure [VAR[transport]] to run these substeps whenever
it notifies of 正常終了の受信 or 中断 with [VAR[is reset]]:
[FIG(steps)[
= [1198] Set [VAR[is abort]] be whether the notification is about 中断 or not.
= [1199] Let [VAR[exit]] be an [[exit status]] whose [F[失敗]] is [VAR[is abort]]
and [F[リセット]] is [VAR[is reset]].
= [1239] If [VAR[ftp]]'s [F[data transport]] is [VAR[transport]] or
[VAR[ftp]]'s [F[data state][FTP connection's data state]] is ''exit state'':
== [1202] If [VAR[ftp]]'s [F[data state][FTP connection's data state]] is
''initial state'':
=== [1203] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]] with [VAR[exit]].
== [1204] Otherwise:
=== [1271] If [VAR[ftp]]'s [F[data state][FTP connection's data state]] is 
''data state'':
==== [1234] [VAR[ftp]]'s [CODE[dataend]] の通知.
==== [1276] If
[VAR[ftp]]'s [F[file length][FTP connection's file length]] is not [[null]] and
[VAR[ftp]]'s [F[file length][FTP connection's file length]] is greater than
[VAR[ftp]]'s [F[data length][FTP connection's data length]]:
===== [1277] Set [VAR[ftp]]'s [F[response][FTP connection's response]]'s
[F[incomplete message][response's incomplete message]] flag.
==== [1236] [VAR[ftp]]'s [F[transport][FTP connection's transport]]'s 正常終了の送信の指示.
=== [1235] [VAR[ftp]]'s 完了の通知 with [VAR[ftp]]'s [F[response][FTP connection's response]]
and [VAR[exit]].
=== [1237] [VAR[ftp]]'s [F[data transport][FTP connection's data transport]]'s
正常終了の送信の指示.
= [1240] Otherwise:
== [1241] [VAR[transport]]'s 正常終了の送信の指示.
]FIG]
= [1242] Resolve [VAR[ftp]]'s [F[data connected promise][FTP connection's data connected promise]].
]FIG]

[1211] The [DFN[data connected steps]] with [VAR[ftp]] are these steps:
[FIG(steps)[
= [1229] [VAR[ftp]]'s 要求の送信完了の通知.
= [1232] Set [VAR[ftp]]'s [F[response][FTP connection's response]] to a [[response]].
[FIG(list members)[
[FIGCAPTION[
[[Response][response]]
]FIGCAPTION]
: [F[status][status code]] : [CODE[200]]
: [F[status text][reason phrase]] : [CODE[OK]]
: [F[body][response body]] :
@@ stream
]FIG]
=
@@
If ?raw, plain text.  Otherwise, FTP directory list.
=
@@
base is: [VAR[ftp]]'s [F[path][FTP connection's path]]
If path does not end with a 0x2F, append a 0x2F byte to path.
= [1230] [VAR[ftp]]'s 応答のヘッダー受信完了の通知 with [VAR[ftp]]'s [F[response][FTP connection's response]].
= [1221] Set [VAR[ftp]]'s [F[data length][FTP connection's data length]] to [N[0]].
= [1231] [VAR[ftp]]'s [CODE[datastart]] の通知.
= [1263] If [VAR[ftp]]'s [F[file length][FTP connection's file length]] is not [[null]] and
[VAR[ftp]]'s [F[file length][FTP connection's file length]] is
[VAR[ftp]]'s [F[data length][FTP connection's data length]]:
== [1264] Set [F[data state][FTP connection's data state]] to ''exit state''.
== [1265] [VAR[ftp]]'s [CODE[dataend]] の通知.
== [1267] [VAR[ftp]]'s [F[data transport][FTP connection's data transport]]'s
正常終了の送信の指示.
== [1268] Set [VAR[ftp]]'s [F[data transport][FTP connection's data transport]] to [[null]].
= [1266] Otherwise:
== [1205] Set [VAR[ftp]]'s [F[data state][FTP connection's data state]] to ''data state''.
]FIG]

** Termination

[1117] To [DFN[request FTP authentication]] of [VAR[ftp]], run these steps:
[FIG(steps)[
= [574] Set [VAR[ftp]]'s [F[is unauthorized][FTP connection's is unauthorized]] to [[true]].
= [1238] [[Abort FTP connection][abort FTP connection]] [VAR[ftp]].
]FIG]

[1093] To [DFN[abort FTP connection]] [VAR[ftp]] with optional [VAR[exit]], run these steps:
[FIG(steps)[
= [1297] If [VAR[exit]] is not specified, set [VAR[exit]] to an [[exit status]]
whose [F[失敗]] is [[true]].
= [1194] [VAR[ftp]]'s [F[transport][FTP connection's transport]]'s 中断の指示.
= [1192] If [VAR[ftp]]'s [F[data transport][FTP connection's data transport]] is not [[null]]:
== [1193] [VAR[ftp]]'s [F[data transport][FTP connection's data transport]]'s 中断の指示.
= [1274] If [VAR[ftp]]'s [F[path][FTP connection's path]] is not [[null]]:
== [1273] [VAR[ftp]]'s 完了の通知 with [VAR[ftp]]'s [F[response][FTP connection's response]]
and [VAR[exit]].
= [1275] Otherwise:
== [1089] Reject [VAR[ftp]]'s [F[established promise][FTP connection's established promise]]
with [VAR[exit]].
]FIG]

@@ [1250] Timeout

* Server-side API

@@ XXX

[1378] To [DFN[prepare metavariables]] for an [[request]] [VAR[request]],
a [[transport]] [VAR[transport]], and
a [[string]] or [CODE[null]] [VAR[scheme key name]], run these steps:
[FIG(steps)[
= [1391] Let [VAR[url]] be [VAR[request]]'s [F[target url][request's target url]].
= [1409] Set [VAR[request version]] to the appropriate value
by [VAR[request]]'s [F[version][request's version]]:
[FIG(switch)[
: [CODE[0.9]] : [CODE[HTTP/0.9]]
: [CODE[1.0]] : [CODE[HTTP/1.0]]
: [CODE[1.1]] : [CODE[HTTP/1.1]]
: [CODE[2.0]] : [CODE[HTTP/2.0]]
]FIG]
= [1379] Let [VAR[vars]] be a [[map]] with following name/value pairs:
[FIG(list members)[
: [CODE(CGI)@en[CONTENT_LENGTH]] : [VAR[request]]'s [F[body length][request's body length]], 
[[serialized][serialize an integer]].
: [CODE[PATH_INFO]] : [VAR[url]]'s [F[path][URL path]], 
[[UTF-8 encoded][UTF-8 encode]] and [[percent-decoded][percent-decode]]
: [CODE[REQUEST_METHOD]] : [VAR[request]]'s [F[method][request's method]]
: [CODE[SCRIPT_NAME]] : The [[empty string]]
: [CODE[SERVER_PROTOCOL]] : [VAR[request version]]
]FIG]
= [1411] If [VAR[scheme key name]] is not [CODE[null]]:
== [1412] Set [VAR[vars]]' [VAR[scheme key name]] to [CODE[http]].
= [1382] If [VAR[transport]]'s [F[protocol][transport's protocol]] is [CODE[tls]]:
== [1383] Set [VAR[transport]] to [VAR[transport]]'s [F[transport][transport's transport]].
== [1388] If [VAR[url]]'s [F[scheme][URL scheme]] is [CODE(URI)@en[https][https:]]:
=== [1386] Set [VAR[vars]]' [CODE[HTTPS]] to [CODE[ON]].
=== [1413] If [VAR[scheme key name]] is not [CODE[null]]:
==== [1414] Set [VAR[vars]]' [VAR[scheme key name]] to [CODE[https]].
= [1384] If [VAR[transport]]'s [F[protocol][transport's protocol]] is [CODE[tcp]]:
== [1385] Set [VAR[vars]]' [CODE[REMOTE_ADDR]] to [VAR[transport]]'s 
[F[remote host][transport's remote host]], 
[[serialized][host serializer]].
== [1407] Set [VAR[vars]]' [CODE[SERVER_NAME]] to [VAR[transport]]'s 
[F[local host][transport's local host]],
[[serialized][host serializer]].
== [1408] Set [VAR[vars]]' [CODE[SERVER_PORT]] to [VAR[transport]]'s
[F[local port][transport's local port]], [[serialized][serialize an integer]].
= [1404] Otherwise:
== [1405] Set [VAR[vars]]'s [CODE[REMOTE_ADDR]] to [CODE[127.0.0.1]].
== [1406] Set [VAR[vars]]'s [CODE[SERVER_NAME]] to [CODE[127.0.0.1]].
== [1395] Set [VAR[vars]]'s [CODE[SERVER_PORT]] to [CODE[0]].
= [1392] If [VAR[url]]'s [F[query][URL query]] is not [CODE[null]]:
== [1393] Set [VAR[vars]]' [CODE[QUERY_STRING]] to [VAR[url]]'s [F[query][URL query]], [[UTF-8 encoded][UTF-8 encode]].
= [1396] For each [VAR[header name]] in [VAR[vars]]' [F[header list][request's header list]],
without any duplicate:
== [1397] If [VAR[header name]] is a string of one or more [[ASCII alphanumeric]] and/or
[CODE[-]] characters and not [[ASCII case-insensitively][ASCII case-insensitive]]
equal to [CODE[Content-Length]]:
=== [1398] Let [VAR[key]] be [VAR[header name]], [[converted to ASCII uppercase]].
=== [1399] Replace any [CODE[-]] in [VAR[header name]] by [CODE[_]].
=== [1400] If [VAR[header name]] is not [CODE[CONTENT_TYPE]]:
==== [1394] Prepend [CODE[HTTP_]] to [VAR[header name]].
=== [1401] Let [VAR[value]] be the header values in [VAR[vars]]'s 
[F[header list][request's header list]] whose name is 
[[ASCII case-insensitively][ASCII case-insensitive]] equal to [VAR[header name]], in order,
[[combined]].
=== [1402] Set [VAR[vars]]' [VAR[key]] to [VAR[value]].
= [1410] Let [VAR[host]] be [VAR[vars]]' [CODE[HTTP_HOST]]'s value, if any, or [CODE[null]].
= [1387] If [VAR[url]]'s [F[scheme][URL scheme]] is [[HTTP(S) scheme]] and
[VAR[url]]'s [F[hostport]], [[UTF-8 encoded][UTF-8 encode]], is [VAR[host]]:
== [1403] Set [VAR[vars]]' [CODE[REQUEST_URI]] to [VAR[url]], [[serialized][URL serializer]] and [[UTF-8 encoded][UTF-8 encode]].
= [1389] Otherwise:
== [1390] Set [VAR[vars]]' [CODE[REQUEST_URI]] to [VAR[request]]'s
[F[target url][request's target url]]'s [F[pathquery]] and [[UTF-8 encoded][UTF-8 encode]].
= [1381] Return [VAR[vars]].
]FIG]

;; [1415] [VAR[scheme key name]] is typically [CODE[wsgi.url_scheme]],
[CODE[psgi.url_scheme]], or similar.

@@ [[ASCII alphanumeric]], [[converted to ASCII uppercase]]
[[combined]]
[F[target url][request's target url]]
[[URL serializer]]
[[percent-decode]]
[[serialize an integer]]
[F[body length][request's body length]]

* References

[242] This specification depends on the [CITE[Infra Standard]].
The terms
[[forgiving-base64 encode]],
[[ordered set]], [[empty][list empty]], [[contains][list contain]],
and
[[pair]]
are defined in the [CITE[Infra Standard]].

[1044] The terms
[DFN[[[encoding]]]], [DFN[[[UTF-8]]]], [DFN[[[UTF-8 encode]]]],
[DFN[[[decode]]]],
[DFN[[CODE(DOMi)@en[TextDecoder]]]],
[DFN[[F[encoding][TextDecoder's encoding]]]],
[DFN[[F[error mode][TextDecoder's error mode]]]],
[DFN[[F[ignore BOM flag][TextDecoder's ignore BOM flag]]]],
[DFN[[CODE(DOMm)@en[decode][TextDecoder's decode]]]],
[DFN[[CODE(DOMi)@en[TextDecodeOptions]]]], and
[DFN[[CODE(DOMa)@en[stream]]]] 
are defined in the [CITE[Encoding Standard]].

[621] The terms 
[DFN[[[C0 controls and space]]]],
[DFN[[[serialize an integer]]]], 
[DFN[[[IPv4 address]]]], 
[DFN[[[IPv4 serializer]]]],
[DFN[[[IPv6 address]]]], [DFN[[[domain]]]],
[DFN[[[host]]]], [DFN[[[host parser]]]], [DFN[[[equals][host equivalence]]]],
[DFN[[[host serializer]]]],
[DFN[[[percent decode]]]],
[DFN[scheme][URL scheme (syntax)]], [DFN[[[network scheme]]]],
[DFN[[[URL parser]]]], [DFN[[[URL serializer]]]],
[DFN[[[URL record]]]],
[DFN[[F[scheme][URL scheme]]]], [DFN[[F[host]]][URL's host]], [DFN[[F[port]]][URL's port]], and
[DFN[[F[query][URL query]]]]
are defined by [CITE[URL Standard]].

[981] The terms [DFN[[[Public Suffix][public suffix]]]] and
[DFN[[[ICANN DOMAINS][ICANN domains]]]] is defined by [CITE[Public Suffix List]].

[1341] [[Status codes][status code]] [CODE[101]] and [CODE[200]] and
[[URL scheme]]s [CODE(URI)@en[http][http:]] and [CODE(URI)@en[https][https:]]
are defined by [[HTTP]].

[1330] HTTP headers
`[DFN[[CODE[Sec-WebSocket-Accept]]]]`,
`[DFN[[CODE[Sec-WebSocket-Extensions]]]]`,
`[DFN[[CODE[Sec-WebSocket-Key]]]]`,
`[DFN[[CODE[Sec-WebSocket-Protocol]]]]`,
`[DFN[[CODE[Sec-WebSocket-Version]]]]`
[[URL scheme]]s [CODE(URI)@en[ws][ws:]] and [CODE(URI)@en[wss][wss:]], and
the terms
[DFN[[[The WebSocket Connection is Established]]]],
[DFN[[[Extensions In Use]]]], [DFN[[[Subprotocol In Use]]]]
[DFN[[[A WebSocket Message Has Been Received]]]],
[DFN[[[The WebSocket Closing Handshake Is Started]]]],
[DFN[[[The WebSocket Connection Is Closed]]]],
[DFN[[[The WebSocket Connection Close Code]]]],
[DFN[[[The WebSocket Connection Close Reason]]]], and
[DFN[[[Fail The WebSocket Connection]]]]
are defined by [[RFC 6455]].

[354] The terms
[DFN[[[bad ports]]]],
[DFN[[[append][append (header list)]]]], [DFN[[[combine][combine (header list)]]]]
[DFN[[[request]]]],
[DFN[[F[url][request's url]]]],
[DFN[[F[current url][request's current url]]]],
[DFN[[F[method][request method]]]],
[DFN[[F[header list][request's header list]]]],
[DFN[[F[body][request body]]]],
[DFN[[F[client][request's client]]]],
[DFN[[F[skip-service-worker flag]]]],
[DFN[[F[synchronous flag]]]],
[DFN[[F[mode][request mode]]]], [DFN[[F[credentials mode]]]], [DFN[[F[cache mode]]]],
[DFN[[F[redirect mode]]]],
[DFN[[[response]]]],
[DFN[[F[status][status code]]]],
[DFN[[F[status message]]]],
[DFN[[F[body][response body]]]],
[DFN[[F[header list][response's header list]]]],
[DFN[[F[HTTPS state]]]],
[DFN[network error]],
[DFN[[[connection]]]],
[DFN[[[obtain a connection]]]],
[DFN[[[obtain a WebSocket connection]]]],
[DFN[[[basic fetch]]]], [DFN[[[HTTP fetch]]]], [DFN[[[HTTP-network-or-cache fetch]]]],
[DFN[[[HTTP-network fetch]]]],
[DFN[[[process response]]]], [DFN[[[process response done]]]], and
[DFN[[[establish a WebSocket connection]]]]
are defined in the [CITE[Fetch Standard]].

[961] The terms
[DFN[[[converted to ASCII lowercase]]]] and
[DFN[[[converted to ASCII uppercase]]]]
are defined in the [CITE[DOM Standard]].

[942] [DFN[[ABBR@en[[[SNI]]][Server Name Indication]]]] is specified in [[RFC 6066]].

[1007] [[WPAD]] is defined by the [[Internet Draft]].

[1008] [[PAC]] is defined by <https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Necko/Proxy_Auto-Configuration_(PAC)_file>
and <https://bugzilla.mozilla.org/show_bug.cgi?id=78176>.

[1298] The term [DFN[[[Strip [VAR[url]] for use as a referrer]]]]
is defined in the [CITE[Referrer Policy]].

* XXX

@@
[65] 
- reset vs abort
- [CODE[451]]
- [CODE[acceptSslCerts]] vs origin

@@ Trailers

* Note

[610] This document does not support [[QUIC]] at this stage, which is supported by [[Chrome]].

[1010] This document does not support [[VMS]]-style path syntax in [[FTP]],
which is supported by [[Firefox]] and [[Chrome]].

[1323] This document does not support persistent FTP control connection,
which is supported by [[Firefox]] and [[IE]].

[914] Test data:

[REFS[
- [1438] [[proxy environment variable parser]]
<https://github.com/wakaba/tests-web/tree/master/url/proxyenv>
]REFS]
