Class: Puma::MiniSSL::Socket
| Relationships & Source Files | |
| Inherits: | Object |
| Defined in: | lib/puma/minissl.rb |
Class Method Summary
- .new(socket, engine) ⇒ Socket constructor
Instance Attribute Summary
- #closed? ⇒ Boolean readonly
- #peeraddr readonly
-
#peercert ⇒ OpenSSL::X509::Certificate?
readonly
OpenSSL is loaded in
ContextBuilderwhen Context#verify_mode is not VERIFY_NONE. -
#ssl_version_state
readonly
Returns a two element array, first is protocol version (SSL_get_version), second is 'handshake' state (SSL_state_string).
- #to_io readonly
- #write_pending? ⇒ Boolean readonly
-
#bad_tlsv1_3? ⇒ Boolean
readonly
private
Used to check the handshake status, in particular when a TCP connection is made with
TLSv1.3as an available protocol.
Instance Method Summary
-
#<<(data)
Alias for #write.
- #close
- #engine_read_all
- #flush
- #read_nonblock(size, *_)
- #readpartial(size)
-
#syswrite(data)
Alias for #write.
- #wait_writable(timeout = nil)
- #write(data) (also: #syswrite, #<<)
-
#write_nonblock(data, exception: true)
As with SSL_write, retry with the same data after
IO::EAGAINWaitWritable - #flush_write_buffer private
- #flush_write_buffer_nonblock private
- #queue_ciphertext private
Constructor Details
.new(socket, engine) ⇒ Socket
# File 'lib/puma/minissl.rb', line 23
def initialize(socket, engine) @socket = socket @engine = engine @peercert = nil @reuse = nil @write_buffer = +'' @write_owed = 0 @write_owed_data = nil end
Instance Attribute Details
#bad_tlsv1_3? ⇒ Boolean (readonly, private)
Used to check the handshake status, in particular when a TCP connection
is made with TLSv1.3 as an available protocol
# File 'lib/puma/minissl.rb', line 58
def bad_tlsv1_3? HAS_TLS1_3 && ssl_version_state == ['TLSv1.3', 'SSLERR'] end
#closed? ⇒ Boolean (readonly)
[ GitHub ]
# File 'lib/puma/minissl.rb', line 38
def closed? @socket.closed? end
#peeraddr (readonly)
[ GitHub ]# File 'lib/puma/minissl.rb', line 227
def peeraddr @socket.peeraddr end
#peercert ⇒ OpenSSL::X509::Certificate? (readonly)
OpenSSL is loaded in ContextBuilder when
Context#verify_mode is not VERIFY_NONE.
When VERIFY_NONE, Engine#peercert is nil, regardless of
whether the client sends a cert.
#ssl_version_state (readonly)
Returns a two element array, first is protocol version (SSL_get_version), second is 'handshake' state (SSL_state_string)
Used for dropping tcp connections to ssl. See OpenSSL ssl/ssl_stat.c SSL_state_string for info
# File 'lib/puma/minissl.rb', line 51
def ssl_version_state IS_JRUBY ? [nil, nil] : @engine.ssl_vers_st end
#to_io (readonly)
[ GitHub ]# File 'lib/puma/minissl.rb', line 34
def to_io @socket end
#write_pending? ⇒ Boolean (readonly)
[ GitHub ]
# File 'lib/puma/minissl.rb', line 121
def write_pending? !@write_buffer.empty? end
Instance Method Details
#<<(data)
Alias for #write.
# File 'lib/puma/minissl.rb', line 154
alias_method :<<, :write
#close
[ GitHub ]# File 'lib/puma/minissl.rb', line 189
def close begin queue_ciphertext unless @engine.shutdown flush_write_buffer_nonblock rescue IOError, SystemCallError # nothing ensure @socket.close end end
#engine_read_all
[ GitHub ]# File 'lib/puma/minissl.rb', line 79
def engine_read_all output = @engine.read while output and additional_output = @engine.read output << additional_output end output end
#flush
[ GitHub ]# File 'lib/puma/minissl.rb', line 184
def flush flush_write_buffer @socket.flush end
#flush_write_buffer (private)
[ GitHub ]# File 'lib/puma/minissl.rb', line 207
def flush_write_buffer return if @write_buffer.empty? @socket.write @write_buffer @write_buffer = +'' end
#flush_write_buffer_nonblock (private)
[ GitHub ]# File 'lib/puma/minissl.rb', line 215
def flush_write_buffer_nonblock until @write_buffer.empty? n = @socket.write_nonblock @write_buffer, exception: false return false if n == :wait_writable @write_buffer = @write_buffer.byteslice(n..-1) end true end
#queue_ciphertext (private)
[ GitHub ]# File 'lib/puma/minissl.rb', line 200
def queue_ciphertext while (enc = @engine.extract) @write_buffer << enc end end
#read_nonblock(size, *_)
# File 'lib/puma/minissl.rb', line 87
def read_nonblock(size, *_) # *_ is to deal with keyword args that were added # at some point (and being used in the wild) output = engine_read_all return output if output raise IO::EAGAINWaitReadable unless flush_write_buffer_nonblock data = @socket.read_nonblock(size, exception: false) if data == :wait_readable || data == :wait_writable # It would make more sense to let @socket.read_nonblock raise # EAGAIN if necessary but it seems like it'll misbehave on Windows. # I don't have a Windows machine to debug this so I can't explain # exactly what's happening in that OS. Please let me know if you # find out! # # In the meantime, we can emulate the correct behavior by # capturing :wait_readable & :wait_writable and raising EAGAIN # ourselves. raise IO::EAGAINWaitReadable elsif data.nil? raise SSLError.exception "HTTP connection?" if bad_tlsv1_3? return nil end @engine.inject(data) output = engine_read_all return output if output queue_ciphertext flush_write_buffer_nonblock raise IO::EAGAINWaitReadable end
#readpartial(size)
[ GitHub ]# File 'lib/puma/minissl.rb', line 63
def readpartial(size) while true output = @engine.read return output if output data = @socket.readpartial(size) @engine.inject(data) output = @engine.read return output if output queue_ciphertext flush_write_buffer end end
#syswrite(data)
Alias for #write.
# File 'lib/puma/minissl.rb', line 153
alias_method :syswrite, :write
#wait_writable(timeout = nil)
[ GitHub ]# File 'lib/puma/minissl.rb', line 180
def wait_writable(timeout = nil) @socket.wait_writable timeout end
#write(data) Also known as: #syswrite, #<<
[ GitHub ]# File 'lib/puma/minissl.rb', line 125
def write(data) return 0 if data.empty? data_size = data.bytesize flush_write_buffer if @write_owed_data && data.byteslice(0, @write_owed_data.bytesize).b == @write_owed_data data = data.byteslice(@write_owed..-1) @write_owed = 0 @write_owed_data = nil return data_size if data.empty? end need = data.bytesize while true wrote = @engine.write data queue_ciphertext flush_write_buffer need -= wrote return data_size if need == 0 data = data.byteslice(wrote..-1) end end
#write_nonblock(data, exception: true)
As with SSL_write, retry with the same data after IO::EAGAINWaitWritable
# File 'lib/puma/minissl.rb', line 157
def write_nonblock(data, exception: true) return 0 if data.empty? @write_owed = 0 if @write_owed_data && data.byteslice(0, @write_owed_data.bytesize).b != @write_owed_data if @write_owed == 0 @write_owed = @engine.write data @write_owed_data = nil queue_ciphertext end unless flush_write_buffer_nonblock @write_owed_data ||= data.byteslice(0, @write_owed).b raise IO::EAGAINWaitWritable if exception return :wait_writable end wrote = @write_owed @write_owed = 0 @write_owed_data = nil wrote end