1
0
mirror of https://github.com/golang/go synced 2024-11-05 17:36:15 -07:00

encoding/base32: handle NoPadding in NewDecoder

This change adds functionality to properly handle NoPadding in NewDecoder.

Removes the following expectations when using NoPadding:

* the input message length is a multiple of 8
* the input message length is 0, or longer than 7 characters

Fixes #25332
This commit is contained in:
Gustav Westling 2018-05-13 18:38:00 +02:00
parent 6495bf1710
commit 68ab8d2291
2 changed files with 88 additions and 6 deletions

View File

@ -404,7 +404,7 @@ type decoder struct {
outbuf [1024 / 8 * 5]byte outbuf [1024 / 8 * 5]byte
} }
func readEncodedData(r io.Reader, buf []byte, min int) (n int, err error) { func readEncodedData(r io.Reader, buf []byte, min int, expectsPadding bool) (n int, err error) {
for n < min && err == nil { for n < min && err == nil {
var nn int var nn int
nn, err = r.Read(buf[n:]) nn, err = r.Read(buf[n:])
@ -415,7 +415,9 @@ func readEncodedData(r io.Reader, buf []byte, min int) (n int, err error) {
err = io.ErrUnexpectedEOF err = io.ErrUnexpectedEOF
} }
// no data was read, the buffer already contains some data // no data was read, the buffer already contains some data
if min < 8 && n == 0 && err == io.EOF { // when padding is disabled this is not an error, as the message can be of
// any length
if expectsPadding && min < 8 && n == 0 && err == io.EOF {
err = io.ErrUnexpectedEOF err = io.ErrUnexpectedEOF
} }
return return
@ -445,15 +447,32 @@ func (d *decoder) Read(p []byte) (n int, err error) {
nn = len(d.buf) nn = len(d.buf)
} }
nn, d.err = readEncodedData(d.r, d.buf[d.nbuf:nn], 8-d.nbuf) // Minimum amount of bytes that needs to be read each cycle
var min int
var expectsPadding bool
if d.enc.padChar == NoPadding {
min = 1
expectsPadding = false
} else {
min = 8 - d.nbuf
expectsPadding = true
}
nn, d.err = readEncodedData(d.r, d.buf[d.nbuf:nn], min, expectsPadding)
d.nbuf += nn d.nbuf += nn
if d.nbuf < 8 { if d.nbuf < min {
return 0, d.err return 0, d.err
} }
// Decode chunk into p, or d.out and then p if p is too small. // Decode chunk into p, or d.out and then p if p is too small.
nr := d.nbuf / 8 * 8 var nr int
nw := d.nbuf / 8 * 5 if d.enc.padChar == NoPadding {
nr = d.nbuf
} else {
nr = d.nbuf / 8 * 8
}
nw := d.enc.DecodedLen(d.nbuf)
if nw > len(p) { if nw > len(p) {
nw, d.end, err = d.enc.decode(d.outbuf[0:], d.buf[0:nr]) nw, d.end, err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
d.out = d.outbuf[0:nw] d.out = d.outbuf[0:nw]

View File

@ -686,3 +686,66 @@ func TestWithoutPaddingClose(t *testing.T) {
} }
} }
} }
func TestDecodeReadAll(t *testing.T) {
encodings := []*Encoding{
StdEncoding,
StdEncoding.WithPadding(NoPadding),
}
for _, pair := range pairs {
for encIndex, encoding := range encodings {
encoded := pair.encoded
if encoding.padChar == NoPadding {
encoded = strings.Replace(encoded, "=", "", -1)
}
decReader, err := ioutil.ReadAll(NewDecoder(encoding, strings.NewReader(encoded)))
if err != nil {
t.Errorf("NewDecoder error: %v", err)
}
if pair.decoded != string(decReader) {
t.Errorf("Expected %s got %s; Encoding %d", pair.decoded, decReader, encIndex)
}
}
}
}
func TestDecodeSmallBuffer(t *testing.T) {
encodings := []*Encoding{
StdEncoding,
StdEncoding.WithPadding(NoPadding),
}
for bufferSize := 1; bufferSize < 200; bufferSize++ {
for _, pair := range pairs {
for encIndex, encoding := range encodings {
encoded := pair.encoded
if encoding.padChar == NoPadding {
encoded = strings.Replace(encoded, "=", "", -1)
}
decoder := NewDecoder(encoding, strings.NewReader(encoded))
var allRead []byte
for {
buf := make([]byte, bufferSize)
n, err := decoder.Read(buf)
allRead = append(allRead, buf[0:n]...)
if err == io.EOF {
break
}
if err != nil {
t.Error(err)
}
}
if pair.decoded != string(allRead) {
t.Errorf("Expected %s got %s; Encoding %d; bufferSize %d", pair.decoded, allRead, encIndex, bufferSize)
}
}
}
}
}