| // Copyright 2011 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package spdy |
| |
| import ( |
| "bytes" |
| "compress/zlib" |
| "http" |
| "os" |
| "testing" |
| ) |
| |
| type frameIoTest struct { |
| desc string |
| data []byte |
| frame Frame |
| readError os.Error |
| readOnly bool |
| } |
| |
| var frameIoTests = []frameIoTest{ |
| { |
| "noop frame", |
| []byte{ |
| 0x80, 0x02, 0x00, 0x05, |
| 0x00, 0x00, 0x00, 0x00, |
| }, |
| ControlFrame( |
| TypeNoop, |
| 0x00, |
| []byte{}, |
| ), |
| nil, |
| false, |
| }, |
| { |
| "ping frame", |
| []byte{ |
| 0x80, 0x02, 0x00, 0x06, |
| 0x00, 0x00, 0x00, 0x04, |
| 0x00, 0x00, 0x00, 0x01, |
| }, |
| ControlFrame( |
| TypePing, |
| 0x00, |
| []byte{0x00, 0x00, 0x00, 0x01}, |
| ), |
| nil, |
| false, |
| }, |
| { |
| "syn_stream frame", |
| []byte{ |
| 0x80, 0x02, 0x00, 0x01, |
| 0x01, 0x00, 0x00, 0x53, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x78, 0xbb, |
| 0xdf, 0xa2, 0x51, 0xb2, |
| 0x62, 0x60, 0x66, 0x60, |
| 0xcb, 0x4d, 0x2d, 0xc9, |
| 0xc8, 0x4f, 0x61, 0x60, |
| 0x4e, 0x4f, 0x2d, 0x61, |
| 0x60, 0x2e, 0x2d, 0xca, |
| 0x61, 0x10, 0xcb, 0x28, |
| 0x29, 0x29, 0xb0, 0xd2, |
| 0xd7, 0x2f, 0x2f, 0x2f, |
| 0xd7, 0x4b, 0xcf, 0xcf, |
| 0x4f, 0xcf, 0x49, 0xd5, |
| 0x4b, 0xce, 0xcf, 0xd5, |
| 0x67, 0x60, 0x2f, 0x4b, |
| 0x2d, 0x2a, 0xce, 0xcc, |
| 0xcf, 0x63, 0xe0, 0x00, |
| 0x29, 0xd0, 0x37, 0xd4, |
| 0x33, 0x04, 0x00, 0x00, |
| 0x00, 0xff, 0xff, |
| }, |
| ControlFrame( |
| TypeSynStream, |
| 0x01, |
| []byte{ |
| 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x78, 0xbb, |
| 0xdf, 0xa2, 0x51, 0xb2, |
| 0x62, 0x60, 0x66, 0x60, |
| 0xcb, 0x4d, 0x2d, 0xc9, |
| 0xc8, 0x4f, 0x61, 0x60, |
| 0x4e, 0x4f, 0x2d, 0x61, |
| 0x60, 0x2e, 0x2d, 0xca, |
| 0x61, 0x10, 0xcb, 0x28, |
| 0x29, 0x29, 0xb0, 0xd2, |
| 0xd7, 0x2f, 0x2f, 0x2f, |
| 0xd7, 0x4b, 0xcf, 0xcf, |
| 0x4f, 0xcf, 0x49, 0xd5, |
| 0x4b, 0xce, 0xcf, 0xd5, |
| 0x67, 0x60, 0x2f, 0x4b, |
| 0x2d, 0x2a, 0xce, 0xcc, |
| 0xcf, 0x63, 0xe0, 0x00, |
| 0x29, 0xd0, 0x37, 0xd4, |
| 0x33, 0x04, 0x00, 0x00, |
| 0x00, 0xff, 0xff, |
| }, |
| ), |
| nil, |
| false, |
| }, |
| { |
| "data frame", |
| []byte{ |
| 0x00, 0x00, 0x00, 0x05, |
| 0x01, 0x00, 0x00, 0x04, |
| 0x01, 0x02, 0x03, 0x04, |
| }, |
| DataFrame( |
| 5, |
| 0x01, |
| []byte{0x01, 0x02, 0x03, 0x04}, |
| ), |
| nil, |
| false, |
| }, |
| { |
| "too much data", |
| []byte{ |
| 0x00, 0x00, 0x00, 0x05, |
| 0x01, 0x00, 0x00, 0x04, |
| 0x01, 0x02, 0x03, 0x04, |
| 0x05, 0x06, 0x07, 0x08, |
| }, |
| DataFrame( |
| 5, |
| 0x01, |
| []byte{0x01, 0x02, 0x03, 0x04}, |
| ), |
| nil, |
| true, |
| }, |
| { |
| "not enough data", |
| []byte{ |
| 0x00, 0x00, 0x00, 0x05, |
| }, |
| Frame{}, |
| os.EOF, |
| true, |
| }, |
| } |
| |
| func TestReadFrame(t *testing.T) { |
| for _, tt := range frameIoTests { |
| f, err := ReadFrame(bytes.NewBuffer(tt.data)) |
| if err != tt.readError { |
| t.Errorf("%s: ReadFrame: %s", tt.desc, err) |
| continue |
| } |
| if err == nil { |
| if !bytes.Equal(f.Header[:], tt.frame.Header[:]) { |
| t.Errorf("%s: header %q != %q", tt.desc, string(f.Header[:]), string(tt.frame.Header[:])) |
| } |
| if f.Flags != tt.frame.Flags { |
| t.Errorf("%s: flags %#02x != %#02x", tt.desc, f.Flags, tt.frame.Flags) |
| } |
| if !bytes.Equal(f.Data, tt.frame.Data) { |
| t.Errorf("%s: data %q != %q", tt.desc, string(f.Data), string(tt.frame.Data)) |
| } |
| } |
| } |
| } |
| |
| func TestWriteTo(t *testing.T) { |
| for _, tt := range frameIoTests { |
| if tt.readOnly { |
| continue |
| } |
| b := new(bytes.Buffer) |
| _, err := tt.frame.WriteTo(b) |
| if err != nil { |
| t.Errorf("%s: WriteTo: %s", tt.desc, err) |
| } |
| if !bytes.Equal(b.Bytes(), tt.data) { |
| t.Errorf("%s: data %q != %q", tt.desc, string(b.Bytes()), string(tt.data)) |
| } |
| } |
| } |
| |
| var headerDataTest = []byte{ |
| 0x78, 0xbb, 0xdf, 0xa2, |
| 0x51, 0xb2, 0x62, 0x60, |
| 0x66, 0x60, 0xcb, 0x4d, |
| 0x2d, 0xc9, 0xc8, 0x4f, |
| 0x61, 0x60, 0x4e, 0x4f, |
| 0x2d, 0x61, 0x60, 0x2e, |
| 0x2d, 0xca, 0x61, 0x10, |
| 0xcb, 0x28, 0x29, 0x29, |
| 0xb0, 0xd2, 0xd7, 0x2f, |
| 0x2f, 0x2f, 0xd7, 0x4b, |
| 0xcf, 0xcf, 0x4f, 0xcf, |
| 0x49, 0xd5, 0x4b, 0xce, |
| 0xcf, 0xd5, 0x67, 0x60, |
| 0x2f, 0x4b, 0x2d, 0x2a, |
| 0xce, 0xcc, 0xcf, 0x63, |
| 0xe0, 0x00, 0x29, 0xd0, |
| 0x37, 0xd4, 0x33, 0x04, |
| 0x00, 0x00, 0x00, 0xff, |
| 0xff, |
| } |
| |
| func TestReadHeader(t *testing.T) { |
| r := NewHeaderReader() |
| h, err := r.Decode(headerDataTest) |
| if err != nil { |
| t.Fatalf("Error: %v", err) |
| return |
| } |
| if len(h) != 3 { |
| t.Errorf("Header count = %d (expected 3)", len(h)) |
| } |
| if h.Get("Url") != "http://www.google.com/" { |
| t.Errorf("Url: %q != %q", h.Get("Url"), "http://www.google.com/") |
| } |
| if h.Get("Method") != "get" { |
| t.Errorf("Method: %q != %q", h.Get("Method"), "get") |
| } |
| if h.Get("Version") != "http/1.1" { |
| t.Errorf("Version: %q != %q", h.Get("Version"), "http/1.1") |
| } |
| } |
| |
| func TestWriteHeader(t *testing.T) { |
| for level := zlib.NoCompression; level <= zlib.BestCompression; level++ { |
| r := NewHeaderReader() |
| w := NewHeaderWriter(level) |
| for i := 0; i < 100; i++ { |
| b := new(bytes.Buffer) |
| gold := http.Header{ |
| "Url": []string{"http://www.google.com/"}, |
| "Method": []string{"get"}, |
| "Version": []string{"http/1.1"}, |
| } |
| w.WriteHeader(b, gold) |
| h, err := r.Decode(b.Bytes()) |
| if err != nil { |
| t.Errorf("(level=%d i=%d) Error: %v", level, i, err) |
| return |
| } |
| if len(h) != len(gold) { |
| t.Errorf("(level=%d i=%d) Header count = %d (expected %d)", level, i, len(h), len(gold)) |
| } |
| for k, _ := range h { |
| if h.Get(k) != gold.Get(k) { |
| t.Errorf("(level=%d i=%d) %s: %q != %q", level, i, k, h.Get(k), gold.Get(k)) |
| } |
| } |
| } |
| } |
| } |