Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,7 @@ Performance/MethodObjectAsBlock:

Metrics/CollectionLiteralLength:
Exclude:
- lib/http/2/header/huffman.rb
- lib/http/2/header/huffman.rb

Metrics/ParameterLists:
Enabled: false
4 changes: 0 additions & 4 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ group :development do
gem "irb" if RUBY_VERSION >= "4.0.0"
end

group :docs do
gem "yard"
end

group :test do
gem "rspec"
gem "simplecov", require: false
Expand Down
9 changes: 5 additions & 4 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require "English"
require "bundler/gem_tasks"
require "open3"
require "rdoc/task"

require_relative "tasks/generate_huffman_table"

Expand All @@ -27,10 +28,10 @@ begin
rescue LoadError
end

begin
require "yard"
YARD::Rake::YardocTask.new
rescue LoadError
RDoc::Task.new do |rdoc|
rdoc.rdoc_dir = "rdoc"
rdoc.options.push("--main", "README.md")
rdoc.rdoc_files.add %w[README.md CHANGELOG.md lib/**/*.rb]
end

namespace :coverage do
Expand Down
2 changes: 1 addition & 1 deletion lib/http/2/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def send_connection_preface
@state = :connected
emit(:frame, CONNECTION_PREFACE_MAGIC)

payload = @local_settings.each_pair.reject { |k, v| v == SPEC_DEFAULT_CONNECTION_SETTINGS[k] }
payload = @local_settings.connection_settings.reject { |k, v| v == SPEC_DEFAULT_CONNECTION_SETTINGS[k] }
settings(payload)
end

Expand Down
7 changes: 3 additions & 4 deletions lib/http/2/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,12 @@ class Connection
attr_accessor :active_stream_count

# Initializes new connection object.
#
def initialize(settings = {})
@local_settings = Settings.new(**settings)
@remote_settings = Settings.new(settings_max_concurrent_streams: Framer::MAX_STREAM_ID)

@compressor = Header::Compressor.new(settings)
@decompressor = Header::Decompressor.new(settings)
@compressor = Header::Compressor.new(@local_settings)
@decompressor = Header::Decompressor.new(@local_settings)

@active_stream_count = 0
@last_stream_id = 0
Expand Down Expand Up @@ -194,7 +193,7 @@ def receive(data)
elsif read_str(@recv_buffer, 24) == CONNECTION_PREFACE_MAGIC
# MAGIC is OK. Send our settings
@state = :waiting_connection_preface
payload = @local_settings.each_pair.reject { |k, v| v == SPEC_DEFAULT_CONNECTION_SETTINGS[k] }
payload = @local_settings.connection_settings.reject { |k, v| v == SPEC_DEFAULT_CONNECTION_SETTINGS[k] }
settings(payload)
else
raise HandshakeError
Expand Down
46 changes: 9 additions & 37 deletions lib/http/2/header/compressor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@ class Compressor
include PackingExtensions
include BufferUtils

# @param options [Hash] encoding options
def initialize(options = {})
@cc = EncodingContext.new(options)
def initialize(settings = Settings.new)
@cc = EncodingContext.new(settings)
end

# Set dynamic table size in EncodingContext
# @param size [Integer] new dynamic table size
# Set dynamic table +size+ in EncodingContext
def table_size=(size)
@cc.table_size = size
end

# Encodes provided value via integer representation.
# Encodes +i+ via integer representation into +buffer+ at the offset set by +offset+.
# - http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-10#section-5.1
#
# If I < 2^N - 1, encode I on N bits
Expand All @@ -30,11 +28,6 @@ def table_size=(size)
# I = I / 128
# encode (I) on 8 bits
#
# @param i [Integer] value to encode
# @param n [Integer] number of available bits
# @param buffer [String] buffer to pack bytes into
# @param offset [Integer] offset to insert packed bytes in buffer
# @return [String] binary string
def integer(i, n, buffer:, offset: buffer.size)
limit = (1 << n) - 1
return pack([i], "C", buffer: buffer, offset: offset) if i < limit
Expand Down Expand Up @@ -65,16 +58,8 @@ def integer(i, n, buffer:, offset: buffer.size)
# * If the bit 7 of the first byte is 0, the string value is
# represented as a list of UTF-8 encoded octets.
#
# +@options [:huffman]+ controls whether to use Huffman encoding:
# :never Do not use Huffman encoding
# :always Always use Huffman encoding
# :shorter Use Huffman when the result is strictly shorter
#
# @param str [String]
# @param buffer [String]
# @return [String] binary string
def string(str, buffer = "".b)
case @cc.options[:huffman]
case @cc.settings.huffman
when :always
huffman_string(str, buffer)
when :never
Expand All @@ -93,11 +78,7 @@ def string(str, buffer = "".b)
end
end

