This repository has been archived by the owner on Jun 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 665
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[proxy] rewrote chunked response handler
1) We cannot send "Connection: close", because the fsouza docker client expects the tcp socket to stay open between requests. 2) Because we cannot force-close the connection, we can't hijack the connection (because go's net/http doesn't let use un-hijack it). 3) Because we need to maintain the individual chunking of messages (for docker-py), we can't just copy the response body, as Go will remove and re-add the chunking willy-nilly. Therefore, we have to read each chunk one-by-one, and flush the ResponseWriter after each one.
- Loading branch information
1 parent
bbacaa4
commit 11663dd
Showing
2 changed files
with
220 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// Based on net/http/internal | ||
package proxy | ||
|
||
import ( | ||
"bufio" | ||
"bytes" | ||
"strconv" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func TestChunk(t *testing.T) { | ||
r := bufio.NewScanner(bytes.NewBufferString( | ||
"7\r\nhello, \r\n17\r\nworld! 0123456789abcdef\r\n0\r\n", | ||
)) | ||
r.Split(splitChunks) | ||
|
||
assertNextChunk(t, r, "hello, ") | ||
assertNextChunk(t, r, "world! 0123456789abcdef") | ||
assertNoMoreChunks(t, r) | ||
} | ||
|
||
func TestMalformedChunks(t *testing.T) { | ||
r := bufio.NewScanner(bytes.NewBufferString( | ||
"7\r\nhello, GARBAGEBYTES17\r\nworld! 0123456789abcdef\r\n0\r\n", | ||
)) | ||
r.Split(splitChunks) | ||
|
||
// First chunk fails | ||
{ | ||
if r.Scan() { | ||
t.Errorf("Expected failure when reading chunks, but got one") | ||
} | ||
e := "malformed chunked encoding" | ||
if r.Err() == nil || r.Err().Error() != e { | ||
t.Errorf("chunk reader errored %q; want %q", r.Err(), e) | ||
} | ||
data := r.Bytes() | ||
if len(data) != 0 { | ||
t.Errorf("chunk should have been empty. got %q", data) | ||
} | ||
} | ||
|
||
if r.Scan() { | ||
t.Errorf("Expected no more chunks, but found too many") | ||
} | ||
} | ||
|
||
func TestChunkTooLarge(t *testing.T) { | ||
data := make([]byte, maxChunkSize+1) | ||
r := bufio.NewScanner(bytes.NewBufferString(strings.Join( | ||
[]string{ | ||
strconv.FormatInt(maxChunkSize+1, 16), string(data), | ||
"0", "", | ||
}, | ||
"\r\n", | ||
))) | ||
r.Split(splitChunks) | ||
|
||
// First chunk fails | ||
{ | ||
if r.Scan() { | ||
t.Errorf("Expected failure when reading chunks, but got one") | ||
} | ||
e := "chunk too long" | ||
if r.Err() == nil || r.Err().Error() != e { | ||
t.Errorf("chunk reader errored %q; want %q", r.Err(), e) | ||
} | ||
data := r.Bytes() | ||
if len(data) != 0 { | ||
t.Errorf("chunk should have been empty. got %q", data) | ||
} | ||
} | ||
|
||
if r.Scan() { | ||
t.Errorf("Expected no more chunks, but found too many") | ||
} | ||
} | ||
|
||
func TestInvalidChunkSize(t *testing.T) { | ||
r := bufio.NewScanner(bytes.NewBufferString( | ||
"foobar\r\nhello, \r\n0\r\n", | ||
)) | ||
r.Split(splitChunks) | ||
|
||
// First chunk fails | ||
{ | ||
if r.Scan() { | ||
t.Errorf("Expected failure when reading chunks, but got one") | ||
} | ||
e := "invalid byte in chunk length" | ||
if r.Err() == nil || r.Err().Error() != e { | ||
t.Errorf("chunk reader errored %q; want %q", r.Err(), e) | ||
} | ||
data := r.Bytes() | ||
if len(data) != 0 { | ||
t.Errorf("chunk should have been empty. got %q", data) | ||
} | ||
} | ||
|
||
if r.Scan() { | ||
t.Errorf("Expected no more chunks, but found too many") | ||
} | ||
} | ||
|
||
func TestBytesAfterLastChunkAreIgnored(t *testing.T) { | ||
r := bufio.NewScanner(bytes.NewBufferString( | ||
"7\r\nhello, \r\n0\r\nGARBAGEBYTES", | ||
)) | ||
r.Split(splitChunks) | ||
|
||
assertNextChunk(t, r, "hello, ") | ||
assertNoMoreChunks(t, r) | ||
} | ||
|
||
func assertNextChunk(t *testing.T, r *bufio.Scanner, expected string) { | ||
if !r.Scan() { | ||
t.Fatalf("Expected chunk, but ran out early: %v", r.Err()) | ||
} | ||
if r.Err() != nil { | ||
t.Fatalf("Error reading chunk: %q", r.Err()) | ||
} | ||
data := r.Bytes() | ||
if string(data) != expected { | ||
t.Errorf("chunk reader read %q; want %q", data, expected) | ||
} | ||
} | ||
|
||
func assertNoMoreChunks(t *testing.T, r *bufio.Scanner) { | ||
if r.Scan() { | ||
t.Errorf("Expected no more chunks, but found too many") | ||
} | ||
if r.Err() != nil { | ||
t.Errorf("Expected no error, but found: %q", r.Err()) | ||
} | ||
} |