Process more settings. Several aren't used yet.

Also, move settings code from frame.go to http2.go.
diff --git a/frame.go b/frame.go
index 12dd565..7bc93e1 100644
--- a/frame.go
+++ b/frame.go
@@ -108,35 +108,6 @@
 	},
 }
 
-// A SettingID is an HTTP/2 setting as defined in
-// http://http2.github.io/http2-spec/#iana-settings
-type SettingID uint16
-
-const (
-	SettingHeaderTableSize      SettingID = 0x1
-	SettingEnablePush           SettingID = 0x2
-	SettingMaxConcurrentStreams SettingID = 0x3
-	SettingInitialWindowSize    SettingID = 0x4
-	SettingMaxFrameSize         SettingID = 0x5
-	SettingMaxHeaderListSize    SettingID = 0x6
-)
-
-var settingName = map[SettingID]string{
-	SettingHeaderTableSize:      "HEADER_TABLE_SIZE",
-	SettingEnablePush:           "ENABLE_PUSH",
-	SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
-	SettingInitialWindowSize:    "INITIAL_WINDOW_SIZE",
-	SettingMaxFrameSize:         "MAX_FRAME_SIZE",
-	SettingMaxHeaderListSize:    "MAX_HEADER_LIST_SIZE",
-}
-
-func (s SettingID) String() string {
-	if v, ok := settingName[s]; ok {
-		return v
-	}
-	return fmt.Sprintf("UNKNOWN_SETTING_%d", uint8(s))
-}
-
 // a frameParser parses a frame given its FrameHeader and payload
 // bytes. The length of payload will always equal fh.Length (which
 // might be 0).
@@ -518,16 +489,6 @@
 	return nil
 }
 
-// Setting is a setting parameter: which setting it is, and its value.
-type Setting struct {
-	// ID is which setting is being set.
-	// See http://http2.github.io/http2-spec/#SettingValues
-	ID SettingID
-
-	// Val is the value.
-	Val uint32
-}
-
 // WriteSettings writes a SETTINGS frame with zero or more settings
 // specified and the ACK bit not set.
 //
diff --git a/http2.go b/http2.go
index b17a9c6..708f00d 100644
--- a/http2.go
+++ b/http2.go
@@ -17,6 +17,7 @@
 package http2
 
 import (
+	"fmt"
 	"net/http"
 	"strconv"
 )
@@ -70,6 +71,69 @@
 	return stateName[st]
 }
 
