|
@@ -0,0 +1,115 @@
|
|
|
|
+// +build !windows
|
|
|
|
+
|
|
|
|
+package hack
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "bytes"
|
|
|
|
+ "io"
|
|
|
|
+ "net"
|
|
|
|
+ "strings"
|
|
|
|
+ "testing"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+func TestHeaderOverrideHack(t *testing.T) {
|
|
|
|
+ client, srv := net.Pipe()
|
|
|
|
+ tests := [][2][]byte{
|
|
|
|
+ {
|
|
|
|
+ []byte("GET /foo\nHost: /var/run/docker.sock\nUser-Agent: Docker\r\n\r\n"),
|
|
|
|
+ []byte("GET /foo\nHost: \r\nConnection: close\r\nUser-Agent: Docker\r\n\r\n"),
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ []byte("GET /foo\nHost: /var/run/docker.sock\nUser-Agent: Docker\nFoo: Bar\r\n"),
|
|
|
|
+ []byte("GET /foo\nHost: \r\nConnection: close\r\nUser-Agent: Docker\nFoo: Bar\r\n"),
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ []byte("GET /foo\nHost: /var/run/docker.sock\nUser-Agent: Docker\r\n\r\ntest something!"),
|
|
|
|
+ []byte("GET /foo\nHost: \r\nConnection: close\r\nUser-Agent: Docker\r\n\r\ntest something!"),
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ []byte("GET /foo\nHost: /var/run/docker.sock\nUser-Agent: Docker\r\n\r\ntest something! " + strings.Repeat("test", 15000)),
|
|
|
|
+ []byte("GET /foo\nHost: \r\nConnection: close\r\nUser-Agent: Docker\r\n\r\ntest something! " + strings.Repeat("test", 15000)),
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ []byte("GET /foo\nFoo: Bar\nHost: /var/run/docker.sock\nUser-Agent: Docker\r\n\r\n"),
|
|
|
|
+ []byte("GET /foo\nFoo: Bar\nHost: /var/run/docker.sock\nUser-Agent: Docker\r\n\r\n"),
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ l := MalformedHostHeaderOverrideConn{client, true}
|
|
|
|
+ read := make([]byte, 4096)
|
|
|
|
+
|
|
|
|
+ for _, pair := range tests {
|
|
|
|
+ go func() {
|
|
|
|
+ srv.Write(pair[0])
|
|
|
|
+ }()
|
|
|
|
+ n, err := l.Read(read)
|
|
|
|
+ if err != nil && err != io.EOF {
|
|
|
|
+ t.Fatalf("read: %d - %d, err: %v\n%s", n, len(pair[0]), err, string(read[:n]))
|
|
|
|
+ }
|
|
|
|
+ if !bytes.Equal(read[:n], pair[1][:n]) {
|
|
|
|
+ t.Fatalf("\n%s\n%s\n", read[:n], pair[1][:n])
|
|
|
|
+ }
|
|
|
|
+ l.first = true
|
|
|
|
+ // clean out the slice
|
|
|
|
+ read = read[:0]
|
|
|
|
+ }
|
|
|
|
+ srv.Close()
|
|
|
|
+ l.Close()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func BenchmarkWithHack(b *testing.B) {
|
|
|
|
+ client, srv := net.Pipe()
|
|
|
|
+ done := make(chan struct{})
|
|
|
|
+ req := []byte("GET /foo\nHost: /var/run/docker.sock\nUser-Agent: Docker\n")
|
|
|
|
+ read := make([]byte, 4096)
|
|
|
|
+ b.SetBytes(int64(len(req) * 30))
|
|
|
|
+
|
|
|
|
+ l := MalformedHostHeaderOverrideConn{client, true}
|
|
|
|
+ go func() {
|
|
|
|
+ for {
|
|
|
|
+ if _, err := srv.Write(req); err != nil {
|
|
|
|
+ srv.Close()
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ l.first = true // make sure each subsequent run uses the hack parsing
|
|
|
|
+ }
|
|
|
|
+ close(done)
|
|
|
|
+ }()
|
|
|
|
+
|
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
|
+ for i := 0; i < 30; i++ {
|
|
|
|
+ if n, err := l.Read(read); err != nil && err != io.EOF {
|
|
|
|
+ b.Fatalf("read: %d - %d, err: %v\n%s", n, len(req), err, string(read[:n]))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ l.Close()
|
|
|
|
+ <-done
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func BenchmarkNoHack(b *testing.B) {
|
|
|
|
+ client, srv := net.Pipe()
|
|
|
|
+ done := make(chan struct{})
|
|
|
|
+ req := []byte("GET /foo\nHost: /var/run/docker.sock\nUser-Agent: Docker\n")
|
|
|
|
+ read := make([]byte, 4096)
|
|
|
|
+ b.SetBytes(int64(len(req) * 30))
|
|
|
|
+
|
|
|
|
+ go func() {
|
|
|
|
+ for {
|
|
|
|
+ if _, err := srv.Write(req); err != nil {
|
|
|
|
+ srv.Close()
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ close(done)
|
|
|
|
+ }()
|
|
|
|
+
|
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
|
+ for i := 0; i < 30; i++ {
|
|
|
|
+ if _, err := client.Read(read); err != nil && err != io.EOF {
|
|
|
|
+ b.Fatal(err)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ client.Close()
|
|
|
|
+ <-done
|
|
|
|
+}
|