go
/
misc
1
0
Fork 0

Merge pull request #2 from spi-ca/ISSUE-1

Issue 1 - fixes Short writes in strutil.LineBreaker
This commit is contained in:
Sangbum Kim 2025-03-04 21:56:00 +09:00 committed by GitHub
commit 3363710364
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 116 additions and 12 deletions

View File

@ -7,6 +7,7 @@ import (
const pemLineLength = 64
// LineBreaker is an io.Writer that advances a newline if one line exceeds 64 bytes.
// this source originally comes from the url(https://cs.opensource.google/go/go/+/refs/tags/go1.24.0:src/encoding/pem/pem.go;l=89)
type LineBreaker struct {
// Out os
Out io.Writer
@ -28,24 +29,32 @@ func (l *LineBreaker) Write(b []byte) (n int, err error) {
return len(b), nil
}
n, err = l.Out.Write(l.line[0:l.used])
_, err = l.Out.Write(l.line[0:l.used:l.used])
if err != nil {
return
}
excess := pemLineLength - l.used
l.used = 0
brk := pemLineLength - l.used
n, err = l.Out.Write(b[0:excess])
if err != nil {
return
var nn int
for len(b) >= brk {
nn, err = l.Out.Write(b[0:brk:brk])
n += nn
if err != nil {
return
}
_, err = l.Out.Write(nl)
if err != nil {
return
}
b = b[brk:]
brk = pemLineLength
}
n, err = l.Out.Write(nl)
if err != nil {
return
}
return l.Out.Write(b[excess:])
l.used = len(b)
copy(l.line[:], b)
n += len(b)
return
}
// Close flushes any pending output from the writer.

95
strutil/chunk_test.go Normal file
View File

@ -0,0 +1,95 @@
package strutil
import (
"io"
"strings"
"testing"
)
type lineBreakerTest struct {
in, out string
}
const sixtyFourCharString = "0123456789012345678901234567890123456789012345678901234567890123"
var lineBreakerTests = []lineBreakerTest{
{"", ""},
{"a", "a\n"},
{"ab", "ab\n"},
{sixtyFourCharString, sixtyFourCharString + "\n"},
{sixtyFourCharString + "X", sixtyFourCharString + "\nX\n"},
{sixtyFourCharString + sixtyFourCharString, sixtyFourCharString + "\n" + sixtyFourCharString + "\n"},
}
func TestLineBreaker(t *testing.T) {
for i, test := range lineBreakerTests {
buf := new(strings.Builder)
var breaker LineBreaker
breaker.Out = buf
_, err := breaker.Write([]byte(test.in))
if err != nil {
t.Errorf("#%d: error from Write: %s", i, err)
continue
}
err = breaker.Close()
if err != nil {
t.Errorf("#%d: error from Close: %s", i, err)
continue
}
if got := buf.String(); got != test.out {
t.Errorf("#%d: got:%s want:%s", i, got, test.out)
}
}
for i, test := range lineBreakerTests {
buf := new(strings.Builder)
var breaker LineBreaker
breaker.Out = buf
for i := 0; i < len(test.in); i++ {
_, err := breaker.Write([]byte(test.in[i : i+1]))
if err != nil {
t.Errorf("#%d: error from Write (byte by byte): %s", i, err)
continue
}
}
err := breaker.Close()
if err != nil {
t.Errorf("#%d: error from Close (byte by byte): %s", i, err)
continue
}
if got := buf.String(); got != test.out {
t.Errorf("#%d: (byte by byte) got:%s want:%s", i, got, test.out)
}
}
}
func FuzzLineBreaker(f *testing.F) {
for _, test := range lineBreakerTests {
f.Add(test.in, len(test.in))
f.Add(test.in, 1)
}
f.Fuzz(func(t *testing.T, in string, chunkSize int) {
if chunkSize <= 0 || chunkSize > len(in)+1 {
return
}
var out strings.Builder
var l LineBreaker
l.Out = &out
chunk := make([]byte, chunkSize)
n, err := io.CopyBuffer(&l, strings.NewReader(in), chunk)
if err != nil {
t.Fatal(err)
}
if n != int64(len(in)) {
t.Errorf("invalid written count: got %d, expected %d", n, len(in))
}
l.Close()
if len(in) > 0 && out.Len() != len(in)+1+(len(in)-1)/pemLineLength {
t.Fatalf("invalid final size: got %d, expected %d", out.Len(), len(in)+1+(len(in)-1)/pemLineLength)
}
})
}