Commit a3faf2be authored by Nick Thomas's avatar Nick Thomas

Limit rendering of commit messages

Commit messages can be an arbitrary length, and we often render large
numbers of them at once, which can be extremely slow. Introducing a
1MiB limit on the content will help to avoid timeouts on pages that
display commits.
parent 428ba0dc
......@@ -37,7 +37,7 @@ class Commit
cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :full_title, pipeline: :single_line
cache_markdown_field :description, pipeline: :commit_description
cache_markdown_field :description, pipeline: :commit_description, limit: 1.megabyte
class << self
def decorate(commits, container)
......
---
title: Limit rendering of commit messages
merge_request: 51485
author:
type: performance
# frozen_string_literal: true
module Banzai
module Filter
class TruncateSourceFilter < HTML::Pipeline::TextFilter
def call
return text unless context.key?(:limit)
text.truncate_bytes(context[:limit])
end
end
end
end
......@@ -6,6 +6,7 @@ module Banzai
def self.filters
FilterArray[
Filter::NormalizeSourceFilter,
Filter::TruncateSourceFilter,
Filter::FrontMatterFilter,
Filter::BlockquoteFenceFilter,
]
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Banzai::Filter::TruncateSourceFilter do
include FilterSpecHelper
let(:short_text) { 'foo' * 10 }
let(:long_text) { ([short_text] * 10).join(' ') }
it 'does nothing when limit is unspecified' do
output = filter(long_text)
expect(output).to eq(long_text)
end
it 'does nothing to a short-enough text' do
output = filter(short_text, limit: short_text.bytesize)
expect(output).to eq(short_text)
end
it 'truncates UTF-8 text by bytes, on a character boundary' do
utf8_text = '日本語の文字が大きい'
truncated = '日…'
expect(filter(utf8_text, limit: truncated.bytesize)).to eq(truncated)
expect(filter(utf8_text, limit: utf8_text.bytesize)).to eq(utf8_text)
expect(filter(utf8_text, limit: utf8_text.mb_chars.size)).not_to eq(utf8_text)
end
end
......@@ -24,4 +24,12 @@ RSpec.describe Banzai::Pipeline::PreProcessPipeline do
expect(result[:output]).to include "> blockquote\n"
end
end
it 'truncates the text if requested' do
text = (['foo'] * 10).join(' ')
result = described_class.call(text, limit: 12)
expect(result[:output]).to eq('foo foo f…')
end
end
......@@ -428,6 +428,19 @@ eos
allow(commit).to receive(:safe_message).and_return(message)
expect(commit.description).to eq(message)
end
it 'truncates html representation if more than 1Mib' do
# Commit message is over 2MiB
huge_commit_message = ['panic', ('panic ' * 350000), 'trailing text'].join("\n")
allow(commit).to receive(:safe_message).and_return(huge_commit_message)
commit.refresh_markdown_cache
description_html = commit.description_html
expect(description_html.bytesize).to be < 2.megabytes
expect(description_html).not_to include('trailing text')
end
end
describe "delegation" do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment