Skip to content

Commit

Permalink
Merge pull request #1024 from grcooper/grcooper/server-error-handling
Browse files Browse the repository at this point in the history
Handle SERVER_ERROR from Memcached
  • Loading branch information
grcooper authored Feb 6, 2025
2 parents 2200124 + 585fe24 commit 5261fb9
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Unreleased
==========

- Fix cannot read response data included terminator `\r\n` when use meta protocol (matsubara0507)
- Support SERVER_ERROR response from Memcached as per the [memcached spec](https://github.com/memcached/memcached/blob/e43364402195c8e822bb8f88755a60ab8bbed62a/doc/protocol.txt#L172) (grcooper)

3.2.8
==========
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ gemspec

group :development, :test do
gem 'connection_pool'
gem 'debug' unless RUBY_PLATFORM == 'java'
gem 'minitest', '~> 5'
gem 'rack', '~> 2.0', '>= 2.2.0'
gem 'rake', '~> 13.0'
Expand Down
3 changes: 3 additions & 0 deletions lib/dalli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class ValueOverMaxSize < DalliError; end
# operation is not permitted in a multi block
class NotPermittedMultiOpError < DalliError; end

# raised when Memcached response with a SERVER_ERROR
class ServerError < DalliError; end

# Implements the NullObject pattern to store an application-defined value for 'Key not found' responses.
class NilObject; end # rubocop:disable Lint/EmptyClass
NOT_FOUND = NilObject.new
Expand Down
8 changes: 6 additions & 2 deletions lib/dalli/protocol/meta/response_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class ResponseProcessor
STAT = 'STAT'
VA = 'VA'
VERSION = 'VERSION'
SERVER_ERROR = 'SERVER_ERROR'

def initialize(io_source, value_marshaller)
@io_source = io_source
Expand Down Expand Up @@ -167,9 +168,12 @@ def header_from_buffer(buf)

def error_on_unexpected!(expected_codes)
tokens = next_line_to_tokens
raise Dalli::DalliError, "Response error: #{tokens.first}" unless expected_codes.include?(tokens.first)

tokens
return tokens if expected_codes.include?(tokens.first)

raise Dalli::ServerError, tokens.join(' ').to_s if tokens.first == SERVER_ERROR

raise Dalli::DalliError, "Response error: #{tokens.first}"
end

def bitflags_from_tokens(tokens)
Expand Down
15 changes: 15 additions & 0 deletions test/integration/test_network.rb
Original file line number Diff line number Diff line change
Expand Up @@ -361,4 +361,19 @@
end
end
end

if MemcachedManager.supported_protocols.include?(:meta)
describe 'ServerError' do
it 'is raised when Memcached response with a SERVER_ERROR' do
memcached_mock(->(sock) { sock.write("SERVER_ERROR foo bar\r\n") }) do
dc = Dalli::Client.new('localhost:19123', protocol: :meta)
err = assert_raises Dalli::ServerError do
dc.get('abc')
end

assert_equal 'SERVER_ERROR foo bar', err.message
end
end
end
end
end

0 comments on commit 5261fb9

Please sign in to comment.