Модуль http.cookies реализует парсер для cookie, по большей части совместимый с RFC 2109 — документом со стандартами работы с cookie и смежными вещами.


Стоит отметить, что реализация чуть менее строгая, чем стандарт, так как Microsoft Internet Explorer 3.0x, а позже современные браузеры облегчили правила для работы с cookie.


Создание и установка значения Cookie


Cookie используются как инструмент для поддержания текущего состояния в браузерных приложениях, поэтому чаще всего они создаются, изменяются и используются сервером, а хранятся у пользователя. Самый простой пример создания пары ключ-значение:


#  http_cookies_setheaders.py
from http import cookies

c = cookies.SimpleCookie()
c['mycookie'] = 'cookie_value'
print(c)

Выводом является валидный Set-Cookie заголовок, готовый к передаче клиенту как часть HTTP ответа.


$ python3 http_cookies_setheaders.py

Set-Cookie: mycookie=cookie_value

Morsel


Также вы можете управлять другими параметрами cookie, такими как время жизни записи, путь и домен. Оказывается, что всеми RFC атрибутами можно управлять с помощью объекта Morsel.


#  http_cookies_Morsel.py
from http import cookies
import datetime

def show_cookie(c):
    print(c)
    for key, morsel in c.items():
        print()
        print('key =', morsel.key)
        print('  value =', morsel.value)
        print('  coded_value =', morsel.coded_value)
        for name in morsel.keys():
            if morsel[name]:
                print('  {} = {}'.format(name, morsel[name]))

c = cookies.SimpleCookie()

# Cookie со значением, которое должно быть закодировано,
# чтобы поместиться в заголовок
c['encoded_value_cookie'] = '"cookie,value;"'
c['encoded_value_cookie']['comment'] = 'Has escaped punctuation'

# А эта cookie применяется только к части сайта
c['restricted_cookie'] = 'cookie_value'
c['restricted_cookie']['path'] = '/sub/path'
c['restricted_cookie']['domain'] = 'PyMOTW'
c['restricted_cookie']['secure'] = True

# Эта cookie истекает через 5 минут
c['with_max_age'] = 'expires in 5 minutes'
c['with_max_age']['max-age'] = 300  # seconds

# Cookie истекает в указанное время
c['expires_at_time'] = 'cookie_value'
time_to_live = datetime.timedelta(hours=1)
expires = (datetime.datetime(2009, 2, 14, 18, 30, 14) +
           time_to_live)

# Формат: Wdy, DD-Mon-YY HH:MM:SS GMT
expires_at_time = expires.strftime('%a, %d %b %Y %H:%M:%S')
c['expires_at_time']['expires'] = expires_at_time

show_cookie(c)

Этот пример включает в себя два различных метода для создания cookie с датой истечения срока жизни. Один устанавливает max-age как количество секунд жизни cookie с момента создания, другой устанавливает параметр expires как дату и время, когда cookie должна быть удалена.


$ python3 http_cookies_Morsel.py

Set-Cookie: encoded_value_cookie="\"cookie\054value\073\"";
Comment="Has escaped punctuation"
Set-Cookie: expires_at_time=cookie_value; expires=Sat, 14 Feb
2009 19:30:14
Set-Cookie: restricted_cookie=cookie_value; Domain=PyMOTW;
Path=/sub/path; Secure
Set-Cookie: with_max_age="expires in 5 minutes"; Max-Age=300

key = encoded_value_cookie
  value = "cookie,value;"
  coded_value = "\"cookie\054value\073\""
  comment = Has escaped punctuation

key = restricted_cookie
  value = cookie_value
  coded_value = cookie_value
  path = /sub/path
  domain = PyMOTW
  secure = True

key = with_max_age
  value = expires in 5 minutes
  coded_value = "expires in 5 minutes"
  max-age = 300

key = expires_at_time
  value = cookie_value
  coded_value = cookie_value
  expires = Sat, 14 Feb 2009 19:30:14

Оба объекта Cookie и Morsel ведут себя как словари. Morsel отвечает за фиксированный набор значений: expires, path, comment, domain, max-age, secure, version.


Закодированные значения


Заголовок cookie должен быть закодирован для того, чтобы потом он был правильно распарсен.


#  http_cookies_coded_value.py
from http import cookies

c = cookies.SimpleCookie()
c['integer'] = 5
c['with_quotes'] = 'He said, "Hello, World!"'

for name in ['integer', 'with_quotes']:
    print(c[name].key)
    print('  {}'.format(c[name]))
    print('  value={!r}'.format(c[name].value))
    print('  coded_value={!r}'.format(c[name].coded_value))
    print()

Morsel.value всегда является закодированным значением cookie, в то время как Morsel.coded_value всегда является представлением, которое используется для передачи значения клиенту. Оба значения всегда являются строками. Значения, которые не являются строками, будут автоматически преобразованы в нужный тип.


$ python3 http_cookies_coded_value.py

integer
  Set-Cookie: integer=5
  value='5'
  coded_value='5'

with_quotes
  Set-Cookie: with_quotes="He said\054 \"Hello\054 World!\""
  value='He said, "Hello, World!"'
  coded_value='"He said\\054 \\"Hello\\054 World!\\""'

Получение и парсинг заголовков Cookie


После того, как Set-cookie заголовки переданы клиенту, он будет возвращать их на сервер в последующих запросах, используя заголовок Cookie. Входящий заголовок может содержать несколько cookie, разделённых символами ;:


Cookie: integer=5; with_quotes="He said, \"Hello, World!\""

В зависимости от веб-сервера и фреймворка, cookie доступы либо прямо из заголовка, либо из значения HTTP_COOKIE.


#  http_cookies_parse.py
from http import cookies

HTTP_COOKIE = '; '.join([
    r'integer=5',
    r'with_quotes="He said, \"Hello, World!\""',
])

print('From constructor:')
c = cookies.SimpleCookie(HTTP_COOKIE)
print(c)

print()
print('From load():')
c = cookies.SimpleCookie()
c.load(HTTP_COOKIE)
print(c)

Чтобы их раскодировать, передайте нужную часть cтроки в SimpleCookie, либо используйте метод load().


$ python3 http_cookies_parse.py

From constructor:
Set-Cookie: integer=5
Set-Cookie: with_quotes="He said, \"Hello, World!\""

From load():
Set-Cookie: integer=5
Set-Cookie: with_quotes="He said, \"Hello, World!\""

Альтернативные форматы вывода


Кроме использования заголовка Set-Cookie, серверы поставляют JavaScript, который добавляет cookie клиенту. SimpleCookie и Morsel генерируют JavaScript при использовании метода js_output().


#  http_cookies_js_output.py
from http import cookies
import textwrap

c = cookies.SimpleCookie()
c['mycookie'] = 'cookie_value'
c['another_cookie'] = 'second value'
js_text = c.js_output()
print(textwrap.dedent(js_text).lstrip())

Результатом является готовый тег script для задания нужных значений cookie.


$ python3 http_cookies_js_output.py

<script type="text/javascript">
<!-- begin hiding
document.cookie = "another_cookie=\"second value\"";
// end hiding -->
</script>

<script type="text/javascript">
<!-- begin hiding
document.cookie = "mycookie=cookie_value";
// end hiding -->
</script>


Комментарии (2)


  1. azureswastika
    03.08.2021 21:39

    это все, конечно хорошо, но где это пригодится?


    1. otter18 Автор
      03.08.2021 21:40

      В целом библиотека http скорее для тестирования или задач, где Django/Flask — это оверкилл. Но работа с http.cookie очень похожа на реализации в фреймворках