Skip to content

Commit de309f7

Browse files
authored
Expose synchronize flush (#16)
1 parent ed274a7 commit de309f7

File tree

4 files changed

+42
-8
lines changed

4 files changed

+42
-8
lines changed

lib/protocol/http2/connection.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,14 @@ def ignore_frame?(frame)
143143
end
144144
end
145145

146+
def synchronize
147+
yield
148+
end
149+
146150
# Reads one frame from the network and processes. Processing the frame updates the state of the connection and related streams. If the frame triggers an error, e.g. a protocol error, the connection will typically emit a goaway frame and re-raise the exception. You should continue processing frames until the underlying connection is closed.
147151
def read_frame
148152
frame = @framer.read_frame(@local_settings.maximum_frame_size)
153+
149154
# puts "#{self.class} #{@state} read_frame: class=#{frame.class} stream_id=#{frame.stream_id} flags=#{frame.flags} length=#{frame.length} (remote_stream_id=#{@remote_stream_id})"
150155
# puts "Windows: local_window=#{@local_window.inspect}; remote_window=#{@remote_window.inspect}"
151156

@@ -207,12 +212,18 @@ def receive_goaway(frame)
207212
end
208213

209214
def write_frame(frame)
210-
@framer.write_frame(frame)
215+
synchronize do
216+
@framer.write_frame(frame)
217+
@framer.flush
218+
end
211219
end
212220

213221
def write_frames
214222
if @framer
215-
yield @framer
223+
synchronize do
224+
yield @framer
225+
@framer.flush
226+
end
216227
else
217228
raise EOFError, "Connection closed!"
218229
end

lib/protocol/http2/framer.rb

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ def initialize(stream, frames = FRAMES)
4141
@frames = frames
4242
end
4343

44+
def flush
45+
@stream.flush
46+
end
47+
4448
def close
4549
@stream.close
4650
end
@@ -69,7 +73,7 @@ def read_frame(maximum_frame_size = MAXIMUM_ALLOWED_FRAME_SIZE)
6973
# Read the header:
7074
length, type, flags, stream_id = read_header
7175

72-
# Async.logger.debug(self) {"read_frame: length=#{length} type=#{type} flags=#{flags} stream_id=#{stream_id} -> klass=#{@frames[type].inspect}"}
76+
# Console.debug(self) {"read_frame: length=#{length} type=#{type} flags=#{flags} stream_id=#{stream_id} -> klass=#{@frames[type].inspect}"}
7377

7478
# Allocate the frame:
7579
klass = @frames[type] || Frame
@@ -78,19 +82,19 @@ def read_frame(maximum_frame_size = MAXIMUM_ALLOWED_FRAME_SIZE)
7882
# Read the payload:
7983
frame.read(@stream, maximum_frame_size)
8084

81-
# Async.logger.debug(self, name: "read") {frame.inspect}
85+
# Console.debug(self, name: "read") {frame.inspect}
8286

8387
return frame
8488
end
8589

90+
# Write a frame to the underlying IO.
91+
# After writing one or more frames, you should call flush to ensure the frames are sent to the remote peer.
92+
# @parameter frame [Frame] the frame to write.
8693
def write_frame(frame)
87-
# Async.logger.debug(self, name: "write") {frame.inspect}
94+
# Console.debug(self, name: "write") {frame.inspect}
8895

8996
frame.write(@stream)
9097

91-
# Don't call @stream.flush here because it can cause significant contention if there is a semaphore around this method.
92-
# @stream.flush
93-
9498
return frame
9599
end
96100

test/protocol/http2/framer.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99
let(:stream) {StringIO.new}
1010
let(:framer) {subject.new(stream)}
1111

12+
with "#flush" do
13+
it "flushes the underlying stream" do
14+
expect(stream).to receive(:flush)
15+
framer.flush
16+
end
17+
end
18+
1219
with "#closed?" do
1320
it "reports the status of the underlying stream" do
1421
expect(stream).to receive(:closed?).and_return(true)

test/protocol/http2/server.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@
4242
expect(server.state).to be == :new
4343
end
4444

45+
it "fails with protocol error if first frame is not settings frame" do
46+
framer.write_connection_preface
47+
48+
data_frame = Protocol::HTTP2::DataFrame.new
49+
data_frame.pack("Hello, World!")
50+
framer.write_frame(data_frame)
51+
52+
expect do
53+
server.read_connection_preface
54+
end.to raise_exception(Protocol::HTTP2::ProtocolError, message: be =~ /First frame must be #{Protocol::HTTP2::SettingsFrame}/)
55+
end
56+
4557
it "cannot read connection preface in open state" do
4658
server.open!
4759
expect do

0 commit comments

Comments
 (0)