Class: Iodine::Http::Http2
- Defined in:
- lib/iodine/http/hpack.rb,
lib/iodine/http/http2.rb
Defined Under Namespace
Classes: HPACK
Instance Attribute Summary
Attributes inherited from Protocol
Class Method Summary collapse
-
.handshake(request, io, data) ⇒ Object
clear text handshake.
-
.pre_handshake(io, data) ⇒ Object
preknowledge handshake.
Instance Method Summary collapse
- #go_away(error_code) ⇒ Object
-
#initialize(io, original_request = nil) ⇒ Http2
constructor
A new instance of Http2.
-
#on_message(data) ⇒ Object
send connection preface (Section 3.5) consisting of a (can be empty) SETTINGS frame (Section 6.5).
- #on_open ⇒ Object
-
#on_shutdown ⇒ Object
Gracefully close HTTP/2 when possible.
- #ping ⇒ Object
- #push(request) ⇒ Object
- #send_response(response) ⇒ Object
- #stream_response(response, finish = false) ⇒ Object
Methods inherited from Protocol
#call, #close, #closed?, each, #id, #on_close, #read, #set_timeout, #ssl?, #timeout?, #write
Constructor Details
#initialize(io, original_request = nil) ⇒ Http2
Returns a new instance of Http2.
4 5 6 7 8 9 10 11 12 13 14 15 |
# File 'lib/iodine/http/http2.rb', line 4 def initialize io, original_request = nil super(io) return unless original_request ::Iodine.warn "Http/2: upgrade handshake settings not implemented. upgrade request:\n#{original_request}" @last_stream = original_request[:stream_id] = 1 original_request[:io] = self # deal with the request['http2-settings'] - NO ACK # HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload> # dispatch the original request ::Iodine.run original_request, &(::Iodine::Http::Http2.dispatch) end |
Class Method Details
.handshake(request, io, data) ⇒ Object
clear text handshake
108 109 110 111 112 113 114 115 |
# File 'lib/iodine/http/http2.rb', line 108 def self.handshake request, io, data return false unless request['upgrade'] =~ /h2c/ && request['http2-settings'] io.write "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: h2c\r\n\r\n" http_2 = self.new(io, request) unless data.eof? http_2. data.read end end |
.pre_handshake(io, data) ⇒ Object
preknowledge handshake
117 118 119 120 121 |
# File 'lib/iodine/http/http2.rb', line 117 def self.pre_handshake io, data return false unless data[0..23] == "PRI * HTTP\/2.0\r\n\r\nSM\r\n\r\n".freeze self.new(io). data true end |
Instance Method Details
#go_away(error_code) ⇒ Object
95 96 97 98 99 100 |
# File 'lib/iodine/http/http2.rb', line 95 def go_away error_code return false if @io.closed? @frame_locker.synchronize { emit_frame [@last_stream, error_code].pack('N*'), 0, 7 } close # Iodine.info "HTTP/2 connection closed with code #{error_code}" end |
#on_message(data) ⇒ Object
send connection preface (Section 3.5) consisting of a (can be empty) SETTINGS frame (Section 6.5).
should prepare to accept a client connection preface which starts with: 0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
PRI * HTTP/2.0rnrnSMrnrn
+ SETTINGS frame
56 57 58 59 60 61 |
# File 'lib/iodine/http/http2.rb', line 56 def data data = ::StringIO.new data parse_preface data unless @connected true while parse_frame data data.string.clear end |
#on_open ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/iodine/http/http2.rb', line 16 def on_open # not fully fanctional. ::Iodine.warn "Http/2 requested - support is still experimental." # update the timeout to 15 seconds (ping will be sent whenever timeout is reached). set_timeout 15 # Header compression is stateful @hpack = ::Iodine::Http::Http2::HPACK.new # the header-stream cache @header_buffer = '' @header_end_stream = false @header_sid = nil @frame_locker = Mutex.new # frame parser starting posotion @frame = {} # Open stream managment @open_streams = {} # connection is only established after the preface was sent @connected = false # the last stream to be processed (For the GOAWAY frame) @last_stream = 0 @refuese_new = false # @complete_stream = 0 # the settings state @settings = DEFAULT_SETTING.dup # send connection preface (Section 3.5) consisting of a (can be empty) SETTINGS frame (Section 6.5). # # should prepare to accept a client connection preface which starts with: # 0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a # == PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n # + SETTINGS frame end |
#on_shutdown ⇒ Object
Gracefully close HTTP/2 when possible
103 104 105 |
# File 'lib/iodine/http/http2.rb', line 103 def on_shutdown go_away NO_ERROR end |
#ping ⇒ Object
82 83 84 |
# File 'lib/iodine/http/http2.rb', line 82 def ping @frame_locker.synchronize { emit_frame "pniodine", 0, 6 } end |
#push(request) ⇒ Object
86 87 88 89 90 91 92 93 |
# File 'lib/iodine/http/http2.rb', line 86 def push request return false if @settings[SETTINGS_ENABLE_PUSH] == 0 @last_push ||= 0 # emit push promise emit_payload @hpack.encode(path: request[:path], method: request[:method], scheme: request[:scheme], authority: request[:authority]), (request[:sid] = (@last_push += 2)), 5, 4 # queue for app dispatch Iodine.run request, &::Iodine::Http::Http2.dispatch end |
#send_response(response) ⇒ Object
63 64 65 66 67 68 69 70 71 |
# File 'lib/iodine/http/http2.rb', line 63 def send_response response request = response.request return false unless send_headers response, request return nil if request.head? body = response.extract_body return (log_finished(response) && body.clear) if request.head? (response.bytes_written += emit_payload(body.to_s, request[:sid], 0, 1) ) && (body.frozen? || body.clear) if body log_finished response end |
#stream_response(response, finish = false) ⇒ Object
72 73 74 75 76 77 78 79 80 |
# File 'lib/iodine/http/http2.rb', line 72 def stream_response response, finish = false request = response.request send_headers response, request return nil if request.head? body = response.extract_body # puts "should stream #{body}" (response.bytes_written += emit_payload body.to_s, request[:sid], 0, (finish ? 1 : 0) ) && (body && !body.frozen? && body.clear) if body || finish log_finished response if finish end |