Class: Protocol::HTTP::Body::Stream

Inherits:
Object
  • Object
show all
Includes:
Reader
Defined in:
lib/protocol/http/body/stream.rb

Overview

The input stream is an IO-like object which contains the raw HTTP POST data. When applicable, its external encoding must be "ASCII-8BIT" and it must be opened in binary mode, for Ruby 1.9 compatibility. The input stream must respond to gets, each, read and rewind.

Defined Under Namespace

Modules: Reader

Constant Summary collapse

NEWLINE =

The default line separator, used by Reader#gets.

"\n"

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Reader

#each, #gets, #read, #read_nonblock, #read_partial, #read_until, #readpartial

Constructor Details

#initialize(input = nil, output = nil) ⇒ Stream

Initialize the stream with the given input and output.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/protocol/http/body/stream.rb', line 20

def initialize(input = nil, output = nil)
  @input = input
  @output = output
  
  if @output
    raise ArgumentError, "Non-writable output!" unless output.respond_to?(:write)
  end
  
  # Will hold remaining data in `#read`.
  @buffer = nil
  
  @closed = false
  @closed_read = false
end

Instance Attribute Details

#inputObject (readonly)

Returns the value of attribute input.



36
37
38
# File 'lib/protocol/http/body/stream.rb', line 36

def input
  @input
end

#outputObject (readonly)

Returns the value of attribute output.



39
40
41
# File 'lib/protocol/http/body/stream.rb', line 39

def output
  @output
end

#The output stream.(outputstream.) ⇒ Object (readonly)



39
# File 'lib/protocol/http/body/stream.rb', line 39

attr :output

Instance Method Details

#<<(buffer) ⇒ Object

Write data to the stream using #write.



324
325
326
# File 'lib/protocol/http/body/stream.rb', line 324

def << buffer
  write(buffer)
end

#close(error = nil) ⇒ Object

Close the input and output bodies.

Closing without an error represents orderly completion or abandonment of both application-facing directions, not cancellation. If the peer has not completed the exchange, the protocol implementation may need to terminate it without reporting an application error.

Repeated calls are safe; each underlying direction will be closed at most once.



395
396
397
398
399
400
401
402
# File 'lib/protocol/http/body/stream.rb', line 395

def close(error = nil)
  self.close_read(error)
  self.close_write(error)
  
  return nil
ensure
  @closed = true
end

#close_read(error = nil) ⇒ Object

Close the application-facing input body. This does not close the output body, which may continue to be written independently.

If the input has not reached end-of-file, any remaining data is abandoned. The protocol implementation must ensure that unread data cannot interfere with subsequent exchanges. Depending on the protocol, it may discard the remaining data, terminate the current exchange, or make the connection non-reusable.

Closing without an error represents orderly application-level abandonment, not a protocol failure.

This method is idempotent. After the first call, subsequent calls have no effect.

If, while processing the data that was read from this stream, an error is encountered, it should be passed to this method.



361
362
363
364
365
366
367
368
369
# File 'lib/protocol/http/body/stream.rb', line 361

def close_read(error = nil)
  if input = @input
    @input = nil
    @closed_read = true
    @buffer = nil
    
    input.close(error)
  end
end

#close_write(error = nil) ⇒ Object

Close the application-facing output body. This does not close the input body, which may continue to be read independently.

Closing without an error indicates that no more output will be produced. Previously written data remains part of the output and should be followed by a normal end-of-stream from the protocol implementation. If an error is provided, the protocol implementation may terminate the exchange instead.

This method is idempotent. After the first call, subsequent calls have no effect.

If, while generating the data that is written to this stream, an error is encountered, it should be passed to this method.



380
381
382
383
384
385
386
# File 'lib/protocol/http/body/stream.rb', line 380

def close_write(error = nil)
  if output = @output
    @output = nil
    
    output.close_write(error)
  end
end

#closed?Boolean

Returns:



405
406
407
# File 'lib/protocol/http/body/stream.rb', line 405

def closed?
  @closed
end

#empty?Boolean

Returns:



425
426
427
428
429
430
431
# File 'lib/protocol/http/body/stream.rb', line 425

def empty?
  if @output
    return @output.empty?
  else
    return true
  end
end

#flushObject

Flush the output stream.

This is currently a no-op.



347
348
# File 'lib/protocol/http/body/stream.rb', line 347

def flush
end

#inspectObject

Inspect the stream.



412
413
414
415
416
417
418
419
420
421
422
# File 'lib/protocol/http/body/stream.rb', line 412

def inspect
  buffer_info = @buffer ? "#{@buffer.bytesize} bytes buffered" : "no buffer"
  
  status = []
  status << "closed" if @closed
  status << "read-closed" if @closed_read
  
  status_info = status.empty? ? "open" : status.join(", ")
  
  return "#<#{self.class} #{buffer_info}, #{status_info}>"
end

#puts(*arguments, separator: NEWLINE) ⇒ Object

Write lines to the stream.

The current implementation buffers the lines and writes them in a single operation.



334
335
336
337
338
339
340
341
342
# File 'lib/protocol/http/body/stream.rb', line 334

def puts(*arguments, separator: NEWLINE)
  buffer = ::String.new
  
  arguments.each do |argument|
    buffer << argument << separator
  end
  
  write(buffer)
end

#The input stream.=(inputstream. = (value)) ⇒ Object



36
# File 'lib/protocol/http/body/stream.rb', line 36

attr :input

#write(buffer) ⇒ Object

Write data to the underlying stream.



303
304
305
306
307
308
309
310
# File 'lib/protocol/http/body/stream.rb', line 303

def write(buffer)
  if @output
    @output.write(buffer)
    return buffer.bytesize
  else
    raise IOError, "Stream is not writable, output has been closed!"
  end
end

#write_nonblock(buffer, exception: nil) ⇒ Object

Write data to the stream using #write.

Provided for compatibility with IO-like objects.



319
320
321
# File 'lib/protocol/http/body/stream.rb', line 319

def write_nonblock(buffer, exception: nil)
  write(buffer)
end