Class: Raptor::Http2::ResponseStream

Inherits:
Object
  • Object
show all
Defined in:
lib/raptor/http2.rb,
sig/generated/raptor/http2.rbs

Overview

Adapts one HTTP/2 response stream to Rack's streaming body interface.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(socket, writer, flow_control, stream_id, trailers) ⇒ ResponseStream

Creates a response stream for a Rack streaming body.

Parameters:

  • socket (OpenSSL::SSL::SSLSocket) —

    the connection socket

  • writer (Writer) —

    frame writer for the connection

  • flow_control (FlowControl) —

    outbound flow controller

  • stream_id (Integer) —

    the HTTP/2 stream identifier

  • trailers (Hash) —

    trailing response headers populated by the Rack application



315
316
317
318
319
320
321
322
323
324
# File 'lib/raptor/http2.rb', line 315

def initialize(socket, writer, flow_control, stream_id, trailers)
  @socket = socket
  @writer = writer
  @flow_control = flow_control
  @stream_id = stream_id
  @trailers = trailers
  @parser = Http2Parser.new
  @bytes_written = 0
  @closed = false
end

Instance Attribute Details

#bytes_written ⇒ Integer (readonly)

Returns the number of response body bytes written to the stream.

Returns:

  • (Integer)


303
304
305
# File 'lib/raptor/http2.rb', line 303

def bytes_written
  @bytes_written
end

Instance Method Details

#<<(chunk) ⇒ ResponseStream

Writes response body bytes and returns the stream.

Parameters:

  • chunk (String) —

    response body bytes

Returns:



363
364
365
366
# File 'lib/raptor/http2.rb', line 363

def <<(chunk)
  write(chunk)
  self
end

#close ⇒ void

This method returns an undefined value.

Finishes the stream.



382
383
384
385
386
387
388
389
390
391
392
393
394
# File 'lib/raptor/http2.rb', line 382

def close
  return if @closed

  @flow_control.check(@stream_id)
  @closed = true
  if @trailers.empty?
    frame = @parser.build_frame(:data, FLAG_END_STREAM, @stream_id, nil)
  else
    encoded = @parser.encode_response_trailers(@trailers)
    frame = @parser.build_frame(:headers, FLAG_END_STREAM | FLAG_END_HEADERS, @stream_id, encoded)
  end
  @writer.write_frames(@socket, [frame])
end

#close_read ⇒ bot

Closes the unsupported read side of the stream.

Returns:

  • (bot)

Raises:

  • (IOError)


401
402
403
# File 'lib/raptor/http2.rb', line 401

def close_read
  raise IOError, "closing non-duplex IO for reading"
end

#close_write ⇒ void

This method returns an undefined value.

Finishes the writable side of the stream.



410
411
412
# File 'lib/raptor/http2.rb', line 410

def close_write
  close
end

#closed? ⇒ Boolean

Returns whether the stream has finished.

Returns:

  • (Boolean)


419
420
421
# File 'lib/raptor/http2.rb', line 419

def closed?
  @closed
end

#flush ⇒ ResponseStream

Flushes the stream. Frame writes are already immediate.

Returns:



373
374
375
# File 'lib/raptor/http2.rb', line 373

def flush
  self
end

#read ⇒ bot

Streaming responses are write-only.

Parameters:

  • (Object)

Returns:

  • (bot)

Raises:

  • (IOError)


331
332
333
# File 'lib/raptor/http2.rb', line 331

def read(*)
  raise IOError, "not opened for reading"
end

#write(chunk) ⇒ Integer

Writes response body bytes to the stream.

Parameters:

  • chunk (String) —

    response body bytes

Returns:

  • (Integer) —

    number of bytes written



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/raptor/http2.rb', line 341

def write(chunk)
  raise IOError, "closed stream" if @closed
  raise TypeError, "body must yield String values" unless chunk.is_a?(String)

  offset = 0
  while offset < chunk.bytesize
    granted = @flow_control.acquire(@stream_id, chunk.bytesize - offset)
    slice = offset.zero? && granted == chunk.bytesize ? chunk : chunk.byteslice(offset, granted)
    offset += granted
    @writer.write_frames(@socket, [@parser.build_frame(:data, 0, @stream_id, slice)])
  end

  @bytes_written += chunk.bytesize
  chunk.bytesize
end