Browse Source

Add Framer.WriteWindowUpdate

Brad Fitzpatrick 11 years ago
parent
commit
111670c41c
2 changed files with 59 additions and 1 deletions
  1. 29 1
      frame.go
  2. 30 0
      frame_test.go

+ 29 - 1
frame.go

@@ -613,12 +613,40 @@ func parseWindowUpdateFrame(fh FrameHeader, p []byte) (Frame, error) {
 	if len(p) != 4 {
 		return nil, ConnectionError(ErrCodeFrameSize)
 	}
+	inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit
+	if inc == 0 {
+		// A receiver MUST treat the receipt of a
+		// WINDOW_UPDATE frame with an flow control window
+		// increment of 0 as a stream error (Section 5.4.2) of
+		// type PROTOCOL_ERROR; errors on the connection flow
+		// control window MUST be treated as a connection
+		// error (Section 5.4.1).
+		if fh.StreamID == 0 {
+			return nil, ConnectionError(ErrCodeProtocol)
+		}
+		return nil, StreamError(ErrCodeProtocol)
+	}
 	return &WindowUpdateFrame{
 		FrameHeader: fh,
-		Increment:   binary.BigEndian.Uint32(p[:4]) & 0x7fffffff, // mask off high reserved bit
+		Increment:   inc,
 	}, nil
 }
 
+// WriteWindowUpdate writes a WINDOW_UPDATE frame.
+// The increment value must be between 1 and 2,147,483,647, inclusive.
+// If the Stream ID is zero, the window update applies to the
+// connection as a whole.
+func (f *Framer) WriteWindowUpdate(streamID, incr uint32) error {
+	// "The legal range for the increment to the flow control window is 1 to 2^31-1 (2,147,483,647) octets."
+	if (incr < 1 || incr > 2147483647) && !f.AllowIllegalWrites {
+		return errors.New("illegal window increment value")
+	}
+	f.startWrite(FrameWindowUpdate, 0, streamID)
+	f.writeUint32(incr)
+	return f.endWrite()
+
+}
+
 // A HeadersFrame is used to open a stream and additionally carries a
 // header block fragment.
 type HeadersFrame struct {

+ 30 - 0
frame_test.go

@@ -332,3 +332,33 @@ func TestWriteSettingsAck(t *testing.T) {
 		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
 	}
 }
+
+func TestWriteWindowUpdate(t *testing.T) {
+	fr, buf := testFramer()
+	const streamID = 1<<24 + 2<<16 + 3<<8 + 4
+	const incr = 7<<24 + 6<<16 + 5<<8 + 4
+	if err := fr.WriteWindowUpdate(streamID, incr); err != nil {
+		t.Fatal(err)
+	}
+	const wantEnc = "\x00\x00\x04\x08\x00\x01\x02\x03\x04\x07\x06\x05\x04"
+	if buf.String() != wantEnc {
+		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
+	}
+	f, err := fr.ReadFrame()
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := &WindowUpdateFrame{
+		FrameHeader: FrameHeader{
+			valid:    true,
+			Type:     0x8,
+			Flags:    0x0,
+			Length:   0x4,
+			StreamID: 0x1020304,
+		},
+		Increment: 0x7060504,
+	}
+	if !reflect.DeepEqual(f, want) {
+		t.Errorf("parsed back %#v; want %#v", f, want)
+	}
+}