зеркало из https://github.com/microsoft/git.git
format-patch: wrap long header lines
Subject and identity headers may be arbitrarily long. In the past, we just assumed that single-line headers would be reasonably short. For multi-line subjects that we squish into a single line, we just "pre-folded" the data in pp_title_line by adding a newline and indentation. There were two problems. One is that, although rare, single-line messages can actually be longer than the recommended line-length limits. The second is that the pre-folding interacted badly with rfc2047 encoding, leading to malformed headers. Instead, let's stop pre-folding the subject lines, and just fold everything based on length in add_rfc2047, whether it is encoded or not. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
98acc837a1
Коммит
a1f6baa5c9
32
pretty.c
32
pretty.c
|
@ -216,7 +216,15 @@ static int is_rfc2047_special(char ch)
|
||||||
static void add_rfc2047(struct strbuf *sb, const char *line, int len,
|
static void add_rfc2047(struct strbuf *sb, const char *line, int len,
|
||||||
const char *encoding)
|
const char *encoding)
|
||||||
{
|
{
|
||||||
int i, last;
|
static const int max_length = 78; /* per rfc2822 */
|
||||||
|
int i;
|
||||||
|
int line_len;
|
||||||
|
|
||||||
|
/* How many bytes are already used on the current line? */
|
||||||
|
for (i = sb->len - 1; i >= 0; i--)
|
||||||
|
if (sb->buf[i] == '\n')
|
||||||
|
break;
|
||||||
|
line_len = sb->len - (i+1);
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
int ch = line[i];
|
int ch = line[i];
|
||||||
|
@ -225,14 +233,21 @@ static void add_rfc2047(struct strbuf *sb, const char *line, int len,
|
||||||
if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
|
if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
|
||||||
goto needquote;
|
goto needquote;
|
||||||
}
|
}
|
||||||
strbuf_add(sb, line, len);
|
strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
needquote:
|
needquote:
|
||||||
strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
|
strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
|
||||||
strbuf_addf(sb, "=?%s?q?", encoding);
|
strbuf_addf(sb, "=?%s?q?", encoding);
|
||||||
for (i = last = 0; i < len; i++) {
|
line_len += strlen(encoding) + 5; /* 5 for =??q? */
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
unsigned ch = line[i] & 0xFF;
|
unsigned ch = line[i] & 0xFF;
|
||||||
|
|
||||||
|
if (line_len >= max_length - 2) {
|
||||||
|
strbuf_addf(sb, "?=\n =?%s?q?", encoding);
|
||||||
|
line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We encode ' ' using '=20' even though rfc2047
|
* We encode ' ' using '=20' even though rfc2047
|
||||||
* allows using '_' for readability. Unfortunately,
|
* allows using '_' for readability. Unfortunately,
|
||||||
|
@ -240,12 +255,14 @@ needquote:
|
||||||
* leave the underscore in place.
|
* leave the underscore in place.
|
||||||
*/
|
*/
|
||||||
if (is_rfc2047_special(ch) || ch == ' ') {
|
if (is_rfc2047_special(ch) || ch == ' ') {
|
||||||
strbuf_add(sb, line + last, i - last);
|
|
||||||
strbuf_addf(sb, "=%02X", ch);
|
strbuf_addf(sb, "=%02X", ch);
|
||||||
last = i + 1;
|
line_len += 3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strbuf_addch(sb, ch);
|
||||||
|
line_len++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strbuf_add(sb, line + last, len - last);
|
|
||||||
strbuf_addstr(sb, "?=");
|
strbuf_addstr(sb, "?=");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1106,11 +1123,10 @@ void pp_title_line(enum cmit_fmt fmt,
|
||||||
const char *encoding,
|
const char *encoding,
|
||||||
int need_8bit_cte)
|
int need_8bit_cte)
|
||||||
{
|
{
|
||||||
const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " ";
|
|
||||||
struct strbuf title;
|
struct strbuf title;
|
||||||
|
|
||||||
strbuf_init(&title, 80);
|
strbuf_init(&title, 80);
|
||||||
*msg_p = format_subject(&title, *msg_p, line_separator);
|
*msg_p = format_subject(&title, *msg_p, " ");
|
||||||
|
|
||||||
strbuf_grow(sb, title.len + 1024);
|
strbuf_grow(sb, title.len + 1024);
|
||||||
if (subject) {
|
if (subject) {
|
||||||
|
|
|
@ -709,4 +709,88 @@ test_expect_success TTY 'format-patch --stdout paginates' '
|
||||||
test_path_is_missing .git/pager_used
|
test_path_is_missing .git/pager_used
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'format-patch handles multi-line subjects' '
|
||||||
|
rm -rf patches/ &&
|
||||||
|
echo content >>file &&
|
||||||
|
for i in one two three; do echo $i; done >msg &&
|
||||||
|
git add file &&
|
||||||
|
git commit -F msg &&
|
||||||
|
git format-patch -o patches -1 &&
|
||||||
|
grep ^Subject: patches/0001-one.patch >actual &&
|
||||||
|
echo "Subject: [PATCH] one two three" >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'format-patch handles multi-line encoded subjects' '
|
||||||
|
rm -rf patches/ &&
|
||||||
|
echo content >>file &&
|
||||||
|
for i in en två tre; do echo $i; done >msg &&
|
||||||
|
git add file &&
|
||||||
|
git commit -F msg &&
|
||||||
|
git format-patch -o patches -1 &&
|
||||||
|
grep ^Subject: patches/0001-en.patch >actual &&
|
||||||
|
echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
M8="foo bar "
|
||||||
|
M64=$M8$M8$M8$M8$M8$M8$M8$M8
|
||||||
|
M512=$M64$M64$M64$M64$M64$M64$M64$M64
|
||||||
|
cat >expect <<'EOF'
|
||||||
|
Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
|
||||||
|
bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
|
||||||
|
foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
|
||||||
|
bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
|
||||||
|
foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
|
||||||
|
bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
|
||||||
|
foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
|
||||||
|
bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
|
||||||
|
foo bar foo bar foo bar foo bar
|
||||||
|
EOF
|
||||||
|
test_expect_success 'format-patch wraps extremely long headers (ascii)' '
|
||||||
|
echo content >>file &&
|
||||||
|
git add file &&
|
||||||
|
git commit -m "$M512" &&
|
||||||
|
git format-patch --stdout -1 >patch &&
|
||||||
|
sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
|
||||||
|
test_cmp expect subject
|
||||||
|
'
|
||||||
|
|
||||||
|
M8="föö bar "
|
||||||
|
M64=$M8$M8$M8$M8$M8$M8$M8$M8
|
||||||
|
M512=$M64$M64$M64$M64$M64$M64$M64$M64
|
||||||
|
cat >expect <<'EOF'
|
||||||
|
Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
|
||||||
|
=?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
|
||||||
|
EOF
|
||||||
|
test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
|
||||||
|
rm -rf patches/ &&
|
||||||
|
echo content >>file &&
|
||||||
|
git add file &&
|
||||||
|
git commit -m "$M512" &&
|
||||||
|
git format-patch --stdout -1 >patch &&
|
||||||
|
sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
|
||||||
|
test_cmp expect subject
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
Загрузка…
Ссылка в новой задаче