2018-11-06 04:45:35 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-02-07 17:06:08 +00:00
|
|
|
module Gitlab
|
|
|
|
module EtagCaching
|
|
|
|
class Store
|
2021-02-24 12:10:54 +00:00
|
|
|
InvalidKeyError = Class.new(StandardError)
|
|
|
|
|
2017-03-23 11:23:13 +00:00
|
|
|
EXPIRY_TIME = 20.minutes
|
2019-08-31 19:25:25 +00:00
|
|
|
SHARED_STATE_NAMESPACE = 'etag:'
|
2017-02-07 17:06:08 +00:00
|
|
|
|
|
|
|
def get(key)
|
2017-07-11 03:35:47 +00:00
|
|
|
Gitlab::Redis::SharedState.with { |redis| redis.get(redis_shared_state_key(key)) }
|
2017-02-07 17:06:08 +00:00
|
|
|
end
|
|
|
|
|
2021-12-03 12:10:23 +00:00
|
|
|
def touch(*keys, only_if_missing: false)
|
|
|
|
etags = keys.map { generate_etag }
|
2017-02-07 17:06:08 +00:00
|
|
|
|
2017-07-11 03:35:47 +00:00
|
|
|
Gitlab::Redis::SharedState.with do |redis|
|
2021-12-03 12:10:23 +00:00
|
|
|
redis.pipelined do
|
|
|
|
keys.each_with_index do |key, i|
|
|
|
|
redis.set(redis_shared_state_key(key), etags[i], ex: EXPIRY_TIME, nx: only_if_missing)
|
|
|
|
end
|
|
|
|
end
|
2017-02-07 17:06:08 +00:00
|
|
|
end
|
|
|
|
|
2021-12-03 12:10:23 +00:00
|
|
|
keys.size > 1 ? etags : etags.first
|
2017-02-07 17:06:08 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def generate_etag
|
|
|
|
SecureRandom.hex
|
|
|
|
end
|
|
|
|
|
2017-07-11 03:35:47 +00:00
|
|
|
def redis_shared_state_key(key)
|
2021-02-24 12:10:54 +00:00
|
|
|
raise InvalidKeyError, "#{key} is invalid" unless valid_key?(key)
|
2017-06-12 07:09:51 +00:00
|
|
|
|
2017-07-11 03:35:47 +00:00
|
|
|
"#{SHARED_STATE_NAMESPACE}#{key}"
|
2021-02-24 12:10:54 +00:00
|
|
|
rescue InvalidKeyError => e
|
|
|
|
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
|
|
|
|
end
|
|
|
|
|
|
|
|
def valid_key?(key)
|
|
|
|
return true if skip_validation?
|
|
|
|
|
|
|
|
path, header = key.split(':', 2)
|
|
|
|
env = {
|
|
|
|
'PATH_INFO' => path,
|
|
|
|
'HTTP_X_GITLAB_GRAPHQL_RESOURCE_ETAG' => header
|
|
|
|
}
|
|
|
|
|
|
|
|
fake_request = ActionDispatch::Request.new(env)
|
|
|
|
!!Gitlab::EtagCaching::Router.match(fake_request)
|
|
|
|
end
|
|
|
|
|
|
|
|
def skip_validation?
|
|
|
|
Rails.env.production?
|
2017-02-07 17:06:08 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|