Module: Protocol::HTTP2::FlowControl

Included in:
Connection, Stream
Defined in:
lib/protocol/http2/flow_control.rb

Instance Method Summary collapse

Instance Method Details

#available_frame_size(maximum_frame_size = self.maximum_frame_size) ⇒ Object

This could be negative if the window has been overused due to a change in initial window size.



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/protocol/http2/flow_control.rb', line 31

def available_frame_size(maximum_frame_size = self.maximum_frame_size)
	available_size = self.available_size
	
	# puts "available_size=#{available_size} maximum_frame_size=#{maximum_frame_size}"
	
	if available_size < maximum_frame_size
		return available_size
	else
		return maximum_frame_size
	end
end

#available_sizeObject



26
27
28
# File 'lib/protocol/http2/flow_control.rb', line 26

def available_size
	@remote_window.available
end

#consume_local_window(frame) ⇒ Object



57
58
59
60
61
62
63
64
65
# File 'lib/protocol/http2/flow_control.rb', line 57

def consume_local_window(frame)
	amount = frame.length
	
	@local_window.consume(amount)
	
	if @local_window.limited?
		self.send_window_update(@local_window.used)
	end
end

#consume_remote_window(frame) ⇒ Object

Keep track of the amount of data sent, and fail if is too much.



44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/protocol/http2/flow_control.rb', line 44

def consume_remote_window(frame)
	amount = frame.length
	
	# Frames with zero length with the END_STREAM flag set (that is, an empty DATA frame) MAY be sent if there is no available space in either flow-control window.
	if amount.zero? and frame.end_stream?
		# It's okay, we can send. No need to consume, it's empty anyway.
	elsif amount >= 0 and amount <= @remote_window.available
		@remote_window.consume(amount)
	else
		raise FlowControlError, "Trying to send #{frame.length} bytes, exceeded window size: #{@remote_window.available} (#{@remote_window})"
	end
end

#consume_window(size = self.available_size) ⇒ Object

Traverse active streams in order of priority and allow them to consume the available flow-control window.

Parameters:

  • amount (Integer)

    the amount of data to write. Defaults to the current window capacity.



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/protocol/http2/flow_control.rb', line 100

def consume_window(size = self.available_size)
	# Don't consume more than the available window size:
	size = [self.available_size, size].min
	# puts "consume_window(#{size}) local_window=#{@local_window} remote_window=#{@remote_window}"
	
	# Return if there is no window to consume:
	return unless size > 0
	
	# Allow the current flow-controlled instance to use up the window:
	if !self.window_updated(size) and children = self.children
		children = children.values.sort_by(&:weight)
		
		# This must always be at least >= `children.count`, since stream weight can't be 0.
		total = children.sum(&:weight)
		
		children.each do |child|
			# Compute the proportional allocation:
			allocated = (child.weight * size) / total
			child.consume_window(allocated)
		end
	end
end

#receive_window_update(frame) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/protocol/http2/flow_control.rb', line 77

def receive_window_update(frame)
	amount = frame.unpack
	
	# puts "expanding remote_window=#{@remote_window} by #{amount}"
	
	if amount != 0
		@remote_window.expand(amount)
	else
		raise ProtocolError, "Invalid window size increment: #{amount}!"
	end
	
	# puts "expanded remote_window=#{@remote_window} by #{amount}"
end

#send_window_update(window_increment) ⇒ Object

Notify the remote end that we are prepared to receive more data:



68
69
70
71
72
73
74
75
# File 'lib/protocol/http2/flow_control.rb', line 68

def send_window_update(window_increment)
	frame = WindowUpdateFrame.new(self.id)
	frame.pack window_increment
	
	write_frame(frame)
	
	@local_window.expand(window_increment)
end

#window_updated(size = self.available_size) ⇒ Boolean

The window has been expanded by the given amount.

Parameters:

  • size (Integer) (defaults to: self.available_size)

    the maximum amount of data to send.

Returns:

  • (Boolean)

    whether the window update was used or not.



94
95
96
# File 'lib/protocol/http2/flow_control.rb', line 94

def window_updated(size = self.available_size)
	return false
end