aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/net/http/internal/chunked.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/http/internal/chunked.go')
-rw-r--r--libgo/go/net/http/internal/chunked.go42
1 files changed, 34 insertions, 8 deletions
diff --git a/libgo/go/net/http/internal/chunked.go b/libgo/go/net/http/internal/chunked.go
index 6d7c69874d9..2e62c00d5db 100644
--- a/libgo/go/net/http/internal/chunked.go
+++ b/libgo/go/net/http/internal/chunked.go
@@ -44,7 +44,7 @@ type chunkedReader struct {
func (cr *chunkedReader) beginChunk() {
// chunk-size CRLF
var line []byte
- line, cr.err = readLine(cr.r)
+ line, cr.err = readChunkLine(cr.r)
if cr.err != nil {
return
}
@@ -104,10 +104,11 @@ func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
// Read a line of bytes (up to \n) from b.
// Give up if the line exceeds maxLineLength.
-// The returned bytes are a pointer into storage in
-// the bufio, so they are only valid until the next bufio read.
-func readLine(b *bufio.Reader) (p []byte, err error) {
- if p, err = b.ReadSlice('\n'); err != nil {
+// The returned bytes are owned by the bufio.Reader
+// so they are only valid until the next bufio read.
+func readChunkLine(b *bufio.Reader) ([]byte, error) {
+ p, err := b.ReadSlice('\n')
+ if err != nil {
// We always know when EOF is coming.
// If the caller asked for a line, there should be a line.
if err == io.EOF {
@@ -120,7 +121,12 @@ func readLine(b *bufio.Reader) (p []byte, err error) {
if len(p) >= maxLineLength {
return nil, ErrLineTooLong
}
- return trimTrailingWhitespace(p), nil
+ p = trimTrailingWhitespace(p)
+ p, err = removeChunkExtension(p)
+ if err != nil {
+ return nil, err
+ }
+ return p, nil
}
func trimTrailingWhitespace(b []byte) []byte {
@@ -134,6 +140,23 @@ func isASCIISpace(b byte) bool {
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}
+// removeChunkExtension removes any chunk-extension from p.
+// For example,
+// "0" => "0"
+// "0;token" => "0"
+// "0;token=val" => "0"
+// `0;token="quoted string"` => "0"
+func removeChunkExtension(p []byte) ([]byte, error) {
+ semi := bytes.IndexByte(p, ';')
+ if semi == -1 {
+ return p, nil
+ }
+ // TODO: care about exact syntax of chunk extensions? We're
+ // ignoring and stripping them anyway. For now just never
+ // return an error.
+ return p[:semi], nil
+}
+
// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
// "chunked" format before writing them to w. Closing the returned chunkedWriter
// sends the final 0-length chunk that marks the end of the stream.
@@ -197,8 +220,7 @@ type FlushAfterChunkWriter struct {
}
func parseHexUint(v []byte) (n uint64, err error) {
- for _, b := range v {
- n <<= 4
+ for i, b := range v {
switch {
case '0' <= b && b <= '9':
b = b - '0'
@@ -209,6 +231,10 @@ func parseHexUint(v []byte) (n uint64, err error) {
default:
return 0, errors.New("invalid byte in chunk length")
}
+ if i == 16 {
+ return 0, errors.New("http chunk length too large")
+ }
+ n <<= 4
n |= uint64(b)
}
return