Class: Async::HTTP::Cache::General

Inherits:
Protocol::HTTP::Middleware
  • Object
show all
Defined in:
lib/async/http/cache/general.rb

Constant Summary collapse

CACHE_CONTROL =
'cache-control'
CONTENT_TYPE =
'content-type'
AUTHORIZATION =
'authorization'
'cookie'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, store: Store.default) ⇒ General

Returns a new instance of General.



39
40
41
42
43
44
45
# File 'lib/async/http/cache/general.rb', line 39

def initialize(app, store: Store.default)
	super(app)
	
	@count = 0
	
	@store = store
end

Instance Attribute Details

#countObject (readonly)

Returns the value of attribute count.



47
48
49
# File 'lib/async/http/cache/general.rb', line 47

def count
  @count
end

#storeObject (readonly)

Returns the value of attribute store.



48
49
50
# File 'lib/async/http/cache/general.rb', line 48

def store
  @store
end

Instance Method Details

#cacheable?(request) ⇒ Boolean

Returns:

  • (Boolean)


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/async/http/cache/general.rb', line 62

def cacheable?(request)
	# We don't support caching requests which have a body:
	if request.body
		return false
	end
	
	# We can't cache upgraded requests:
	if request.protocol
		return false
	end
	
	# We only support caching GET and HEAD requests:
	unless request.method == 'GET' || request.method == 'HEAD'
		return false
	end
	
	if request.headers[AUTHORIZATION]
		return false
	end
	
	if request.headers[COOKIE]
		return false
	end
	
	# Otherwise, we can cache it:
	return true
end

#call(request) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/async/http/cache/general.rb', line 109

def call(request)
	key = self.key(request)
	
	cache_control = request.headers[CACHE_CONTROL]
	
	unless cache_control&.no_cache?
		if response = @store.lookup(key, request)
			Async.logger.debug(self) {"Cache hit for #{key}..."}
			@count += 1
			
			# Return the cached response:
			return response
		end
	end
	
	unless cache_control&.no_store?
		if cacheable?(request)
			return wrap(key, request, super)
		end
	end
	
	return super
end

#closeObject



50
51
52
53
54
# File 'lib/async/http/cache/general.rb', line 50

def close
	@store.close
ensure
	super
end

#key(request) ⇒ Object



56
57
58
59
60
# File 'lib/async/http/cache/general.rb', line 56

def key(request)
	@store.normalize(request)
	
	[request.authority, request.method, request.path]
end

#wrap(key, request, response) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/async/http/cache/general.rb', line 90

def wrap(key, request, response)
	if response.status != 200
		return response
	end
	
	if request.head? and body = response.body
		unless body.empty?
			Async.logger.warn(self) {"HEAD request resulted in non-empty body!"}
			
			return response
		end
	end
	
	return Body.wrap(response) do |response, body|
		Async.logger.debug(self) {"Updating cache for #{key}..."}
		@store.insert(key, request, Response.new(response, body))
	end
end