dalli 5.2.7 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -3
- data/README.md +30 -0
- data/lib/dalli/client.rb +189 -76
- data/lib/dalli/key_grouping.rb +50 -0
- data/lib/dalli/key_manager.rb +30 -0
- data/lib/dalli/pipelined_deleter.rb +7 -16
- data/lib/dalli/pipelined_getter.rb +64 -58
- data/lib/dalli/pipelined_setter.rb +6 -15
- data/lib/dalli/protocol/base.rb +117 -41
- data/lib/dalli/protocol/connection_manager.rb +106 -2
- data/lib/dalli/protocol/key_regularizer.rb +5 -0
- data/lib/dalli/protocol/meta.rb +37 -9
- data/lib/dalli/protocol/request_formatter.rb +62 -33
- data/lib/dalli/protocol/response_processor.rb +49 -6
- data/lib/dalli/protocol/ttl_sanitizer.rb +13 -4
- data/lib/dalli/ring.rb +4 -0
- data/lib/dalli/servers_arg_normalizer.rb +19 -1
- data/lib/dalli/socket.rb +5 -0
- data/lib/dalli/version.rb +1 -1
- data/lib/dalli.rb +14 -1
- data/lib/rack/session/dalli.rb +13 -7
- metadata +2 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
3
5
|
module Dalli
|
|
4
6
|
##
|
|
5
7
|
# This module contains methods for validating and normalizing the servers
|
|
@@ -26,6 +28,8 @@ module Dalli
|
|
|
26
28
|
module ServersArgNormalizer
|
|
27
29
|
ENV_VAR_NAME = 'MEMCACHE_SERVERS'
|
|
28
30
|
DEFAULT_SERVERS = ['127.0.0.1:11211'].freeze
|
|
31
|
+
URI_CREDENTIAL_WARNING = 'Dalli 5.0 removed SASL authentication. ' \
|
|
32
|
+
'Credentials in memcached:// URIs are ignored.'
|
|
29
33
|
|
|
30
34
|
##
|
|
31
35
|
# Normalizes the argument into an array of servers.
|
|
@@ -34,7 +38,21 @@ module Dalli
|
|
|
34
38
|
def self.normalize_servers(arg)
|
|
35
39
|
arg = apply_defaults(arg)
|
|
36
40
|
validate_type(arg)
|
|
37
|
-
Array(arg).flat_map { |s| s.split(',') }.reject(&:empty?)
|
|
41
|
+
Array(arg).flat_map { |s| s.split(',') }.reject(&:empty?).map { |s| without_credentials(s) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Dalli 5 doesn't use credentials in a memcached:// URI, so they are
|
|
45
|
+
# dropped here, with a warning, rather than kept in the client's server
|
|
46
|
+
# list where #inspect would show them.
|
|
47
|
+
def self.without_credentials(server)
|
|
48
|
+
return server unless server.start_with?('memcached://') && server.include?('@')
|
|
49
|
+
|
|
50
|
+
uri = URI.parse(server)
|
|
51
|
+
return server unless uri.userinfo
|
|
52
|
+
|
|
53
|
+
Dalli.logger.warn(URI_CREDENTIAL_WARNING)
|
|
54
|
+
uri.user = nil # clears the password too
|
|
55
|
+
uri.to_s
|
|
38
56
|
end
|
|
39
57
|
|
|
40
58
|
def self.apply_defaults(arg)
|
data/lib/dalli/socket.rb
CHANGED
|
@@ -192,6 +192,9 @@ module Dalli
|
|
|
192
192
|
end
|
|
193
193
|
|
|
194
194
|
def self.init_socket_options(sock, options)
|
|
195
|
+
# CRuby sets this on every socket; TruffleRuby doesn't, so a process
|
|
196
|
+
# the app spawns would inherit the connection and hold it open
|
|
197
|
+
sock.close_on_exec = true
|
|
195
198
|
configure_tcp_options(sock, options)
|
|
196
199
|
configure_socket_buffers(sock, options)
|
|
197
200
|
configure_timeout(sock, options)
|
|
@@ -317,6 +320,8 @@ module Dalli
|
|
|
317
320
|
end
|
|
318
321
|
|
|
319
322
|
def self.init_socket_options(sock, options)
|
|
323
|
+
# Not inherited by spawned processes; see TCP.init_socket_options
|
|
324
|
+
sock.close_on_exec = true
|
|
320
325
|
# https://man7.org/linux/man-pages/man7/unix.7.html
|
|
321
326
|
sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_SNDBUF, options[:sndbuf]) if options[:sndbuf]
|
|
322
327
|
sock.timeout = options[:socket_timeout] if options[:socket_timeout] && sock.respond_to?(:timeout=)
|
data/lib/dalli/version.rb
CHANGED
data/lib/dalli.rb
CHANGED
|
@@ -29,7 +29,19 @@ module Dalli
|
|
|
29
29
|
class ServerError < DalliError; end
|
|
30
30
|
|
|
31
31
|
# socket/server communication error that can be retried
|
|
32
|
-
class RetryableNetworkError < NetworkError
|
|
32
|
+
class RetryableNetworkError < NetworkError
|
|
33
|
+
def initialize(message = nil, request_sent: false)
|
|
34
|
+
super(message)
|
|
35
|
+
@request_sent = request_sent
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# True when some of the failed request was handed to the socket, so
|
|
39
|
+
# memcached may have applied it even though its reply was lost. Only a
|
|
40
|
+
# request that is safe to send twice is retried then.
|
|
41
|
+
def request_sent?
|
|
42
|
+
@request_sent
|
|
43
|
+
end
|
|
44
|
+
end
|
|
33
45
|
|
|
34
46
|
# a multi-get reply named a key that wasn't requested, so the rest of that
|
|
35
47
|
# server's replies can't be trusted
|
|
@@ -71,6 +83,7 @@ require_relative 'dalli/compressor'
|
|
|
71
83
|
require_relative 'dalli/cache_result'
|
|
72
84
|
require_relative 'dalli/client'
|
|
73
85
|
require_relative 'dalli/key_manager'
|
|
86
|
+
require_relative 'dalli/key_grouping'
|
|
74
87
|
require_relative 'dalli/pipelined_getter'
|
|
75
88
|
require_relative 'dalli/pipelined_setter'
|
|
76
89
|
require_relative 'dalli/pipelined_deleter'
|
data/lib/rack/session/dalli.rb
CHANGED
|
@@ -46,7 +46,10 @@ module Rack
|
|
|
46
46
|
#
|
|
47
47
|
# It is not recommended to set `:expires_in`. Instead, use `:expire_after`,
|
|
48
48
|
# which will control both the expiration of the client cookie as well
|
|
49
|
-
# as the expiration of the corresponding entry in memcached.
|
|
49
|
+
# as the expiration of the corresponding entry in memcached. Without
|
|
50
|
+
# `:expire_after`, sessions are stored with no expiry: one stays in
|
|
51
|
+
# memcached until it's deleted (for example by a logout) or memcached
|
|
52
|
+
# evicts it, and a stolen session cookie keeps working until then.
|
|
50
53
|
#
|
|
51
54
|
# Rack::Session::Dalli also accepts a host of options that control how
|
|
52
55
|
# the sessions and session cookies are managed, including the
|
|
@@ -144,6 +147,11 @@ module Rack
|
|
|
144
147
|
sid.private_id if sid.respond_to?(:private_id)
|
|
145
148
|
end
|
|
146
149
|
|
|
150
|
+
# A session that can't be decoded, for example after a change of
|
|
151
|
+
# serializer or a deploy that removed a class stored in it, is treated
|
|
152
|
+
# as missing, so the request gets a new session. Otherwise the session
|
|
153
|
+
# id couldn't be used or replaced, and the user couldn't log in until
|
|
154
|
+
# the cookie was cleared.
|
|
147
155
|
def existing_session_for_sid(client, sid)
|
|
148
156
|
return nil unless sid && !sid.empty?
|
|
149
157
|
|
|
@@ -151,6 +159,9 @@ module Rack
|
|
|
151
159
|
return nil if key.nil?
|
|
152
160
|
|
|
153
161
|
client.get(key)
|
|
162
|
+
rescue ::Dalli::UnmarshalError => e
|
|
163
|
+
::Dalli.logger.warn("#{self.class} couldn't decode a stored session, so it started a new one: #{e.message}")
|
|
164
|
+
nil
|
|
154
165
|
end
|
|
155
166
|
|
|
156
167
|
def create_sid_with_empty_session(client)
|
|
@@ -184,12 +195,9 @@ module Rack
|
|
|
184
195
|
end
|
|
185
196
|
end
|
|
186
197
|
|
|
187
|
-
# Rails stores an ActionDispatch::Request::Session::Options in the env, not a
|
|
188
|
-
# Hash. It implements [] (and to_hash) but not Hash#slice, so slicing it
|
|
189
|
-
# raised NoMethodError instead of returning this 401.
|
|
190
198
|
def missing_session_response(env)
|
|
191
199
|
options = env[Rack::RACK_SESSION_OPTIONS] || @default_options
|
|
192
|
-
cookie = Rack::Utils.delete_set_cookie_header(key,
|
|
200
|
+
cookie = Rack::Utils.delete_set_cookie_header(key, options.slice(:path, :domain))
|
|
193
201
|
[401, { 'content-type' => 'text/plain', 'set-cookie' => cookie }, ['Wrong session ID']]
|
|
194
202
|
end
|
|
195
203
|
|
|
@@ -234,8 +242,6 @@ module Rack
|
|
|
234
242
|
def with_dalli_client(result_on_error = nil, &)
|
|
235
243
|
@data.with(&)
|
|
236
244
|
rescue ::Dalli::DalliError, Errno::ECONNREFUSED
|
|
237
|
-
raise if $ERROR_INFO.message.include?('undefined class')
|
|
238
|
-
|
|
239
245
|
if $VERBOSE
|
|
240
246
|
warn "#{self} is unable to find memcached server."
|
|
241
247
|
warn $ERROR_INFO.inspect
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dalli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter M. Goldstein
|
|
@@ -44,6 +44,7 @@ files:
|
|
|
44
44
|
- lib/dalli/flags.rb
|
|
45
45
|
- lib/dalli/instrumentation.rb
|
|
46
46
|
- lib/dalli/json_serializer.rb
|
|
47
|
+
- lib/dalli/key_grouping.rb
|
|
47
48
|
- lib/dalli/key_manager.rb
|
|
48
49
|
- lib/dalli/options.rb
|
|
49
50
|
- lib/dalli/pipelined_deleter.rb
|