Skip to content

Commit 21c3864

Browse files
dimsthaJeztah
authored andcommitted
Add options to customize limits
Guard against oversized SPDY frames Signed-off-by: Davanum Srinivas <davanum@gmail.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent acf9b45 commit 21c3864

5 files changed

Lines changed: 99 additions & 1 deletion

File tree

connection.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,13 @@ type Connection struct {
224224
// NewConnection creates a new spdy connection from an existing
225225
// network connection.
226226
func NewConnection(conn net.Conn, server bool) (*Connection, error) {
227-
framer, framerErr := spdy.NewFramer(conn, conn)
227+
return NewConnectionWithOptions(conn, server)
228+
}
229+
230+
// NewConnectionWithOptions creates a new spdy connection and applies frame
231+
// parsing limits via options.
232+
func NewConnectionWithOptions(conn net.Conn, server bool, opts ...spdy.FramerOption) (*Connection, error) {
233+
framer, framerErr := spdy.NewFramerWithOptions(conn, conn, opts...)
228234
if framerErr != nil {
229235
return nil, framerErr
230236
}

spdy/options.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package spdy
2+
3+
// FramerOption allows callers to customize frame parsing limits.
4+
type FramerOption func(*Framer)
5+
6+
// WithMaxControlFramePayloadSize sets the control-frame payload limit.
7+
func WithMaxControlFramePayloadSize(size uint32) FramerOption {
8+
return func(f *Framer) {
9+
f.maxFrameLength = size
10+
}
11+
}
12+
13+
// WithMaxHeaderFieldSize sets the per-header name/value size limit.
14+
func WithMaxHeaderFieldSize(size uint32) FramerOption {
15+
return func(f *Framer) {
16+
f.maxHeaderFieldSize = size
17+
}
18+
}
19+
20+
// WithMaxHeaderCount sets the maximum number of headers in a frame.
21+
func WithMaxHeaderCount(count uint32) FramerOption {
22+
return func(f *Framer) {
23+
f.maxHeaderCount = count
24+
}
25+
}

spdy/options_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package spdy
2+
3+
import (
4+
"net"
5+
"testing"
6+
)
7+
8+
func TestNewFramerWithOptions(t *testing.T) {
9+
serverConn, clientConn := net.Pipe()
10+
defer func() {
11+
_ = clientConn.Close()
12+
_ = serverConn.Close()
13+
}()
14+
15+
framer, err := NewFramerWithOptions(clientConn, clientConn,
16+
WithMaxControlFramePayloadSize(1024),
17+
WithMaxHeaderFieldSize(128),
18+
WithMaxHeaderCount(16),
19+
)
20+
if err != nil {
21+
t.Fatalf("Error creating spdy connection with options: %s", err)
22+
}
23+
24+
if got := framer.maxFrameLength; got != 1024 {
25+
t.Fatalf("Unexpected MaxControlFramePayloadSize: %d", got)
26+
}
27+
if got := framer.maxHeaderFieldSize; got != 128 {
28+
t.Fatalf("Unexpected MaxHeaderFieldSize: %d", got)
29+
}
30+
if got := framer.maxHeaderCount; got != 16 {
31+
t.Fatalf("Unexpected MaxHeaderCount: %d", got)
32+
}
33+
}

spdy/types.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,16 @@ type Framer struct {
278278
// from/to the Reader and Writer, so the caller should pass in an appropriately
279279
// buffered implementation to optimize performance.
280280
func NewFramer(w io.Writer, r io.Reader) (*Framer, error) {
281+
return newFramer(w, r)
282+
}
283+
284+
// NewFramerWithOptions allocates a new Framer for a given SPDY connection and
285+
// applies frame parsing limits via options.
286+
func NewFramerWithOptions(w io.Writer, r io.Reader, opts ...FramerOption) (*Framer, error) {
287+
return newFramer(w, r, opts...)
288+
}
289+
290+
func newFramer(w io.Writer, r io.Reader, opts ...FramerOption) (*Framer, error) {
281291
compressBuf := new(bytes.Buffer)
282292
compressor, err := zlib.NewWriterLevelDict(compressBuf, zlib.BestCompression, []byte(headerDictionary))
283293
if err != nil {
@@ -289,5 +299,10 @@ func NewFramer(w io.Writer, r io.Reader) (*Framer, error) {
289299
headerCompressor: compressor,
290300
r: r,
291301
}
302+
for _, opt := range opts {
303+
if opt != nil {
304+
opt(framer)
305+
}
306+
}
292307
return framer, nil
293308
}

spdy_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,25 @@ func TestSpdyStreams(t *testing.T) {
174174
wg.Wait()
175175
}
176176

177+
func TestNewConnectionWithOptions(t *testing.T) {
178+
serverConn, clientConn := net.Pipe()
179+
defer func() {
180+
_ = clientConn.Close()
181+
_ = serverConn.Close()
182+
}()
183+
184+
_, err := NewConnectionWithOptions(
185+
clientConn,
186+
false,
187+
spdy.WithMaxControlFramePayloadSize(1024),
188+
spdy.WithMaxHeaderFieldSize(128),
189+
spdy.WithMaxHeaderCount(16),
190+
)
191+
if err != nil {
192+
t.Fatalf("Error creating spdy connection with options: %s", err)
193+
}
194+
}
195+
177196
func TestPing(t *testing.T) {
178197
var wg sync.WaitGroup
179198
server, listen, serverErr := runServer(&wg)

0 commit comments

Comments
 (0)