Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serializer: reraise all .load errors as UnmarshalError #1011

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
46 changes: 4 additions & 42 deletions lib/dalli/protocol/value_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,55 +33,17 @@ def store(value, req_options, bitflags)
[store_value, bitflags]
end

# TODO: Some of these error messages need to be validated. It's not obvious
# that all of them are actually generated by the invoked code
# in current systems
# rubocop:disable Layout/LineLength
TYPE_ERR_REGEXP = %r{needs to have method `_load'|exception class/object expected|instance of IO needed|incompatible marshal file format}.freeze
ARGUMENT_ERR_REGEXP = /undefined class|marshal data too short/.freeze
NAME_ERR_STR = 'uninitialized constant'
# rubocop:enable Layout/LineLength

def retrieve(value, bitflags) # rubocop:disable Metrics/MethodLength
def retrieve(value, bitflags)
serialized = (bitflags & FLAG_SERIALIZED) != 0
if serialized
if serializer.is_a?(Marshal)
begin
serializer.load(value)
rescue StandardError => e
raise UnmarshalError, "Unable to unmarshal value: #{e.message}"
end
else
# Use Dalli's existing exception filtering for deserialization when not using Marshal to serialize.
begin
serializer.load(value)
rescue StandardError
olleolleolle marked this conversation as resolved.
Show resolved Hide resolved
raise UnmarshalError, 'Unable to unmarshal value'
end
else
value
end
rescue TypeError => e
filter_type_error(e)
rescue ArgumentError => e
filter_argument_error(e)
rescue NameError => e
filter_name_error(e)
end

def filter_type_error(err)
raise err unless TYPE_ERR_REGEXP.match?(err.message)

raise UnmarshalError, "Unable to unmarshal value: #{err.message}"
end

def filter_argument_error(err)
raise err unless ARGUMENT_ERR_REGEXP.match?(err.message)

raise UnmarshalError, "Unable to unmarshal value: #{err.message}"
end

def filter_name_error(err)
raise err unless err.message.include?(NAME_ERR_STR)

raise UnmarshalError, "Unable to unmarshal value: #{err.message}"
end

def serializer
Expand Down
65 changes: 8 additions & 57 deletions test/protocol/test_value_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@

describe 'when the bitflags specify serialization' do
it 'should deserialize the value' do
serializer.expect :is_a?, true, [Marshal]
serializer.expect :load, deserialized_dummy, [raw_value]
bitflags = rand(32)
bitflags |= 0x1
Expand All @@ -182,7 +181,7 @@
end
end

assert_equal exception.message, "Unable to unmarshal value: #{error_message}"
assert_equal exception.cause.message, error_message
end
end

Expand All @@ -199,7 +198,7 @@
end
end

assert_equal exception.message, "Unable to unmarshal value: #{error_message}"
assert_equal exception.cause.message, error_message
end
end

Expand All @@ -213,7 +212,7 @@
vs.retrieve(raw_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end

assert_equal exception.message, "Unable to unmarshal value: #{error_message}"
assert_equal exception.cause.message, error_message
end
end

Expand All @@ -227,23 +226,7 @@
vs.retrieve(raw_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end

assert exception.message.start_with?("Unable to unmarshal value: #{error_message}")
end
end

describe 'when deserialization raises a TypeError with a non-matching message' do
let(:error_message) { SecureRandom.hex(10) }
let(:serializer) { Marshal }

it 're-raises TypeError' do
error = ->(_arg) { raise TypeError, error_message }
exception = serializer.stub :load, error do
assert_raises TypeError do
vs.retrieve(raw_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end
end

assert_equal error_message, exception.message
assert exception.cause.message.start_with?(error_message)
end
end

Expand All @@ -260,23 +243,7 @@
end
end

assert exception.message.start_with?("Unable to unmarshal value: #{error_message}")
end
end

describe 'when deserialization raises a NameError with a non-matching message' do
let(:error_message) { SecureRandom.hex(10) }
let(:serializer) { Marshal }

it 're-raises NameError' do
error = ->(_arg) { raise NameError, error_message }
exception = serializer.stub :load, error do
assert_raises NameError do
vs.retrieve(raw_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end
end

assert exception.message.start_with?(error_message)
assert exception.cause.message.start_with?(error_message)
end
end

Expand All @@ -290,7 +257,7 @@
vs.retrieve(raw_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end

assert_equal exception.message, "Unable to unmarshal value: #{error_message}"
assert_equal exception.cause.message, error_message
end
end

Expand All @@ -304,23 +271,7 @@
vs.retrieve(raw_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end

assert_equal exception.message, "Unable to unmarshal value: #{error_message}"
end
end

describe 'when deserialization raises an ArgumentError with a non-matching message' do
let(:error_message) { SecureRandom.hex(10) }
let(:serializer) { Marshal }

it 're-raises ArgumentError' do
error = ->(_arg) { raise ArgumentError, error_message }
exception = serializer.stub :load, error do
assert_raises ArgumentError do
vs.retrieve(raw_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end
end

assert_equal exception.message, error_message
assert_equal exception.cause.message, error_message
end
end

Expand All @@ -335,7 +286,7 @@
deserialized_value
end

it 'raises UnmarshalError for non-seriaized data' do
it 'raises UnmarshalError for non-serialized data' do
assert_raises Dalli::UnmarshalError do
vs.retrieve(:not_serialized_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end
Expand Down