| // 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" | |
| "http" | |
| "io" | |
| "reflect" | |
| "testing" | |
| ) | |
| func TestHeaderParsing(t *testing.T) { | |
| headers := http.Header{ | |
| "Url": []string{"http://www.google.com/"}, | |
| "Method": []string{"get"}, | |
| "Version": []string{"http/1.1"}, | |
| } | |
| var headerValueBlockBuf bytes.Buffer | |
| writeHeaderValueBlock(&headerValueBlockBuf, headers) | |
| const bogusStreamId = 1 | |
| newHeaders, err := parseHeaderValueBlock(&headerValueBlockBuf, bogusStreamId) | |
| if err != nil { | |
| t.Fatal("parseHeaderValueBlock:", err) | |
| } | |
| if !reflect.DeepEqual(headers, newHeaders) { | |
| t.Fatal("got: ", newHeaders, "\nwant: ", headers) | |
| } | |
| } | |
| func TestCreateParseSynStreamFrame(t *testing.T) { | |
| buffer := new(bytes.Buffer) | |
| framer := &Framer{ | |
| headerCompressionDisabled: true, | |
| w: buffer, | |
| headerBuf: new(bytes.Buffer), | |
| r: buffer, | |
| } | |
| synStreamFrame := SynStreamFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypeSynStream, | |
| }, | |
| Headers: http.Header{ | |
| "Url": []string{"http://www.google.com/"}, | |
| "Method": []string{"get"}, | |
| "Version": []string{"http/1.1"}, | |
| }, | |
| } | |
| if err := framer.WriteFrame(&synStreamFrame); err != nil { | |
| t.Fatal("WriteFrame without compression:", err) | |
| } | |
| frame, err := framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame without compression:", err) | |
| } | |
| parsedSynStreamFrame, ok := frame.(*SynStreamFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) { | |
| t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame) | |
| } | |
| // Test again with compression | |
| buffer.Reset() | |
| framer, err = NewFramer(buffer, buffer) | |
| if err != nil { | |
| t.Fatal("Failed to create new framer:", err) | |
| } | |
| if err := framer.WriteFrame(&synStreamFrame); err != nil { | |
| t.Fatal("WriteFrame with compression:", err) | |
| } | |
| frame, err = framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame with compression:", err) | |
| } | |
| parsedSynStreamFrame, ok = frame.(*SynStreamFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) { | |
| t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame) | |
| } | |
| } | |
| func TestCreateParseSynReplyFrame(t *testing.T) { | |
| buffer := new(bytes.Buffer) | |
| framer := &Framer{ | |
| headerCompressionDisabled: true, | |
| w: buffer, | |
| headerBuf: new(bytes.Buffer), | |
| r: buffer, | |
| } | |
| synReplyFrame := SynReplyFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypeSynReply, | |
| }, | |
| Headers: http.Header{ | |
| "Url": []string{"http://www.google.com/"}, | |
| "Method": []string{"get"}, | |
| "Version": []string{"http/1.1"}, | |
| }, | |
| } | |
| if err := framer.WriteFrame(&synReplyFrame); err != nil { | |
| t.Fatal("WriteFrame without compression:", err) | |
| } | |
| frame, err := framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame without compression:", err) | |
| } | |
| parsedSynReplyFrame, ok := frame.(*SynReplyFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) { | |
| t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame) | |
| } | |
| // Test again with compression | |
| buffer.Reset() | |
| framer, err = NewFramer(buffer, buffer) | |
| if err != nil { | |
| t.Fatal("Failed to create new framer:", err) | |
| } | |
| if err := framer.WriteFrame(&synReplyFrame); err != nil { | |
| t.Fatal("WriteFrame with compression:", err) | |
| } | |
| frame, err = framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame with compression:", err) | |
| } | |
| parsedSynReplyFrame, ok = frame.(*SynReplyFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) { | |
| t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame) | |
| } | |
| } | |
| func TestCreateParseRstStream(t *testing.T) { | |
| buffer := new(bytes.Buffer) | |
| framer, err := NewFramer(buffer, buffer) | |
| if err != nil { | |
| t.Fatal("Failed to create new framer:", err) | |
| } | |
| rstStreamFrame := RstStreamFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypeRstStream, | |
| }, | |
| StreamId: 1, | |
| Status: InvalidStream, | |
| } | |
| if err := framer.WriteFrame(&rstStreamFrame); err != nil { | |
| t.Fatal("WriteFrame:", err) | |
| } | |
| frame, err := framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame:", err) | |
| } | |
| parsedRstStreamFrame, ok := frame.(*RstStreamFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(rstStreamFrame, *parsedRstStreamFrame) { | |
| t.Fatal("got: ", *parsedRstStreamFrame, "\nwant: ", rstStreamFrame) | |
| } | |
| } | |
| func TestCreateParseSettings(t *testing.T) { | |
| buffer := new(bytes.Buffer) | |
| framer, err := NewFramer(buffer, buffer) | |
| if err != nil { | |
| t.Fatal("Failed to create new framer:", err) | |
| } | |
| settingsFrame := SettingsFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypeSettings, | |
| }, | |
| FlagIdValues: []SettingsFlagIdValue{ | |
| {FlagSettingsPersistValue, SettingsCurrentCwnd, 10}, | |
| {FlagSettingsPersisted, SettingsUploadBandwidth, 1}, | |
| }, | |
| } | |
| if err := framer.WriteFrame(&settingsFrame); err != nil { | |
| t.Fatal("WriteFrame:", err) | |
| } | |
| frame, err := framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame:", err) | |
| } | |
| parsedSettingsFrame, ok := frame.(*SettingsFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(settingsFrame, *parsedSettingsFrame) { | |
| t.Fatal("got: ", *parsedSettingsFrame, "\nwant: ", settingsFrame) | |
| } | |
| } | |
| func TestCreateParseNoop(t *testing.T) { | |
| buffer := new(bytes.Buffer) | |
| framer, err := NewFramer(buffer, buffer) | |
| if err != nil { | |
| t.Fatal("Failed to create new framer:", err) | |
| } | |
| noopFrame := NoopFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypeNoop, | |
| }, | |
| } | |
| if err := framer.WriteFrame(&noopFrame); err != nil { | |
| t.Fatal("WriteFrame:", err) | |
| } | |
| frame, err := framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame:", err) | |
| } | |
| parsedNoopFrame, ok := frame.(*NoopFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(noopFrame, *parsedNoopFrame) { | |
| t.Fatal("got: ", *parsedNoopFrame, "\nwant: ", noopFrame) | |
| } | |
| } | |
| func TestCreateParsePing(t *testing.T) { | |
| buffer := new(bytes.Buffer) | |
| framer, err := NewFramer(buffer, buffer) | |
| if err != nil { | |
| t.Fatal("Failed to create new framer:", err) | |
| } | |
| pingFrame := PingFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypePing, | |
| }, | |
| Id: 31337, | |
| } | |
| if err := framer.WriteFrame(&pingFrame); err != nil { | |
| t.Fatal("WriteFrame:", err) | |
| } | |
| frame, err := framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame:", err) | |
| } | |
| parsedPingFrame, ok := frame.(*PingFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(pingFrame, *parsedPingFrame) { | |
| t.Fatal("got: ", *parsedPingFrame, "\nwant: ", pingFrame) | |
| } | |
| } | |
| func TestCreateParseGoAway(t *testing.T) { | |
| buffer := new(bytes.Buffer) | |
| framer, err := NewFramer(buffer, buffer) | |
| if err != nil { | |
| t.Fatal("Failed to create new framer:", err) | |
| } | |
| goAwayFrame := GoAwayFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypeGoAway, | |
| }, | |
| LastGoodStreamId: 31337, | |
| } | |
| if err := framer.WriteFrame(&goAwayFrame); err != nil { | |
| t.Fatal("WriteFrame:", err) | |
| } | |
| frame, err := framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame:", err) | |
| } | |
| parsedGoAwayFrame, ok := frame.(*GoAwayFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(goAwayFrame, *parsedGoAwayFrame) { | |
| t.Fatal("got: ", *parsedGoAwayFrame, "\nwant: ", goAwayFrame) | |
| } | |
| } | |
| func TestCreateParseHeadersFrame(t *testing.T) { | |
| buffer := new(bytes.Buffer) | |
| framer := &Framer{ | |
| headerCompressionDisabled: true, | |
| w: buffer, | |
| headerBuf: new(bytes.Buffer), | |
| r: buffer, | |
| } | |
| headersFrame := HeadersFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypeHeaders, | |
| }, | |
| } | |
| headersFrame.Headers = http.Header{ | |
| "Url": []string{"http://www.google.com/"}, | |
| "Method": []string{"get"}, | |
| "Version": []string{"http/1.1"}, | |
| } | |
| if err := framer.WriteFrame(&headersFrame); err != nil { | |
| t.Fatal("WriteFrame without compression:", err) | |
| } | |
| frame, err := framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame without compression:", err) | |
| } | |
| parsedHeadersFrame, ok := frame.(*HeadersFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) { | |
| t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame) | |
| } | |
| // Test again with compression | |
| buffer.Reset() | |
| framer, err = NewFramer(buffer, buffer) | |
| if err := framer.WriteFrame(&headersFrame); err != nil { | |
| t.Fatal("WriteFrame with compression:", err) | |
| } | |
| frame, err = framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame with compression:", err) | |
| } | |
| parsedHeadersFrame, ok = frame.(*HeadersFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) { | |
| t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame) | |
| } | |
| } | |
| func TestCreateParseDataFrame(t *testing.T) { | |
| buffer := new(bytes.Buffer) | |
| framer, err := NewFramer(buffer, buffer) | |
| if err != nil { | |
| t.Fatal("Failed to create new framer:", err) | |
| } | |
| dataFrame := DataFrame{ | |
| StreamId: 1, | |
| Data: []byte{'h', 'e', 'l', 'l', 'o'}, | |
| } | |
| if err := framer.WriteFrame(&dataFrame); err != nil { | |
| t.Fatal("WriteFrame:", err) | |
| } | |
| frame, err := framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame:", err) | |
| } | |
| parsedDataFrame, ok := frame.(*DataFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(dataFrame, *parsedDataFrame) { | |
| t.Fatal("got: ", *parsedDataFrame, "\nwant: ", dataFrame) | |
| } | |
| } | |
| func TestCompressionContextAcrossFrames(t *testing.T) { | |
| buffer := new(bytes.Buffer) | |
| framer, err := NewFramer(buffer, buffer) | |
| if err != nil { | |
| t.Fatal("Failed to create new framer:", err) | |
| } | |
| headersFrame := HeadersFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypeHeaders, | |
| }, | |
| Headers: http.Header{ | |
| "Url": []string{"http://www.google.com/"}, | |
| "Method": []string{"get"}, | |
| "Version": []string{"http/1.1"}, | |
| }, | |
| } | |
| if err := framer.WriteFrame(&headersFrame); err != nil { | |
| t.Fatal("WriteFrame (HEADERS):", err) | |
| } | |
| synStreamFrame := SynStreamFrame{ControlFrameHeader{Version, TypeSynStream, 0, 0}, 0, 0, 0, nil} | |
| synStreamFrame.Headers = http.Header{ | |
| "Url": []string{"http://www.google.com/"}, | |
| "Method": []string{"get"}, | |
| "Version": []string{"http/1.1"}, | |
| } | |
| if err := framer.WriteFrame(&synStreamFrame); err != nil { | |
| t.Fatal("WriteFrame (SYN_STREAM):", err) | |
| } | |
| frame, err := framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame (HEADERS):", err, buffer.Bytes()) | |
| } | |
| parsedHeadersFrame, ok := frame.(*HeadersFrame) | |
| if !ok { | |
| t.Fatalf("expected HeadersFrame; got %T %v", frame, frame) | |
| } | |
| if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) { | |
| t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame) | |
| } | |
| frame, err = framer.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame (SYN_STREAM):", err, buffer.Bytes()) | |
| } | |
| parsedSynStreamFrame, ok := frame.(*SynStreamFrame) | |
| if !ok { | |
| t.Fatalf("expected SynStreamFrame; got %T %v", frame, frame) | |
| } | |
| if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) { | |
| t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame) | |
| } | |
| } | |
| func TestMultipleSPDYFrames(t *testing.T) { | |
| // Initialize the framers. | |
| pr1, pw1 := io.Pipe() | |
| pr2, pw2 := io.Pipe() | |
| writer, err := NewFramer(pw1, pr2) | |
| if err != nil { | |
| t.Fatal("Failed to create writer:", err) | |
| } | |
| reader, err := NewFramer(pw2, pr1) | |
| if err != nil { | |
| t.Fatal("Failed to create reader:", err) | |
| } | |
| // Set up the frames we're actually transferring. | |
| headersFrame := HeadersFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypeHeaders, | |
| }, | |
| Headers: http.Header{ | |
| "Url": []string{"http://www.google.com/"}, | |
| "Method": []string{"get"}, | |
| "Version": []string{"http/1.1"}, | |
| }, | |
| } | |
| synStreamFrame := SynStreamFrame{ | |
| CFHeader: ControlFrameHeader{ | |
| version: Version, | |
| frameType: TypeSynStream, | |
| }, | |
| Headers: http.Header{ | |
| "Url": []string{"http://www.google.com/"}, | |
| "Method": []string{"get"}, | |
| "Version": []string{"http/1.1"}, | |
| }, | |
| } | |
| // Start the goroutines to write the frames. | |
| go func() { | |
| if err := writer.WriteFrame(&headersFrame); err != nil { | |
| t.Fatal("WriteFrame (HEADERS): ", err) | |
| } | |
| if err := writer.WriteFrame(&synStreamFrame); err != nil { | |
| t.Fatal("WriteFrame (SYN_STREAM): ", err) | |
| } | |
| }() | |
| // Read the frames and verify they look as expected. | |
| frame, err := reader.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame (HEADERS): ", err) | |
| } | |
| parsedHeadersFrame, ok := frame.(*HeadersFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type:", frame) | |
| } | |
| if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) { | |
| t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame) | |
| } | |
| frame, err = reader.ReadFrame() | |
| if err != nil { | |
| t.Fatal("ReadFrame (SYN_STREAM):", err) | |
| } | |
| parsedSynStreamFrame, ok := frame.(*SynStreamFrame) | |
| if !ok { | |
| t.Fatal("Parsed incorrect frame type.") | |
| } | |
| if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) { | |
| t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame) | |
| } | |
| } |