[535] [[HTTP]] 通信の直接の当事者間の[[仮想回路]]を、
[DFN[[RUBYB[[[接続]]]@en[connection]]]]といいます。

[564] [[接続]]の両端は[[クライアント]]と[[鯖]]ですが、[[串]]が介在する場合、
一方又は両方が[[串]]となることもあります。

* 仕様書

[REFS[
- [131] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-3.5>
- [515] '''[CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-6>'''
-- [539] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-6.3.1>
-- [548] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-6.4>
-- [553] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-6.5>
- [3] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-3.3.3>
- [512] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2014-06-07 01:59:35 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-5.6>
- [108] [CITE@en[RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing]] ([TIME[2015-04-23 00:49:39 +09:00]] 版) <https://tools.ietf.org/html/rfc7230#section-9.1>
- [577] [CITE@en[RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content]] ([TIME[2014-08-07 05:54:02 +09:00]] 版) <https://tools.ietf.org/html/rfc7231#section-6.6.4>
- [63] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540>
-- [45] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-2.2>
-- [47] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-3>
-- [62] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-5.1.1>
-- [73] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-5.4>
-- [60] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-6.8>
-- [76] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-7>
-- [82] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-8.1.4>
-- [90] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-9.1>
-- [109] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-10.1>
-- [111] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-10.2>
-- [115] [CITE@en[RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)]] ([TIME[2015-05-15 10:14:54 +09:00]] 版) <https://tools.ietf.org/html/rfc7540#section-10.8>
- [203] [CITE@en-US[Fetch Standard]] ([TIME[2016-04-19 01:53:35 +09:00]] 版) <https://fetch.spec.whatwg.org/#connections>
- [230] [CITE@en[Resource Hints]] ([TIME[2016-05-21 01:13:13 +09:00]]) <https://w3c.github.io/resource-hints/#dfn-initiate-a-preconnect>
- [234] [CITE@en[RFC 6455 - The WebSocket Protocol]] ([TIME[2015-03-11 20:42:50 +09:00]] 版) <http://tools.ietf.org/html/rfc6455#section-4>
- [235] [CITE[RFC Errata Report]] ([TIME[2015-05-16 22:26:12 +09:00]] 版) <http://www.rfc-editor.org/errata_search.php?rfc=6455>
]REFS]

* 状態

[46] [DFN[[RUBYB[接続]@en[connection]]]]は、2つの[[エンドポイント]]の間の[[トランスポート層]]の[[接続]]です [SRC[>>45]]。

[50] [[接続]]の[[エンドポイント]]は、[[クライアント]]か[[サーバー]]かのいずれかです。

[48] [[HTTP/0.9]] や [[HTTP/1.0]]、[[HTTP/1.1]]、[[HTTP/2]] [SRC[>>47]] の[[接続]]は、 
[[TCP接続]]上で動作する[[アプリケーション層プロトコル]][[輸送路]]です。

;; [49] [[TLS]] が間に挟まることもあります。 [[TCP]] の代わりに[[プロキシ]]プロトコルを用いる場合もあります。
(>>516)

[204] [[利用者エージェント][利用者エージェント (Web)]]は、
[F[接続プール]]として[[接続][HTTP接続]]群を保持します [SRC[>>203]]。

[205] [[接続][HTTP接続]]は、[F[起源]]と[F[credentials]]の組で識別されます [SRC[>>203]]。

[119] [[エンドポイント]]は、[[接続]]ごとに次の状態を持ちます。
[FIG(list members)[
: [F[起源]] : [[起源]]オブジェクト [SRC[>>203]]。
: [F[credentials]] : [[真偽値]] [SRC[>>203]]。
:下位層の情報:自身と [[peer]] の[[ホスト名]]や[[IPアドレス]]、[[ポート番号]]、
[[TLSセッション]]、[[RTT]] など。
:プロトコルの版:[[HTTP/0.9]]、[[HTTP/1.0]]、[[HTTP/1.1]]、[[HTTP/2]] のいずれか。
:自身の[[HTTP設定]]群:自身が値を決定した [[HTTP/2]] [[設定]]の各[[引数]]の値です。
:[[peer]] の [[HTTP設定]]群:[[peer]] から値を受信した [[HTTP/2]] [[設定]]の各[[引数]]の値です。
:[[HTTPストリーム]]群:[[HTTP/2接続]]内にある0個[[以上]]の[[HTTPストリーム]]の情報です。
初期状態では、空です (が [CODE(HTTP)@en[[[Upgrade: h2c]]]] でははじめに[[ストリーム]]が作られます)。
:[[HPACK]] 符号化用[[動的表]]:[[HTTP/2]] [[ヘッダーブロック]]の生成に使う[[動的表]]です。
:[[HPACK]] 復号用[[動的表]]:[[HTTP/2]] [[ヘッダーブロック]]の解釈に使う[[動的表]]です。
:[[依存性木]]:[[HTTP/2]] [[ストリーム]]の[[優先度]]を表す[[木]]です。
:[CODE(HTTP)@en[[[GOAWAY]]]] 送信[[最大ストリームID]]:[CODE(HTTP)@en[[[GOAWAY]]]]
を送信した場合その[[最大ストリームID]]。それより大きな[[ストリーム]]は以後処理しない。
:[CODE(HTTP)@en[[[GOAWAY]]]] 受信[[最大ストリームID]]:[CODE(HTTP)@en[[[GOAWAY]]]]
を受信した場合その[[最大ストリームID]]。
:タイムスタンプ:タイムアウトによる切断のために必要な情報。開始時刻、最後の送受信時刻など。
:[CODE(HTTP)@en[[[SETTINGS]]]] タイムスタンプ:
自身が最後に送信し、まだ [[ACK]] を受信していない [CODE(HTTP)@en[[[SETTINGS]]]]
[[フレーム]]の送信時刻です。一定時間経過後、タイムアウトによるエラーとなります。
:[CODE(HTTP)@en[[[GOAWAY]]]] 送信時刻:[CODE(HTTP)@en[[[GOAWAY]]]] 
を送信した場合そのタイムスタンプ。
:[[接続フロー制御窓]]:
:[[HTTP/1.1]] 以下の状態:[[HTTP接続の処理]]を参照。
]FIG]

[217] [[WebSocket接続]]は、更に [[WebSocket]] 固有の状態を持ちます。

;; [[WebSocket接続]]の項を参照。

* HTTP の版

[566] [[接続]]がどのように処理されるかは、[[HTTPの版]]によって異なっています。
[[HTTPの版]]は、 [[HTTP/1.1]] [[以下]]と [[HTTP/2]] のいずれであるかは
[[TLS]] の [[ALPN]] により示され、更に [[HTTP/1.1]] [[以下]]の場合には[[接続]]上を流れる[[HTTPメッセージ]]の[[先頭行]]でそのいずれであるかが示されます。

[FIG(switch)[
:[[ALPN]] で [CODE[[[h2]]]]: [[HTTP/2]]
:[[ALPN]] で [CODE[http/1.1]] または [[ALPN]] なし:
[FIG(switch)[
:[[先頭行]]が [CODE[[[HTTP/1.1]]]]: [[HTTP/1.1]]
:それ以外で[[先頭行]]に[[プロトコルの版]]: [[HTTP/1.0]]
:それ以外: [[HTTP/0.9]]
]FIG]
: それ以外 : 非 [[HTTP]]
]FIG]

[10] [[HTTP/1.1]] [[以下]]の場合、理論上は[[要求]]ごと、
あるいは[[応答]]ごとに異なる[[プロトコルの版]]を記述することもできますが、
普通はそのようなことはありません。
そのような状況で[[受信者]]がどう処理するべきかは不明です。

[136] 実際の [[Webブラウザー]]は、 [[HTTP/1.1]] と [[HTTP/1.0]] と [[HTTP/0.9]]
が同じ[[接続]]内に混在しても、それぞれの動作に従い処理します。
[CODE(HTTP)[[[1xx]]]] と[[最後の応答]]で[[プロトコルの版]]が異なっていても構いません。

;; [137] [[HTTPの構文解析]]、[[状態行]]、[[HTTP/0.9]]、[CODE(HTTP)[[[1xx]]]]
を参照。なお、一部ブラウザーで例外的にエラーとなることがあります (各項参照)。

[11] [[鯖]]がおかしな[[メッセージ]]を返したことによって [[HTTP/1.1]] や [[HTTP/1.0]]
の[[接続]]の途中で [[HTTP/0.9]] [[メッセージ]]が出現したと判断し、おかしな動作をする
[[Webブラウザー]]もありました。セキュリティー上の問題となる可能性もありますから、
注意が必要です。

;; [[HTTP/0.9]>>7]参照。

;; [118] 途中で版が変わる場合にはエラー[[応答]]を返したり、[[接続]]を切断したりするべきなのかもしれません。
なお[[プロキシ]]は受信したメッセージをそのまま[[転送]]するのではなく、
自身の対応する適切な版を選択して適宜書き換えて[[転送]]することが期待されていますから、
[[プロキシ]]との通信であっても途中で版が変わることはないはずです。

[54] [[HTTPの版]]の決定方法については、[[プロトコルの版]]を参照してください。

[78] [[HTTP/2]] から [[HTTP/1.1]] への切り替えもあります (>>79)。

[313] 
近年、
[[HTTP/0.9]]
や
[[HTTP/1.0]]
の[[要求]]にエラーを返す[[サーバー]]も出てきています。
[SEE[ [[426]] ]]

* 接続を得る

[206] [[利用者エージェント]][VAR[クライアント]]が[[起源]][VAR[起源]]、
[[boolean]] [VAR[credentials]]、
[[boolean]] [VAR[事前]] (既定値は[[偽]]) 
について[DFN[[RUBYB[接続を得る]@en[obtain a connection]]]]には、
次のようにします [SRC[>>203]]。
[FIG(steps)[
= [207] [VAR[クライアント]]の[F[接続プール]]に、
[F[起源]]が[VAR[起源]]で[F[credentials]]が[VAR[credentials]]の[[接続][HTTP接続]]があれば、
== [208] それを返し、ここで停止します。
= [209] [VAR[接続]]を、[VAR[起源]]への [[HTTP接続]]を確立した結果に設定します。
[VAR[credentials]] が[[偽]]なら、[[TLSクライアント証明書]]を送信しません。
本 [[fetch]] が [[terminate][terminate (fetch)]] されたら、接続を中断します。
= [289] 本 [[fetch]] が [[terminate][terminate (fetch)]] されている場合、
== [290] [VAR[接続]]が [CODE[null]] 以外の場合、
=== [291] [VAR[接続]]を閉じます。
=== [292] [[失敗]]を返し、ここで停止します。
= [210] [VAR[接続]]が[[失敗]]なら、
== [211] [[失敗]]を返し、ここで停止します。
= [212] [VAR[接続]]の[F[起源]]を、[VAR[起源]]に設定します。
= [213] [VAR[接続]]の[F[credentials]]を、[VAR[credentials]]に設定します。
= [214] [VAR[接続]]を、[VAR[クライアント]]の[F[接続プール]]に追加します。
= [215] [VAR[接続]]を返します。
]FIG]

[231] [VAR[事前]]が[[真]]の場合、[[HTTP接続]]の確立 (>>209)
はできれば完全に行う[SHOULD[べき]]ですが、
[[資源]]制約その他の理由で叶わなければ、
一部または全部を省略して構いません [SRC[>>230]]。

[EG[
[232] 例えば [[DNS]] の[[名前解決]]のみとしたり、 [[TCP]] までで [[TLS]]
は行わなかったりしても構いません。 [SRC[>>230]]
]EG]

;; [233] もちろん、その[[事前接続]]を後から実際に利用するためには、
接続の確立の処理を完了させる必要があります。

[219] 後述の通り、同じ[[サーバー]]に複数の[[接続][HTTP接続]]を同時に確立できます。
[F[接続プール]]には、[F[起源]]と[F[credentials]]の組が同じ[[接続][HTTP接続]]が複数含まれているかもしれません。
何個まで含められるかや、それらからどうやって選ぶか(選ばないか)は、
[VAR[クライアント]]に委ねられています。 
([[パフォーマンス]]や利用可能[[資源]]などの[[トレードオフ]]を考慮する必要があります。)
[VAR[事前]]が[[真]]なら、
既に十分な数の接続があれば、新たな接続を確立しないことにするかもしれません。 
[VAR[事前]]が[[偽]]なら、接続数が減少するまで[[HTTP接続]]の確立の実処理を遅延させる必要がありそうです。

[216] [[WebSocket接続を得る]]手順は、これとは別に用意されています (詳細はそちらの項を参照)。
通常の[[HTTP接続を得る]]手順とおおむね同趣旨ではあるのですが、
[[WebSocket]] は必ず新しい[[接続][HTTP接続]]を使うので、[F[接続プール]]は参照しません。
(これは[[事前接続]]が利用されないことも意味します。)

[218] これらは、 [[HTTP-network fetch]] から呼び出されます。

[224] [[接続を得る]]は、[[事前接続の開始]]からも呼び出されます。

** 接続先の決定

[531] [[接続]]先の[[鯖]]は、他の[[インターネット]]の[[アプリケーション層プロトコル]]と同じように、
[[URL]] などによって指定された[[ドメイン名]]や [[IPアドレス]]などと[[ポート番号]]とを使って識別されます。

;; [532] [CODE(URI)@en[[[http:]]]] の項も参照してください。

[67] [[URL scheme]] が [CODE(URI)@en[[[http:]]]] なら [[TCP]] を、
[CODE(URI)@en[[[https:]]]] なら [[TLS]] over [[TCP]] を下位層として使います。

;; [68] [[HSTS]] では特定の条件を満たす [CODE(URI)@en[[[http:]]]] [[URL]]
に接続する前に [CODE(URI)@en[[[https:]]]] [[URL]] へと書き換えます。
この処理は [[fetch]] で行われます。 [[HTTP接続]]の確立の段階では、
既に書き換え済みです。

[197] [[クライアント]]が[[代替サービス]]に対応しており、接続先の [[URL scheme]]、
[[ホスト]]、[[ポート]]の組に対して適用可能な[[代替サービス]]を知っている場合、
接続先の[[プロトコル]]、[[ホスト]]、[[ポート]]をその[[代替サービス]]のものとします。

