Merge pull request #2 from spi-ca/ISSUE-1
Issue 1 - fixes Short writes in strutil.LineBreaker
This commit is contained in:
commit
3363710364
|
@ -7,6 +7,7 @@ import (
|
||||||
const pemLineLength = 64
|
const pemLineLength = 64
|
||||||
|
|
||||||
// LineBreaker is an io.Writer that advances a newline if one line exceeds 64 bytes.
|
// 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 {
|
type LineBreaker struct {
|
||||||
// Out os
|
// Out os
|
||||||
Out io.Writer
|
Out io.Writer
|
||||||
|
@ -28,24 +29,32 @@ func (l *LineBreaker) Write(b []byte) (n int, err error) {
|
||||||
return len(b), nil
|
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 {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
excess := pemLineLength - l.used
|
brk := pemLineLength - l.used
|
||||||
l.used = 0
|
|
||||||
|
|
||||||
n, err = l.Out.Write(b[0:excess])
|
var nn int
|
||||||
if err != nil {
|
for len(b) >= brk {
|
||||||
return
|
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)
|
l.used = len(b)
|
||||||
if err != nil {
|
copy(l.line[:], b)
|
||||||
return
|
n += len(b)
|
||||||
}
|
return
|
||||||
|
|
||||||
return l.Out.Write(b[excess:])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close flushes any pending output from the writer.
|
// Close flushes any pending output from the writer.
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue