Кратко

  • RFC 1867 и RFC 2388 описывали несколько файлов из одного поля как вложенную часть multipart/mixed внутри multipart/form-data.
  • RFC 7578 зафиксировала отсутствие известных отправляющих реализаций этой схемы, заменила её отдельной внешней частью на каждый файл с одинаковым именем поля и сохранила ожидание совместимости для получателей старого формата.

Поле формы должно было стать сообщением

До появления общего браузерного способа передавать выбранные локальные файлы службе часто требовалось специальное клиентское приложение. RFC 1867 1995 года предложила элемент HTML INPUT TYPE=FILE и MIME-представление, способное нести обычные поля и содержимое файлов. Документ имел статус Experimental, а не завершённого интернет-стандарта. В нём также рассматривался переход для пользовательских программ, которые ещё не поддерживали загрузку файлов.

Предложение задавало два уровня. Внешняя часть multipart/form-data называла поле формы. Если в этом поле выбирали несколько файлов, внутренняя multipart/mixed собирала их в отдельную структуру. На бумаге каждый слой отвечал за своё: один связывал данные с полем, другой представлял группу файлов.

RFC 2388 получила статус Standards Track в 1998 году и определила multipart/form-data независимо от HTML и HTTP, чтобы его могли использовать и другие приложения с формами. Но для нескольких файлов в одном поле сохранила внутреннюю часть multipart/mixed. Экспериментальная схема стала переиспользуемой спецификацией, не изменив этого элемента.

В новой спецификации не нашлось отправителей

RFC 7578 заменила RFC 2388 в 2015 году и необычно прямо описала разрыв между правилом и известными отправителями. Вложенный вариант перестали рекомендовать создателям сообщений и требовать от получателей, поскольку не было известно отправляющих реализаций. Чтобы соответствовать реализации, которую авторы могли подтвердить, каждому файлу назначили собственную внешнюю часть; части одного поля повторяют параметр name.

Место группировки изменилось. Раньше одна часть с именем поля содержала внутренний перечень файлов. Теперь во внешнем потоке шли соседние части, объединённые тем же именем поля. RFC 7578 не объявила старое вложение недействительным. Получателям общего назначения по-прежнему рекомендовалось понимать его. Правило отправки обновилось, а совместимость чтения сохранилась.

Фраза «известных отправляющих реализаций нет» отражает знания авторов RFC 7578, а не доказывает, что такая структура никогда не отправлялась. Документ не называет браузер или сервер, не приводит долю внедрения, дату перехода или частоту отказов. Он подтверждает более узкий факт: авторы пересмотрели стандарт, поскольку не могли указать отправителей формы, описанной предыдущей редакцией.

Повторённое имя — не повод сливать значения

RFC 2388 также не определяла, должна ли последовательность возвращённых частей соответствовать порядку полей формы, и как обрабатывать повторные имена. RFC 7578 требует сохранять заданный формой порядок, запрещает посредникам переставлять результаты и не позволяет объединять части с одинаковыми именами. Повтор имени тем самым сохраняет несколько значений одного поля, вместо того чтобы стирать их как конфликт.

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

Работающий код как свидетельство

В эссе Heng Lu о Running-Code Primacy подчёркивается разница между текстом протокола и поведением систем в работе. RFC 2388 даёт ограниченный и наглядный пример: RFC 7578 не сохранила старое правило только потому, что оно уже было написано. Авторы изменили форму нескольких файлов в соответствии с отправителями, которых смогли подтвердить, и оставили принимающей стороне совместимость со старой формой.

Документы не сообщают, кто предложил изменение, сколько систем было затронуто или какие эксплуатационные затраты повлияли на решение. Они не доказывают, что реализации всегда правы, или что стандарт должен принимать любую программную привычку. Вывод скромнее: описать формат, найти системы, которые действительно его отправляют, и при изменении правила продумать чтение старых данных.

Источники