[3] [[HTTP]] の [DFN[[CODE(HTTP)@en[Set-Cookie:]] [[応答頭欄]]]]は、 [[クライアント]]に対して [[Cookie]] を設定することを指示します。 [322] [CODE(HTTP)@en[[[Set-Cookie:]]]] [[頭欄]]は [[Netscape]] 社によってはじめに定義・実装され、 後に[[Webブラウザー]]を含む数多くの [[HTTP]] [[利用者エージェント]]で実装されるに至りました。 なお、 [CODE(HTTP)@en[[[Set-Cookie]]]] (>>311) やその改訂版 [CODE(HTTP)@en[[[Set-Cookie2]]]] (>>308) は [[IETF]] によって [[RFC 2109]], [[RFC 2965]] として標準化されましたが、 [[Netscape]] の定義と互換性がないため無視され、事実上死文化しています。 * 仕様書 [REFS[ - [371] [CITE@en[RFC 6265 - HTTP State Management Mechanism]] ([TIME[2012-03-01 09:57:02 +09:00]] 版) - [377] '''[CITE@en[RFC 6265 - HTTP State Management Mechanism]] ([TIME[2012-03-01 09:57:02 +09:00]] 版) ''' ]REFS] * 構文 [4] [CODE(HTTP)@en[Set-Cookie:]] 欄の[[欄本体]]は [PRE(HTTP example code)[ Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure ]PRE] のように名前と値の組 ([RUBYB[[[属性]]]@en[attribute]]) の連続として記述します [SRC[>>2]]。 [378] [CODE(HTTP)@en[[[Set-Cookie:]]]] 欄の構文は次のように定義されています。 [[起源鯖]]はこの構文に従う[['''べきです''']] [SRC[>>377]]。 ;; [379] なぜか違反を完全に禁止はされていません... [FIG[ [FIGCAPTION[ [380] [[RFC 6265]] による [CODE(HTTP)@en[[[Set-Cookie:]]]] 欄の構文 ]FIGCAPTION] [PRE(ABNF code)[ set-cookie-header = "Set-Cookie:" [[SP]] set-cookie-string set-cookie-string = [[cookie-pair]] *( ";" [[SP]] [[cookie-av]] ) ]PRE] ]FIG] ;; [381] 詳しくは [[Cookieの属性]]の項をご覧下さい。 ** 文脈 [321] [[起源鯖]]は、 [CODE(HTTP)@en[[[Set-Cookie:]]]] 欄を任意の[[HTTP]] [[応答]]に含めて[['''構いません''']] [SRC[>>371]]。 ;; [[RFC 2109]], [[RFC 2965]] は [CODE(HTTP)@en[[[Set-Cookie]]]], [CODE(HTTP)@en[[[Set-Cookie2]]]] を任意の[[応答]]に含めて[['''構わない''']]としていました。 [SRC[>>319, >>318]] ** 複数のヘッダー [16] [[起源鯖]]は複数の [CODE(HTTP)@en[[[Set-Cookie:]]]] 欄を含めて[['''構いません''']] [SRC[>>2, >>371]]。 [373] [[起源鯖]]は複数の [CODE(HTTP)@en[[[Set-Cookie:]]]] 欄を1つに[[折り畳み]]する[['''べきではありません''']]。 [CODE(HTTP)[[[,]]]] は構文上、値の中に普通に使える[[文字]]なので、[[折り畳み]]によって意味が変わってしまうことがあります。 [SRC[>>371]] ;; [374] なぜ完全に禁止じゃなくて[['''べき''']]なんでしょうね。正当な理由ってあるのでしょうか。 [[アプリケーション鯖]]と [[HTTP]] [[鯖]]が分かれていて、[[アプリケーション]]から [[HTTP]] を完全に制御できなくて、 [[HTTP]] で勝手に[[折り畳み]]してしまう糞実装とか考慮してるんでしょうか・・・。 ;; [14] 元々 [CODE(char)[[[,]]]] の使用が禁止されていたのは複数の [CODE(HTTP)@en[[[Set-Cookie:]]]] [[頭欄]]を連結した時に [CODE(char)[[[,]]]] が使われることへの配慮でしょうか、と思いきや、 [CODE(HTTP)@en[[[Expires]]]] では [CODE(char)[[[,]]]] が[[曜日]]の後に使われています。 それならなんで禁止されているのでしょう。 [18] 複数の [CODE(HTTP)@en[[[Set-Cookie:]]]] [[頭欄]]で同じ [CODE(HTTP)@en[[VAR[NAME]]]] が指定されていたときにどれが生き残るのか (>>17) は仕様に明記されていません。 ;; [320] [[RFC 2109]], [[RFC 2965]] でも複数の [CODE(HTTP)@en[[[Set-Cookie]]]], [CODE(HTTP)@en[[[Set-Cookie2]]]] が[[応答]]1つに含まれても[['''構わない''']]と明記していました。 また、途中の[RUBYB[[[関門]]]@en[gateway]]で[RUBYB[[[折り畳み]]]@en[fold]]され得ることにも言及されていました。 [SRC[>>319, >>318]] * 属性 [382] [CODE(HTTP)@en[[[Set-Cookie:]]]] 欄の値としては、名前と値の組 ([[cookie-pair]]) と、それに続く0個以上の[[属性]を指定することができます。詳しくは [[Cookieの属性]]の項をご覧下さい。 * 利用者エージェントの処理モデル ** 状態符号との関係 [375] [CODE(HTTP)@en[[[Set-Cookie:]]]] は[[状態符号]]に関わらず任意の [[HTTP]] [[応答]]で使うことができます。 [[利用者エージェント]]は [CODE(HTTP)[[[1xx]]]] の場合にこれを無視して[['''構いません''']]が、 それ以外の場合は処理しなければ[['''なりません''']]。 [SRC[>>371]] [305] [[利用者エージェント]]は[[状態符号]]が[[リダイレクト]]であっても、 (その[[リダイレクト]]が帰ってきた[[要求]]の [[URL]] に関して) [CODE(HTTP)@en[[[Set-Cookie:]]]] [[頭欄]]に従った処理をするべきです。 ** 上書き [17] [CODE(HTTP)@en[[[Domain]]]] と [CODE(HTTP)@en[[[Path]]]] と [CODE(HTTP)@en[[VAR[NAME]]]] が同じ [[Cookie]] があれば、 値は上書きされて、最新のものだけが残ります。 [SRC[>>2]] ;; [19] 仕様上は [CODE(HTTP)@en[[[Path]]]] と [CODE(HTTP)@en[[VAR[NAME]]]] とありますが、 [CODE(HTTP)@en[[[Domain]]]] も実際には見ています。 [20] >>17 の上書き判定における [CODE(HTTP)@en[[[Path]]]] は完全一致 [SRC[>>2]] なので、 例えば [CODE(URI)[/foo]] と [CODE(URI)[/foo/bar]] で同じ名前の [[Cookie]] が設定されると、 [CODE(URI)@en[/foo/bar]] では両方が有効になります。 ;; [345] [[RFC 2109]] では [CODE(HTTP)@en[[VAR[NAME]]]] が同じで [CODE(HTTP)@en[[[Path]]]]、[CODE(HTTP)@en[[[Domain]]]] が[[文字列]]として[[一致]]するなら [SRC[>>343]]、[[RFC 2965]] では [CODE(HTTP)@en[[VAR[NAME]]]] が同じで [CODE(HTTP)@en[[[Path]]]] が[[文字列]]として[[一致]]、 [CODE(HTTP)@en[[[Domain]]]] が[[大文字・小文字を区別しない]]で[[一致]]するなら上書きする [SRC[>>344]]、 とされていました。 ;; [349] [[RFC 2965]] でも [CODE(HTTP)[[[Port]]]] [[属性]]はここでの[[一致]]判定には含まれないようです。 ;; [350] [[RFC 2109]]、[[RFC 2965]] では[[属性]]の名前の[[大文字と小文字を区別しない]]ことになっていますが、 ここでの扱いは明確にされていません。 [346] 新しい [[Cookie]] の [CODE(HTTP)@en[[[Expires]]]] が過去であれば、 古い [[Cookie]] は削除され、新しい [[Cookie]] も蓄積されません。 ;; [347] [[RFC 2109]]、[[RFC 2965]] では [CODE(HTTP)@en[[[Max-Age]]]] が [CODE(HTTP)[[[0]]]] であれば、あるいは [[RFC 2965]] では [CODE(HTTP)@en[[[Discard]]]] [[属性]]があれば、古い [[Cookie]] は削除され、新しい [[Cookie]] も蓄積されません。 [SRC[>>343, >>344]] * 串とキャッシュの処理モデル [22] [[串]]は [CODE(HTTP)@en[[[Set-Cookie:]]]] [[頭欄]]をそのまま[[クライアント]]に渡すべきです。 [[状態符号]]が [CODE(HTTP)@en[[[200]]]] であれ [CODE(HTTP)[[[304]]]] であれ、です。 [SRC[>>2]] ** キャッシュ可能性 [376] [CODE(HTTP)@en[[[Set-Cookie:]]]] 欄の有無は[[キャッシュ可能性]]に影響しません [SRC[>>371]]。 [21] [CODE(HTTP)@en[[[Set-Cookie:]]]] [[頭欄]]は[[キャッシュ]]するべきではありません。 [SRC[>>2]] ;; [361] [[RFC 2109]] と [[RFC 2965]] は、[[HTTP/1.0]] に基づく[[串]]の [CODE(HTTP)@en[[[Set-Cookie:]]]] や [CODE(HTTP)@en[[[Set-Cookie2:]]]] との関わりを考察しています [SRC[>>359, >>360]]。[[キャッシュ不能]]なら問題はないのですが、 [[pre-expired]] な場合、状況によっては[[起源鯖]]による[[妥当性検証]]をスキップして[[クライアント]]に送られてしまい、 他の[[クライアント]]向けの [[Cookie]] がその[[クライアント]]に渡る可能性があることを指摘しています。 ;; [[HTTP/1.1]] に従っているなら [CODE(HTTP)@en[[[Cache-Control:]]]] によりもっと細かく制御できるので大丈夫ということなのでしょう。 * 歴史 ** Netscape Cookie [REFS[ - [2] [[Netscape Cookie]] -- [CITE[Client Side State - HTTP Cookies]] ]REFS] ** RFC 2109 の [CODE(HTTP)@en[Set-Cookie:]] 欄 [311] [[IETF]] は [[Cookie]] の標準化を試み、[[RFC 2109]] で [[Netscape Cookie]] とは非互換な [DFN[[CODE(HTTP)@en[[[Set-Cookie:]]]] [[頭欄]]]]を定義していました。 ;; [351] 新旧 Cookie の互換性については、あまり役に立たない情報が多少 [[RFC 2109]] の最後に載っています。詳しくは [CODE(HTTP)@en[[[Cookie:]]]] の項の「歴史」の節をご覧ください。 *** 仕様書 - [312] [DEL[[[RFC 2109]]]] ([[廃止]]済み) -- [313] [CSECTION@en[4.1 Syntax: General]] -- [319] [CSECTION@en[3.2.1 General]] -- [324] '''[CSECTION@en[4.2.2 Set-Cookie Syntax]]''' -- [331] [CSECTION@en[4.2.3 Controlling Caching]] -- [340] [CSECTION@en[4.3.1 Interpreting Set-Cookie]] -- [343] [CSECTION@en[4.3.3 Cookie Management]] -- [42] [CSECTION@en[4.5 Caching Proxy Role]] -- [359] [CSECTION@en[10.2 Caching and HTTP/1.0]] ** [CODE(HTTP)@en[Set-Cookie2:]] 欄 [308] [[RFC 2109]] を廃止して代わりに発行された [[RFC 2965]] は [CODE(HTTP)@en[[[Set-Cookie]]]] を捨てて非互換な [DFN[[CODE(HTTP)@en[[[Set-Cookie2:]]]] [[頭欄]]]] を定義していました。 [353] [[RFC 2965]] は (廃止した [[RFC 2109]] には触れずに) [[Netscape Cookie]] との互換性について次のように規定していました。 - [354] [CODE(HTTP)@en[[[Set-Cookie:]]]] と [CODE(HTTP)@en[[[Set-Cookie2:]]]] の両方があれば、 [CODE(HTTP)@en[[[Set-Cookie:]]]] を捨てなければ[['''なりません''']] [SRC[>>352]]。 - [355] [CODE(HTTP)@en[[[Set-Cookie2:]]]] があれば、[[起源鯖]]は [[RFC 2965]] の [CODE(HTTP)@en[[[Cookie:]]]] を理解できるとみなさなければ[['''なりません''']] [SRC[>>352]]。 - [356] 新 [[Cookie]] はそれと[[一致]]する [WEAK[(名前などが同じ)]] 新旧どちらの [[Cookie]] も置き換えなければ[['''なりません''']] [SRC[>>352]]。 - [358] 新旧 [[Cookie]] を理解する[[利用者エージェント]]が [CODE(HTTP)@en[[[Set-Cookie:]]]] だけを受け取ったときは、 [[Netscape Cookie]] による [CODE(HTTP)@en[[[Cookie:]]]] [[頭欄]]に加え、 [CODE(HTTP)@en[[[Cookie2:]]]] [[頭欄]]も送る[['''べきです''']] [SRC[>>352]]。 [357] >>356 は新 [[Cookie]] による旧 [[Cookie]] の置き換えを命じていますが、 旧 [[Cookie]] による新 [[Cookie]] の置き換えには触れていません。 [370] [CODE(HTTP)@en[[[Set-Cookie2:]]]] は [[RFC 6265]] により廃止されました [SRC[>>369]]。 *** 仕様書 [REFS[ - [309] [[RFC 2965]] -- [310] [CSECTION@en[3.1 Syntax: General]] -- [318] [CSECTION@en[3.2.1 General]] -- [323] '''[CSECTION@en[3.2.2 Set-Cookie2 Syntax]]''' -- [332] [CSECTION@en[3.2.3 Controlling Caching]] -- [341] [CSECTION@en[3.3.1 Interpreting Set-Cookie2]] -- [344] [CSECTION@en[3.3.3 Cookie Management]] -- [43] [CSECTION@en[3.5 Caching Proxy Role]] -- [352] CSECTION@en[9.1 Compatibility with Existing Implementations]] -- [360] [CSECTION@en[9.2 Caching and HTTP/1.0]] - [369] [CITE@en[RFC 6265 - HTTP State Management Mechanism]] ([TIME[2012-03-01 09:57:02 +09:00]] 版) ]REFS] *** メモ [306] [CITE['''['''JavaHouse-Brewers:31373''']''' Re: Cookie.setMaxAge() について]] ([TIME[2001-11-24 20:53:20 +09:00]] 版) > =Cookie.serVersion(1)としたクッキーを送信した場合、 Set-CookieとSet-Cookie2ヘッダの両方がクライアントに送信されていました。 =NN4.7とIE5では、Set-Cookie2ヘッダはサポートしていないようです。 [307] [CITE[IRC logs: freenode / #whatwg / 20090808]] ([TIME[2009-10-06 23:37:54 +09:00]] 版) > - [18:02] annevk42: if you're interested in the cookie stuff, you should join the mailing list and comment on the charter - [18:02] annevk42: in general, i'm trying to keep the focus narrow - [18:03] annevk42: speccing cookie2 is going to take a lot more work and a lot more time than speccing cookie0 - [18:18] abarth, if you're going to spec cookies as implemented set-cookie2 is relevant, no? - [18:18] annevk2: depends how widely its used - [18:18] there was a recent message to the list - [18:19] that suggested very few sites use it - [18:19] i'm not sure we want to lock down the behavior of cookie2 - [18:19] hmm, if we could actually get impl to remove support for it that'd be cool - [18:19] which user agents implement it? - [18:20] I thougt set-cookie2, not cookie2, was implemented, but maybe not - [18:20] i know they're in opera - [18:20] but i'm not sure where else - [18:20] interesting - [18:22] if we're the only ones by all means don't spec it or simply say it's obsolete - [18:23] if we need extensions we can prolly extend cookie0 somehow once the processing model is written down - [18:23] i don't think we want to say it's obsolete. cookie suck in a number of ways. it would be good to have a long term plan for how to dig ourselves out of the mess - [18:23] yeah, that's a good point - [18:23] that's what 2109 originally tried to do with Version=1 - [18:24] but i think they put the cart a bit in front of the horse - [18:24] besides rough consensus you need running code :p - [18:24] (also, versioning sucks :)) ** IETF のキャッシュ制御に関する規定 [330] [[RFC 2109]]、[[RFC 2965]] は以下のようなキャッシュ制御に関する規定がありました [SRC[>>331, >>332]]。 - [333] [CODE(HTTP)@en[[[Set-Cookie]]]], [CODE(HTTP)@en[[[Set-Cookie2]]]] の[[キャッシュ]]を防ぐため、 [PRE(HTTP example code)[ [[Cache-Control]]: [[no-cache]]="set-cookie" ]PRE] や [PRE(HTTP example code)[ [[Cache-Control]]: [[no-cache]]="set-cookie2" ]PRE] を指定する[['''べきです''']]。 - [334] 次のいずれかを指定する[['''べきです''']]。 -- [335] 私的な文書でキャッシュするべきではないとき [PRE(HTTP example code)[ [[Cache-Control]]: [[private]] ]PRE] -- [336] キャッシュしても良いけど[[再検証]]が必要なとき [PRE(HTTP example code)[ [[Cache-Control]]: [[must-revalidate]], [[max-age]]=0 ]PRE] -- [337] [[利用者エージェント]]はキャッシュをそのまま使ってよいけど、[[串]]はキャッシュしても[[再検証]]が必要なとき [PRE(HTTP example code)[ [[Cache-Control]]: [[proxy-revalidate]], [[max-age]]=0 ]PRE] -- [338] キャッシュしても良いけどできれば[[再検証]]してほしいとき [PRE(HTTP example code)[ [[Cache-Control]]: [[max-age]]=0 ]PRE] - [339] あらかじめ [[HTTP/1.0]] [[串]]が存在しないと分かっている場合を除き、過去の日付の [CODE(HTTP)@en[[[Expires:]]]] 欄を含めなければ[['''なりません''']]。 [WEAK[([[HTTP/1.1]] [[串]]は [CODE(HTTP)@en[[[Cache-Control]]]] を優先するので無視します。)]] - [44] [[串]]は勝手に[[要求]]に [CODE(HTTP)@en[[[Set-Cookie]]]], [CODE(HTTP)@en[[[Set-Cookie2]]]] を自分で付け足しては[['''なりません''']] [SRC[>>42, >>43]]。 * 実装 [364] [CITE[CGI::Cookie - search.cpan.org]] ([TIME[2010-08-01 16:28:43 +09:00]] 版) [[Netscape Cookie]] 対応と銘打っていますが、 [CODE(HTTP)@en[[[Max-Age]]]] と [CODE(HTTP)@en[[[HttpOnly]]]] にもちゃんと対応しています。 [365] [CITE[CGI::Simple::Cookie - search.cpan.org]] ([TIME[2010-08-01 16:32:05 +09:00]] 版) [[Netscape Cookie]] と [CODE(HTTP)@en[[[HttpOnly]]]] に対応しています。 [CODE(HTTP)@en[[[Max-Age]]]] には対応していません。 [362] [CITE[Servlet::Http::Cookie - search.cpan.org]] ([TIME[2010-08-01 16:15:08 +09:00]] 版) この [[Perlモジュール]]は、 [[RFC 2109]] に基づいた [[Cookie]] [[API]] を提供しています。 [[Netscape Cookie]] と [[RFC 2109]] の両方に対応しているようで、[[既定値]]は [[Netscape Cookie]] になっています。 [366] [CITE[Apache2::Cookie - search.cpan.org]] ([TIME[2010-08-01 16:33:25 +09:00]] 版) [CODE(HTTP)@en[[[Comment]]]]、[CODE(HTTP)@en[[[CommentURL]]]]、 [CODE(HTTP)@en[[[Expires]]]] には対応していますが、 [CODE(HTTP)@en[[[Port]]]]、 [CODE(HTTP)@en[[[Max-Age]]]]、[CODE(HTTP)@en[[[HttpOnly]]]] には対応していません。謎な実装です。 [363] [CITE[Mojo::Cookie::Response - search.cpan.org]] ([TIME[2010-08-01 16:18:15 +09:00]] 版) この [[Perlモジュール]]は [[RFC 2965]] の実装を名乗っています。 しかし [CODE(HTTP)@en[[[CommentURL]]]] には対応しておらず、 [CODE(HTTP)@en[[[Expires]]]] や [CODE(HTTP)@en[[[HttpOnly]]]] には対応しています (仕様違反?)。[[引用文字列]]は [CODE(HTTP)@en[[[Port]]]] [[属性]]でのみ使います (仕様違反)。(対象は[[欄本体]]だけなので、 [CODE(HTTP)@en[[[Set-Cookie2:]]]] にも [CODE(HTTP)@en[[[Set-Cookie]]]] にも使えるようです。) * メモ [1] [CITE[苦い開発: クッキーの有効期限の更新]] ([TIME[2009-06-06 09:06:11 +09:00]] 版) > Apache2.2 と IE6 でsetcookie()で既存の同じ名前と値を設定する場合、有効期限(期間)は更新されない。 有効期限0で一旦セットしてから同じ有効期間をセットする。 > [PRE(PHP example code)[ setcookie($name, $name, 0); setcookie($name, $name, time()+60*60*24*365); ]PRE] [367] [CITE@en[Web Applications 1.0 r5486 Define http-equiv='set-cookie'Fixing http://www.w3.org/Bugs/Public/show_bug.cgi?id=9578]] ( ([TIME[2010-09-26 00:46:00 +09:00]] 版)) [368] [CITE[Apache HTTP Server Project]] ( ([TIME[2011-05-28 00:58:55 +09:00]] 版))