[8] [[キャッシュ]]が有効であるとただちに確認できる期限を[DFN[[RUBYB[[[満期時刻]]]@en[expiration time]]]]といいます。
[[満期時刻]]までの[[時間]]を[DFN[[RUBYB[[[新鮮寿命]]]@en[freshness lifetime]]]]といいます。[[新鮮寿命]]を過ぎていない[[応答]]を[DFN[[RUBYB[[[新鮮応答]]]@en[freshness response]]]]、
過ぎている[[応答]]を[DFN[[RUBYB[[[腐敗応答]]]@en[stale response]]]]といいます。

* 仕様書

[REFS[
- [2] [CITE@en[RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching]] ([TIME[2014-09-11 10:19:59 +09:00]] 版) <https://tools.ietf.org/html/rfc7234#section-4.2>
-- [9] [CITE@en[RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching]] ([TIME[2014-09-11 10:19:59 +09:00]] 版) <https://tools.ietf.org/html/rfc7234#section-4.2.1>
-- [19] [CITE@en[RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching]] ([TIME[2014-09-11 10:19:59 +09:00]] 版) <https://tools.ietf.org/html/rfc7234#section-4.2.2>
-- [23] [CITE@en[RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching]] ([TIME[2014-09-11 10:19:59 +09:00]] 版) <https://tools.ietf.org/html/rfc7234#section-4.2.4>
- [34] [CITE@en[RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching]] ([TIME[2014-09-11 10:19:59 +09:00]] 版) <https://tools.ietf.org/html/rfc7234#section-4.3.5>
- [33] [CITE@en[RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching]] ([TIME[2014-09-11 10:19:59 +09:00]] 版) <https://tools.ietf.org/html/rfc7234#section-4.4>
- [40] [CITE@en[RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching]] ([TIME[2014-09-11 10:19:59 +09:00]] 版) <https://tools.ietf.org/html/rfc7234#section-5.5.4>
- [42] [CITE@en[RFC 5789 - PATCH Method for HTTP]] ([TIME[2014-09-22 15:11:26 +09:00]] 版) <http://tools.ietf.org/html/rfc5789#section-2>
]REFS]

* 満期時刻

[27] [DFN[[RUBYB[[[明示的満期時刻]]]@en[explicit expiration time]]]]は、
[[キャッシュ]]がそれ以降は[[蓄積]]された[[応答]]を[[検証]]なしで利用できなくなると[[起源鯖]]が意図する[[時刻]]です
[SRC[>>2]]。

;; [[明示的満期時刻]]は [CODE(HTTP)@en[[[Expires:]]]] [[ヘッダー]]や
[CODE(HTTP)@en[[[Cache-Control:]]]] [[ヘッダー]]の [CODE(HTTP)@en[[[max-age]]]]
[[指示子]]で指定できます。

[29] 通常は[[起源鯖]]は[[表現]]がそれまでは[[意味的]]に大きく変わらないだろうという将来の[[明示的満期時刻]]を指定しますが、
[[要求]]があるたびに[[キャッシュ]]に[[検証]]させたい時は過去の[[明示的満期時刻]]を指定することもできます [SRC[>>2]]。

[28] [DFN[[RUBYB[[[発見的満期時刻]]]@en[heuristic expiration time]]]]は、
[[明示的満期時刻]]が利用できない ([[鯖]]が指定していない)
ときに[[キャッシュ]]が割り当てるものです [SRC[>>2]]。
[[明示的満期時刻]]がある場合、[[発見的満期時刻]]を使っては[['''なりません''']] [SRC[>>19]]。

[20] [[発見的満期時刻]]を決定する方法は [[HTTP]] 仕様としては特に規定されていません
[SRC[>>19]]。また発見的方法を使うことも必須ではありません。使わない場合は、
明示されていない限り[[腐敗]]とみなすことになります。

[21] [[応答]]が [CODE(HTTP)@en[[[Last-Modified:]]]] [[ヘッダー]]を持つ場合、
その[[時刻]]からの[[時間間隔]]の何割か分を超えないような発見的な値を使うことが[RUBYB[推奨]@en[encourage]]されています。典型的な割合は10%です。 [SRC[>>19]]

;; [17] [[満期]]でもただちに[[蓄積]]された[[応答]]を破棄する必要はありません。
[[キャッシュ]]が[[検証]]を実装していれば、[[満期]]後の[[応答]]
([[腐敗応答]]) を[[検証]]して有効であれば[[応答]]として再利用できます。

[43] [[明示的満期時刻]]の有無は、 [CODE(HTTP)@en[[[POST]]]] [[要求]]や
[CODE(HTTP)@en[[[PATCH]]]] [[要求]] [SRC[>>42]] に対する[[応答]]の[[キャッシュ可能性]]に影響します。

* 新鮮寿命

