Skip to content

Commit

Permalink
emit SETTINGS as part of connection header
Browse files Browse the repository at this point in the history
  • Loading branch information
igrigorik committed Oct 9, 2013
1 parent 9e67f60 commit 3438bc7
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 29 deletions.
7 changes: 5 additions & 2 deletions lib/http/2/client.rb
Expand Up @@ -20,12 +20,13 @@ module HTTP2
class Client < Connection

# Initialize new HTTP 2.0 client object.
def initialize
def initialize(*args)
@stream_id = 1
@state = :connection_header
@compressor = Header::Compressor.new(:request)
@decompressor = Header::Decompressor.new(:response)
super()

super
end

# Send an outgoing frame. Connection and stream flow control is managed
Expand All @@ -38,6 +39,8 @@ def send(frame)
if @state == :connection_header
emit(:frame, CONNECTION_HEADER)
@state = :connected

settings(stream_limit: @stream_limit, window_limit: @window_limit)
end

super(frame)
Expand Down
27 changes: 17 additions & 10 deletions lib/http/2/connection.rb
Expand Up @@ -40,14 +40,14 @@ class Connection

# Initializes new connection object.
#
def initialize
@stream_limit = Float::INFINITY
def initialize(streams: 100, window: DEFAULT_FLOW_WINDOW)
@stream_limit = streams
@active_stream_count = 0
@streams = {}

@framer = Framer.new
@window = DEFAULT_FLOW_WINDOW
@window_limit = DEFAULT_FLOW_WINDOW
@window = window
@window_limit = window

@recv_buffer = Buffer.new
@send_buffer = []
Expand Down Expand Up @@ -97,13 +97,19 @@ def goaway(error = :no_error, payload = nil)
@state = :closed
end

# Sends a connection SETTINGS frame to the peer.
# Sends a connection SETTINGS frame to the peer. Setting window size
# to Float::INFINITY disables flow control.
#
# @param payload [Hash]
# @option payload [Symbol] :settings_max_concurrent_streams
# @option payload [Symbol] :settings_flow_control_options
# @option payload [Symbol] :settings_initial_window_size
def settings(payload)
# @param stream_limit [Integer] maximum number of concurrent streams
# @param window_limit [Float] maximum flow window size
def settings(stream_limit: @stream_limit, window_limit: @window_limit)
payload = { settings_max_concurrent_streams: stream_limit }
if window_limit.to_f.infinite?
payload[:settings_flow_control_options] = 1
else
payload[:settings_initial_window_size] = window_limit
end

send({type: :settings, stream: 0, payload: payload})
end

Expand Down Expand Up @@ -134,6 +140,7 @@ def receive(data)
raise HandshakeError.new
else
@state = :connection_header
settings(stream_limit: @stream_limit, window_limit: @window_limit)
end
end

Expand Down
5 changes: 3 additions & 2 deletions lib/http/2/server.rb
Expand Up @@ -22,12 +22,13 @@ module HTTP2
class Server < Connection

# Initialize new HTTP 2.0 server object.
def initialize
def initialize(*args)
@stream_id = 2
@state = :new
@compressor = Header::Compressor.new(:response)
@decompressor = Header::Decompressor.new(:request)
super()

super
end

private
Expand Down
17 changes: 15 additions & 2 deletions spec/client_spec.rb
Expand Up @@ -12,12 +12,25 @@
@client.new_stream.id.should_not be_even
end

it "should emit connection header on new client connection" do
it "should emit connection header and SETTINGS on new client connection" do
frames = []
@client.on(:frame) { |bytes| frames << bytes }
@client.ping("12345678")

frames.first.should eq CONNECTION_HEADER
frames[0].should eq CONNECTION_HEADER
f.parse(frames[1])[:type].should eq :settings
end

it "should initialize client with custom connection settings" do
frames = []

@client = Client.new(streams: 200)
@client.on(:frame) { |bytes| frames << bytes }
@client.ping("12345678")

frame = f.parse(frames[1])
frame[:type].should eq :settings
frame[:payload][:settings_max_concurrent_streams].should eq 200
end
end

Expand Down
21 changes: 8 additions & 13 deletions spec/connection_spec.rb
Expand Up @@ -25,8 +25,8 @@
end

context "stream management" do
it "should initialize to default stream limit (infinite)" do
@conn.stream_limit.should eq Float::INFINITY
it "should initialize to default stream limit (100)" do
@conn.stream_limit.should eq 100
end

it "should change stream limit to received SETTINGS value" do
Expand Down Expand Up @@ -246,10 +246,7 @@
it "should emit encoded frames via on(:frame)" do
bytes = nil
@conn.on(:frame) {|d| bytes = d }
@conn.settings({
settings_max_concurrent_streams: 10,
settings_flow_control_options: 1
})
@conn.settings(stream_limit: 10, window_limit: Float::INFINITY)

bytes.should eq f.generate(SETTINGS)
end
Expand Down Expand Up @@ -361,18 +358,16 @@

context "API" do
it ".settings should emit SETTINGS frames" do
settings = {
settings_max_concurrent_streams: 10,
settings_flow_control_options: 1
}

@conn.should_receive(:send) do |frame|
frame[:type].should eq :settings
frame[:payload].should eq settings
frame[:payload].should eq({
settings_max_concurrent_streams: 10,
settings_flow_control_options: 1
})
frame[:stream].should eq 0
end

@conn.settings settings
@conn.settings(stream_limit: 10, window_limit: Float::INFINITY)
end

it ".ping should generate PING frames" do
Expand Down
21 changes: 21 additions & 0 deletions spec/server_spec.rb
Expand Up @@ -11,6 +11,27 @@
it "should return even stream IDs" do
@srv.new_stream.id.should be_even
end

it "should emit SETTINGS on new connection" do
frames = []
@srv.on(:frame) { |recv| frames << recv }
@srv << CONNECTION_HEADER

f.parse(frames[0])[:type].should eq :settings
end

it "should initialize client with custom connection settings" do
frames = []

@srv = Server.new(streams: 200, window: 2**10)
@srv.on(:frame) { |recv| frames << recv }
@srv << CONNECTION_HEADER

frame = f.parse(frames[0])
frame[:type].should eq :settings
frame[:payload][:settings_max_concurrent_streams].should eq 200
frame[:payload][:settings_initial_window_size].should eq 2**10
end
end

it "should allow server push" do
Expand Down

0 comments on commit 3438bc7

Please sign in to comment.