;; 詳細は[[代替サービス]]参照。

[EG[
[199] [[Chrome]] は、 [[QUIC]] が利用可能なら、そちらに切り替えます。
]EG]

[EG[
[285] [[Firefox]] は、 [[Opportunistic HTTP/2 Security]] が利用可能なら、
そちらに切り替えます。
]EG]

[533] [[プロキシ]]は、[[利用者エージェント]]の設定などの実装依存の方法で指定されます。
[[串]]が指定されている場合は、[[接続]]先は[[サーバー]]ではなく、[[プロキシ]]となります。

;; [534] 多くの[[Webブラウザー]]は、 [[proxy.pac]] による指定に対応しています。

;; [198] [[代替サービス]]に接続する場合も、必要に応じて[[プロキシ]]を使います。

[19] [[串]]に[[名前解決]]を委ねる場合を除き、通常は[[ホスト]]部の[[名前解決]]を行い、
[[IPアドレス]]を取得し、それを[[接続]]先の[[鯖]]とします。[[名前解決]]は [[DNS]]
によって行うのが基本ですが、 [CODE[[[/etc/hosts]]]] や [[NetBIOS]] 
など当該システムが実装している他の[[名前解決]]の仕組みが用いられることもあります。

;; [[名前解決]]を参照。

;; [[インターネット]]の [[DNS]] による[[名前解決]]と [CODE[[[localhost]]]]、
それに [[IPアドレス]]による直接指定を除くと、
システム依存の[[名前解決]]方式に依存した接続先の指定は[[相互運用]]不能です。

;; [120] [[WebSocket接続の確立]]も参照。

** 接続の開始

[530] [[接続]]は、[[クライアント]]が[[鯖]] (または[[串]]) 
に対して下位層プロトコルの[[接続]]を確立することにより、開始されます。
[[鯖]]は下位層プロトコルと [[OS]] 等の [[API]] ([[ソケット]]など)
の規定に基づき予め[[接続]]を受け付ける状態で待っている必要があります。

;; [69] 下位層プロトコルの章 (>>516) も参照。

[536] [[HTTP/1.1]] [[以下]]では、他の多くの[[アプリケーション層プロトコル]]とは違って、
[[接続]]の初期化のようなプロトコル上の手続きはなく、すぐに[[要求]]を送信できます。

;; [70] [[HTTP認証]]は、[[接続]]レベルではなく、個々の[[要求]]のレベルで行われるのが原則です。
([[HTTP認証]]の項を参照。) 従って、 [[HTTP]] レベルでは[[接続]]の確立の段階で
[[challenge]] や [[credentials]] の送信など[[認証]]操作は行われません。
もちろん、[[サーバー]]は必要なら下位層の接続が確立された (確立しようとする) 時点で
[[IPアドレス]]や[[TLSクライアント証明書]]などを使って [[HTTP]]
よりも前に認証を行うことはできます。

[568] [[接続]]が確立されると、[[クライアント]]は[[鯖]]に[[要求]]を送信します。
その送信のタイミングは特に規定されていませんが、通常は即座に送信します。
後述の通り、[[鯖]]は通常タイムアウトを設定しており、一定時間内に[[要求]]が送信されなければ、
エラーとして扱います。

[20] [[クライアント]]が[[名前解決]]に失敗した場合や下位層プロトコルの[[接続]]の確立に失敗した場合は、
当然ながら [[HTTP接続]]を利用することはできず、[[要求]]を送信できません。

*** cross-protocol attack

[121] [[HTTP/1.1]] 以下は単純なテキストベースのプロトコルなので、
攻撃者の指示により[[クライアント]]が他のプロトコルに接続できる文字列を送ることができてしまう場合があります
([RUBYB[[[プロトコル横断攻撃]]][cross-protocol attack]])。

;; [114] [CODE(MIME)@en[[[multipart/form-data]]]] により[[フォームデータ]]を [[HTTP]]
で送信することで、 [[cross-protocol attack]] が試みられることがあります。

;; [122] [[HTTPヘッダー]]など他のプロトコルで解釈できない部分を未知の命令などとして無視するプロトコルを攻撃できます。

[113] [[Webブラウザー]]は [[port blocking]] により他の[[プロトコル]]が使うことが多い[[ポート]]へのアクセスを拒み、
[[cross-protocol attack]] を難しくしています。

[110] [[HTTP/2]] over [[TLS]] は [[ALPN]] によりプロトコルを明示でき、
また[[暗号化]]のため [[TCP]] 上のバイト列を制御することが難しいため、
[[cross-protocol attack]] は困難です [SRC[>>111]]。

[123] [[HTTP/1.1]] [[以下]] over [[TLS]] は[[暗号化]]のため、[[平文]]プロトコルを攻撃することは困難です。
しかし [[ALPN]] を使わなくて良いため、 [[TLS]] 上の非 [[HTTP]]
[[プロトコル]]は攻撃できるかもしれません。

[112] [[HTTP/2]] over [[TCP]] は[[接続序文]]により [[HTTP/1.1]] [[以下]]の実装の誤動作を防ごうとしていますが、
非 [[HTTP]] [[プロトコル]]に対する [[cross-protocol attack]] を防ぐものではありません [SRC[>>111]]。

[311] [[HTTPサーバー]]の実装によっては、
[[HTTPS]] が期待されるところに[[HTTP要求]]を受信すると、
エラーの[[HTTP応答]]を返します。

[312] [[IRC]] サーバーの実装によっては、
[[HTTP要求]]を受信すると、
エラーを返し切断します。

** 接続の並行性

[87] [[HTTP/1.1]] [[以下]]では、1つの[[接続]]で同時に送受信できる[[応答]]は1つだけです。
1つの[[文書]]に埋め込まれた複数の[[画像]]が存在する場合など、
[[クライアント]]側の処理性能の向上のためには複数の[[接続]]を[[並列]]に確立する必要があります。

[88] [[HTTP/1.0]] の [[keep-alive]] や [[HTTP/1.1]] の[[持続的接続]]や[[パイプライン]]化を用いると
1つの[[接続]]を再利用して次の[[応答]]を受信することができ、 [[TCP接続]]の再[[確立]]や次の[[要求]]の送受信の時間を節約できますが、
前の[[応答]]が完了するまで次の[[応答]]は送信できませんから、
すぐに[[レンダリング]]開始したいなら、やはり複数の[[接続]]が必要となります。

[89] しかし[[接続]]数が多すぎると[[サーバー]]や[[ネットワーク]]に過剰な負荷を与えてしまう虞があるため、
[[クライアント]]は適当な上限を設けるべきです。

[550] 旧仕様の [[RFC 2616]] までは、ある[[クライアント]]からある[[鯖]] (や[[串]])
への同時接続数は2[[以下]]とするべきだとされていました [SRC[>>549]]。

[551] [[RFC 7230]] は、[[応用]]によっては非現実的なので、特定の上限は設けないが、
[[クライアント]]は[[接続]]を開くのには保守的であるようにと求めています [SRC[>>548]]。

[552] 多くの [[Webブラウザー]]は、00年代前半までは [[RFC]] の上限を既定値とし、
設定によっては更に増やすこともできるようになっていました。
しかしその後 [[Ajax]] の普及などに伴い徐々に制限が緩和されています。

