From 828af96d4226442eeb69a807c03c909e565c99f7 Mon Sep 17 00:00:00 2001
From: iamqizhao <toqizhao@gmail.com>
Date: Tue, 31 Mar 2015 19:05:09 -0700
Subject: [PATCH] send settingsAck when receiving a settings frame following
 http2 spec

---
 transport/control.go      |  4 ++--
 transport/http2_client.go | 10 +++++++++-
 transport/http2_server.go | 10 +++++++++-
 3 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/transport/control.go b/transport/control.go
index 056d8ac9..6baa634e 100644
--- a/transport/control.go
+++ b/transport/control.go
@@ -60,8 +60,8 @@ func (windowUpdate) isItem() bool {
 }
 
 type settings struct {
-	id  http2.SettingID
-	val uint32
+	ack bool
+	setting []http2.Setting
 }
 
 func (settings) isItem() bool {
diff --git a/transport/http2_client.go b/transport/http2_client.go
index 28caf6c4..3c1044be 100644
--- a/transport/http2_client.go
+++ b/transport/http2_client.go
@@ -524,6 +524,9 @@ func (t *http2Client) handleRSTStream(f *http2.RSTStreamFrame) {
 }
 
 func (t *http2Client) handleSettings(f *http2.SettingsFrame) {
+	if f.IsAck() {
+		return
+	}
 	f.ForeachSetting(func(s http2.Setting) error {
 		if v, ok := f.Value(s.ID); ok {
 			t.mu.Lock()
@@ -541,6 +544,7 @@ func (t *http2Client) handleSettings(f *http2.SettingsFrame) {
 		}
 		return nil
 	})
+	t.controlBuf.put(&settings{ack: true})
 }
 
 func (t *http2Client) handlePing(f *http2.PingFrame) {
@@ -680,7 +684,11 @@ func (t *http2Client) controller() {
 				case *windowUpdate:
 					t.framer.writeWindowUpdate(true, i.streamID, i.increment)
 				case *settings:
-					t.framer.writeSettings(true, http2.Setting{i.id, i.val})
+					if i.ack {
+						t.framer.writeSettingsAck(true)
+					} else {
+						t.framer.writeSettings(true, i.setting...)
+					}
 				case *resetStream:
 					t.framer.writeRSTStream(true, i.streamID, i.code)
 				case *flushIO:
diff --git a/transport/http2_server.go b/transport/http2_server.go
index 1609ac83..b43aef88 100644
--- a/transport/http2_server.go
+++ b/transport/http2_server.go
@@ -360,6 +360,9 @@ func (t *http2Server) handleRSTStream(f *http2.RSTStreamFrame) {
 }
 
 func (t *http2Server) handleSettings(f *http2.SettingsFrame) {
+	if f.IsAck() {
+		return
+	}
 	f.ForeachSetting(func(s http2.Setting) error {
 		if v, ok := f.Value(http2.SettingInitialWindowSize); ok {
 			t.mu.Lock()
@@ -371,6 +374,7 @@ func (t *http2Server) handleSettings(f *http2.SettingsFrame) {
 		}
 		return nil
 	})
+	t.controlBuf.put(&settings{ack: true})
 }
 
 func (t *http2Server) handlePing(f *http2.PingFrame) {
@@ -588,7 +592,11 @@ func (t *http2Server) controller() {
 				case *windowUpdate:
 					t.framer.writeWindowUpdate(true, i.streamID, i.increment)
 				case *settings:
-					t.framer.writeSettings(true, http2.Setting{i.id, i.val})
+					if i.ack {
+						t.framer.writeSettingsAck(true)
+					} else {
+						t.framer.writeSettings(true, i.setting...)
+					}
 				case *resetStream:
 					t.framer.writeRSTStream(true, i.streamID, i.code)
 				case *flushIO: