Spec-Zone.ru › Ruby 4.0
  1. OpenSSL::
  2. Буферизация

модуль OpenSSL::Buffering

Подключённые модули:
Enumerable

OpenSSL IO модуль-подмешивание для буферизации.

Этот модуль позволяет OpenSSL::SSL::SSLSocket вести себя как IO.

Обычно этот модуль не используют напрямую; пример его реализации можно найти в OpenSSL::SSL::SSLSocket.

Константы

BLOCK_SIZE

Размер по умолчанию для чтения из SSLSocket и записи в него при операциях с буфером.

Атрибуты

sync [RW]

«Режим синхронизации» SSLSocket.

Полное описание см. в IO#sync.

Публичные методы класса

new (*) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 59
def initialize(*)
  super
  @eof = false
  @rbuffer = Buffer.new
  @sync = @io.sync
end

Создаёт экземпляр модуля IO OpenSSL для буферизации.

Вызывает метод суперкласса

Публичные методы экземпляра

<< (s) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 440
def <<(s)
  do_write(s)
  self
end

Записывает s в поток. s будет преобразовано в String с помощью метода .to_s.

close () Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 501
def close
  flush rescue nil
  sysclose
end

Закрывает SSLSocket и сбрасывает все незаписанные данные.

each (eol=$/) { |line| ... } Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 262
def each(eol=$/)
  while line = self.gets(eol)
    yield line
  end
end

Выполняет блок для каждой строки потока, где строки разделяются символом eol.

См. также gets

Также имеет псевдоним: each_line
each_byte () { |byte| ... } Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 303
def each_byte # :yields: byte
  while c = getc
    yield(c.ord)
  end
end

Вызывает переданный блок один раз для каждого байта в потоке.

each_line (eol=$/)
Псевдоним для: each
eof ()
Псевдоним для: eof?
eof? () Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 334
def eof?
  fill_rbuff if !@eof && @rbuffer.empty?
  @eof && @rbuffer.empty?
end

Возвращает true, если поток достиг конца файла, то есть больше нет данных для чтения.

Также имеет псевдоним: eof
flush () Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 489
def flush
  osync = @sync
  @sync = true
  do_write ""
  return self
ensure
  @sync = osync
end

Сбрасывает буферизованные данные в SSLSocket.

getbyte → 81 Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 102
def getbyte
  read(1)&.ord
end

