Class: Protocol::HTTP2::Framer

Inherits:
Object
  • Object
show all
Defined in:
lib/protocol/http2/framer.rb

Overview

Handles frame serialization and deserialization for HTTP/2 connections. This class manages the reading and writing of HTTP/2 frames to/from a stream.

Instance Method Summary collapse

Constructor Details

#initialize(stream, frames = FRAMES) ⇒ Framer

Initialize a new framer with a stream and frame definitions.



51
52
53
54
# File 'lib/protocol/http2/framer.rb', line 51

def initialize(stream, frames = FRAMES)
	@stream = stream
	@frames = frames
end

Instance Method Details

#closeObject

Close the underlying stream.



62
63
64
# File 'lib/protocol/http2/framer.rb', line 62

def close
	@stream.close
end

#closed?Boolean

Check if the underlying stream is closed.



68
69
70
# File 'lib/protocol/http2/framer.rb', line 68

def closed?
	@stream.closed?
end

#flushObject

Flush the underlying stream.



57
58
59
# File 'lib/protocol/http2/framer.rb', line 57

def flush
	@stream.flush
end

#read_connection_prefaceObject

Read and validate the HTTP/2 connection preface from the stream.



79
80
81
82
83
84
85
86
87
# File 'lib/protocol/http2/framer.rb', line 79

def read_connection_preface
	string = @stream.read(CONNECTION_PREFACE.bytesize)
	
	unless string == CONNECTION_PREFACE
		raise HandshakeError, "Invalid connection preface: #{string.inspect}"
	end
	
	return string
end

#read_frame(maximum_frame_size = MAXIMUM_ALLOWED_FRAME_SIZE) ⇒ Frame

Returns the frame that has been read from the underlying IO.

Raises:

  • if the underlying IO fails for some reason.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/protocol/http2/framer.rb', line 91

def read_frame(maximum_frame_size = MAXIMUM_ALLOWED_FRAME_SIZE)
	# Read the header:
	length, type, flags, stream_id = read_header
	
	# Console.debug(self) {"read_frame: length=#{length} type=#{type} flags=#{flags} stream_id=#{stream_id} -> klass=#{@frames[type].inspect}"}
	
	# Allocate the frame:
	klass = @frames[type] || Frame
	frame = klass.new(stream_id, flags, type, length)
	
	# Read the payload:
	frame.read(@stream, maximum_frame_size)
	
	# Console.debug(self, name: "read") {frame.inspect}
	
	return frame
end

#read_headerObject

Read a frame header from the stream.

Raises:

  • (EOFError)


123
124
125
126
127
128
129
130
131
# File 'lib/protocol/http2/framer.rb', line 123

def read_header
	if buffer = @stream.read(9)
		if buffer.bytesize == 9
			return Frame.parse_header(buffer)
		end
	end
	
	raise EOFError, "Could not read frame header!"
end

#write_connection_prefaceObject

Write the HTTP/2 connection preface to the stream.



73
74
75
# File 'lib/protocol/http2/framer.rb', line 73

def write_connection_preface
	@stream.write(CONNECTION_PREFACE)
end

#write_frame(frame) ⇒ Object

Write a frame to the underlying IO. After writing one or more frames, you should call flush to ensure the frames are sent to the remote peer.



112
113
114
115
116
117
118
# File 'lib/protocol/http2/framer.rb', line 112

def write_frame(frame)
	# Console.debug(self, name: "write") {frame.inspect}
	
	frame.write(@stream)
	
	return frame
end