[6] [[応答]]の[DFN[[RUBYB[[[新鮮寿命]]]@en[freshness lifetime]]]]は、
[[応答]]の[[起源鯖]]における[[生成]]と[[満期時刻]]までの間の[[時間]]です。

[10] [[新鮮寿命]]は次のように決定します [SRC[>>9]]。

[FIG(steps)[
= [18] [[明示的満期時刻]]があれば、それまでの時間を次のようにして決定します。
== [11] [[共有キャッシュ]]であり、 [CODE(HTTP)@en[[[Cache-Control:]] [[s-maxage]]]]
が[[応答]]に含まれるなら、その値を返し、ここで終わります。
== [12] [CODE(HTTP)@en[[[Cache-Control:]] [[max-age]]]] が[[応答]]に含まれるなら、
その値を返し、ここで終わります。
== [13] [CODE(HTTP)@en[[[Expires:]]]] [[ヘッダー]]が[[応答]]に含まれるなら、
[CODE(HTTP)@en[[[Expires:]]]] の値から [CODE(HTTP)@en[[[Date:]]]]
の値を引いた結果を返し、ここで終わります。
= [14] [[発見的満期時刻]]までの時間を返します。
]FIG]

[15] 決定時に使う [CODE(HTTP)@en[[[Cache-Control:]]]] [[指令]]や
[CODE(HTTP)@en[[[Expires:]]]] が複数ある場合は、値は[[非妥当]]とみなします。
その場合[[腐敗]]とみなすことが[RUBYB[推奨]@en[encouraged]]されています。 [SRC[>>9]]

[37] [CODE(HTTP)@en[[[Expires:]]]] の値が[[非妥当]]な時も、
過去の時刻、すなわち[[腐敗]]とみなすことになっています ([CODE(HTTP)@en[[[Expires:]]]]
参照)。

[38] [CODE(HTTP)@en[[[Date:]]]] が[[非妥当]]な時については明記されていませんが、
やはり[[非妥当]]で[[腐敗]]とみなすべきでしょう。

[39] [CODE(HTTP)@en[[[Date:]]]] が存在しない時は、[[キャッシュ]]時に付与することになっています
([CODE(HTTP)@en[[[Date:]]]] 参照)。

[41] [[要求]]の [CODE(HTTP)@en[[[Cache-Control:]] [[max-age]]]] で指定された値は[[満期時刻]]の決定に寄与しないようですが、[[応答]]が[[検証]]なしで返されるかどうかには影響します。

;; [CODE(HTTP)@en[[[max-age]]]] 参照。

* 新鮮応答と腐敗応答

[3] [DFN[[RUBYB[[[新鮮応答]]]@en[fresh response]]]]は、
[[齢]]が[[新鮮寿命]]をまだ超えていない[[応答]]です [SRC[>>2]]。

[4] [DFN[[RUBYB[[[腐敗応答]]]@en[stale response]]]]は、
[[齢]]が[[新鮮寿命]]を超えた[[応答]]です [SRC[>>2]]。

;; [7] [[新鮮]]か[[腐敗]]かは、[[キャッシュ]]操作にのみ適用されるものです。
[[利用者エージェント]]は[[腐敗]]していても表示し続けて何ら問題ありません。 [SRC[>>2]]

* 非妥当化

[32] [[蓄積された応答]]は[DFN[[RUBYB[[[非妥当化]]]@en[invalidate]]]]されることがあります。
これは[[蓄積された応答]]を削除するか、または「非妥当」フラグを立てるかのいずれかを意味しています
[SRC[>>33]]。[[蓄積された応答]]は、
[CODE(HTTP)@en[[[HEAD]]]] [[要求]] [SRC[>>34]] や[[非安全要求メソッド]] [SRC[>>33]]
に対する[[応答]]により[[非妥当化]]されます (詳細はそれぞれの項を参照)。
[[非妥当]]な場合は[[蓄積された応答]]を利用する前に[[検証]]が必要であり [SRC[>>33]]、
「[[腐敗]]とする」 [SRC[>>34]] とも表現されています。

[184] [CODE(HTTP)@en[[[DELETE]]]] [[メソッド]]は[[キャッシュ]]を[[非妥当]]化します。

;; [CODE(HTTP)@en[[[DELETE]]]] 参照。

[186] [CODE(HTTP)@en[[[PATCH]]]] [[要求]]の[[対象URL]]に関する[[キャッシュ項目]]は、
[[腐敗]]したものとして扱う[['''べきです''']] [SRC[>>42]]。

* 転送

[22] [[キャッシュ]]は、[[新鮮寿命]]の計算に[[発見的満期時刻]]を使った場合は [SRC[>>40, >>19]]、
その[[新鮮寿命]]が24時間よりも大きな場合 [SRC[>>40]]、
[[齢]] ([[current_age]]) が24時間よりも大きければ [SRC[>>40, >>19]]、
[[警告符号]] [CODE(HTTP)[[[113]]]] の [CODE(HTTP)@en[[[Warning:]]]] [[ヘッダー]]を
(既に無ければ [SRC[>>19]]) [[生成]]する[['''べきです''']] [SRC[>>40, >>19]]。

