Markdown-it — это мощная библиотека для парсинга Markdown в JavaScript, обеспечивающая гибкость и расширяемость. Одним из ключевых аспектов работы с Markdown-it является контроль сложности обрабатываемого Markdown, что важно для предотвращения чрезмерной нагрузки на процессор при работе с большими или потенциально вредоносными документами.
Markdown позволяет создавать вложенные структуры, такие как списки внутри списков или блоки цитат. При отсутствии контроля глубины вложенности существует риск бесконечной рекурсии или значительной нагрузки на парсер.
В Markdown-it для ограничения глубины используется опция
maxNesting:
const MarkdownIt = require('markdown-it');
const md = new MarkdownIt({
maxNesting: 10 // Максимальная глубина вложенности
});
Это особенно важно при обработке Markdown из ненадёжных источников, чтобы избежать DoS-атак через чрезмерно сложные структуры.
Каждый элемент Markdown, будь то заголовок, абзац или ссылка, превращается в токен с содержимым. Длинные строки могут привести к росту потребления памяти и замедлению обработки.
Markdown-it позволяет реализовать контроль длины токенов через кастомные правила:
md.core.ruler.push('limit_token_length', state => {
state.tokens.forEach(token => {
if (token.content.length > 1000) {
token.content = token.content.slice(0, 1000) + '...';
}
});
});
Большие списки или таблицы создают значительное количество токенов. Markdown-it не имеет встроенной опции для ограничения количества элементов, но это реализуется через пользовательские правила:
md.core.ruler.push('limit_list_items', state => {
state.tokens.forEach(token => {
if (token.type === 'bullet_list_open' || token.type === 'ordered_list_open') {
let count = 0;
for (let t of state.tokens) {
if (t.type === 'list_item_open') count++;
if (count > 50) {
t.hidden = true; // скрываем лишние элементы
}
}
}
});
});
Markdown-it выполняет синхронную обработку Markdown, что делает невозможным точный контроль времени выполнения через опции. Однако для защиты от «тяжёлых» документов можно использовать разделение на чанки:
Пример:
function safeRender(md, text, maxLength = 10000) {
if (text.length > maxLength) {
text = text.slice(0, maxLength);
}
return md.render(text);
}
Markdown-it поддерживает плагины, которые могут добавлять или ограничивать возможности парсера. Для ограничения сложности можно создавать плагины, проверяющие:
h1–h6).Пример базового плагина для контроля изображений:
function limitImages(md, maxImages = 10) {
md.core.ruler.push('limit_images', state => {
let imageCount = 0;
state.tokens.forEach(token => {
if (token.type === 'inline') {
token.children.forEach(child => {
if (child.type === 'image') {
imageCount++;
if (imageCount > maxImages) child.hidden = true;
}
});
}
});
});
}
md.use(limitImages, 5);
maxNesting, особенно для
документов от пользователей.Ограничение сложности в Markdown-it позволяет создавать безопасные и предсказуемые рендеры Markdown, избегая чрезмерной нагрузки на сервер и обеспечивая устойчивость системы к потенциально вредоносным документам.