From 5588d4e88e3913c1ae00a6b57b466b2248cc493c Mon Sep 17 00:00:00 2001
From: tobi <31960611+tsmethurst@users.noreply.github.com>
Date: Thu, 10 Aug 2023 18:26:56 +0200
Subject: [PATCH] [bugfix] Use length in runes when trimming for RSS (#2094)
---
internal/typeutils/internaltorss.go | 30 +++++++++---
internal/typeutils/internaltorss_test.go | 61 ++++++++++++++++++++++++
2 files changed, 84 insertions(+), 7 deletions(-)
diff --git a/internal/typeutils/internaltorss.go b/internal/typeutils/internaltorss.go
index 91f733884..adec26a30 100644
--- a/internal/typeutils/internaltorss.go
+++ b/internal/typeutils/internaltorss.go
@@ -32,8 +32,8 @@
)
const (
- rssMaxTitleChars = 128
- rssDescriptionMaxChars = 256
+ rssTitleMaxRunes = 128
+ rssDescriptionMaxRunes = 256
)
func (c *converter) StatusToRSSItem(ctx context.Context, s *gtsmodel.Status) (*feeds.Item, error) {
@@ -43,9 +43,9 @@ func (c *converter) StatusToRSSItem(ctx context.Context, s *gtsmodel.Status) (*f
// example: Venice Film Festival Tries to Quit Sinking
var title string
if s.ContentWarning != "" {
- title = trimTo(s.ContentWarning, rssMaxTitleChars)
+ title = trimTo(s.ContentWarning, rssTitleMaxRunes)
} else {
- title = trimTo(s.Text, rssMaxTitleChars)
+ title = trimTo(s.Text, rssTitleMaxRunes)
}
// Link -- The URL of the item.
@@ -97,7 +97,7 @@ func (c *converter) StatusToRSSItem(ctx context.Context, s *gtsmodel.Status) (*f
descriptionBuilder.WriteString("\"")
}
- description := trimTo(descriptionBuilder.String(), rssDescriptionMaxChars)
+ description := trimTo(descriptionBuilder.String(), rssDescriptionMaxRunes)
// ID -- A string that uniquely identifies the item.
// example: http://inessential.com/2002/09/01.php#a2
@@ -167,10 +167,26 @@ func (c *converter) StatusToRSSItem(ctx context.Context, s *gtsmodel.Status) (*f
}, nil
}
+// trimTo trims the given `in` string to
+// the length `to`, measured in runes.
+//
+// The reason for using runes is to avoid
+// cutting off UTF-8 characters in the
+// middle, and generating garbled bytes.
+//
+// If trimming was necessary, the returned
+// string will be suffixed with ellipsis
+// (`...`) to indicate omission.
func trimTo(in string, to int) string {
- if len(in) <= to {
+ var (
+ runes = []rune(in)
+ runesLen = len(runes)
+ )
+
+ if runesLen <= to {
+ // Fine as-is.
return in
}
- return in[:to-3] + "..."
+ return string(runes[:to-3]) + "..."
}
diff --git a/internal/typeutils/internaltorss_test.go b/internal/typeutils/internaltorss_test.go
index 510106fe8..ea6f3cc93 100644
--- a/internal/typeutils/internaltorss_test.go
+++ b/internal/typeutils/internaltorss_test.go
@@ -19,9 +19,13 @@
import (
"context"
+ "encoding/xml"
"testing"
"github.com/stretchr/testify/suite"
+ "github.com/superseriousbusiness/gotosocial/internal/ap"
+ "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
+ "github.com/superseriousbusiness/gotosocial/internal/util"
)
type InternalToRSSTestSuite struct {
@@ -80,6 +84,63 @@ func (suite *InternalToRSSTestSuite) TestStatusToRSSItem2() {
suite.Equal("hello world! #welcome ! first post on the instance !", item.Content)
}
+func (suite *InternalToRSSTestSuite) TestStatusToRSSItem3() {
+ account := suite.testAccounts["admin_account"]
+ s := >smodel.Status{
+ ID: "01H7G0VW1ACBZTRHN6RSA4JWVH",
+ URI: "http://localhost:8080/users/admin/statuses/01H7G0VW1ACBZTRHN6RSA4JWVH",
+ URL: "http://localhost:8080/@admin/statuses/01H7G0VW1ACBZTRHN6RSA4JWVH",
+ ContentWarning: "这是简体中文帖子的一些示例内容。\n\n我希望我能读到这个,因为与无聊的旧 ASCII 相比,这些字符绝对漂亮。 不幸的是,我是一个愚蠢的西方人。\n\n无论如何,无论是谁读到这篇文章,你今天过得怎么样? 希望你过得愉快! 如果您有一段时间没有这样做,请从椅子上站起来,喝一杯水,并将您的眼睛集中在远处的物体上,而不是电脑屏幕上!",
+ Content: "这是另一段,只是为了确保这篇文章足够长。 通过前肢上长而弯曲的爪子的数量可以轻松识别不同的树懒类别。 顾名思义,二趾树懒的前肢上有两个爪子,而三趾树懒的四个肢上都有三个爪子。 二趾树懒也比三趾树懒稍大,并且都属于不同的分类科。 美洲共有六种树懒,主要分布在中美洲和南美洲的热带雨林中。\n\n\n\n\t霍夫曼二趾树懒 (Choloepus hoffmanni)\n\n\t林奈二趾树懒 (Choloepus didactylus)\n\n\t侏儒三趾树懒 (Bradypus pygmaeus)\n\n\t鬃三趾树懒 (Bradypus torquatus)\n\n\t棕喉树懒 (Bradypus variegatus)\n\n\t浅喉树懒 (Bradypus tridactylus)\n\n\n\n目前,有 4 种树懒被 IUCN 濒危物种红色名录列为最不受关注的物种。 鬃毛三趾树懒很脆弱,而侏儒三趾树懒则极度濒危,树懒物种面临最大的灭绝风险。",
+ Local: util.Ptr(true),
+ AccountURI: account.URI,
+ AccountID: account.ID,
+ Visibility: gtsmodel.VisibilityDefault,
+ ActivityStreamsType: ap.ObjectNote,
+ Federated: util.Ptr(true),
+ Boostable: util.Ptr(true),
+ Replyable: util.Ptr(true),
+ Likeable: util.Ptr(true),
+ }
+ item, err := suite.typeconverter.StatusToRSSItem(context.Background(), s)
+ suite.NoError(err)
+
+ data, err := xml.MarshalIndent(item, "", " ")
+ if err != nil {
+ suite.FailNow(err.Error())
+ }
+
+ suite.Equal(`-
+ 这是简体中文帖子的一些示例内容。
我希望我能读到这个,因为与无聊的旧 ASCII 相比,这些字符绝对漂亮。 不幸的是,我是一个愚蠢的西方人。
无论如何,无论是谁读到这篇文章,你今天过得怎么样? 希望你过得愉快! 如果您有一段时间没有这样做,请从椅...
+
+ http://localhost:8080/@admin/statuses/01H7G0VW1ACBZTRHN6RSA4JWVH
+
+
+
+
+
+
+ @admin@localhost:8080
+
+
+ @admin@localhost:8080 made a new post
+ http://localhost:8080/@admin/statuses/01H7G0VW1ACBZTRHN6RSA4JWVH
+ 0001-01-01T00:00:00Z
+ 0001-01-01T00:00:00Z
+
+
+
+
+
+ 这是另一段,只是为了确保这篇文章足够长。 通过前肢上长而弯曲的爪子的数量可以轻松识别不同的树懒类别。 顾名思义,二趾树懒的前肢上有两个爪子,而三趾树懒的四个肢上都有三个爪子。 二趾树懒也比三趾树懒稍大,并且都属于不同的分类科。 美洲共有六种树懒,主要分布在中美洲和南美洲的热带雨林中。
霍夫曼二趾树懒 (Choloepus hoffmanni)
林奈二趾树懒 (Choloepus didactylus)
侏儒三趾树懒 (Bradypus pygmaeus)
鬃三趾树懒 (Bradypus torquatus)
棕喉树懒 (Bradypus variegatus)
浅喉树懒 (Bradypus tridactylus)
目前,有 4 种树懒被 IUCN 濒危物种红色名录列为最不受关注的物种。 鬃毛三趾树懒很脆弱,而侏儒三趾树懒则极度濒危,树懒物种面临最大的灭绝风险。
+
`, string(data))
+}
+
func TestInternalToRSSTestSuite(t *testing.T) {
suite.Run(t, new(InternalToRSSTestSuite))
}