Как разделить значения заголовка?

Я анализирую заголовки HTTP. Я хочу разделить значения заголовка на массивы, где это имеет смысл.

Например, Cache-Control: no-cache, no-store должен вернуться ['no-cache','no-store'],

HTTP RFC2616 говорит:

Несколько полей заголовка сообщения с одним и тем же именем поля МОГУТ присутствовать в сообщении тогда и только тогда, когда все значение поля для этого поля заголовка определено как список, разделенный запятыми [т.е. #(значения)]. ДОЛЖНО быть возможно объединить несколько полей заголовка в одну пару "имя-поля: поле-значение", не изменяя семантику сообщения, добавляя каждое последующее значение поля к первому, каждое из которых разделяется запятой. Порядок, в котором принимаются поля заголовка с одинаковым именем поля, поэтому важен для интерпретации объединенного значения поля, и, следовательно, прокси НЕ ДОЛЖЕН изменять порядок этих значений поля при пересылке сообщения.

Но я не уверен, верно ли обратное - безопасно ли разделять запятыми?

Я уже нашел один пример, где это вызывает проблемы. Моя строка User-Agent, например,

Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36

т.е. он содержит запятую после "KHTML". Очевидно, у меня не более одного пользовательского агента, поэтому разбивать этот заголовок не имеет смысла.

Является ли строка User-Agent единственным исключением или их больше?

3 ответа

Решение

Нет, разделять заголовки на запятые небезопасно. В качестве примера, Accept: foo/bar;p="A,B,C", bob/dole;x="apples,oranges" является допустимым заголовком, но если вы попытаетесь разделить запятую с целью получения списка mime-типов, вы получите недопустимые результаты.

Правильный ответ заключается в том, что каждый заголовок определяется с использованием ABNF, большинство из них в различных RFC, например Accept: определено в RFC7231, раздел 5.3.2.

У меня была эта конкретная проблема, я написал парсер и протестировал его на крайних случаях. Мало того, что синтаксический анализ заголовка является нетривиальным, его интерпретация и получение правильного результата также не тривиальны.

Некоторые заголовки являются более сложными, чем другие, но по сути каждый заголовок имеет свою собственную грамматику, которую следует соблюдать для правильной (и безопасной) обработки.

если все значение поля для этого поля заголовка определено как разделенный запятыми список [т.е. #(значения)]

Так что все наоборот. Вы можете только предполагать, что Field: value1, value2 эквивалентно Field: value1 + Field: value2 когда спецификации говорят, что Field опоры #(value)то есть разделенный запятыми список значений.

Читая спецификации, я пришел к выводу, что следующие заголовки поддерживают несколько (через запятую) значений:

  • принимать
  • Accept-Charset
  • Accept-Encoding
  • Accept-Language
  • Accept-Patch
  • Accept-Ranges
  • Разрешать
  • Cache-Control
  • соединение
  • Content-Encoding
  • Content-Language
  • ожидать
  • If-Match
  • If-None-Match
  • Pragma
  • Proxy-Authenticate
  • TE
  • трейлер
  • Transfer-Encoding
  • Обновить
  • изменяться
  • С помощью
  • Предупреждение
  • WWW-Authenticate
  • X-Forwarded-For

Вы можете использовать это для создания белого списка разделяемых заголовков.

Другие вопросы по тегам