# Encodes header command with appropriate header representation.
#
# @param h [Hash] header command
# @param buffer [String]
# @return [Buffer]
# Encodes +h+ header command with appropriate header representation into +buffer+.
def header(h, buffer = "".b)
type = h[:type]
rep = HEADREP[type]
Expand Down Expand Up @@ -128,9 +109,6 @@ def header(h, buffer = "".b)
end

# Encodes provided list of HTTP headers.
#
# @param headers [Array] +[[name, value], ...]+
# @return [Buffer]
def encode(headers)
buffer = "".b
headers.partition { |f, _| f.start_with? ":" }.each do |hs|
Expand All @@ -144,9 +122,7 @@ def encode(headers)

private

# @param str [String]
# @param buffer [String]
# @return [String] binary string
# encodes +str+ into +buffer+ using Huffman encoding.
def huffman_string(str, buffer = "".b)
huffman_offset = buffer.bytesize
buffer << "\x00".b
Expand All @@ -162,18 +138,14 @@ def huffman_string(str, buffer = "".b)
buffer
end

# @param str [String]
# @param buffer [String]
# @return [String] binary string
# encodes +str+ into +buffer+.
def plain_string(str, plain = "".b)
integer(str.bytesize, 7, buffer: plain)
append_str(plain, str)
plain
end

# @param buffer [String]
# @param huffman_offset [Integer] buffer offset where huffman string was introduced
# @return [String] binary string
# encodes the huffman string size from +buffer+ into the string at the offset indicated by +huffman_offset+
def set_huffman_size(buffer, huffman_offset)
integer(buffer.bytesize - huffman_offset, 7, buffer: buffer, offset: huffman_offset)
buffer.setbyte(huffman_offset, buffer.getbyte(huffman_offset) | 0x80)
Expand Down
35 changes: 8 additions & 27 deletions lib/http/2/header/decompressor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,22 @@ module Header
# Responsible for decoding received headers and maintaining compression
# context of the opposing peer. Decompressor must be initialized with
# appropriate starting context based on local role: client or server.
#
# @example
# server_role = Decompressor.new(:request)
# client_role = Decompressor.new(:response)
class Decompressor
include Error
include BufferUtils

FORBIDDEN_HEADERS = %w[connection te].freeze

# @param options [Hash] decoding options. Only :table_size is effective.
def initialize(options = {})
@cc = EncodingContext.new(options)
def initialize(settings = Settings.new)
@cc = EncodingContext.new(settings)
end

# Set dynamic table size in EncodingContext
# @param size [Integer] new dynamic table size
# Set dynamic table +size+ in EncodingContext
def table_size=(size)
@cc.table_size = size
end

# Decodes integer value from provided buffer.
#
# @param buf [String]
# @param n [Integer] number of available bits
# @return [Integer]
# Decodes integer value from provided +buffer+.
def integer(buf, n)
limit = (1 << n) - 1
if n.zero?
Expand All @@ -55,11 +45,9 @@ def integer(buf, n)
i
end

# Decodes string value from provided buffer.
# Decodes string value from provided +buf+.
#
# @param buf [String]
# @return [String] UTF-8 encoded string
# @raise [CompressionError] when input is malformed
# raises CompressionError when input is malformed
def string(buf)
raise CompressionError, "invalid header block fragment" if buf.empty?

Expand All @@ -72,10 +60,7 @@ def string(buf)
str.force_encoding(Encoding::UTF_8)
end

# Decodes header command from provided buffer.
#
# @param buf [Buffer]
# @return [Hash] command
# Decodes header command from provided +buf+.
def header(buf)
peek = buf.getbyte(0)

Expand Down Expand Up @@ -109,11 +94,7 @@ def header(buf)
end
end

# Decodes and processes header commands within provided buffer.
#
# @param buf [Buffer]
# @param frame [HTTP2::Frame, nil]
# @return [Array] +[[name, value], ...]
# Decodes and processes header commands within provided +buf+.
def decode(buf, frame = nil)
list = [] #: Array[header_pair]
decoding_pseudo_headers = true
Expand Down
Loading
Loading