[REFS[
- [549] [CITE@en[RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1]] ([TIME[2014-06-07 01:51:52 +09:00]] 版) <http://tools.ietf.org/html/rfc2616#page-47>
- [243] [CITE@en[Network.http.max-connections - MozillaZine Knowledge Base]] ([TIME[2015-11-24 06:40:48 +09:00]]) <http://kb.mozillazine.org/Network.http.max-connections>
- [244] [CITE@en[Network.http.max-connections-per-server - MozillaZine Knowledge Base]] ([TIME[2008-03-20 12:13:05 +09:00]]) <http://kb.mozillazine.org/Network.http.max-connections-per-server>
- [245] [CITE@en[Network.http.max-persistent-connections-per-proxy - MozillaZine Knowledge Base]] ([TIME[2008-03-20 12:16:57 +09:00]]) <http://kb.mozillazine.org/Network.http.max-persistent-connections-per-proxy>
- [246] [CITE@en[Network.http.max-persistent-connections-per-server - MozillaZine Knowledge Base]] ([TIME[2015-11-24 06:46:13 +09:00]]) <http://kb.mozillazine.org/Network.http.max-persistent-connections-per-server>
- [251] [CITE@en[33259 – So, should we make a number of http connections configurable]] ([TIME[2016-06-17 10:47:33 +09:00]]) <https://bugzilla.mozilla.org/show_bug.cgi?id=33259>
- [247] [CITE@en[83526 – http should use fewer connections per server per page]] ([TIME[2016-06-17 10:33:47 +09:00]]) <https://bugzilla.mozilla.org/show_bug.cgi?id=83526>
- [250] [CITE@en[103070 – No new connections issued when waiting for timeout]] ([TIME[2016-06-17 10:42:51 +09:00]]) <https://bugzilla.mozilla.org/show_bug.cgi?id=103070>
- [248] [CITE@en[423377 – (wedidntstartthefire) Change max-persistent-connections-per-server to 6.]] ([TIME[2016-06-17 10:38:45 +09:00]]) <https://bugzilla.mozilla.org/show_bug.cgi?id=423377>
- [252] [CITE@en[648570 – increase total idle pconn tool to 256 (matches chrome)]] ([TIME[2016-06-17 10:48:31 +09:00]]) <https://bugzilla.mozilla.org/show_bug.cgi?id=648570>
- [253] [CITE@en[692260 – Increase in network.http.max-connections appears to cause hang, requires browser restart]] ([TIME[2016-06-17 10:53:06 +09:00]]) <https://bugzilla.mozilla.org/show_bug.cgi?id=692260>
- [254] [CITE@en[Issue 12066 - chromium - Match Firefox's per-host connection limit of 15 - Monorail]] ([TIME[2016-06-17 10:59:20 +09:00]]) <https://bugs.chromium.org/p/chromium/issues/detail?id=12066>
- [255] [CITE@en[Issue 19052 - chromium - Option to configure max-persistent-connections-per-proxy - Monorail]] ([TIME[2016-06-17 11:00:09 +09:00]]) <https://bugs.chromium.org/p/chromium/issues/detail?id=19052>
- [259] [CITE@en[Issue 44501 - chromium - Consider changing connections per proxy server limit - Monorail]] ([TIME[2016-06-17 11:04:52 +09:00]]) <https://bugs.chromium.org/p/chromium/issues/detail?id=44501>
- [256] [CITE@en[Issue 63658 - chromium - Policy: Add policy to manage max number of concurrent connections per proxy server - Monorail]] ([TIME[2016-06-17 11:01:13 +09:00]]) <https://bugs.chromium.org/p/chromium/issues/detail?id=63658>
- [258] [CITE@en[Issue 85323 - chromium - Configurable connections-per-host - Monorail]] ([TIME[2016-06-17 11:03:42 +09:00]]) <https://bugs.chromium.org/p/chromium/issues/detail?id=85323>
- [257] [CITE@en[Issue 87381 - chromium - Allow configuring of max connections and max connections per proxy - Monorail]] ([TIME[2016-06-17 11:02:04 +09:00]]) <https://bugs.chromium.org/p/chromium/issues/detail?id=87381>
- [6] [CITE[AnyEvent::HTTP - search.cpan.org]] ([TIME[2014-10-22 08:11:41 +09:00]] 版) <http://search.cpan.org/dist/AnyEvent-HTTP/HTTP.pm#%24AnyEvent%3A%3AHTTP%3A%3AMAX_PER_HOST>
]REFS]

[91] [[HTTP/2]] では[[持続的接続]]が基本動作となっており、
[[クライアント]]は必要が無いと判断するまで[[接続]]を閉じずにいることが期待されています
[SRC[>>90]]。[[クライアント]]は 1つの[[接続]]で複数の[[ストリーム]]を使って[[並行]]して[[応答]]を受信できます。
[[クライアント]]は、[[プロキシ]]を含む[[サーバー]]への[[接続]]を、
[[ホスト]]と[[ポート]]の組に対して複数開く[['''べきではありません''']] [SRC[>>90]]。

;; [116] これは[[サーバー]]が[[利用者]]の動作を追跡しやすくすることになり、
注意が必要です。 [SRC[>>115]]

[93] [[HTTP/2]] [[クライアント]]は、異なる値を [[SNI]] に指定する場合や異なる [[TLS]]
[[クライアント証明書]]を指定する場合は、同じ [[IPアドレス]]と [[TCPポート]]に対して複数の[[接続]]を開いて構いません。
しかし同じ指定で複数の[[接続]]を開くことは避ける[['''べきです''']]。 [SRC[>>90]]

;; [103] 逆に複数の[[ホスト]]が同じ[[接続]]を共有する場合 (>>96) があります。

[92] [[HTTP/2]] [[クライアント]]は、既存の[[接続]]が[[ストリーム識別子]]空間を使い果たしつつある場合や、
[[TLSセッション]]の鍵の更新のため必要な場合、
[[エラー]]を検出した場合には、代替となる[[接続]]を新たに開くことができます [SRC[>>90]]。

*** 他の接続を待つ

[237] [[WebSocket]] に関しては、他の接続が閉じられるのを待つ処理が明文化されています。

[236] [DFN[他の接続を待つ]]場合は、次のようにしなければ[MUST[なりません]] [SRC[>>234]]。
[FIG(steps)[
= [[ホスト]]から、 [[IPアドレス]]を得ます ([[名前解決]])。
= [[ホスト]]から[[IPアドレス]]を得られない場合 (例えば[[名前解決]]を[[プロキシ]]に委ねている場合)、
== [VAR[host]] を、[[ホスト]]に設定します。
== [VAR[n]] を、十分小さな値とする[SHOULD[べきです]]。例えば開いている[[タブ]]数を考慮して決めます。
= それ以外の場合、
== [VAR[host]] を、[[IPアドレス]]に設定します。
== [VAR[n]] を、1 に設定します。
= 同じ [VAR[host]] と[[ポート]]への状態が [CODE[[[CONNECTING]]]]
である[[WebSocket接続]]があるか調べます。
= その数が [VAR[n]] [[未満]]となるまで、待ちます。
]FIG]

[238] この制限は、[[著者]]が多数の [[WebSocket接続]]を開いて [[DoS攻撃]]することを難しくするためのものです
[SRC[>>234]]。

;; [239] [[ホスト]]のみで制限する実装と[[ホスト]]と[[ポート]]の組で制限する実装があります
[SRC[>>235]]。

;; [240] これをうまく使うとある[[ホスト]]とある[[ホスト]]が同じ [[IPアドレス]]かどうかをある程度の精度で推測できるかもしれませんが、
それによって何か問題になることはあまり無さそうです。

[241] [[HTTP/1]] (非 [[WebSocket]]) と [[HTTP/2]] に関しては明文規定はありませんが、
[VAR[n]] 以外は同様に処理するべきものと思われます。 
([[プロキシ]]への接続と[[起源サーバー]]への接続とでも [VAR[n]] は違いそうです。)

** 接続の再利用

[94] [[HTTP/1.0]] [[keep-alive]]、[[HTTP/1.1]] [[持続的接続]]、[[HTTP/2]]
では、同じ[[接続]]を複数の[[要求]]と[[応答]]の組の送受信に再利用できます。

[95] [[HTTP/1.0]] と [[HTTP/1.1]] でどのような場合に[[接続]]を再利用できるのかは、
明確な規定がありません。

[96] [[HTTP/2]] の[[起源サーバー]]への接続は、直接のものであれ [CODE(HTTP)@en[[[CONNECT]]]]
[[トンネル]]経由であれ、 [[authority]] が異なっていても当該[[起源サーバー]]が
[[authoritative]] である限り、再利用できます。 [SRC[>>90]]

[97] 具体的には、 [[TLS]] 無しの [[TCP]] では、[[ホスト]]が同じ [[IPアドレス]]に[[解決]]されることをいいます。 [SRC[>>90, >>108, >>109]]
(もちろん[[ポート番号]]も一致する必要があります。)

[98] [CODE(URI)@en[[[https]]]] では、 [[TCP]] のみの場合の条件に加え、
[[サーバー証明書]]が新しい [[TLS接続]]の場合と同様の検査を満足しなければ[['''なりません''']]。
[SRC[>>90, >>108, >>109]]

;; [99] [[SAN]] や[[ワイルドカード証明書]]を使うと、同じ[[証明書]]で複数の
[[authority]] に対応できます。

;; [102] 複数の[[ホスト]]へ同じ[[接続]]を利用できる本規定と、
同時接続の禁止 (>>91) がどう関係するのかは不明です。

;; [117] [[起源]]を超えて[[サーバー]]が[[利用者]]の行動を追跡しやすくなりますから、
注意が必要です [SRC[>>115]]。

[104] [[サーバー]]の構成によっては、 [[SNI]] で指定された[[ホスト]]によって[[中間器]]が異なる[[起源サーバー]]を選択する場合など、
[[クライアント]]が (機密かもしれない) [[要求]]を誤った[[サーバー]]に送ってしまう可能性もあります。
[[サーバー]]は、[[クライアント]]に[[接続]]を再利用してほしくない場合、
[[authoritative]] でないことを [CODE(HTTP)[[[421]]]]
[[応答]]によって表明できます。 [SRC[>>90]]

;; [105] [[クライアント]]は事前に判定できないので、[[要求]]が他者に漏洩してしまう可能性があるわけですが、
良いのでしょうか... [[クラウド]]サービスの共通の[[逆串]]などで[[証明書]]まで共有していても異なる[[起源サーバー]]に接続されることはあるでしょうから、その場合[[クラウド]]サービス提供者は確実に
[CODE(HTTP)[[[421]]]] [[応答]]を返すよう注意が必要です。

[106] [[HTTP/2]] [[プロキシ]]を使う[[クライアント]]は、
すべての[[要求]]を同じ[[接続][HTTP接続]]に送信します [SRC[>>90]]。

;; [185] [[要求URL]]も参照。

[283] [[代替サービス]]に関してはまた別の要件があります。

* 接続上を流れるもの

[401] 通常の [[HTTP]] の通信では、[[HTTPメッセージ]]が[[接続]]上を送受信されます。

[523] [[HTTPメッセージ]]は、[[要求メッセージ]]または[[応答メッセージ]]です。
現在の [[HTTP]] では[[クライアント]]から[[鯖]]へと送信されるのが[[要求]]、
[[鯖]]から[[クライアント]]へ送信されるのが[[応答]]と決まっています。

[52] テキスト形式プロトコルである [[HTTP/1.1]] [[以下]]では、
[[メッセージ]]は [[RFC 822]] 風のテキスト形式で表現され、
[[接続]]上を直接送受信されます。

[53] バイナリー形式プロトコルである [[HTTP/2]] では、
[[メッセージ]]は複数の[[フレーム]]の列で表現され、
[[接続]]内の[[ストリーム]]上のバイト列として送受信されます。

** HTTP/1.1 以下

[55] [[要求]]を[[クライアント]]から[[サーバー]]へと送信し、
それに対して[[応答]]を[[サーバー]]から[[クライアント]]へと送信するのが基本的な動作です。
[[接続]]を開き、送受信を行ってから、[[接続]]を閉じます。

[FIG(sequence)[
:C:[[クライアント]]
:S:[[鯖]]
:C ## S:[[接続の確立]]
:C -> S:[[要求]]
:S -> C:[[応答]]
:C ## S:[[接続]]を閉じる
]FIG]

[522] [[持続的接続]]機能を使うと、1つの[[接続]]で複数の[[要求]]と[[応答]]の組をやりとりすることができます。

;; [9] [[持続的接続]]は [[HTTP/1.1]] では標準機能となっています。
([[HTTP/1.0]] では [[Keep-Alive]] は実験的に追加された機能でした。)
詳しくは[[持続的接続]]を参照。

[513] [[要求]]と[[応答]]の対応関係は、明示されません。
[[要求]]が送信されたのと同じ順に[[応答]]が送信されます。 [SRC[>>512]]

;; [524] ですから、下位層プロトコルは順序を保証するものである必要があります。

[525] [[応答]]は、必ず[[要求]]に対する反応として送信されます。
[[要求]]がないのに[[応答]]が送信されることは、原則としてありません。

;; [526] 例外的に、[[接続]]をはじめてから何も送られないままタイムアウトした場合など、
特別に[[応答]]が送信され、ただちに[[接続]]が閉じられるケースがあります。

[528] [[メッセージ]]の境界は、[[メッセージ]]自体によって、または[[接続]]が閉じられることにより識別されます。下位層プロトコルは[[オクテット列]]の送受信のみが要求されています。

;; [529] 詳しくは[[メッセージ]]と[[メッセージ本体]]の項を参照してください。

[132] [[鯖]]は、少なくても1つは[[要求行]]の前の [[CRLF]] を無視する[['''べきです''']]
[SRC[>>131]]。 実際には他の[[改行]]と同じく、省略可能な [[CR]] とその後の [[LF]] 
が無視されるようです。

[133] [[Apache]] も [[nginx]] も、[[要求]]の前の任意の個数の[[改行]]を無視するようです。
[TIME[2015-06-15T12:58:39.600Z]]

;; [134] すべての実装がそのように動作するなら、 [[ping]] の代用とできるかもしれません。
実際どうなのかは定かではありません。

[546] [[パイプライン]]化により、[[要求]]に対する[[応答]]の到着を待たずに次の[[要求]]を送ることもできます。

;; 詳しくは[[HTTPパイプライン]]の項を参照してください。

[402] [CODE(HTTP)@en[[[CONNECT]]]] [[メソッド]]に対して [CODE(HTTP)[[[2xx]]]]
[[応答]]が返された場合、[[メッセージ]]はそこで終端され、
以後は[[トンネル]]となります。詳しくは [CODE(HTTP)@en[[[CONNECT]]]]
の項を参照してください。

[562] [CODE(HTTP)@en[[[Upgrade:]]]] によって[[プロトコル]]が切り替えられる場合、
[[鯖]]によって [CODE(HTTP)[[[101]]]] が返され、それよりも後は新しい[[プロトコル]]に切り替わります。
詳しくは [CODE(HTTP)@en[[[Upgrade:]]]] や [[WebSocket接続の確立]]、
[[WebSocket接続]]の項を参照してください。

;; [38] [[パイプライン化]]と [CODE(HTTP)@en[[[CONNECT]]]] や [CODE(HTTP)@en[[[Upgrade:]]]]
の組み合わせは思わぬ副作用を生むかもしれません。例えば別のプロトコルに切り替わる前に[[クライアント]]がデータを送信していると、
[[鯖]]がそれをどう解釈するかが曖昧となり、[[セキュリティー]]や[[相互運用性]]の問題を引き起こすことがあります。
[[RFC 7472]] や [[HTTPS]] の歴史の項も参照。

;; [43] [[クライアント]]が対応していない [CODE(HTTP)[[[101]]]]
[[応答]]を受信した場合の[[クライアント]]の処理は、[CODE(HTTP)[[[101]]]]
を参照してください。

*** 応答間のデータ

[167] 前の[[応答]]を受信し終えてから次の[[要求]]の送信を始めるまでの間に受信したデータは、
どのブラウザーも捨てるようです。 [TIME[2015-09-12T14:34:03.900Z]]

[168] [[素のHTTP]] ではどのブラウザーも最初の[[要求]]の送信前に受信した
(であろう) データは最初の[[要求]]への[[応答]]とみなすようです。 [TIME[2015-09-12T14:35:47.200Z]]

[169] [[HTTPS]] では [[Chrome]] と [[IE]] は ([[TLS handshake]] 後に送られた)
最初の[[要求]]の送信前にデータを受信したら、最初の[[要求]]を[[ネットワークエラー]]とするようです。 [TIME[2015-09-12T14:37:41.400Z]]

[171] [[Firefox]] は [[HTTPS]] で最初の[[要求]]の前に受信しても最初の[[応答]]とみなすように見えます。
しかし[[応答]]後に受信したデータがあると次の[[要求]]にその[[接続]]を使わないように見えます。
([[Chrome]] では [[HTTP]] と同じく[[応答]]後のデータは無視するように見えます。) 
[TIME[2015-09-12T14:49:57.500Z]]

[265] [[nginx]] や [[Apache]] は最初の[[要求]]の前に LF または CRLF があれば、これを無視します。
それ以外の CR と LF の列があると、 [[nginx]] はおかしな状態になり、
[[Apache]] は[[要求行]]として解釈しようとしてエラーを返します。 [TIME[2016-09-09T07:57:44.000Z]]

[266] [[nginx]] は最初の[[要求]]と次の[[要求]]の間で任意の CR と LF
の列を無視します。 [[Apache]] は LF または CRLF の任意個の繰り返しを無視します。 [TIME[2016-09-09T07:58:13.600Z]]

;; [170] いずれの場合についても[[ネットワーク]]や [[TCP/IPスタック]]の状況によって[[アプリケーション]]に到達するタイミングが左右される上、
[[接続]]の確立から最初の[[要求]]を送信するまでの時間はごくわずかなので、
動作は不確かです。

** HTTP/2

[80] [[ストリーム]]の処理については、[[ストリーム]]や[[フレーム]]を参照。

[81] [[メッセージ]]の送受信については、[[HTTPメッセージ]]、
[[HTTP要求]]、[[HTTP応答]]、[[サーバープッシュ]]を参照。

[51] 両[[エンドポイント]]は、[[メッセージ]]を構成する[[フレーム]]の他、
適宜 [CODE[[[PING]]]] [[フレーム]]、
[[フロー制御]]のための [CODE[[[WINDOW_UPDATE]]]] [[フレーム]]、
[[設定]]変更のための [CODE[[[SETTINGS]]]] [[フレーム]]などを送受信することになります。

;; [57] [[HTTP/2]] [CODE(HTTP)@en[[[CONNECT]]]] [[要求メソッド]]は、
[[ストリーム]]内のデータの送受信を[[トンネル]]として使います。 [[HTTP/1.1]]
とは違って[[接続]]全体が切り替わるのではないので、他の[[ストリーム]]により
(または同じ[[ストリーム]]の [CODE[[[DATA]]]] 以外の[[フレーム型]]により)
[[HTTP]] データの送受信は継続できます。

;; [58] [[HTTP/2]] では [CODE(HTTP)@en[[[Upgrade:]]]] は使えません。

** 最初の要求と応答

[284] [[Opportunistic Security for HTTP/2]] では、
実際の[[要求]]と[[応答]]の送受信の前に、
[CODE[/.well-known/http-opportunistic]] の送受信が発生します。
ただし、[[HTTPキャッシュ]]により省略される場合もあります。

;; [CODE[/.well-known/http-opportunistic]] 参照。

** 要求の時機

[225] 基本的には、[[接続][HTTP接続]]が確立されたら、すぐに最初の[[要求]]が送信されます。

[226] [[事前接続]]を用いる場合は、[[接続][HTTP接続]]の確立から最初の[[要求]]の送信までに若干の時間があるかもしれません。

[228] 同じ[[接続][HTTP接続]]を再利用 (>>94) して次の[[要求]]を送信する場合もあります。
これも前の[[要求]]と[[応答]]の後すぐに送信される場合もあれば、時間を置く場合もあります。

;; [229] [[HTTP/1]] では理論上 [[HTTPパイプライン]]により前の[[応答]]を待たずに次の[[要求]]を送ることができますが、
実際には不可能です。
[[HTTP/2]] では複数の[[ストリーム][HTTPストリーム]]を同時に用いられるので、
他の[[要求]]・[[応答]]のタイミングに関わらず次の[[要求]]を送信できます。

[227] [[サーバー]]は、一定時間内に[[要求]]が送信されなければ、
[[タイムアウト]] (>>554) で[[接続][HTTP接続]]を閉じるかもしれません。

** 応答の時機

[569] [[応答]]が送信されるタイミングは、特に規定されていません。
[[鯖]]が[[要求]]の末尾まで読み終えるよりも先に送信される可能性もありますし、
[[要求]]がすべて読み終わってからしばらく経ってようやく送信される可能性もあります。
[[要求]]が送信され始めるより前に[[応答]]が返されることもあるかもしれません。
[[long poll]] では、[[応答]]の送信開始や送信完了までの待機時間が長いかもしれません。

[579] [[要求]]が[[非妥当]]である場合や、[[要求]]の[[要求行]]や[[ヘッダー]]、
あるいは[[メッセージ本体]]の途中で[[鯖]]が処理できないと判断した場合、
[[鯖]]が[[要求]]をすべて読み終わる前や[[クライアント]]が[[要求]]を送信し終わる前に[[鯖]]がエラー
([CODE(HTTP)[[[400]]]] や [CODE(HTTP)[[[413]]]] や [CODE(HTTP)[[[505]]]] など) を返したり、
[[接続]]を閉じたりすることがあります。

[44] [[クライアント]]は通常タイムアウトを設定しており、一定時間内に[[応答]]の一部または全部が返されなければ、
通信やサーバーのエラーとみなします。タイムアウトまでの[[時間]]は、[[アプリケーション]]の性質や[[サーバー]]や[[クライアント]]の用途、
想定される[[ネットワーク]]の状態など様々な因子に依存するため、一概には決められません。

[572] [[メッセージ]]を構成するデータの送信速度は、一様でなくても構いません。
例えば、[[鯖]]が [CODE(MIME)@en[[[multipart/x-mixed-replace]]]] [[応答]]を返す場合、
ある程度の時間をあけて複数の[[本体部分]]を送信し続けることになります。

;; もちろん、実装によってはタイムアウトがありますから、
あまりにも長時間データの送信が行われないと、エラーとみなして[[接続]]が閉じられることがあります。

[573] 用途によっては、 [[payload body]] が無限に長いこともあります。
その場合は、相手側によって[[接続]]が閉じられたり、
ネットワークエラーなど外部的な要因で[[接続]]が閉じられたりしない限り、
データの送信が継続されます。

;; [574] ですから、 [[HTTP]] の実装は、[[メッセージ]]が有限の長さを持つことを仮定することはできません。

** [CODE(HTTP)[1xx]] 応答

[514] [CODE(HTTP)[[[1xx]]]] [[応答]]が最終[[応答]]より前に送信される場合には、
1つの[[要求]]に複数の[[応答]]が対応することとなります。 [SRC[>>512]]

[FIG(sequence)[
:C:[[クライアント]]
:S:[[鯖]]
:C -> S:[[要求]]
:S -> C:[CODE(HTTP)[[[1xx]]]] [[応答]]
:S -> C:[CODE(HTTP)[[[1xx]]]] [[応答]]
:S -> C:[[最後の応答]]
]FIG]

;; [527] [[要求]]送信後に[[接続]]が閉じられた場合など例外的なケースを除けば、
[[要求]]には必ず[[応答]]が送られます。

[56] [CODE(HTTP)[[[1xx]]]] [[応答]]は、 [[HTTP/1.1]] [[以上]]の場合に、
[[最後の応答]]の前に0個[[以上]]使うことができます。

[FIG(railroad)[
= *
== [CODE(HTTP)[[[1xx]]]] [[応答]]
= [[最後の応答]]
]FIG]

;; [162] [CODE(HTTP)[[[101]]]] の後 [[WebSocket]] に切り替わる場合は、
[[最後の応答]]はありません。

[570] [[要求]]に [CODE(HTTP)[[[100-continue]]]] が指定されている場合には、
[[要求]]の[[ヘッダー部]]を読み終えた時点で[[鯖]]が [CODE(HTTP)[[[100]]]]
[[応答]]を返し、その後[[要求]]の[[メッセージ本体]]を処理してから最終的な[[応答]]を返すことが期待されています。
(詳しくは [CODE(HTTP)[[[100-continue]]]] を参照してください。)

** サーバープッシュ

[65] [[HTTP/2]] では、[[クライアント]]が[[要求]]するかわりに[[サーバー]]が[[要求]]を[[クライアント]]へ送信し、
その後[[サーバー]]から[[クライアント]]へ[[応答]]を送信できます。

[66] 構文上は[[サーバー]]は任意の [[URL]] の[[応答]]を送信できます。
実際には当該[[サーバー]]が [[authoritative]] であることなどいくつかの制限があります。

;; 詳細は[[サーバープッシュ]]および >>96 を参照。

* 接続を閉じる

[558] [[クライアント]]、[[鯖]]、[[串]]はいずれも任意の時点で[[接続]]を閉じて構いません
[SRC[>>553, >>73]]。

[61] [[HTTP/2]] では、まず [CODE(HTTP)@en[[[GOAWAY]]]] [[フレーム]]を送信する[['''べきです''']]
[SRC[>>60, >>90, >>73]]。
しかし送信しない実装もあります。 [CODE(HTTP)[[[GOAWAY]]]] を参照。

[184] [[Firefox]] は、相手が [CODE(HTTP)@en[[[GOAWAY]]]] なしで接続を閉じた場合でも、
(他に問題がなければ) [[誤り符号]] [CODE[[[NO_ERROR]]]] の [CODE[[[GOAWAY]]]]
を送信してから、接続を閉じます。 [[Chrome]] はすぐに接続を閉じます。
[TIME[2015-10-12T04:44:18.00Z]]

[576] [[鯖]]は過負荷時に [WEAK[([CODE(HTTP)[[[503]]]] を返すか、または)]]
直ちに[[接続]]を閉じても構いません [SRC[>>577]]。

[540] [[接続]]はいつでも予告なく閉じられることがあります [SRC[>>539]]
から、[[実装]]は、[[接続]]の終了に対して[[頑強]]でなければなりません。

[567] [[HTTP/0.9]] や [[HTTP/1.0]] では、 [CODE(HTTP)@en[[[Keep-Alive]]]] が有効な場合を除き、
[[メッセージ]]の終わりで[[接続]]も閉じなければなりません。

[537] [[持続的接続]]の終了は、 [CODE(HTTP)@en[[[Connection:]] [[close]]]]
によって表します。

;; 詳しくは [CODE(HTTP)@en[[[close]]]] や[[持続的接続]]の項を参照してください。

[4] [[HTTP/1.1]] [[以下]]では、[[メッセージ本体]]の終了を[[接続]]を閉じることによって通知することがあります。

;; [[メッセージ本体]]の項を参照してください。

[561] [[鯖]]は、下位層プロトコルの特性により[[メッセージ]]の一部又は全部が失われないように注意して[[接続]]を閉じる必要があります。
詳しくは[[TCPリセット問題]]を参照してください。

;; [571] [CODE(HTTP)@en[[[CONNECT]]]] の項も参照してください。

[165] [[サーバー]]によっては [CODE[[[FIN]]]] を受け取った時点で[[応答]]の残りの転送を取りやめるようなので、
[[クライアント]]は[[応答]]の受信が終わるまで、[[要求]]の送信が終わったとしても[[接続]]を閉じてはいけません。

[64] [[HTTP/2]] では、[[ストリーム識別子]]が枯渇するとそれ以上[[メッセージ]]を送受信できなくなってしまいます。
[[クライアント]]は、新しい[[接続]]を確立して新しい[[ストリーム]]を作成できます
[SRC[>>62]]。[[サーバー]]は、 [CODE(HTTP)@en[[[GOAWAY]]]] [[フレーム]]を送信して[[クライアント]]に新しい[[接続]]を開くように求められます [SRC[>>62]]。

[135] [[Chrome]] と [[Firefox]] は、 [[abort a document]] による [[fetch]]
の中止の際は、正常に ([CODE[[[FIN]]]] で) [[接続]]を閉じるようです。
[[IE]] は [CODE[[[RST]]]] を使うようです。 [TIME[2015-08-01T15:17:36.000Z]]

** エラーによる接続の終了

[5] [[メッセージ本体]]が存在し、 [CODE(HTTP)@en[[[Transfer-Encoding:]]]]
[[ヘッダー]]の最後の[[転送符号化]]が [CODE(HTTP)@en[[[chunked]]]]
以外である[[要求メッセージ]]を受け取った時は、 [CODE(HTTP)[[[400]]]]
[[応答]]を返して[[接続]]を閉じなければ[['''なりません''']] [SRC[>>3]]。

[510] [CODE(HTTP)[[[Content-Length:]]]] が無視されない場合で、
複数あったり[[非妥当]]だったりする場合は、
[[接続]]を閉じなければ[['''なりません''']] [SRC[>>3]]。

[511] [CODE(HTTP)[[[Content-Length:]]]] が無視されない場合で、
その長さの[[メッセージ本体]]を受け取らずに[[接続]]が閉じられたり、
[[タイムアウト]]したりした時には、[[接続]]を閉じなければ[['''なりません''']] [SRC[>>3]]。

[538] 下位ネットワークの障害や[[接続]]の当事者のシステム上の障害などによって、
[[メッセージ]]の途中で[[接続]]が中断されたり、
何の送受信も発生しないまま長時間経過したりすることがあります。
こうした場合の処理については、[[メッセージ]]や[[メッセージ本体]]の項を参照してください。

[547] [[パイプライン化]]している場合で途中で[[接続]]が閉じられたときの処理は、
[[HTTPパイプライン]]の項を参照してください。

[40] [[サーバー]]の[[死活監視]]を行うソフトウェアの中には、 [[TCP]]
レベルでの検査を行うものもあります。これは [[TCP接続]]が[[確立]]できることを確認すると、
すぐに切断するものです。この場合 [[HTTPメッセージ]]を送受信することなく[[接続]]が終了しますから、
[[サーバー]]はそのような場合も適切に処理できる必要があります。

[559] [[鯖]]は、[[クライアント]]が再試行すると期待して[[接続]]を閉じるよりは、
できれば[[持続的接続]]を維持して、一時的な過負荷は[[トランスポート層]]の[[フロー制御]]に任せる[['''べきです''']]
(閉じて再試行させる方が[[輻輳]]を悪化させるかもしれません) [SRC[>>553]]。

[560] [[クライアント]]は[[メッセージ本体]]の送信中に[[接続]]を監視して、
[[鯖]]が受信を望まず[[接続]]を閉じようとしていることがわかれば、
すぐに転送をやめて[[接続]]を閉じる[['''べきです''']] [SRC[>>553]]。

;; [580] [CODE(HTTP)[[[100]]]] や [CODE(HTTP)[[[413]]]] も参照してください。

[578] [[串]]は[[上流]]から[[非妥当]]な[[応答]]を受け取った時、
[[転送]]するかわりに [CODE(HTTP)[[[502]]]] [[応答]]を返すことができます。
[CODE(HTTP)@en[[[Content-Length:]]]] が[[非妥当]]な場合は更に[[接続]]を閉じなければならないこともあります。
詳しくは [CODE(HTTP)[[[502]]]] を参照してください。

[74] [[HTTP/2]] [[接続エラー]]の場合、 ([CODE(HTTP)@en[[[GOAWAY]]]] の後)
[[TCP接続]]を閉じなければ[['''なりません''']] [SRC[>>73]]。

;; [[接続エラー]]を参照。

[77] [[誤り符号]] [DFN[[CODE[[[ENHANCE_YOUR_CALM]]]]]] ([CODE[[[0xb]]]])
は、 [[過負荷]]を引き起こしかねない動作を [[peer]] が示したことを表します [SRC[>>76]]。

-*-*-

[340] [CITE[Esperanto for English Speakers]], [[tecc]], [TIME[2025-05-21T08:38:55.000Z]] <https://web.archive.org/web/20010608064435im_/http://www.geocities.com/CapitolHill/Lobby/7146/efes.html>

[341] >>340 [CODE[Content-Length]] の大きさに到達する前に接続が閉じられる。
[[Firefox]] では一応受信した部分は表示される。 [[Chrome]]
では内容が表示されない (が背景色の指定は適用されるので、一応先頭部分は解釈しているらしい)。
[TIME[2025-05-21T08:41:24.500Z]]

[343] [CITE[METU - Activities]], [TIME[2025-11-15T09:45:40.000Z]] <https://web.archive.org/web/20050223004623id_/http://activity.metu.edu.tr/show.php?TR=en_>

[345] [CITE[Yahoo! Sports]], [TIME[2025-11-23T02:00:08.000Z]], [TIME[1999-01-16T23:25:56.920Z]] <https://web.archive.org/web/19990116231624/http://yahoo.co.jp/>

[344] >>343 >>345 途中で接続が閉じられる。


** タイムアウト

[554] [[鯖]]は普通は[[タイムアウト]]を設定しており、
活性状態でない[[接続]]をそれ以上維持しません。 [SRC[>>553]]

[555] [[串]]は、[[クライアント]]が同じ[[串]]により多く[[接続]]して来るであろうことから、
[[タイムアウト]]を大きめにするかもしれません。 [SRC[>>553]]

[556] [[クライアント]]も[[タイムアウト]]を設定して、
必要のない[[接続]]をそれ以上維持しないかもしれません。

[557] [[タイムアウト]]したい[[クライアント]]や[[鯖]]は、
当該[[接続]]を [[graceful close]] する[['''べきです''']] [SRC[>>553]]。
[[実装]]は定期的に[[接続]]を閉じる信号を監視して、
適宜応答する[['''べきです''']] [SRC[>>553]]。

[12] [[鯖]]によっては、[[HTTP/1.0]] [[応答]]を送り終えた後もしばらく[[接続]]を閉じないものがあるといわれています。

[71] [[nginx]] は、接続後何も送信しないでいると、タイムアウトにより何も返さずに[[接続]]を閉じるようです。
[TIME[2015-06-14T09:24:37.200Z]]

[264] [[nginx]] は標準状態では60s何も受信しないと、タイムアウトとするようです [SRC[>>263]]。

[REFS[
- [263] [CITE[Module ngx_http_core_module]] ([TIME[2016-08-29 21:17:12 +09:00]]) <https://nginx.org/en/docs/http/ngx_http_core_module.html>
]REFS]

[154] [[応答]]の受信後に次の[[要求]]を送信するため保持した状態の[[接続]]について、
[[Chrome]] は約300s、 [[Firefox]] は115s [SRC[>>159]] 未使用なら、閉じるようです。
[[IE]] は60s未使用なら、 [CODE[[[RST]]]] するようです [SRC[>>141]]。

[155] [[IE]] は、[[要求]]の送信があった後 3600s [[サーバー]]から送信がなければ、 
[CODE[[[RST]]]] するようです。 (どこから起算しているかは未調査。最後の受信?)
[TIME[2015-08-16T05:11:42.000Z]]

[156] [[Firefox]] は [[TCP keep alive]] (>>153) が無効に設定されている時は、
300s 間[[サーバー]]から送信がなければ、タイムアウトとして接続を閉じます [SRC[>>142]]。

[160] [[Chrome]] や、[[Firefox]] で [[TCP keep alive]] が有効な場合 (既定の状態)
では、[[要求]]が送信された後[[応答]]を受信するまで ([[応答]]の一部を受信しようがしまいが)
タイムアウトは無いように見えます。 (少なくても20時間以上は切断されません。) [TIME[2015-08-16T08:18:24.200Z]]

;; [161] [[XHR]] の [CODE(DOMa)@en[[[timeout]]]] [[属性]]は、
[[接続]]の状態に関わらず、[[fetch]] の開始からの経過時間により[[fetch]]を中断するものです。

[195] [[クライアントライブラリー]]によっては、
[[要求]]の開始や[[応答]]の受信開始からの経過時間で[[タイムアウト]]を決めるものもあります。
しかし[[応答]]完了まで (正常時でも) 非常に時間がかかる[[サーバー]]もありますから、
相当に大きな値とする必要があります。それでは逆に異常時に[[タイムアウト]]エラーとなるまでかなり時間がかかってしまいますから、
あまりよい実装戦略ではなさそうです。

[196] [[サーバー]]によっては、無限に長い[[応答]]を送ることがあります。
従って[[対話的]]でない[[クライアント]]は、正常な受信中であっても、
一定時間経過後に受信を打ち切るようにする必要がありそうです。

[321] 
もちろん、恒久的に[[接続]]を維持してデータを受信し続けたいこともあります。
そのような用途を想定したい[[クライアント]]は、
受信を打ち切るべき[[タイムアウト]]を∞にも設定可能とする必要があります。

** 接続枠解放

[260] [[持続的接続]]等で現時点で未使用の[[接続][HTTP接続]]を後で利用する(可能性がある)ため保持している場合で、
実装全体での、あるいは特定[[サーバー]]宛ての接続数上限に達した場合、
その未使用[[接続][HTTP接続]]を閉じて接続枠を開ける必要があるかもしれません。

;; [[接続プール]]参照。

* 要求の再試行

[541] [[実装]]は、[[接続]]が閉じられた時に回復しないといけないかもしれないことを想定しておく[RUBYB[べき]@en[ought to]]です
[SRC[>>539]]。

[542] [[クライアント]]は、[[内向き]]の[[接続]]が意図せず閉じられたとき、
中断された[[要求]]群がすべて[[冪等]]なメソッドだった場合には、
新しい[[接続]]を開いてその[[要求]]を自動的に再転送して構いません。 [SRC[>>539]]

[544] [[利用者エージェント]]は、何らかの手段で[[要求]]が本当は[[冪等]]であると分かっている場合や元の[[要求]]が適用されなかったと分かっている場合を除き、
[[冪等]]でない[[メソッド]]の[[要求]]を自動的に再試行しては[['''なりません''']]。
[SRC[>>539]]

[545] [[クライアント]]は、失敗した自動再試行を自動的に再試行する[['''べきではありません''']]
[SRC[>>539]]。

[543] [[串]]は、[[冪等]]でない[[要求]]を自動的に再試行しては[['''なりません''']]
[SRC[>>539]]。

;; [565] [CODE(HTTP)@en[[[Expect:]] [[100-continue]]]] についても、
自動的な再試行に関する規定があります。

[75] [[HTTP/2]] の [[TCP接続]]が閉じられたり [[RST]] されたりした時に [[open]]
や [[half-closed]] の[[状態]]だった[[ストリーム]]は、
自動的に再試行することはできません [SRC[>>73]]。

[83] [[HTTP/2]] では、次の場合、[[クライアント]]は[[要求]]が処理されていないことが保証されます [SRC[>>82]]。
[FIG(list)[
- [84] [CODE(HTTP)@en[[[GOAWAY]]]] [[フレーム]]で示された最大[[ストリーム識別子]]よりも大きな[[ストリーム識別子]]の[[ストリーム]]の[[要求]]は、
処理されていません。
- [85] [CODE(HTTP)@en[[[RST_STREAM]]]] [[フレーム]]で[[誤り符号]]
[CODE(HTTP)@en[[[REFUSED_STREAM]]]] が指定されていれば、その[[ストリーム]]の[[要求]]は処理されていません。
]FIG]

[86] これらの処理されていない[[要求]]は、失敗ではなく、
[[クライアント]]は[[冪等]]か否かに関わらず自動的に再試行して構いません [SRC[>>82]]。

[107] [CODE(HTTP)[[[421]]]] [[応答]]を受信した[[クライアント]]は、
[[冪等]]か否かに関わらず自動的に再試行して構いません [SRC[>>90]]。
[[代替サービス]]から受信した場合は、当該[[代替サービス]]情報は削除しなければ[MUST[ならず]]、
他の[[代替サービス]]や[[起源サーバー]]に再試行して構いません。

;; [CODE(HTTP)[421]] 参照。

[138] [[Chrome]] も [[Firefox]] も [[IE]] も、 ([CODE(HTTP)@en[[[GET]]]] でも
[CODE(HTTP)@en[[[POST]]]] でも) [[持続的接続]]の2つ目の[[要求]]に対して[[応答]]を受信せず[[接続]]が切断された場合、
他の[[接続]]で改めて[[要求]]を送信するようです。 [TIME[2015-08-12T10:25:17.300Z]]

[322] 
[[クライアント]]から見て[[TCP接続]]が有効のままであっても、
実は[[HTTPサーバー]]との接続状態は失われているケースがままあるため、
このような挙動にしなければならないようです。

* 版の切り替え

[79] [[誤り符号]] [DFN[[CODE[[[HTTP_1_1_REQUIRED]]]]]] ([CODE[[[0xd]]]])
は、 [[HTTP/2]] ではなく [[HTTP/1.1]] が必要であることを示します [SRC[>>76]]。

[179] その詳細な処理方法はどこでも規定されていません。いつこれを送れるのかも明確ではありません。

[183] [[HTTP/2]] では[[再折衝]]が禁止されているため、[[クライアント認証]]が必要な時は
[CODE[[[HTTP_1_1_REQUIRED]]]] を送信するべきだとされています。

[174] [[Chrome]] も [[Firefox]] も、 [CODE[[[HEADERS]]]] より前に
[CODE[[[RST_STREAM]]]] や [CODE[[[GOAWAY]]]] で [CODE[[[HTTP_1_1_REQUIRED]]]]
を受信すると、 [[HTTP/1.1]] で接続し直すようです。
[TIME[2015-10-11T15:03:47.200Z]]

;; [175] 既に [[HTTP/1.1]] の接続があれば、再利用するかもしれません (未検証)。

[176] [[Chrome]] は [CODE[[[HEADERS]]]] より後だと、 ([CODE[[[RST_STREAM]]]] であっても)
接続を閉じて、[[ネットワークエラー]]とするようです。 [TIME[2015-10-11T15:04:59.500Z]]

[177] [[Firefox]] は [CODE[[[HEADERS]]]] より後だと、
[[ネットワークエラー]]とするようです。 [TIME[2015-10-11T15:05:21.500Z]]

[178] [[Chrome]] も [[Firefox]] も、再接続時には [[ALPN]] で [CODE[[[http/1.1]]]]
だけを指定します。 [TIME[2015-10-11T15:06:38.200Z]]

[180] (にも関わらず) [[サーバー]]が [[ALPN]] で [CODE[[[h2]]]] を指定すると、
[[Chrome]] も [[Firefox]] も [[HTTP/2]] を使います。更に [CODE[[[HTTP_1_1_REQUIRED]]]]
を返すと、 [[Firefox]] は何度か試して諦めますが、 [[Chrome]] は無限に(?)試し続けます。
[TIME[2015-10-11T15:07:56.500Z]]

[201] 理論上は [CODE(HTTP)@en[Upgrade: h2c]] によって [[HTTP/1]] から
[[HTTP/2]] への切り替えを指示できます (が実装されていません)。

[200] [[Chrome]] は、 [CODE(HTTP)@en[Alt-Svc:]] [[ヘッダー]]によって
[[QUIC]] が利用可能なことを認識できます。

;; [CODE(HTTP)@en[Alt-Svc:]] 参照。

* ヘッダー

[521] [CODE(HTTP)@en[[[Connection:]]]] [[ヘッダー]]は、[[接続]]の取り扱いを指定するものです。

[21] [CODE(HTTP)@en[[[Expect:]] [[100-continue]]]] はデータの送信のタイミングについて指示するものです。

;; [CODE(HTTP)@en[[[100-continue]]]] 参照。

* 下位層プロトコル

[516] [[HTTP]] の[[メッセージ]]は下位の ([[トランスポート層]]や[[セッション層]]の)
[[プロトコル]]に依存しておらず、[[信頼できる]]輸送路であって、
[[要求]]の順序を保存した配送と[[応答]]の順序を保存した配送のみを要求しています [SRC[>>515]]。

[2] 実際には [[HTTP]] は、下位層プロトコルとして、
[FIG(list short)[
- [517] [[TCP]]
- [518] [[TLS]]
- [[Unix domain socket]]
- [[HTTP]] [CODE(HTTP)@en[[[CONNECT]]]]
- [[SOCKS]]
]FIG]
... のいずれかを用います。

;; [7] [[UPnP]] では [[UDP]] が使われます ([[SSDP]])。

;; [37] [[HTTP over SCTP]] も提案されましたが、関心を集められませんでした。

[519] [[HTTP]] の[[要求]]や[[応答]]の構造と下位層プロトコルのデータ単位との対応関係は、
[[HTTP]] の仕様書の[[適用範囲]]外とされています [SRC[>>515]]。

;; [520] それ、[[アプリケーション層プロトコル]]の重要なところじゃないのでしょうか。。。

[59] [[HTTP/2]] では [[HTTP/1.1]] よりは詳しく規定があります (が完全ではありません)。

** HTTP over TCP

[192] [[HTTP]] over [[TCP]] は、
[[HTTP]] が開発された[[平成時代]]初期以来、
[[平成時代]]後期頃まで標準の接続方法でした。
現在は安全ではないと考えられているため、徐々に [[HTTPS]] に置き換えられてきています。

[193] [[HTTP]] over [[TCP]] を [[HTTPS]] と区別するため、
[DFN[素のHTTP]]と呼ぶことがあります。

[41] [[HTTP]] over [[TCP]] は、 [CODE(URI)@en[[[http:]]]] [[URL]] によって表されます。

[323] 
[[素のHTTP]]は安全ではないので、使うべきではありません。
[SEE[ [[保安輸送路]] ]]
にも関わらず、
次の場面では未だ使われています。

- [324] [[HTTPS]] で提供される[[Webサーバー]]であっても、
[[素のHTTP]]で [[TCPポート]] [N[80]] で接続を待ち受け、
[CODE[http:]] から [CODE[https:]] に[[リダイレクト][HTTPリダイレクト]]するのが普通です。
- [325] 長年提供され続けている[[Webサーバー]]は、
旧来の[[素のHTTP]]を利用し続けていることがあります。
- [326] [[中華人民共和国]]や[[ロシア連邦]]など、
[[政治的理由]]で [[HTTPS]] の利用に支障のある地域もあります。
- [327] [[ルーター]]の設定画面など専ら [[LAN]] 内で使われる[[装置]]は、
[[内部名]]等の適切な[[TLS証明書]]を設定することが困難で、
[[素のHTTP]]を使う場合がほとんどです。
- [328] [[データセンター]]の内部ネットワークなど一定の安全性が確保された環境では、
[[TLS]] の処理負荷や[[TLS証明書]]設定の手間を省くため[[素のHTTP]]
を使う場合が多いです。
- [329] [[Web開発者]]の手元の[[計算機]]上の開発環境など、
開発目的で実行する[[Webサーバー]]は開発の便宜のため[[素のHTTP]]
を使う場合も多いです。


[34] 通常は [[HTTP]] over [[TCP]] と [[HTTP]] over [[TLS]] over [[TCP]]
は別の[[ポート]]を使いますが、両方を同じ[[ポート]]で受け付けられないこともありません
(両者は区別可能です)。

[EG[
[35] [[IPP]] over [[HTTP]] と [[IPP]] over [[HTTPS]] はどちらも[[既定のポート番号]]
[CODE[[[631]]]] を共有しており、両方を受け付ける実装もあります [SRC[>>36]]。

[REFS[
- [36] [CITE@en[RFC 7472 - Internet Printing Protocol (IPP) over HTTPS Transport Binding and the 'ipps' URI Scheme]] ([TIME[2015-03-04 12:23:14 +09:00]] 版) <https://tools.ietf.org/html/rfc7472#section-4.3>
]REFS]
]EG]

[163] [[Apache]] や [[nginx]] は、 [[HTTPS]] のポートに平文の [[HTTP要求]]のようなものが書き込まれると、
[CODE(HTTP)[[[400]]]] [[応答]]を返して切断するようです。 [TIME[2015-09-06T01:20:16.100Z]]

;; [164] 他の[[HTTPサーバー]]の実装は、何も返さず直ちに閉じたり、
純粋に [[TLS]] として扱ってエラーを返して閉じたり、
[CODE[[[RST]]]] を送ったりするようです。

-*-*-


[17] [[three-way handshake]] を経て [[TCP]] [[接続]]が確立された後に [[TCP]]
によって伝送される[[オクテット列]]が [[HTTP接続]]の[[オクテット列]]です。
なお [[TCP]] [[セグメント]]の境界は [[HTTP接続]]に反映されません。
[[TCP]] [[セグメント]]の境界と [[HTTP接続]]上の[[メッセージ]]境界と一致しているとは限りません。

[33] [[TCP]] [CODE[[[PSH]]]] フラグの取り扱いについて [[HTTP]] 特有の規定は特に無いと思われます。
(例えば[[HTTPメッセージ]]の最後で [CODE[[[PSH]]]] フラグを立てなければならないというようなことは特にありません。)

[16] [[TCP]] [[緊急データ]]と [[HTTP]] の関係は明文化されていません。

[125] [[応答]]の受信中に[[緊急データ]]が含まれていた場合、次のように動作するようです
(いずれも [[Windows]])。 [TIME[2015-06-15T03:40:23.400Z]]
[FIG(list)[
- [126] [[IE]] はレンダリングを[[非文書表示]]に切り替えます。 [[Firefox]] と [[Chrome]]
は通常通りです。
- [127] [[IE]] と [[Firefox]] は [CODE[[[RST]]]] を送信します。
- [128] [[Firefox]] も [[Chrome]] も、[[緊急ポインター]]が指す1バイトを無視し、その前後のバイト列のみが送られたものとして処理します。
]FIG]

-*-*-

[18] [[HTTP接続]]を閉じる、あるいは閉じられるとは、 [[TCP]] [[接続]]を閉じる、あるいは閉じられることを意味します。
[[HTTP接続]]を閉じると [CODE[[[FIN]]]] [[セグメント]]が送信されることになります。
[CODE[[[FIN]]]] [[セグメント]]を受信すると [[HTTP接続]]が相手に閉じられたことを表します。
その他に [CODE[[[RST]]]] や[[タイムアウト]]など [[TCP]] プロトコル上の規定や実装によって正常でない形で接続が閉じられることもあります。

[72] [[応答]]の受信中に [CODE[[[RST]]]] を受信した場合、次のように動作するようです
(いずれも [[Windows]])。
[TIME[2015-06-14T14:27:40.700Z]]
[FIG(list)[
- (前提として) [[Firefox]] はできるだけすぐに[[レンダリング]]を開始するようです。
[[IE]] と [[Chrome]] はある程度のデータを受信しないと処理開始しないようです。
- [[Firefox]] と [[IE]] は、レンダリング開始後であっても、 [CODE[[[RST]]]]
を受信したら [CODE[[[RST]]]] を受信した旨の[[非文書表示]]に切り替えます。
[[Chrome]] はレンダリング開始前ならそうしますが、開始後なら何も表示しません
([[開発者ツール]]にはエラーが表示されます)。
- ただし [[Firefox]] は場合によっては切り替わらない、あるいは自動的に再試行しようとするようです (詳細不明)。
]FIG]

;; [124] [[TCP]] が [CODE[[[RST]]]] を受信した時点でまだ[[アプリケーション]]に渡されていないデータの扱いは、
[[TCP]] の実装によって異なるようです。エラーとして扱う以外に[[相互運用可能]]な方法はなさそうです。

-*-*-

[152] [[Chrome]] と [[Firefox]] は [CODE[[[SO_NODELAY]]]] を[[真]]に設定
([[Nagleアルゴリズム]]を無効化) するようです。 [TIME[2015-08-16T05:01:08.200Z]]

;; [[HTTPS]] でも [[TCP接続]]について [[Nagleアルゴリズム]]を無効化するようです。

[186] [[HTTPクライアント]]ライブラリー等で [[Nagleアルゴリズム]]を無効化しないものも少なくありません。
そのために[[TCP/IPスタック]]内で送信待ちが発生して、[[応答]]の受信までに無駄な遅延が生じることがあります。
(気が付きにくいです。) プロトコルの仕様と用法から、 [[HTTP]] で
[[Nagleアルゴリズム]]は不要です。  [DEL[([[WebSocket]] なら利用方法によっては有効に働くかもしれませんが、一概にはいえないので[[アプリケーション]]や[[Webブラウザー]]側で適当に扱うべきでしょう。)]]

[275] [[Nagleアルゴリズム]]を無効にしないのは、[[Web互換]]では無いようです [SRC[>>270]]。

[REFS[
- [270] [CITE@en[WebSocket Nagle アルゴリズム問題]]
([TIME[2016-11-13 01:19:49 +09:00]])
<https://gist.github.com/uupaa/6281381>
]REFS]

-*-*-

[153] [[Chrome]] と [[Firefox]] は [CODE[[[SO_KEEPALIVE]]]] ([[TCP keep alive]])
を使うようです。 [[Chrome]] は最初の keep alive 送信まで ([CODE[[[TCP_KEEPIDLE]]]]) 45s、
二度目以降の送信まで ([CODE[[[TCP_KEEPINTVL]]]]) 45s とします
([CODE[[[TCP_KEEPCNT]]]] は未設定で [[OS]] の既定値) [SRC[>>145]]。
[[Firefox]] はより細かく調整します [SRC[>>143]]。

;; [CODE[[[TCP_KEEPIDLE]]]] と [CODE[[[TCP_KEEPINTVL]]]] (と 
[CODE[[[TCP_KEEPCNT]]]]) は [[Linux]] のみのオプションなので、他の [[OS]]
では設定され(でき)ません。

[173] [[Firefox]] は [[HTTP/2]] の時 [[TCP keepalive]] を無効にし、かわりに
90s ほどの間を置いて [[HTTP/2]] [CODE(HTTP)@en[[[PING]]]] を送ります。返答がなければ
[CODE(HTTP)@en[[[INTERNAL_ERROR]]]] の [CODE(HTTP)@en[[[GOAWAY]]]]
を送信して接続を閉じます。一方 [[Chrome]] は [CODE(HTTP)@en[[[PING]]]]
を送っておらず、 [[HTTP/1]] 同様に [[TCP keepalive]] を使っているようです。 [TIME[2015-09-27T11:37:07.0Z]]



*** 素のHTTPのポート

[189] [DFN[[CODE[80]]]] が [[HTTP]] / [CODE(URI)@en[http:]] [[URL scheme]]
の[[既定のポート番号]]です。ほとんどの [[HTTP]] over [[TCP]]
[[サーバー]]は、 [CODE[80]] 番を使っています。

[273] 
[[1990年代]]には[[既定のポート]]以外の [[Webサーバー]]もたまに見かけましたが、
次第に[[既定のポート]]以外あまり使わなくなりました。

[274] 現在でも、

- [334] [[逆プロキシ]]からのみアクセスを受け付ける[[アプリケーションサーバー]]、
- [335] [[開発者][Web開発者]]の手元で実行される開発中の[[アプリケーションサーバー]]、
- [336] 主目的が[[Webサーバー]]ではない[[プログラム]]の制御機能を
[[Web]] 経由で利用できる形の[[サーバー]]

など、
一般的な[[利用者]]に直接見えない形では[[既定のポート]]以外が使われる場面があります。

[191] [[素のHTTP]]では、 [N[8000]] や [N[8080]] がしばしば使われます。

[190] [[HTTP]] としては任意の[[ポート]]を利用可能ですが、
[[Webブラウザー]]は[[プロトコル交差攻撃]]防止のため接続可能な[[ポート]]を制限しています。
[[Webブラウザー]]以外の[[クライアント]]の実装は制限していないこともありますが、
[[サーバー]]は特別理由がなければ制限されたポートを避けるのが無難です。
[SEE[ [[port blocking]] ]]


-*-*-

[331] 
最初の[[Webブラウザー]]である [[WorldWideWeb]]
は、
[TIME[1992-01-24]]の
[N[80]]
の割当以後、
[N[80]]
で接続を試みて失敗したら
[N[2784]]
で再試行する挙動でした。
[SRC[>>330]]

[332] 
それ以前は最初から [N[2784]]
に接続していたと思われます。

[333] 
当時存在していた他の [[Webブラウザー]]も同様の挙動だったと推測されます。

[REFS[

-
[330] 
[CITE@en[Inside the Code — WorldWideWeb NeXT Application]], [[CERN]], [TIME[2020-12-14T20:30:11.000Z]], [TIME[2024-08-31T01:42:11.854Z]] <https://worldwideweb.cern.ch/code/>

]REFS]

** HTTP over TLS

[14] [[SSL]] や [[TLS]] でも [[HTTP]] は利用されます。
[SEE[ [[HTTPS]] ]]
[[平成時代]]後期から現在に至るまで、
最も標準的な
[[HTTP]]
の利用方法です。

[42] [[HTTP]] over [[TLS]] over [[TCP]] は、 [CODE(URI)@en[[[https:]]]] [[URL]] 
によって表されます。

[HISTORY[
[282] [[Opportunistic Security for HTTP/2]] に対応している場合、
本来 [[HTTP]] over [[TCP]] を使う [CODE(URI)@en[http:]] [[URL]] 
へのアクセスも、 [[HTTP]] over [[TLS]] を使います。
]HISTORY]

[271] [[HTTP]] over [[TLS]] over [[TCP]] では、
[N[443]] が[[既定のポート番号]]です。

[272] 
[[素のHTTP]]の場合
(>>274)
同様[[HTTPS]]も既定以外の[[ポート]]が使われるケースはあるものの、
やはり一般的ではありません。


- [342] [CITE@en[CommuniGate Pro cni.org Entrance]], [TIME[2025-10-21T07:06:02.000Z]] <https://mail2.cni.org:9100/>



** Unix ドメインソケット

[15] (同じ [[Unix]] 環境上で動作する) [[逆串]]から[[アプリケーション鯖]]への通信などに
[[Unixドメインソケット]]を使う場合があります。

[30] [[鯖]]が予め[[ソケット]]を作成しておき、[[クライアント]]がこれに[[接続]]することで、
当該[[ソケット]]を使った読み書きが [[HTTP接続]]となります。[[ソケット]]による[[接続]]を閉じる、
または閉じられると、 [[HTTP接続]]が閉じる、あるいは閉じられることとなります。

;; [8] [[HTTP]] に特化した仕様書は特にありません。

[276] [[Unixドメインソケット]]を使った [[HTTP]] のアクセスを表す [[URL]]
はありません。主用途が[[アプリケーションサーバー]]への接続なので、
[[相互運用性]]に関わるものでなく[[標準化]]の機運が高まらないようです。
実装依存の非標準の [[URL]] を用いるものもあれば、
[[コマンドラインオプション]]など [[URL]] 以外の指定方法を提供するものもあります。
[SEE[ [[Unix domain socket]] ]]

[277] [[要求]]に [CODE(HTTP)@en[Host:]] [[ヘッダー]]が無い場合、
[[要求]]に含まれる情報だけから[[実効要求URL]]を確定できません。
[CODE(HTTP)@en[Host:]] [[ヘッダー]]が無い場合をエラーとして扱うか、
[[サーバー]]の設定によって自身の既定の[[ホスト]]と[[ポート]]を決めておく必要があります。

[29] 次のような実装例があります。

[REFS[
- [26] [CITE[Curl: HTTP connection to unix socket]] ([[Bart Whiteley (bwhiteley_at_novell.com)]] 著, [TIME[2010-12-20 03:05:05 +09:00]] 版) <http://curl.haxx.se/mail/lib-2008-04/0279.html>
- [28] [CITE[Module ngx_http_proxy_module]] ([TIME[2015-02-26 15:57:24 +09:00]] 版) <http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass>
- [27] [CITE@en[Starlet + Server::Stater で UNIX domain socketに対応しました - Hateburo: kazeburo hatenablog]] ([TIME[2015-03-07 17:04:32 +09:00]] 版) <http://kazeburo.hatenablog.com/entry/2013/11/26/002727>
]REFS]

** HTTP [CODE(HTTP)@en[CONNECT]]

[129] [[HTTP]] [CODE(HTTP)@en[[[CONNECT]]]] [[メソッド]]は任意の [[TCP]]
[[アプリケーション]]の[[トンネリング]]に使うことができますので、
[[HTTP]] の下位層としても使うことができます。

[130] しかし通常は [[HTTPS]] の[[トンネリング]]に使うので、直接
[CODE(HTTP)@en[[[CONNECT]]]] [[トンネル]]内が [[HTTP]] となることはありません。

;; [[HTTPS]]、[CODE(HTTP)@en[[[CONNECT]]]] を参照。

** SOCKS

[22] [[SOCKS proxy]] ([[SOCKS]] [[プロトコル]]による [[TCP/IP]] [[トンネル]])
を介して [[HTTP]] [[クライアント]]から [[HTTP]] [[鯖]]に[[接続]]することがあります。

[25] 多くの[[Webブラウザー]]その他の [[HTTP]] [[クライアント]]が、[[串]]の一種として
[[SOCKS]] に対応しています。また [[socksify]] や [[tsocks]] のようなソフトウェアによって通常の
[[TCP/IP]] [[接続]]が [[SOCKS]] の[[接続]]に置き換えられることもあります。

[23] 他の [[TCP]] [[アプリケーション]]と同様に、[[SOCKS]] [[鯖]]が[[接続]]するべき
[[IPアドレス]]または[[ホスト名]]と [[TCP]] [[ポート]]を指定して[[接続]]を確立します。
以後 [[SOCKS]] [[プロトコル]]上の送受信データが [[HTTP接続]]となります。
[[SOCKS]] の[[接続]]が閉じる、あるいは閉じられると、 [[HTTP接続]]が閉じる、
あるいは閉じられることとなります。

[32] [[SOCKS]] の下位層の [[TCP/IP]] [[ネットワーク]]エラーその他の原因で [[SOCKS]]
[[接続]]が異常に閉じられることがあります。

;; [24] [[HTTP]] に特化した仕様書は特にありません。

** captive portal ログイン

[308] 
[[OS]] の[[ネットワーク]]機能の一部として、
[[captive portal]] を表示して[[ログイン]]するために
[[Webブラウザー]]の機能 ([[組み込みブラウザー]])
が使われる場合があります。

[309] 
そうした用途に使われる[[組み込みブラウザー]]は、
通常の[[プロキシ設定]]や他の[[ネットワークインターフェイス]]経由で利用可能なネットワーク接続を無視し、
ログインしようとしている[[ネットワークインターフェイス]]を通じて
[[captive portal]] に ([[HTTP]] over [[TCP]] または [[HTTPS]] over [[TCP]] で)
接続できる必要があります。

[EG[
[310] 
例えば [[Android]] で [[4G]] ネットワークで[[インターネット]]へのアクセスが確保されている場合であっても、
それとは別の [[WiFi]] [[アクセスポイント]]で [[captive portal]]
が存在していると、 (単独の [[Chrome]] ブラウザーとは異なる) 
[[OS]] の[[ネットワーク]]設定機能に組み込まれた
[[Webブラウザー]]によってその [[captive portal]]
にアクセスできます。
]EG]

* MIME 型

[563] [[接続]]そのものではありませんが、[[接続]]上の[[要求]]の列または[[応答]]の列を表す
[[MIME型]] [CODE(MIME)@en[[[application/http]]]] があります。

;; [CODE(MIME)@en[[[application/http]]]] 参照。

* URL

[31] [[HTTP接続]]自体を表す [[URL scheme]] はありません。
[[HTTP接続]]を使った[[資源]]へのアクセスを表す [[URL]]
は、 [CODE(URI)@en[[[http:]]]], [CODE(URI)@en[[[https:]]]] を参照。

;; [202] [[HTTPプロキシ]]を [CODE(URI)@en[http:]],
[CODE[https:]]
の
[[URL][HTTP(S) URL]]
で表すことがあり、これはある意味で[[HTTP接続]]を表す [[URL]]
とも言えるかもしれません。

* 歴史

[FIG(quote)[
[FIGCAPTION[
[1] [[HTTP]] ([[RFC 1945]] 1.2, [[RFC 2068]] 1.3, [[RFC 2616]] 1.3)
]FIGCAPTION]

>
:connection:A transport layer virtual circuit established between two [DEL[[INS[{1945}]] application]]
programs for the purpose of communication.

:接続:2つの[DEL[応用]]プログラム間の通信目的で確立される[[転送層]]仮想回路。
]FIG]


[337] [CITE[HTTP Persistent Connections Minutes]], [TIME[2024-09-28T05:14:37.000Z]], [TIME[1996-11-04T03:34:54.322Z]] <https://web.archive.org/web/19961104033339/http://ugly.resnova.com/persistminutes.html>

[338] [CITE[Wayback Machine]], [TIME[2024-09-28T05:15:07.000Z]] <https://web.archive.org/web/19961104033225/http://ugly.resnova.com/draft-ietf-http-ses-ext-01.txt>

[339] [CITE[Wayback Machine]], [TIME[2024-09-28T05:16:02.000Z]] <https://web.archive.org/web/19961104033215/http://ugly.resnova.com/draft-ietf-http-ses-ext-00.txt>


[575] [CITE@en[Re: Fetch: HTTP authentication and CORS]]
( ([[Jonas Sicking]] 著, [TIME[2013-05-05 14:39:46 +09:00]] 版))
<http://lists.w3.org/Archives/Public/public-webapps/2013AprJun/0502.html>

[581] [CITE@en[RFC 6202 - Known Issues and Best Practices for the Use of Long Polling and Streaming in Bidirectional HTTP]]
( ([TIME[2014-07-20 07:14:03 +09:00]] 版))
<http://tools.ietf.org/html/rfc6202#section-5.1>

[582] [CITE@en[draft-mogul-http-ooo-00 - Support for out-of-order responses in HTTP]]
( ([TIME[2014-10-18 15:27:44 +09:00]] 版))
<https://tools.ietf.org/html/draft-mogul-http-ooo-00>

[13] [CITE@en[draft-zhu-http-fullduplex-08 - Implications of Full-Duplex HTTP]]
([TIME[2014-10-20 09:40:59 +09:00]] 版)
<https://tools.ietf.org/html/draft-zhu-http-fullduplex-08>

[39] [CITE[Part2 - browsersec - Browser Security Handbook, part 2 - Browser Security Handbook - Google Project Hosting]]
([TIME[2015-03-31 16:43:55 +09:00]] 版)
<https://code.google.com/p/browsersec/wiki/Part2#Simultaneous_connection_limits>

[FIG(quote)[
[FIGCAPTION[
[139] [CITE[How to change the default keep-alive time-out value in Internet Explorer]]
([TIME[2015-08-16 12:55:22 +09:00]] 版)
<https://support.microsoft.com/en-us/kb/813827>
]FIGCAPTION]

> After the connection is idle for one minute, Internet Explorer resets the connection. 

]FIG]


[140] [CITE@en[205140 – Prefs: remove "network.http.*.timeout"]]
([TIME[2015-08-16 12:57:40 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=205140>

[FIG(quote)[
[FIGCAPTION[
[141] [CITE[Internet Explorer error "connection timed out" when server does not respond]]
([TIME[2015-08-16 12:59:23 +09:00]] 版)
<https://support.microsoft.com/en-us/kb/181050>
]FIGCAPTION]

> Internet Explorer imposes a time-out limit for the server to return data. By default, the time-out limit is as follows:
> Internet Explorer 4.0 and Internet Explorer 4.01	5 minutes
> Internet Explorer 5.x and Internet Explorer 6.x	60 minutes
> Internet Explorer 7 and Internet Explorer 8	60 minutes

]FIG]


[142] [CITE@en[1024015 – network.http.response.timeout breaks applications with long lived http connetions]]
([TIME[2015-08-16 13:05:04 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=1024015>

[143] [CITE@en[444328 – TCP-level keep alive timer]]
([TIME[2015-08-16 13:19:19 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=444328>

[FIG(quote)[
[FIGCAPTION[
[144] [CITE@en[HTTP keep-alive connection timeouts | FastMail Weblog]]
([TIME[2015-08-16 13:20:43 +09:00]] 版)
<http://blog.fastmail.com/2011/06/28/http-keep-alive-connection-timeouts/>
]FIGCAPTION]

> Opera 11.11 – 120 seconds
> Chrome 13 – at least 300 seconds (server closed after 300 second timeout)
> IE 9 – 60 seconds (changeable in the registry, appears to apply to IE 8/9 as well though the page only mentions IE 5/6/7)
> Firefox 4 – 115 seconds (changeable in about:config with network.http.keep-alive.timeout preference)
> Interestingly one of the other things I noticed while doing this test with Wireshark is that after 45 seconds, Chrome would send a TCP keep-alive packet, and would keep doing that every 45 seconds until the 5 minute timeout. No other browser would do this.

]FIG]


[145] [CITE[Issue 27400 - chromium - Long lived connections are being dropped by some network setups - An open-source project to help move the web forward. - Google Project Hosting]]
([TIME[2015-08-16 13:24:20 +09:00]] 版)
<https://code.google.com/p/chromium/issues/detail?id=27400>

[146] [CITE@en[947391 – HTTP connections (exc. XHR, SPDY) should have a response timeout]]
([TIME[2015-08-16 13:27:15 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=947391>

[147] [CITE@en[1005808 – New response timeout is affecting request requiring significant processing time]]
([TIME[2015-08-16 13:29:07 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=1005808>

[148] [CITE@en[Bug 102079 – Disable Nagle algorithm on WebSocket implementation]]
([TIME[2015-08-16 13:35:35 +09:00]] 版)
<https://bugs.webkit.org/show_bug.cgi?id=102079>

[149] [CITE@en[WebSocket Nagle アルゴリズム問題]]
([TIME[2015-08-16 13:35:40 +09:00]] 版)
<https://gist.github.com/uupaa/6281381>

[FIG(quote)[
[FIGCAPTION[
[150] [CITE[Issue 450258 - chromium - Websocket is stalling "OnMessage" javascript events until a certain number of bytes or a timer elapses - An open-source project to help move the web forward. - Google Project Hosting]]
([TIME[2015-08-16 13:37:48 +09:00]] 版)
<https://code.google.com/p/chromium/issues/detail?id=450258>
]FIGCAPTION]

> Windows 7 delays acks very aggressively for up to 200ms. If the server is using the Nagle algorithm, it won't send new messages until the acks arrive (or the send buffer fills).
> Any decent WebSocket server should have Nagle disabled, which is why we haven't seen this until now.
> Fortunately (?) pywebsocket in standalone mode does not disable the Nagle algorithm, and so I was able to reproduce quite easily. I then used Wireshark to confirm that the issue was happening at the TCP/IP level.
> The best fix is to disable Nagle on the server. This will avoid other, more subtle, problems that the Nagle algorithm can cause.
> 

]FIG]


[151] [CITE@en[542401 – set TCP_NODELAY for all SocketTransport sockets (not just SSL)]]
([TIME[2015-08-16 13:45:59 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=542401>

[FIG(quote)[
[FIGCAPTION[
[157] [CITE[IE9、IE10のリクエストタイムアウト時間]]
([TIME[2015-08-16 15:25:48 +09:00]] 版)
<https://social.technet.microsoft.com/Forums/ja-JP/5d64ea16-39cc-4f30-8077-ebf65a52f298/ie9ie10?forum=internetexplorerja>
]FIGCAPTION]

> 手元の次環境で、SleepするだけのCGIにリクエストした所、ともに受信タイムアウトは60分ちょうどでした。
> Win8 & IE10
> Win7 & IE9
> HTTPレスポンス受信に無通信のまま60分経つと、IE側から切断していました。(最初の受信データかによらず)
> レジストリにタイムアウト値(ReceiveTimeout)は設定していません。
> # 「切断する」とは、FINパケットを先にどちらが送出したかで確認を行いました。
>  
> 上記リンク先のIE9が5分後にリクエストをリトライする事象は、
> 最初、私もこれに引っかかってしまいましたが、
> サーバにApache2.2をデフォルト設定のままで使用していると発生すると思います。
> CGIがいつまでも応答がない場合に、Apacheがコネクションを切断してしまうためでした。(Timeoutの第3項も参照)
> このときIE側からは、すぐに別コネクションで接続が行われ、同一のリクエストを送信していました。
> (よーするに、1TCPコネクション内の再送ではなく、アプリレベルの再送)
> 設定変更すると5分以上経ってもIEは受信し続けてくれました。

]FIG]


[FIG(quote)[
[FIGCAPTION[
[158] [CITE@en[HTTPS and Keep-Alive Connections - IEInternals - Site Home - MSDN Blogs]]
([TIME[2015-08-16 15:34:10 +09:00]] 版)
<http://blogs.msdn.com/b/ieinternals/archive/2011/03/26/https-and-connection-close-is-your-apache-modssl-server-configuration-set-to-slow.aspx>
]FIGCAPTION]

> In the first, a thoughtful web developer or operations team reasons: “Hey, HTTPS connections are expensive to maintain on the server. Let’s be sure to tear those down as soon as possible to free up the server to accept new connections.”  That, of course, completely misses the point that if the server wasn’t tearing down the connections, the server would be under significantly lighter load to begin with! Sites that were deliberately written with this bad pattern load slowly in all browsers.
> We also found another root cause—ancient advice for the configuration of Apache+OpenSSL. Prior to IE6, ancient and unpatched versions of IE sometimes encountered connection failures when interacting with HTTPS servers when Keep-Alive is used. That problem was fixed nearly a decade ago, but outdated 1999-era configuration advice continues to harm performance for unaware server administrators:

]FIG]


[159] [CITE@en[Network.http.keep-alive.timeout - MozillaZine Knowledge Base]]
([TIME[2011-09-29 04:13:03 +09:00]] 版)
<http://kb.mozillazine.org/Network.http.keep-alive.timeout>

[166] [CITE[javascript - Max parallel http connections in a browser? - Stack Overflow]]
([TIME[2015-09-07 11:35:14 +09:00]] 版)
<http://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser/985704>

[FIG(quote)[
[FIGCAPTION[
[172] [CITE@en[gecko-dev/nsHttpConnection.cpp at master · mozilla/gecko-dev]]
([TIME[2015-09-26 22:49:37 +09:00]] 版)
<https://github.com/mozilla/gecko-dev/blob/master/netwerk/protocol/http/nsHttpConnection.cpp>
]FIGCAPTION]

> 
>     // Disable TCP Keepalives - use SPDY ping instead.
>     rv = DisableTCPKeepalives();

]FIG]


[181] [CITE@en[1091263 – ''''''[''''''http/2'''''']'''''' HTTP_1_1_REQUIRED error code]]
([TIME[2015-10-12 00:12:43 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=1091263>

[182] [CITE[Issue 431306 - chromium - Implement HTTP/2 error code HTTP_1_1_REQUIRED. - An open-source project to help move the web forward. - Google Project Hosting]]
([TIME[2015-10-12 00:14:53 +09:00]] 版)
<https://code.google.com/p/chromium/issues/detail?id=431306>

[FIG(quote)[
[FIGCAPTION[
[187] ([TIME[2015-05-14 12:35:34 +09:00]] 版)
<http://cpansearch.perl.org/src/MLEHMANN/AnyEvent-HTTP-2.22/Changes>
]FIGCAPTION]

> 
>         - do not recurse on POST requests, as per HTTP/1.'''['''01''']''' (this might
>           change as the recommendation isn't followed by anybody else).

]FIG]


[188] [CITE@en[Support full-duplex HTTP streaming · Issue #229 · whatwg/fetch]]
([TIME[2016-03-09 18:08:17 +09:00]] 版)
<https://github.com/whatwg/fetch/issues/229>

[194] [CITE@en[Allow for a request to finish after a response starts to arrive · whatwg/fetch@3a41b6f]]
([TIME[2016-03-26 11:54:19 +09:00]] 版)
<https://github.com/whatwg/fetch/commit/3a41b6f04996d4aac13ecad5b38635827dcd0df3>

[220] [CITE@en[1190136 – Firefox should decide whether reuse connection separately for IPv4 and IPv6]]
( ([TIME[2016-05-08 22:26:22 +09:00]]))
<https://bugzilla.mozilla.org/show_bug.cgi?id=1190136>

[FIG(quote)[
[FIGCAPTION[
[221] [CITE[cURL - How To Use]]
( ([TIME[2016-05-31 06:05:05 +09:00]]))
<https://curl.haxx.se/docs/manpage.html#--http2-prior-knowledge>
]FIGCAPTION]

> --http2-prior-knowledge
> (HTTP) Tells curl to issue its non-TLS HTTP requests using HTTP/2 without HTTP/1.1 Upgrade. It requires prior knowledge that the server supports HTTP/2 straight away. HTTPS requests will still do HTTP/2 the standard way with negotiated protocol version in the TLS handshake.

]FIG]


[FIG(quote)[
[FIGCAPTION[
[222] [CITE[cURL - How To Use]]
( ([TIME[2016-05-31 06:05:05 +09:00]]))
<https://curl.haxx.se/docs/manpage.html#--keepalive-time>
]FIGCAPTION]

> --keepalive-time <seconds>
> This option sets the time a connection needs to remain idle before sending keepalive probes and the time between individual keepalive probes. It is currently effective on operating systems offering the TCP_KEEPIDLE and TCP_KEEPINTVL socket options (meaning Linux, recent AIX, HP-UX and more). This option has no effect if --no-keepalive is used. (Added in 7.18.0)

]FIG]


[FIG(quote)[
[FIGCAPTION[
[223] [CITE[cURL - How To Use]]
( ([TIME[2016-05-31 06:05:05 +09:00]]))
<https://curl.haxx.se/docs/manpage.html#--unix-socket>
]FIGCAPTION]

> --unix-socket <path>
> (HTTP) Connect through this Unix domain socket, instead of using the network. (Added in 7.40.0)

]FIG]

[242] [CITE@en[Issue 170165 - chromium - Websocket handshake delay when server is unavailable - Monorail]]
( ([TIME[2016-06-16 19:51:11 +09:00]]))
<https://bugs.chromium.org/p/chromium/issues/detail?id=170165>

[FIG(quote)[
[FIGCAPTION[
[249] [CITE@en[Ajax Performance]]
( ([TIME[2016-06-17 10:40:16 +09:00]]))
<http://www.tophotelshongkong.com/en/ajaxperformance.html>
]FIGCAPTION]

> IE8: The Performance Implications
> March 7, 2008 on 1:25 am | In ajax | No Comments
> Mix08 is here, and with it the first beta of IE8. John has a great roundup of the JS/Dom work, noting that “Internet Explorer 8 is our release.” He’s right.
> I’ll run through a few of the items that have particular implications for performance.
> This one is the most exciting for me: the IE team has finally upped the connection limit to 6 per host from the default of 2. I’ve talked before about DNS tricks to get around the 2 connection limitation, but having this support out of the box will be a great assistance in the war on round-trip latency as it’s easier to make more expensive network calls in parallel. This is especially sweet for Comet and the like where the persistent connection could previously monopolize half of the connections to your site. As you would expect, Joe Walker of DWR is happy.
> One thing I haven’t seen mentioned anywhere is the total connection limit. Previous versions supported 2 per host and 6 total. Is the new version 6 per host / 6 total or 6 per host / 18 total. I really doubt it on the latter, but if no one has the answer I’ll grab the beta this weekend and test it out.

]FIG]

[261] [CITE@en[Retrying HTTP Requests]]
( ([TIME[2016-08-26 20:45:33 +09:00]]))
<https://mnot.github.io/I-D/httpbis-retry/>

[FIG(quote)[
[FIGCAPTION[
[262] [CITE@en-CA[POST request fails on certain sites, showing connection reset page (Regressed) | Firefox Site Compatibility]]
( ([TIME[2016-09-08 14:46:36 +09:00]]))
<https://www.fxsitecompat.com/en-CA/docs/2016/post-request-fails-on-certain-sites-showing-connection-reset-page/>
]FIGCAPTION]

> Firefox 46 has changed the way to handle broken connections so that it will no longer automatically retry unsafe requests such as POST. However, various Web sites do not work with the new behaviour, resulting in an error page “connection to the server was reset”, because they expect the browser to retry connections even for POST requests. KanColle, a popular Japanese Flash game is known to be affected.

]FIG]


[267] [CITE@ja[nginx ちょっと不思議だったリクエストリトライのお話 - Cybozu Inside Out | サイボウズエンジニアのブログ]]
([TIME[2016-10-07 00:11:03 +09:00]])
<http://blog.cybozu.io/entry/2016/05/09/080000>

[FIG(quote)[
[FIGCAPTION[
[268] [CITE[Apache Tomcat Configuration Reference (6.0.45) - The HTTP Connector]]
([[Craig R. McClanahan]]著, [TIME[2016-02-11 23:00:17 +09:00]])
<http://tomcat.apache.org/tomcat-6.0-doc/config/http.html>
]FIGCAPTION]

> tcpNoDelay	
> If set to true, the TCP_NO_DELAY option will be set on the server socket, which improves performance under most circumstances. This is set to true by default.

]FIG]


[FIG(quote)[
[FIGCAPTION[
[269] [CITE[Apache Tomcat Configuration Reference (6.0.45) - The HTTP Connector]]
([[Craig R. McClanahan]]著, [TIME[2016-02-11 23:00:17 +09:00]])
<http://tomcat.apache.org/tomcat-6.0-doc/config/http.html>
]FIGCAPTION]

> socket.tcpNoDelay	
> (bool)same as the standard setting tcpNoDelay. Default value is false
> socket.soKeepAlive	
> (bool)Boolean value for the socket's keep alive setting (SO_KEEPALIVE). Default is false.
> socket.ooBInline	
> (bool)Boolean value for the socket OOBINLINE setting. Default value is true
> socket.soReuseAddress	
> (bool)Boolean value for the sockets reuse address option (SO_REUSEADDR). Default value is true
> socket.soLingerOn	
> (bool)Boolean value for the sockets so linger option (SO_LINGER). Default value is true. This option is paired with the soLingerTime value.
> socket.soLingerTime	
> (bool)Value in seconds for the sockets so linger option (SO_LINGER). Default value is 25 seconds. This option is paired with the soLinger value.
> socket.soTimeout	
> (int)Value in milliseconds for the sockets read timeout (SO_TIMEOUT). Default value is 5000 milliseconds.
> socket.soTrafficClass	
> (byte)Value between 0 and 255 for the traffic class on the socket, 0x04 | 0x08 | 0x010

]FIG]




[FIG(quote)[
[FIGCAPTION[
[278] [CITE@en[Webmention]]
([TIME[2017-01-11 04:06:01 +09:00]])
<https://webmention.net/draft/#h-limits-on-get-requests>
]FIGCAPTION]

> Receivers should place limits on the amount of data and time they spend fetching unverified source URLs. For example, if a source URL doesn't respond within 5 seconds, it can treat that as a failure. Similarly, the receiver can fetch only the first 1mb of the page, since any reasonable HTML or JSON page will be smaller than that.

]FIG]


[279] [CITE[HTTP/1.1 and Nagle's Algorithm]]
([TIME[1998-04-30 05:00:47 +09:00]])
<https://www.w3.org/Protocols/HTTP/Performance/Nagle/>

[280] [CITE@en[draft-pardue-quic-http-mcast-00 - Hypertext Transfer Protocol (HTTP) over multicast QUIC]]
([TIME[2017-04-09 17:31:30 +09:00]])
<https://tools.ietf.org/html/draft-pardue-quic-http-mcast-00>

[FIG(quote)[
[FIGCAPTION[
[281] [CITE@en-US[nsHttpConnectionMgr.cpp - DXR]]
([TIME[2017-05-11 16:01:12 +09:00]])
<https://dxr.mozilla.org/mozilla-beta/source/netwerk/protocol/http/nsHttpConnectionMgr.cpp#2727>
]FIGCAPTION]

> 
>     // For backup connections, we disable IPv6. That's because some users have
>     // broken IPv6 connectivity (leading to very long timeouts), and disabling
>     // IPv6 on the backup connection gives them a much better user experience
>     // with dual-stack hosts, though they still pay the 250ms delay for each new
>     // connection. This strategy is also known as "happy eyeballs".

]FIG]


[286] [CITE[Service Name and Transport Protocol Port Number Registry]]
([TIME[2017-06-29 05:36:49 +09:00]])
<https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?&page=2>

[287] [CITE@en[Clarify rules around half-closed TCP connections · Issue #22 · httpwg/http11bis]]
([TIME[2017-09-08 15:17:21 +09:00]])
<https://github.com/httpwg/http11bis/issues/22>

[288] [CITE@en[Abortable fetch]]
([[jakearchibald]]著, [TIME[2017-09-20 21:59:57 +09:00]])
<https://github.com/whatwg/fetch/commit/0bcd5dfc71ef44319873887f4b83119bd6d0b71d>

[293] [CITE@en[Warp should respond with HTTP_1_1_REQUIRED for connection takeovers. · Issue #417 · yesodweb/wai]]
([TIME[2017-11-18 16:56:00 +09:00]])
<https://github.com/yesodweb/wai/issues/417>

[294] [CITE@en[516237 - Chrom{e,ium} refuses to talk HTTP/2 to a server once it's seen HTTP_1_1_REQUIRED for any resource. - chromium - Monorail]]
([TIME[2017-11-18 16:58:44 +09:00]])
<https://bugs.chromium.org/p/chromium/issues/detail?id=516237>

[295] [CITE@en[685741 - ERR_UNEXPECTED Displays briefly before page loads - chromium - Monorail]]
([TIME[2017-11-18 16:59:40 +09:00]])
<https://bugs.chromium.org/p/chromium/issues/detail?id=685741>

[296] [CITE@en[1091263 - '''['''http/2''']''' HTTP_1_1_REQUIRED error code]]
([TIME[2017-11-18 17:00:03 +09:00]])
<https://bugzilla.mozilla.org/show_bug.cgi?id=1091263>

[297] [CITE@en['''['''WFLY-7662''']''' CLIENT-CERT authentication doesn't work - JBoss Issue Tracker]]
([TIME[2017-11-18 17:02:38 +09:00]])
<https://issues.jboss.org/browse/WFLY-7662?_sscc=t>

[298] [CITE@en[errors: change timeout errors from 408 to 500 HTTP status code]]
([[andreastt]]著, [TIME[2018-08-21 18:40:30 +09:00]])
<https://github.com/w3c/webdriver/commit/c377c21186f672105a05383d5152e0a3b2a00374>

[299] [CITE@en[HTTP status code 408 causes clients to retry · Issue #1287 · w3c/webdriver]]
([TIME[2018-09-29 17:23:06 +09:00]])
<https://github.com/w3c/webdriver/issues/1287>

[300] [CITE@en[errors: change timeout errors from 408 to 500 HTTP status code by andreastt · Pull Request #1292 · w3c/webdriver]]
([TIME[2018-09-29 17:24:13 +09:00]])
<https://github.com/w3c/webdriver/pull/1292>

[301] [CITE@ja[Microsoft Edge でローカルホストにアクセスできない問題を解決する - Browser]]
([TIME[2018-12-13 12:23:37 +09:00]])
<http://browser.hatenablog.com/entry/2016/01/29/190856>

[302] [CITE@ja[Microsoft Edgeでローカルの仮想マシン上に構築したWebサイト(Webアプリケーション)にアクセスできない - YoshinoriN's Memento]]
([[YoshinoriN]]著, [TIME[2018-12-11 00:02:38 +09:00]])
<https://yoshinorin.net/2016/07/03/vagrant-edge/>

[303] [CITE[dns - Why does Microsoft Edge open some local websites, but not others, where the domain name is routed to 127.0.0.1 in hosts file - Stack Overflow]]
([TIME[2018-12-19 14:53:53 +09:00]])
<https://stackoverflow.com/questions/32384571/why-does-microsoft-edge-open-some-local-websites-but-not-others-where-the-doma/37848210>

[304] [CITE[#15565 (Host adapter showing zero bytes traffic) – Oracle VM VirtualBox]]
([TIME[2018-12-19 14:56:02 +09:00]])
<https://www.virtualbox.org/ticket/15565>

[305] [CITE@en[Tracking Compliance and Scope]]
([TIME[2019-01-19 00:57:42 +09:00]])
<https://www.w3.org/TR/tracking-compliance/#dfn-network-interaction>

[306] [CITE@en[Tracking Compliance and Scope]]
([TIME[2019-01-19 00:57:42 +09:00]])
<https://www.w3.org/TR/2019/NOTE-tracking-compliance-20190122/#dfn-network-interaction>

[307] [CITE@en[Tracking Preference Expression (DNT)]]
([TIME[2019-01-16 01:50:48 +09:00]])
<https://www.w3.org/TR/2019/NOTE-tracking-dnt-20190117/#dfn-network-interaction>

[314] [CITE[curl - How To Use]]
([TIME[2020-09-21T09:01:13.000Z]], [TIME[2020-10-01T05:59:11.520Z]])
<https://curl.haxx.se/docs/manpage.html#--connect-timeout>

[315] [CITE[curl - How To Use]]
([TIME[2020-09-21T09:01:13.000Z]], [TIME[2020-10-01T05:59:40.545Z]])
<https://curl.haxx.se/docs/manpage.html#--connect-to>

[316] [CITE[curl - How To Use]]
([TIME[2020-09-21T09:01:13.000Z]], [TIME[2020-10-01T06:15:47.950Z]])
<https://curl.haxx.se/docs/manpage.html#--http2-prior-knowledge>

[317] [CITE@en[GNU Wget 1.20 Manual]]
([TIME[2020-10-01T07:17:21.000Z]])
<https://www.gnu.org/software/wget/manual/wget.html#index-timeout>

[318] [CITE@en[GNU Wget 1.20 Manual]]
([TIME[2020-10-01T07:19:42.000Z]])
<https://www.gnu.org/software/wget/manual/wget.html#index-Persistent-Connections_002c-disabling>

[319] [CITE@en[Command-Line Interface — Streamlink 1.6.0 documentation]]
([TIME[2020-09-30T20:32:48.000Z]], [TIME[2020-10-01T07:52:32.334Z]])
<https://streamlink.github.io/cli.html#cmdoption-http-timeout>

[320] [CITE@en[Disabled HTTP/1.0 requests with Transfer-Encoding.]]
([[Sergey Kandaurov]], [TIME[2021-08-10 00:12:12 +09:00]], [TIME[2021-08-20T04:56:27.000Z]])
<https://github.com/nginx/nginx/commit/7bcb50c0610a18bf43bef0062b2d2dc550823b53>