Получает следующий 8-битный байт из ‘ssl`. Возвращает `nil` при достижении конца файла.

getc () Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 296
def getc
  read(1)
end

Читает один символ из потока. Возвращает nil, если вызван в конце файла.

gets (eol=$/, limit=nil, chomp: false) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 234
def gets(eol=$/, limit=nil, chomp: false)
  idx = @rbuffer.index(eol)
  until @eof
    break if idx
    fill_rbuff
    idx = @rbuffer.index(eol)
  end
  if eol.is_a?(Regexp)
    size = idx ? idx+$&.size : nil
  else
    size = idx ? idx+eol.size : nil
  end
  if size && limit && limit >= 0
    size = [size, limit].min
  end
  line = consume_rbuff(size)
  if chomp && line
    line.chomp!(eol)
  end
  line
end

Читает следующую «строку» из потока. Строки разделяются символом eol. Если задан limit, длина результата не превысит указанное количество байтов.

eol может быть String или Regexp.

В отличие от IO#gets, прочитанная строка не будет присвоена +$_+.

В отличие от IO#gets, если задано ограничение длины, необходимо указать разделитель.

print (*args) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 468
def print(*args)
  s = Buffer.new
  args.each{ |arg| s.append_as_bytes(arg.to_s) }
  do_write(s)
  nil
end

Записывает args в поток.

Полное описание см. в IO#print.

printf (s, *args) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 481
def printf(s, *args)
  do_write(s % args)
  nil
end

Форматирует и записывает данные в поток, преобразуя параметры в соответствии со строкой формата.

Сведения о строке формата см. в Kernel#sprintf.

puts (*args) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 450
def puts(*args)
  s = Buffer.new
  if args.empty?
    s.append_as_bytes("\n")
  end
  args.each{|arg|
    s.append_as_bytes(arg.to_s)
    s.sub!(/(?<!\n)\z/, "\n")
  }
  do_write(s)
  nil
end

Записывает args в поток вместе с разделителем записей.

Полное описание см. в IO#puts.

read (size=nil, buf=nil) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 118
def read(size=nil, buf=nil)
  if size == 0
    if buf
      buf.clear
      return buf
    else
      return ""
    end
  end
  until @eof
    break if size && size <= @rbuffer.size
    fill_rbuff
  end
  ret = consume_rbuff(size) || ""
  if buf
    buf.replace(ret)
    ret = buf
  end
  (size && ret.empty?) ? nil : ret
end

Читает из потока size байтов. Если задан buf, он должен ссылаться на строку, в которую будут записаны данные.

Полное описание см. в IO#read.

read_nonblock (maxlen, buf=nil, exception: true) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 203
def read_nonblock(maxlen, buf=nil, exception: true)
  if maxlen == 0
    if buf
      buf.clear
      return buf
    else
      return ""
    end
  end
  if @rbuffer.empty?
    return sysread_nonblock(maxlen, buf, exception: exception)
  end
  ret = consume_rbuff(maxlen)
  if buf
    buf.replace(ret)
    ret = buf
  end
  ret
end

Неблокирующим способом читает не более maxlen байтов.

Если данные невозможно прочитать без блокировки, возникает исключение OpenSSL::SSL::SSLError, дополненное модулем IO::WaitReadable или IO::WaitWritable.

IO::WaitReadable означает, что SSL необходимо выполнить внутреннее чтение, поэтому read_nonblock следует вызвать снова, когда нижележащий IO станет доступен для чтения.

IO::WaitWritable означает, что SSL необходимо выполнить внутреннюю запись, поэтому read_nonblock следует вызвать снова, когда нижележащий IO станет доступен для записи.

Для OpenSSL::Buffering#read_nonblock необходимы два блока rescue, например:

# emulates blocking read (readpartial).
begin
  result = ssl.read_nonblock(maxlen)
rescue IO::WaitReadable
  IO.select([io])
  retry
rescue IO::WaitWritable
  IO.select(nil, [io])
  retry
end

Обратите внимание: одна из причин, по которой read_nonblock выполняет запись в нижележащий IO, — запрос узла-партнёра на новое TLS/SSL-рукопожатие. Подробнее см. в FAQ по openssl. www.openssl.org/support/faq.html

Указав ключевой аргумент exception для false, можно указать, что read_nonblock не должно вызывать исключение IO::Wait*able, а должно возвращать символ :wait_writable или :wait_readable. При достижении конца файла метод вернёт nil вместо вызова исключения EOFError.

readbyte () Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 107
def readbyte
  raise EOFError if eof?
  getbyte
end

Получает следующий 8-битный байт. При достижении конца файла вызывает исключение EOFError.

readchar () Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 313
def readchar
  raise EOFError if eof?
  getc
end

Читает из потока строку из одного символа. В конце файла вызывает исключение EOFError.

readline (eol=$/) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 287
def readline(eol=$/)
  raise EOFError if eof?
  gets(eol)
end

Читает из потока строку, разделённую символом eol.

В конце файла вызывает исключение EOFError.

readlines (eol=$/) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 274
def readlines(eol=$/)
  ary = []
  while line = self.gets(eol)
    ary << line
  end
  ary
end

Читает из потока строки, разделённые символом eol.

См. также gets

readpartial (maxlen, buf=nil) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 145
def readpartial(maxlen, buf=nil)
  if maxlen == 0
    if buf
      buf.clear
      return buf
    else
      return ""
    end
  end
  if @rbuffer.empty?
    begin
      return sysread(maxlen, buf)
    rescue Errno::EAGAIN
      retry
    end
  end
  ret = consume_rbuff(maxlen)
  if buf
    buf.replace(ret)
    ret = buf
  end
  ret
end

Читает из потока не более maxlen байтов. Если задан buf, он должен ссылаться на строку, в которую будут записаны данные.

Полное описание см. в IO#readpartial.

ungetc (c) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 326
def ungetc(c)
  @rbuffer[0,0] = c.chr
end

Возвращает символ c в поток, чтобы при последующем буферизованном чтении символа был получен именно он.

В отличие от IO#getc, в поток можно вернуть несколько байтов.

Не влияет на чтение без буферизации (например, sysread).

write (*s) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 387
def write(*s)
  s.inject(0) do |written, str|
    do_write(str)
    written + str.bytesize
  end
end

Записывает s в поток. Если аргумент не является String, он будет преобразован с помощью метода .to_s. Возвращает количество записанных байтов.

write_nonblock (s, exception: true) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 431
def write_nonblock(s, exception: true)
  flush
  syswrite_nonblock(s, exception: exception)
end

Неблокирующим способом записывает s.

Если имеются буферизованные данные, сначала они сбрасываются. Эта операция может блокировать выполнение.

write_nonblock возвращает количество байтов, записанных в соединение SSL.

Если данные невозможно записать без блокировки, возникает исключение OpenSSL::SSL::SSLError, дополненное модулем IO::WaitReadable или IO::WaitWritable.

IO::WaitReadable означает, что SSL необходимо выполнить внутреннее чтение, поэтому write_nonblock следует вызвать снова, когда нижележащий IO станет доступен для чтения.

IO::WaitWritable означает, что SSL необходимо выполнить внутреннюю запись, поэтому write_nonblock следует вызвать снова, когда нижележащий IO станет доступен для записи.

Таким образом, для OpenSSL::Buffering#write_nonblock необходимы два блока rescue, например:

# emulates blocking write.
begin
  result = ssl.write_nonblock(str)
rescue IO::WaitReadable
  IO.select([io])
  retry
rescue IO::WaitWritable
  IO.select(nil, [io])
  retry
end

Обратите внимание: одна из причин, по которой write_nonblock выполняет чтение из нижележащего IO, — запрос узла-партнёра на новое TLS/SSL-рукопожатие. Подробнее см. в FAQ по openssl. www.openssl.org/support/faq.html

Указав ключевой аргумент exception для false, можно указать, что write_nonblock не должно вызывать исключение IO::Wait*able, а должно возвращать символ :wait_writable или :wait_readable.

Приватные методы экземпляра

consume_rbuff (size=nil) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 87
def consume_rbuff(size=nil)
  if @rbuffer.empty?
    nil
  else
    size = @rbuffer.size unless size
    @rbuffer.slice!(0, size)
  end
end

Потребляет из буфера size байтов.

do_write (s) Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 349
def do_write(s)
  @wbuffer = Buffer.new unless defined? @wbuffer
  @wbuffer.append_as_bytes(s)

  @sync ||= false
  buffer_size = @wbuffer.bytesize
  if @sync or buffer_size > BLOCK_SIZE
    nwrote = 0
    begin
      while nwrote < buffer_size do
        begin
          chunk = if nwrote > 0
            @wbuffer.byteslice(nwrote, @wbuffer.bytesize)
          else
            @wbuffer
          end

          nwrote += syswrite(chunk)
        rescue Errno::EAGAIN
          retry
        end
      end
    ensure
      if nwrote < @wbuffer.bytesize
        @wbuffer[0, nwrote] = ""
      else
        @wbuffer.clear
      end
    end
  end
end

Записывает s в буфер. Когда буфер заполнен или sync имеет значение true, буфер сбрасывается в нижележащий сокет.

fill_rbuff () Показать исходный код
# File ext/openssl/lib/openssl/buffering.rb, line 74
def fill_rbuff
  begin
    @rbuffer.append_as_bytes(self.sysread(BLOCK_SIZE))
  rescue Errno::EAGAIN
    retry
  rescue EOFError
    @eof = true
  end
end

Заполняет буфер данными из нижележащего SSLSocket.

Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API