модуль OpenSSL::Buffering
OpenSSL IO буферизующий модуль.
Этот модуль позволяет OpenSSL::SSL::SSLSocket вести себя как IO.
Обычно вы не будете использовать этот модуль напрямую, вы можете увидеть его реализацию в OpenSSL::SSL::SSLSocket.
Константы
- BLOCK_SIZE
-
Размер по умолчанию для чтения или записи в SSLSocket для операций с буфером.
Атрибуты
«Режим синхронизации» SSLSocket.
Для получения подробной информации см. IO#sync.
Публичные методы класса
# File ext/openssl/lib/openssl/buffering.rb, line 39 def initialize(*) super @eof = false @rbuffer = "" @sync = @io.sync end
Создаёт экземпляр буферизующего модуля IO OpenSSL.
Методы публичного экземпляра
# File ext/openssl/lib/openssl/buffering.rb, line 385 def << (s) do_write(s) self end
Записывает s в поток. s будет преобразовано в строку с использованием String#to_s.
# File ext/openssl/lib/openssl/buffering.rb, line 448 def close flush rescue nil sysclose end
Закрывает SSLSocket и сбрасывает все не записанные данные.
# File ext/openssl/lib/openssl/buffering.rb, line 223
def each(eol=$/)
while line = self.gets(eol)
yield line
end
end Выполняет блок для каждой строки в потоке, где строки разделены eol.
См. также gets
# File ext/openssl/lib/openssl/buffering.rb, line 264
def each_byte # :yields: byte
while c = getc
yield(c.ord)
end
end Вызывает заданный блок один раз для каждого байта в потоке.
# File ext/openssl/lib/openssl/buffering.rb, line 295 def eof? fill_rbuff if !@eof && @rbuffer.empty? @eof && @rbuffer.empty? end
Возвращает true, если поток находится в конце файла, что означает, что больше данных для чтения нет.
# File ext/openssl/lib/openssl/buffering.rb, line 436 def flush osync = @sync @sync = true do_write "" return self ensure @sync = osync end
Сбрасывает буферизованные данные в SSLSocket.
# File ext/openssl/lib/openssl/buffering.rb, line 257 def getc read(1) end
Считывает один символ из потока. Возвращает nil, если вызов осуществляется в конце файла.
# File ext/openssl/lib/openssl/buffering.rb, line 199
def gets(eol=$/, limit=nil)
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
consume_rbuff(size)
end Считывает следующую «строку» из потока. Строки разделены eol. Если limit предоставлено, результат не будет длиннее указанного количества байтов.
eol может быть строкой или Regexp.
В отличие от IO#gets, считанная строка не будет назначена +$_+.
В отличие от IO#gets, разделитель должен быть предоставлен, если предоставлен предел.
# File ext/openssl/lib/openssl/buffering.rb, line 415
def print(*args)
s = ""
args.each{ |arg| s << arg.to_s }
do_write(s)
nil
end Записывает args в поток.
См. IO#print для подробных сведений.
# File ext/openssl/lib/openssl/buffering.rb, line 428 def printf(s, *args) do_write(s % args) nil end
Форматирует и записывает в поток, преобразуя параметры в соответствии со строкой формата.
См. Kernel#sprintf для подробностей о строке формата.
# File ext/openssl/lib/openssl/buffering.rb, line 395
def puts(*args)
s = ""
if args.empty?
s << "\n"
end
args.each{|arg|
s << arg.to_s
if $/ && /\n\z/ !~ s
s << "\n"
end
}
do_write(s)
nil
end Записывает args в поток вместе с разделителем записей.
См. IO#puts для подробных сведений.
# File ext/openssl/lib/openssl/buffering.rb, line 86
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 для подробных сведений.
# File ext/openssl/lib/openssl/buffering.rb, line 167
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
raise EOFError if ret.empty?
ret
end Считывает не более maxlen байтов в режиме без блокировки.
Когда данные не могут быть прочитаны без блокировки, генерируется OpenSSL::SSL::SSLError, дополненный IO::WaitReadable или IO::WaitWritable.
IO::WaitReadable означает, что SSL необходимо прочитать внутри, поэтому #read_nonblock следует вызвать снова, когда базовый IO доступен для чтения.
IO::WaitWritable означает, что SSL необходимо записать внутри, поэтому #read_nonblock следует вызвать снова после того, как базовый IO доступен для записи.
#read_nonblock требует двух блоков обработки исключений, как указано ниже:
# 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. Дополнительные сведения см. в часто задаваемых вопросах OpenSSL. www.openssl.org/support/faq.html
# File ext/openssl/lib/openssl/buffering.rb, line 274 def readchar raise EOFError if eof? getc end
Считывает строку из одного символа из потока. При достижении конца файла генерируется EOFError.
# File ext/openssl/lib/openssl/buffering.rb, line 248 def readline(eol=$/) raise EOFError if eof? gets(eol) end
Считывает строку из потока, разделенную eol.
При достижении конца файла генерируется EOFError.
# File ext/openssl/lib/openssl/buffering.rb, line 235
def readlines(eol=$/)
ary = []
while line = self.gets(eol)
ary << line
end
ary
end Считывает строки из потока, разделенные eol.
См. также gets
# File ext/openssl/lib/openssl/buffering.rb, line 113
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
raise EOFError if ret.empty?
ret
end Считывает не более maxlen байтов из потока. Если buf предоставлен, он должен ссылаться на строку, которая получит данные.
См. IO#readpartial для подробных сведений.
# File ext/openssl/lib/openssl/buffering.rb, line 287 def ungetc(c) @rbuffer[0,0] = c.chr end
Возвращает символ c обратно в поток, таким образом, последующее чтение буферизованного символа вернёт его.
В отличие от IO#getc, может быть возвращено несколько байтов обратно в поток.
Не оказывает никакого влияния на операции чтения без буферизации (например, sysread).
# File ext/openssl/lib/openssl/buffering.rb, line 338 def write(s) do_write(s) s.bytesize end
Записывает s в поток. Если аргумент не является строкой, он будет преобразован с помощью String#to_s. Возвращает количество записанных байтов.
# File ext/openssl/lib/openssl/buffering.rb, line 376 def write_nonblock(s, exception: true) flush syswrite_nonblock(s, exception: exception) end
Записывает str в асинхронном режиме.
Если есть буферизованные данные, они сначала сбрасываются. Это может заблокировать выполнение.
#write_nonblock возвращает количество байтов, записанных в соединение SSL.
Если данные не могут быть записаны без блокировки, возникает исключение OpenSSL::SSL::SSLError, дополненное IO::WaitReadable или IO::WaitWritable.
IO::WaitReadable означает, что SSL требует внутреннего чтения, поэтому #write_nonblock следует вызвать снова после того, как подлежащий IO станет доступным для чтения.
IO::WaitWritable означает, что SSL требует внутреннего записи, поэтому #write_nonblock следует вызвать снова после того, как подлежащий IO станет доступным для записи.
Поэтому #write_nonblock требует двух блоков обработки исключений, как показано ниже.
# 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
Приватные методы экземпляра
# File ext/openssl/lib/openssl/buffering.rb, line 67
def consume_rbuff(size=nil)
if @rbuffer.empty?
nil
else
size = @rbuffer.size unless size
ret = @rbuffer[0, size]
@rbuffer[0, size] = ""
ret
end
end Потребляет size байта из буфера
# File ext/openssl/lib/openssl/buffering.rb, line 310
def do_write(s)
@wbuffer = "" unless defined? @wbuffer
@wbuffer << s
@wbuffer.force_encoding(Encoding::BINARY)
@sync ||= false
if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/)
remain = idx ? idx + $/.size : @wbuffer.length
nwritten = 0
while remain > 0
str = @wbuffer[nwritten,remain]
begin
nwrote = syswrite(str)
rescue Errno::EAGAIN
retry
end
remain -= nwrote
nwritten += nwrote
end
@wbuffer[0,nwritten] = ""
end
end Записывает s в буфер. Когда буфер заполнен или sync имеет значение true, буфер сбрасывается в подлежащий сокет.
# File ext/openssl/lib/openssl/buffering.rb, line 54
def fill_rbuff
begin
@rbuffer << self.sysread(BLOCK_SIZE)
rescue Errno::EAGAIN
retry
rescue EOFError
@eof = true
end
end Заполняет буфер данными из подлежащего SSLSocket
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.