[24] [[キャッシュ]]は、明示的に禁止された場合
(例えば [CODE(HTTP)@en[[[no-store]]]], [CODE(HTTP)@en[[[no-cache]]]],
[CODE(HTTP)@en[[[must-revalidate]]]], [CODE(HTTP)@en[[[s-maxage]]]],
[CODE(HTTP)@en[[[proxy-revalidate]]]] が適用される場合) には、
[[腐敗応答]]を[[生成]]しては[['''なりません''']] [SRC[>>23]]。

[25] [[キャッシュ]]は、[[起源鯖]]と接続できないなど“切断されている”場合や
[CODE(HTTP)@en[[[max-stale]]]] などで明示的に認められている場合を除き、
[[腐敗応答]]を送っては[['''なりません''']] [SRC[>>23]]。

[26] [[キャッシュ]]は、[[腐敗応答]]に[[警告符号]] [CODE(HTTP)[[[110]]]]
の [CODE(HTTP)@en[[[Warning:]]]] [[ヘッダー]]を[[生成]]する[['''べきです''']] [SRC[>>23]]。
[CODE(HTTP)[[[111]]]] を[[生成]]するべき場合もあります。

;; [CODE(HTTP)[[[110]]]], [CODE(HTTP)[[[111]]]] も参照。

[30] [[キャッシュ]]は、[[キャッシュ]]が“切断されている”場合の[[腐敗応答]]に[[警告符号]] [CODE(HTTP)[[[112]]]]
の [CODE(HTTP)@en[[[Warning:]]]] [[ヘッダー]]を[[生成]]する[['''べきです''']] [SRC[>>23]]。

[31] [[キャッシュ]]は、 [CODE(HTTP)@en[[[Age:]]]] [[ヘッダー]]を持たない[[応答]]を[[転送]]する場合には、
[CODE(HTTP)@en[[[Warning:]]]] [[ヘッダー]]を新たに[[生成]]する[['''べきではありません''']]。
[[キャッシュ]]は転送中に[[腐敗]]した[[応答]]を[[検証]]する必要はありません。 [SRC[>>23]]

[36] [CODE(HTTP)@en[[[min-fresh]]]] が指定されている場合は、
[[新鮮]]であってもそのまま[[再利用]]できないことがあります。

* 歴史

[FIG(quote)[
[FIGCAPTION[
[1] [[HTTP]] ([[RFC2068]] 1.3, [[RFC2616]] 1.3)
]FIGCAPTION]
>
:fresh: A response is fresh if its age has not yet exceeded its freshness lifetime.

:新鮮:[[応答]]は、その[[齢]]が[[新鮮寿命]]をまだ超えていなければ、[DFN[新鮮]]です。
]FIG]

[FIG(quote)[
[FIGCAPTION[
[5] [[HTTP]] ([[RFC 2068]] 1.3, [[RFC 2616]] 1.3)
]FIGCAPTION]
>
:freshness lifetime: The length of time between the generation of a response and its
expiration time.

:新鮮寿命:[[応答]]の生成からその[[満期時刻]]までの間の時間の長さ。
]FIG]

[FIG(quote)[
[FIGCAPTION[
[35] [[HTTP]] ([[RFC 2068]] 1.3, [[RFC 2616]] 1.3)
]FIGCAPTION]
>
:heuristic expiration time: An expiration time assigned by a cache when no explicit expiration time is available.

:発見的満期時刻: [[明示満期時刻]]が利用可能でないときに[[キャッシュ]]が割り当てた[[満期時刻]]。
]FIG]

[FIG(quote)[
[FIGCAPTION[
[16] [[HTTP]] ([[RFC2068]] 1.3, [[RFC2616]] 1.3)
]FIGCAPTION]
>
:stale: A response is stale if its age has passed its freshness lifetime.

:[RUBYB[腐敗]@en[stale]]:[[応答]]は、その[[齢]]が[[新鮮寿命]]を過ぎていれば腐っています。
]FIG]

* 実装

[44] [[Chrome]] は、 [[リダイレクト]]に [CODE(HTTP)@en[[[Cache-Control:]] [[public]]]]
と [CODE(HTTP)@en[[[Last-Modified:]]]] を指定するだけではその[[応答]]を[[キャッシュ]]して再利用しません。
([[キャッシュ可能性]]の条件は満たしているはずで、[[発見的満期時刻]]が使われるなら、
再利用されて良さそうですが。) それに更に [CODE(HTTP)@en[[[max-age]]]]
を指定すると、再利用されるようになります。
[TIME[2015-10-27T10:06:02.100Z]]