Подтвердить что ты не робот

Как браузер точно анализирует тег script?

Я просто столкнулся с патологическим случаем с разбором HTML. Я всегда думал, что тег <script> будет работать до первого закрывающего тега </script>. Но оказывается, что это не всегда так.

Это действительно:

<script><!--
alert('<script></script>');
--></script>

И даже это действительно:

<script><!--
alert('<script></script>');
</script>

Но это не так:

<script><!--
alert('</script>');
--></script>

И это не так:

<script>
alert('<script></script>');
</script>

Такое поведение согласуется с Firefox и Chrome. Таким образом, как трудно полагать, браузеры, похоже, принимают тег open + close script внутри комментария html внутри тега script. Итак, вопрос в том, как браузер действительно анализирует теги script? Это имеет значение, потому что библиотека разбора HTML, которую я использую, Nokogiri, принимала очевидное (но неправильное) правило до первого закрытия и не обрабатывала этот край. Я полагаю, что большинство других библиотек тоже не справятся.

4b9b3361

Ответ 1

После просмотра ссылок предоставленных Тимом и Jukka Я пришел к следующему ответу:

  • после открытия тега <script>, синтаксический анализатор переходит в состояние data1
  • Если <!-- встречается в состоянии data1, переключитесь в состояние data2
  • Если --> встречается в любом состоянии, переключитесь в состояние data1
  • Если <script[\s/>] встречается в состоянии data2, переключитесь в состояние data3
  • Если </script[\s/>] встречается в состоянии data3, переключитесь в состояние data2
  • Если </script[\s/>] встречается в любом другом состоянии, прекратите синтаксический анализ

Ответ 2

Все примеры недопустимы в соответствии со спецификацией HTML 4.01: содержимое script объявляется как CDATA, а description из CDATA говорит:

"Хотя элементы STYLE и SCRIPT используют CDATA для своей модели данных, для этих элементов CDATA должен обрабатываться по-разному с помощью пользовательских агентов. Разметка и объекты должны обрабатываться как исходный текст и передаваться в приложение как есть. первое вхождение символьной последовательности" </ "(разделитель конца конечного тега) рассматривается как завершение конца содержимого элемента. В действительных документах это будет конечным тегом для элемента."

Как вы заметили, браузеры могут не применять это правило, но вместо этого распознавать пары стартовых и конечных тегов в некоторых ситуациях. С точки зрения спецификации это обработка недопустимых документов, то есть обработка ошибок. Неясно, что именно они здесь делают и почему. Кажется, что это зависит от наличия <!--, что не должно влиять на разбор HTML 4.01 (он не является комментарием в тексте CDATA).

В XHTML применяются несколько другие правила, поскольку в XHTML <!-- открывается комментарий в содержимом элемента script.

В стороне все примеры недействительны HTML 4.01 и неверный XHTML из-за отсутствия атрибута type в script. Атрибут не требуется (браузеры по умолчанию обрабатывают контент как JavaScript), но его требуется для этих спецификаций.

В HTML5 применяются другие правила. Они довольно сложны, и они должны описывать поведение браузера. В дополнение к наложению ограничений на контент (запрещающий, например, <!-- без соответствия -->), HTML5 также указывает правила анализа.

Ответ 3

Содержимое тегов по-прежнему является HTML, если вы не отметили его как не HTML. В HTML <word> воспринимается как тег, < необходимо записать как &lt;, чтобы избежать такого поведения. В качестве альтернативы вы хотите сделать содержимое <script> текстовым node; используйте эту формулу:

<script type="text/javascript">
//<![CDATA[
  // your code, with < and & and "", woohoo!
//]]>
</script>

<![CDATA[ ... ]]> определяет часть документа как чистый текст без разметки. Слэш там, поэтому JavaScript не запутался; первый набор косой черты находится вне CDATA, но они безопасны для HTML, поэтому проблем нет.

EDIT: Просто понял, что речь идет о разборе, а не написании HTML. К сожалению.

Ответ 4

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

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

1-й случай

<script><!--
alert('<script></script>');
--></script>

Внутри другого <script></script> есть набор <script></script>. Парсер может сначала игнорировать имя тегов и просто проверяет правильность открытия и закрытия этих тегов. Затем он анализирует комментарии.

<script><!--
--></script>

Итак, это действительно.

Второй случай

<script><!--
alert('<script></script>');
</script>

Внутри другого <script></script> есть набор <script></script>. Затем он анализирует комментарии.

<script><!--

Комментарий распространяется до конца документа. Это не является строго правильным, но браузер правильно его обрабатывает.

Третий случай

<script><!--
alert('</script>');
--></script>

В наборе <script></script> есть один закрытый тег. Он недействителен перед тем, как он проанализирует </script> как комментарии.

4-й случай

<script>
alert('<script></script>');
</script>

Внутри другого <script></script> есть набор <script></script>, и комментариев нет. Первый проход действителен, но затем он действительно просматривает теги, чтобы узнать, что они собой представляют. Он может не принимать пару тегов <script> внутри другого, что делает его недействительным.