+// Setting is a setting parameter: which setting it is, and its value.
+type Setting struct {
+	// ID is which setting is being set.
+	// See http://http2.github.io/http2-spec/#SettingValues
+	ID SettingID
+
+	// Val is the value.
+	Val uint32
+}
+
+func (s Setting) String() string {
+	return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
+}
+
+// Valid reports whether the setting is valid.
+func (s Setting) Valid() error {
+	// Limits and error codes from 6.5.2 Defined SETTINGS Parameters
+	switch s.ID {
+	case SettingEnablePush:
+		if s.Val != 1 && s.Val != 0 {
+			return ConnectionError(ErrCodeProtocol)
+		}
+	case SettingInitialWindowSize:
+		if s.Val > 1<<31-1 {
+			return ConnectionError(ErrCodeFlowControl)
+		}
+	case SettingMaxFrameSize:
+		if s.Val < 16384 || s.Val > 1<<24-1 {
+			return ConnectionError(ErrCodeProtocol)
+		}
+	}
+	return nil
+}
+
+// A SettingID is an HTTP/2 setting as defined in
+// http://http2.github.io/http2-spec/#iana-settings
+type SettingID uint16
+
+const (
+	SettingHeaderTableSize      SettingID = 0x1
+	SettingEnablePush           SettingID = 0x2
+	SettingMaxConcurrentStreams SettingID = 0x3
+	SettingInitialWindowSize    SettingID = 0x4
+	SettingMaxFrameSize         SettingID = 0x5
+	SettingMaxHeaderListSize    SettingID = 0x6
+)
+
+var settingName = map[SettingID]string{
+	SettingHeaderTableSize:      "HEADER_TABLE_SIZE",
+	SettingEnablePush:           "ENABLE_PUSH",
+	SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
+	SettingInitialWindowSize:    "INITIAL_WINDOW_SIZE",
+	SettingMaxFrameSize:         "MAX_FRAME_SIZE",
+	SettingMaxHeaderListSize:    "MAX_HEADER_LIST_SIZE",
+}
+
+func (s SettingID) String() string {
+	if v, ok := settingName[s]; ok {
+		return v
+	}
+	return fmt.Sprintf("UNKNOWN_SETTING_%d", uint8(s))
+}
+
 func validHeader(v string) bool {
 	if len(v) == 0 {
 		return false
diff --git a/http2_test.go b/http2_test.go
index fa11422..8007913 100644
--- a/http2_test.go
+++ b/http2_test.go
@@ -26,6 +26,21 @@
 	flag.BoolVar(&VerboseLogs, "verboseh2", false, "Verbose HTTP/2 debug logging")
 }
 
+func TestSettingString(t *testing.T) {
+	tests := []struct {
+		s    Setting
+		want string
+	}{
+		{Setting{SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"},
+	}
+	for i, tt := range tests {
+		got := fmt.Sprint(tt.s)
+		if got != tt.want {
+			t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want)
+		}
+	}
+}
+
 type twriter struct {
 	t testing.TB
 }
diff --git a/server.go b/server.go
index 4f30990..a84f0f0 100644
--- a/server.go
+++ b/server.go
@@ -88,21 +88,24 @@
 
 func (srv *Server) handleConn(hs *http.Server, c net.Conn, h http.Handler) {
 	sc := &serverConn{
-		hs:                hs,
-		conn:              c,
-		handler:           h,
-		framer:            NewFramer(c, c), // TODO: write to a (custom?) buffered writer that can alternate when it's in buffered mode.
-		streams:           make(map[uint32]*stream),
-		readFrameCh:       make(chan frameAndGate),
-		readFrameErrCh:    make(chan error, 1), // must be buffered for 1
-		wantWriteFrameCh:  make(chan frameWriteMsg, 8),
-		writeFrameCh:      make(chan frameWriteMsg, 1), // may be 0 or 1, but more is useless. (max 1 in flight)
-		wroteFrameCh:      make(chan struct{}, 1),
-		flow:              newFlow(initialWindowSize),
-		doneServing:       make(chan struct{}),
-		maxWriteFrameSize: initialMaxFrameSize,
-		initialWindowSize: initialWindowSize,
-		serveG:            newGoroutineLock(),
+		hs:                   hs,
+		conn:                 c,
+		handler:              h,
+		framer:               NewFramer(c, c), // TODO: write to a (custom?) buffered writer that can alternate when it's in buffered mode.
+		streams:              make(map[uint32]*stream),
+		readFrameCh:          make(chan frameAndGate),
+		readFrameErrCh:       make(chan error, 1), // must be buffered for 1
+		wantWriteFrameCh:     make(chan frameWriteMsg, 8),
+		writeFrameCh:         make(chan frameWriteMsg, 1), // may be 0 or 1, but more is useless. (max 1 in flight)
+		wroteFrameCh:         make(chan struct{}, 1),
+		flow:                 newFlow(initialWindowSize),
+		doneServing:          make(chan struct{}),
+		maxWriteFrameSize:    initialMaxFrameSize,
+		initialWindowSize:    initialWindowSize,
+		headerTableSize:      initialHeaderTableSize,
+		maxConcurrentStreams: -1, // no limit
+		serveG:               newGoroutineLock(),
+		pushEnabled:          true,
 	}
 	sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
 	sc.hpackDecoder = hpack.NewDecoder(initialHeaderTableSize, sc.onNewHeaderField)
@@ -142,12 +145,16 @@
 	flow   *flow         // connection-wide (not stream-specific) flow control
 
 	// Everything following is owned by the serve loop; use serveG.check():
+	pushEnabled           bool
 	sawFirstSettings      bool // got the initial SETTINGS frame after the preface
 	needToSendSettingsAck bool
 	maxStreamID           uint32 // max ever seen
 	streams               map[uint32]*stream
-	maxWriteFrameSize     uint32 // TODO: update this when settings come in
+	maxWriteFrameSize     uint32
 	initialWindowSize     int32
+	headerTableSize       uint32
+	maxHeaderListSize     uint32            // zero means unknown (default)
+	maxConcurrentStreams  int64             // negative means no limit.
 	canonHeader           map[string]string // http2-lower-case -> Go-Canonical-Case
 	sentGoAway            bool
 	req                   requestParam    // non-zero while reading request headers
@@ -723,24 +730,39 @@
 
 func (sc *serverConn) processSetting(s Setting) error {
 	sc.serveG.check()
+	if err := s.Valid(); err != nil {
+		return err
+	}
 	sc.vlogf("processing setting %v", s)
 	switch s.ID {
+	case SettingHeaderTableSize:
+		sc.headerTableSize = s.Val
+		return nil
+	case SettingEnablePush:
+		sc.pushEnabled = s.Val != 0
+		return nil
+	case SettingMaxConcurrentStreams:
+		sc.maxConcurrentStreams = int64(s.Val)
+		return nil
 	case SettingInitialWindowSize:
 		return sc.processSettingInitialWindowSize(s.Val)
+	case SettingMaxFrameSize:
+		sc.maxWriteFrameSize = s.Val
+		return nil
+	case SettingMaxHeaderListSize:
+		sc.maxHeaderListSize = s.Val
+		return nil
 	}
-	log.Printf("TODO: handle %v", s)
+	// Unknown setting: "An endpoint that receives a SETTINGS
+	// frame with any unknown or unsupported identifier MUST
+	// ignore that setting."
 	return nil
 }
 
 func (sc *serverConn) processSettingInitialWindowSize(val uint32) error {
 	sc.serveG.check()
-	if val > (1<<31 - 1) {
-		// 6.5.2 Defined SETTINGS Parameters
-		// "Values above the maximum flow control window size of
-		// 231-1 MUST be treated as a connection error (Section
-		// 5.4.1) of type FLOW_CONTROL_ERROR."
-		return ConnectionError(ErrCodeFlowControl)
-	}
+	// Note: val already validated to be within range by
+	// processSetting's Valid call.
 
 	// "A SETTINGS frame can alter the initial flow control window
 	// size for all current streams. When the value of