"http.cookies" --- HTTP 狀態管理
********************************

**原始碼：**Lib/http/cookies.py

======================================================================

"http.cookies" 模組定義了 cookie 概念的抽象化的類別，cookie 是一種
HTTP 狀態管理機制。它支援簡單的純字串 cookie，也提供了將任何可序列化的
資料型別作為 cookie 值的抽象化。

此模組原先嚴格遵循了 **RFC 2109** 和 **RFC 2068** 規範所描述的剖析規則
。自從發現 MSIE 3.0x 並不遵循這些規範所描述的字元規則，許多目前的瀏覽
器和伺服器也在處理 cookie 時放寬了剖析規則。因此，此模組現在使用的剖析
規則比之前的更為寬鬆。

字元集 "string.ascii_letters"、"string.digits" 和 "!#$%&'*+-.^_`|~" 表
示此模組在 cookie 名稱 ("key") 中允許的合法字元集合。

在 3.3 版的變更: 允許 ':' 作為有效的 cookie 名稱字元。

備註:

  當遇到無效的 cookie 時，會引發 "CookieError"，因此如果你的 cookie 資
  料來自瀏覽器，在剖析時你應該總是為無效資料作準備並捕捉 "CookieError"
  。

exception http.cookies.CookieError

   因為不符合 **RFC 2109** 而引發的例外：不正確的屬性、不正確的 *Set-
   Cookie* 標頭等。

class http.cookies.BaseCookie([input])

   這個類別是一個類似字典的物件，其中的鍵是字串，而值則是 "Morsel" 實
   例。請注意，當設定鍵的值時，值會先被轉換為一個包含該鍵和值的
   "Morsel"。

   如果有給定 *input*，它會被傳遞給 "load()" 方法。

class http.cookies.SimpleCookie([input])

   這個類別繼承自 "BaseCookie" 並覆寫了 "value_decode()" 和
   "value_encode()"。"SimpleCookie" 支援字串作為 cookie 值。當設定值時
   ，"SimpleCookie" 會呼叫內建的 "str()" 來將值轉換為字串。從 HTTP 接
   收的值會保持為字串。

也參考:

  "http.cookiejar" 模組
     用於網路*用戶端*的 HTTP cookie 處理。"http.cookiejar" 和
     "http.cookies" 模組互不相依。

  **RFC 2109** - HTTP 狀態管理機制
     這是此模組實作的狀態管理規範。


Cookie 物件
===========

BaseCookie.value_decode(val)

   從字串表示回傳 "(real_value, coded_value)" 的元組。"real_value" 可
   以是任何型別。此方法在 "BaseCookie" 中不做解碼 --- 它存在以便可以被
   覆寫。

BaseCookie.value_encode(val)

   回傳一個元組 "(real_value, coded_value)"。*val* 可以是任何型別，但
   "coded_value" 總是會被轉換為字串。此方法在 "BaseCookie" 中不做編碼
   --- 它存在以便可以被覆寫。

   一般來說，"value_encode()" 和 "value_decode()" 應該在
   *value_decode* 的範圍內是互逆的 (inverse)。

BaseCookie.output(attrs=None, header='Set-Cookie:', sep='\r\n')

   回傳一個適合作為 HTTP 標頭來傳送的字串表示。*attrs* 和 *header* 會
   傳送給每個 "Morsel" 的 "output()" 方法。*sep* 用來連接標頭，預設為
   "'\r\n'" (CRLF) 的組合。

BaseCookie.js_output(attrs=None)

   回傳一個可嵌入的 JavaScript 片段，如果在支援 JavaScript 的瀏覽器上
   執行，它的行為會與 HTTP 標頭被傳送的情況相同。

   *attrs* 的意義與 "output()" 裡的相同。

   自從版本 3.15 後不推薦使用，將會自版本 3.19 中移除。: This method
   generates a JavaScript snippet to set cookies in the browser, which
   is no longer considered a standard or recommended approach. Use
   "output()" instead to generate HTTP headers.

BaseCookie.load(rawdata)

   如果 *rawdata* 是字串，會將其作為 "HTTP_COOKIE" 剖析，並將在其中找
   到的值當作 "Morsel" 新增。如果它是一個字典，則等同於：

      for k, v in rawdata.items():
          cookie[k] = v


Morsel 物件
===========

class http.cookies.Morsel

   抽象化一個鍵 / 值對，它有一些 **RFC 2109** 屬性。

   Morsel 是一種類似字典的物件，其鍵的集合是固定的 --- 有效的 **RFC
   2109** 屬性，它們是：

      expires
      path
      comment
      domain
      max-age
      secure
      version
      httponly
      samesite
      partitioned

   屬性 "httponly" 指定 cookie 僅在 HTTP 請求中傳輸，而不可透過
   JavaScript 存取。這是為了減輕某些形式的跨網站腳本攻擊。

   "samesite" 屬性控制瀏覽器要在何時將 cookie 與跨網站請求一起傳送，這
   有助於減輕 CSRF 攻擊。有效值為 "Strict"（僅在同站請求時傳送）、
   "Lax"（同站請求和頂層導航時傳送）和 "None"（同站請求和跨站請求時傳
   送）。使用 "None" 時，必須同時設定 "secure" 屬性，這是現代瀏覽器的
   要求。

   屬性 "partitioned" 向 user agent（使用者代理）表明這些跨網站 cookie
   *應該*只能在與首次設定 cookie 時相同的頂層情境中使用。要讓 user
   agent 接受此設定，你**必須**同時設定 "Secure"。

   此外，建議在設定 partitioned（分區）cookie 時使用 "__Host" 前綴，使
   其綁定到主機名稱而非可註冊網域。請閱讀 CHIPS (Cookies Having
   Independent Partitioned State) 以取得完整細節和範例。

   鍵不區分大小寫，其預設值為 "''"。

   在 3.5 版的變更: "__eq__()" 現在會考慮 "key" 和 "value"。

   在 3.7 版的變更: 屬性 "key"、"value" 和 "coded_value" 是唯讀的。請
   使用 "set()" 來設定它們。

   在 3.8 版的變更: 新增對 "samesite" 屬性的支援。

   在 3.14 版的變更: 新增對 "partitioned" 屬性的支援。

Morsel.value

   cookie 的值。

Morsel.coded_value

   cookie 的編碼值 --- 這是應該被傳送的值。

Morsel.key

   cookie 的名稱。

Morsel.set(key, value, coded_value)

   設定 *key*、*value* 和 *coded_value* 屬性。

Morsel.isReservedKey(K)

   *K* 是否為 "Morsel" 的鍵集合中的成員。

Morsel.output(attrs=None, header='Set-Cookie:')

   回傳適合作為 HTTP 標頭傳送的 Morsel 的字串表示。預設會包含所有屬性
   ，除非有給定 *attrs*，在此情況下，它應該是一個要使用的屬性的串列。
   預設的 *header* 是 ""Set-Cookie:""。

Morsel.js_output(attrs=None)

   回傳一個可嵌入的 JavaScript 片段，如果在支援 JavaScript 的瀏覽器上
   執行，它的行為會與 HTTP 標頭被傳送的情況相同。

   *attrs* 的意義與 "output()" 裡的相同。

   自從版本 3.15 後不推薦使用，將會自版本 3.19 中移除。: This method
   generates a JavaScript snippet to set cookies in the browser, which
   is no longer considered a standard or recommended approach. Use
   "output()" instead to generate HTTP headers.

Morsel.OutputString(attrs=None)

   回傳表示 Morsel 的字串，不包含周圍任何的 HTTP 或 JavaScript。

   *attrs* 的意義與 "output()" 裡的相同。

Morsel.update(values)

   更新 Morsel 字典中的值為 *values* 字典中的值。如果 *values* 字典中
   的任何鍵不是有效的 **RFC 2109** 屬性則引發錯誤。

   在 3.5 版的變更: 對於無效的鍵會引發錯誤。

Morsel.copy(value)

   回傳 Morsel 物件的淺層複製。

   在 3.5 版的變更: 回傳 Morsel 物件而不是字典。

Morsel.setdefault(key, value=None)

   如果鍵不是一個有效的 **RFC 2109** 屬性會引發錯誤，否則行為與
   "dict.setdefault()" 相同。


範例
====

以下範例示範如何使用 "http.cookies" 模組。

   >>> from http import cookies
   >>> C = cookies.SimpleCookie()
   >>> C["fig"] = "newton"
   >>> C["sugar"] = "wafer"
   >>> print(C) # 產生 HTTP 標頭
   Set-Cookie: fig=newton
   Set-Cookie: sugar=wafer
   >>> print(C.output()) # 同上
   Set-Cookie: fig=newton
   Set-Cookie: sugar=wafer
   >>> C = cookies.SimpleCookie()
   >>> C["rocky"] = "road"
   >>> C["rocky"]["path"] = "/cookie"
   >>> print(C.output(header="Cookie:"))
   Cookie: rocky=road; Path=/cookie
   >>> print(C.output(attrs=[], header="Cookie:"))
   Cookie: rocky=road
   >>> C = cookies.SimpleCookie()
   >>> C.load("chips=ahoy; vienna=finger") # 從字串（HTTP 標頭）載入
   >>> print(C)
   Set-Cookie: chips=ahoy
   Set-Cookie: vienna=finger
   >>> C = cookies.SimpleCookie()
   >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";')
   >>> print(C)
   Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;"
   >>> C = cookies.SimpleCookie()
   >>> C["oreo"] = "doublestuff"
   >>> C["oreo"]["path"] = "/"
   >>> print(C)
   Set-Cookie: oreo=doublestuff; Path=/
   >>> C = cookies.SimpleCookie()
   >>> C["twix"] = "none for you"
   >>> C["twix"].value
   'none for you'
   >>> C = cookies.SimpleCookie()
   >>> C["number"] = 7 # 等同於 C["number"] = str(7)
   >>> C["string"] = "seven"
   >>> C["number"].value
   '7'
   >>> C["string"].value
   'seven'
   >>> print(C)
   Set-Cookie: number=7
   Set-Cookie: string=seven
