rewritten 0.15.2 → 0.16.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/.rubocop.yml +12 -0
- data/.rubocop_todo.yml +116 -0
- data/Gemfile +1 -1
- data/HISTORY.rdoc +4 -0
- data/Rakefile +1 -5
- data/bin/rewritten-dump.rb +11 -14
- data/bin/rewritten-import.rb +9 -12
- data/bin/rewritten-web.rb +7 -9
- data/config.ru +0 -1
- data/lib/rack/canonical.rb +6 -14
- data/lib/rack/dummy.rb +7 -14
- data/lib/rack/html.rb +4 -13
- data/lib/rack/record.rb +3 -9
- data/lib/rack/subdomain.rb +5 -13
- data/lib/rack/url.rb +19 -24
- data/lib/rewritten.rb +45 -69
- data/lib/rewritten/config.ru +0 -1
- data/lib/rewritten/document.rb +6 -7
- data/lib/rewritten/helpers.rb +0 -1
- data/lib/rewritten/rails/url_helpers.rb +0 -3
- data/lib/rewritten/server.rb +58 -73
- data/lib/rewritten/server/test_helper.rb +2 -2
- data/lib/rewritten/version.rb +1 -2
- data/rewritten.gemspec +19 -22
- data/test/rack/rewritten_canonical_test.rb +23 -31
- data/test/rack/rewritten_html_test.rb +16 -21
- data/test/rack/rewritten_url_test.rb +77 -95
- data/test/rewritten/document_test.rb +28 -28
- data/test/rewritten_test.rb +25 -36
- data/test/test_helper.rb +2 -4
- metadata +4 -2
data/lib/rack/subdomain.rb
CHANGED
@@ -1,39 +1,31 @@
|
|
1
1
|
require 'rack'
|
2
2
|
|
3
3
|
module Rack
|
4
|
-
|
5
4
|
module Rewritten
|
6
|
-
|
7
5
|
class Subdomain
|
8
|
-
|
9
6
|
def initialize(app, *fqdns)
|
10
7
|
@app = app
|
11
8
|
@fqdns = fqdns
|
12
9
|
end
|
13
10
|
|
14
11
|
def call(env)
|
15
|
-
puts
|
12
|
+
puts '-> Rack::Rewritten::Subdomain'
|
16
13
|
req = Rack::Request.new(env)
|
17
14
|
|
18
15
|
@fqdns.each do |n|
|
19
16
|
if req.host =~ /(.+)\.#{n}$/
|
20
|
-
if
|
17
|
+
if Regexp.last_match(1) == 'www'
|
21
18
|
break
|
22
19
|
else
|
23
|
-
env[
|
24
|
-
env[
|
20
|
+
env['SUBDOMAIN'] = Regexp.last_match(1)
|
21
|
+
env['FQDN'] = n
|
25
22
|
break
|
26
23
|
end
|
27
24
|
end
|
28
25
|
end
|
29
26
|
|
30
|
-
@app.call(env)
|
27
|
+
@app.call(env)
|
31
28
|
end
|
32
|
-
|
33
29
|
end
|
34
|
-
|
35
30
|
end
|
36
|
-
|
37
31
|
end
|
38
|
-
|
39
|
-
|
data/lib/rack/url.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
require 'rack'
|
2
2
|
|
3
3
|
module Rack
|
4
|
-
|
5
4
|
module Rewritten
|
6
|
-
|
7
5
|
class Url
|
8
|
-
|
9
6
|
attr_accessor :base_url
|
10
7
|
|
11
8
|
def initialize(app, &block)
|
@@ -17,37 +14,39 @@ module Rack
|
|
17
14
|
instance_eval(&block) if block_given?
|
18
15
|
end
|
19
16
|
|
20
|
-
def
|
21
|
-
url.nil?
|
17
|
+
def internal_target?(url)
|
18
|
+
url.nil? || url.start_with?('/') || url.start_with?(@base_url)
|
22
19
|
end
|
23
20
|
|
24
|
-
def
|
25
|
-
!
|
21
|
+
def external_target?(url)
|
22
|
+
!internal_target?(url)
|
26
23
|
end
|
27
24
|
|
28
25
|
def call(env)
|
29
26
|
req = Rack::Request.new(env)
|
30
27
|
|
31
|
-
subdomain = env[
|
28
|
+
subdomain = env['SUBDOMAIN'] ? "#{env['SUBDOMAIN']}:" : ''
|
32
29
|
|
33
30
|
path = "#{subdomain}#{req.path_info}"
|
34
31
|
path.downcase! if downcase_before_lookup?
|
35
32
|
|
36
33
|
target_url = ::Rewritten.translate(path)
|
37
34
|
|
38
|
-
if
|
35
|
+
if external_target?(target_url)
|
39
36
|
r = Rack::Response.new
|
40
37
|
r.redirect(target_url, 301)
|
41
38
|
r.finish
|
42
|
-
elsif ::Rewritten.includes?(path.chomp(
|
39
|
+
elsif ::Rewritten.includes?(req.fullpath) || ::Rewritten.includes?(path.chomp('/')) || backwards = (translate_backwards? && ::Rewritten.exist_translation_for?(path))
|
43
40
|
|
44
|
-
to = ::Rewritten.includes?(
|
41
|
+
to = ::Rewritten.includes?(req.fullpath)
|
42
|
+
to ||= ::Rewritten.includes?(path.chomp('/')) || path
|
45
43
|
|
46
44
|
current_path = ::Rewritten.get_current_translation(to)
|
47
|
-
current_path = current_path.split(
|
45
|
+
current_path = current_path.split(':').last
|
46
|
+
current_path_with_query = current_path
|
48
47
|
current_path = current_path.split('?')[0]
|
49
48
|
|
50
|
-
if (current_path == req.path_info)
|
49
|
+
if (req.fullpath == current_path_with_query || current_path == req.path_info) || (::Rewritten.base_from(req.path_info) == current_path) || ::Rewritten.flag?(path, 'L')
|
51
50
|
# if this is the current path, rewrite path and parameters
|
52
51
|
tpath, tparams = split_to_path_params(to)
|
53
52
|
env['QUERY_STRING'] = Rack::Utils.build_nested_query(tparams.merge(req.params))
|
@@ -59,12 +58,12 @@ module Rack
|
|
59
58
|
|
60
59
|
r = Rack::Response.new
|
61
60
|
|
62
|
-
new_path = env[
|
63
|
-
new_path <<
|
64
|
-
new_path << env[
|
61
|
+
new_path = env['rack.url_scheme'].dup
|
62
|
+
new_path << '://'
|
63
|
+
new_path << env['HTTP_HOST'].dup.sub(/^#{subdomain.chomp(':')}\./, '')
|
65
64
|
new_path << current_path
|
66
65
|
new_path << ::Rewritten.appendix(path) unless backwards
|
67
|
-
new_path << '?' << env[
|
66
|
+
new_path << '?' << env['QUERY_STRING'] unless (env['QUERY_STRING'] || '').empty?
|
68
67
|
|
69
68
|
r.redirect(new_path, 301)
|
70
69
|
a = r.finish
|
@@ -85,24 +84,20 @@ module Rack
|
|
85
84
|
@translate_backwards
|
86
85
|
end
|
87
86
|
|
88
|
-
|
89
|
-
@translate_backwards = yes_or_no
|
90
|
-
end
|
87
|
+
attr_writer :translate_backwards
|
91
88
|
|
92
89
|
def downcase_before_lookup?
|
93
90
|
@downcase_before_lookup
|
94
91
|
end
|
95
92
|
|
96
|
-
|
97
|
-
@downcase_before_lookup = yes_or_no
|
98
|
-
end
|
93
|
+
attr_writer :downcase_before_lookup
|
99
94
|
|
100
95
|
def translate_partial?
|
101
96
|
@translate_partial
|
102
97
|
end
|
103
98
|
|
104
99
|
def translate_partial=(yes_or_no)
|
105
|
-
$stderr.puts
|
100
|
+
$stderr.puts 'DEPRECATED. Please use Rewritten.translate_partial'
|
106
101
|
::Rewritten.translate_partial = yes_or_no
|
107
102
|
end
|
108
103
|
end
|
data/lib/rewritten.rb
CHANGED
@@ -24,26 +24,24 @@ module Rewritten
|
|
24
24
|
case server
|
25
25
|
when String
|
26
26
|
if server =~ /redis\:\/\//
|
27
|
-
redis = Redis.connect(:
|
27
|
+
redis = Redis.connect(url: server, thread_safe: true)
|
28
28
|
else
|
29
29
|
server, namespace = server.split('/', 2)
|
30
30
|
host, port, db = server.split(':')
|
31
|
-
redis = Redis.new(:
|
32
|
-
|
31
|
+
redis = Redis.new(host: host, port: port,
|
32
|
+
thread_safe: true, db: db)
|
33
33
|
end
|
34
34
|
namespace ||= :rewritten
|
35
35
|
|
36
|
-
@redis = Redis::Namespace.new(namespace, :
|
36
|
+
@redis = Redis::Namespace.new(namespace, redis: redis)
|
37
37
|
when Redis::Namespace
|
38
38
|
@redis = server
|
39
39
|
else
|
40
|
-
@redis = Redis::Namespace.new(:rewritten, :
|
40
|
+
@redis = Redis::Namespace.new(:rewritten, redis: server)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
|
45
|
-
@translate_partial = yes_or_no
|
46
|
-
end
|
44
|
+
attr_writer :translate_partial
|
47
45
|
|
48
46
|
def translate_partial?
|
49
47
|
@translate_partial
|
@@ -53,8 +51,8 @@ module Rewritten
|
|
53
51
|
# create a new one.
|
54
52
|
def redis
|
55
53
|
return @redis if @redis
|
56
|
-
self.redis = Redis.respond_to?(:connect) ? Redis.connect :
|
57
|
-
|
54
|
+
self.redis = Redis.respond_to?(:connect) ? Redis.connect : 'localhost:6379'
|
55
|
+
redis
|
58
56
|
end
|
59
57
|
|
60
58
|
def redis_id
|
@@ -62,7 +60,7 @@ module Rewritten
|
|
62
60
|
if redis.respond_to?(:server)
|
63
61
|
redis.server
|
64
62
|
elsif redis.respond_to?(:nodes) # distributed
|
65
|
-
redis.nodes.map
|
63
|
+
redis.nodes.map(&:id).join(', ')
|
66
64
|
else
|
67
65
|
redis.client.id
|
68
66
|
end
|
@@ -81,9 +79,7 @@ module Rewritten
|
|
81
79
|
|
82
80
|
# Set a proc that will be called in the parent process before the
|
83
81
|
# worker forks for the first time.
|
84
|
-
|
85
|
-
@before_first_fork = before_first_fork
|
86
|
-
end
|
82
|
+
attr_writer :before_first_fork
|
87
83
|
|
88
84
|
# The `before_fork` hook will be run in the **parent** process
|
89
85
|
# before every job, so be careful- any changes you make will be
|
@@ -96,9 +92,7 @@ module Rewritten
|
|
96
92
|
end
|
97
93
|
|
98
94
|
# Set the before_fork proc.
|
99
|
-
|
100
|
-
@before_fork = before_fork
|
101
|
-
end
|
95
|
+
attr_writer :before_fork
|
102
96
|
|
103
97
|
# The `after_fork` hook will be run in the child process and is passed
|
104
98
|
# the current job. Any changes you make, therefore, will only live as
|
@@ -111,9 +105,7 @@ module Rewritten
|
|
111
105
|
end
|
112
106
|
|
113
107
|
# Set the after_fork proc.
|
114
|
-
|
115
|
-
@after_fork = after_fork
|
116
|
-
end
|
108
|
+
attr_writer :after_fork
|
117
109
|
|
118
110
|
def to_s
|
119
111
|
"Rewritten Client connected to #{redis_id}"
|
@@ -127,12 +119,10 @@ module Rewritten
|
|
127
119
|
end
|
128
120
|
alias_method :inline, :inline?
|
129
121
|
|
130
|
-
|
131
|
-
@inline = inline
|
132
|
-
end
|
122
|
+
attr_writer :inline
|
133
123
|
|
134
124
|
#
|
135
|
-
# translations
|
125
|
+
# translations
|
136
126
|
#
|
137
127
|
|
138
128
|
def add_translation(line, to)
|
@@ -143,14 +133,14 @@ module Rewritten
|
|
143
133
|
redis.hset("from:#{from}", :to, to)
|
144
134
|
redis.hset("from:#{from}", :flags, flags) if flags
|
145
135
|
|
146
|
-
redis.sadd(:froms, from)
|
147
|
-
redis.sadd(:tos, to)
|
136
|
+
redis.sadd(:froms, from)
|
137
|
+
redis.sadd(:tos, to)
|
148
138
|
score = redis.zcard("to:#{to}") || 0
|
149
|
-
redis.zadd("to:#{to}", score, from)
|
139
|
+
redis.zadd("to:#{to}", score, from)
|
150
140
|
end
|
151
141
|
|
152
142
|
def add_translations(to, froms)
|
153
|
-
froms.each {|from| add_translation(from, to)}
|
143
|
+
froms.each { |from| add_translation(from, to) }
|
154
144
|
end
|
155
145
|
|
156
146
|
def num_translations(to)
|
@@ -195,29 +185,26 @@ module Rewritten
|
|
195
185
|
Rewritten.redis.zrange("to:#{to}", 0, -1)
|
196
186
|
end
|
197
187
|
|
198
|
-
def get_current_translation(path, tail=nil)
|
199
|
-
|
188
|
+
def get_current_translation(path, tail = nil)
|
200
189
|
uri = URI.parse(path)
|
201
190
|
|
202
191
|
# find directly
|
203
192
|
translation = Rewritten.z_range("to:#{path}", -1)
|
204
|
-
|
205
|
-
unless translation
|
206
|
-
translation = Rewritten.z_range("to:#{uri.path}", -1)
|
207
|
-
end
|
193
|
+
|
194
|
+
translation = Rewritten.z_range("to:#{uri.path}", -1) unless translation
|
208
195
|
|
209
196
|
if translation.nil?
|
210
197
|
if translate_partial? && path.count('/') > 1
|
211
198
|
parts = path.split('/')
|
212
|
-
shorter_path = parts.slice(0, parts.size-1).join('/')
|
213
|
-
appendix = parts.last + (tail ?
|
214
|
-
return get_current_translation(shorter_path, appendix)
|
199
|
+
shorter_path = parts.slice(0, parts.size - 1).join('/')
|
200
|
+
appendix = parts.last + (tail ? '/' + tail : '')
|
201
|
+
return get_current_translation(shorter_path, appendix)
|
215
202
|
else
|
216
203
|
return path
|
217
204
|
end
|
218
205
|
end
|
219
206
|
|
220
|
-
complete_path = (tail ? translation+
|
207
|
+
complete_path = (tail ? translation + '/' + tail : translation)
|
221
208
|
translated_uri = URI.parse(complete_path)
|
222
209
|
uri.path = translated_uri.path
|
223
210
|
uri.query = [translated_uri.query, uri.query].compact.join('&')
|
@@ -225,10 +212,8 @@ module Rewritten
|
|
225
212
|
uri.to_s
|
226
213
|
end
|
227
214
|
|
228
|
-
|
229
215
|
# infinitive for translations only!
|
230
216
|
def infinitive(some_from)
|
231
|
-
|
232
217
|
some_from ||= ''
|
233
218
|
|
234
219
|
conjugated = some_from.chomp('/')
|
@@ -236,9 +221,9 @@ module Rewritten
|
|
236
221
|
to = translate(conjugated)
|
237
222
|
to = translate(conjugated.split('?')[0]) unless to
|
238
223
|
|
239
|
-
if to.nil? && translate_partial? && conjugated.count('/') > 1
|
224
|
+
if to.nil? && translate_partial? && conjugated.count('/') > 1
|
240
225
|
parts = conjugated.split('/')
|
241
|
-
shorter_path = parts.slice(0, parts.size-1).join('/')
|
226
|
+
shorter_path = parts.slice(0, parts.size - 1).join('/')
|
242
227
|
infinitive(shorter_path)
|
243
228
|
else
|
244
229
|
conjugated = get_current_translation(to) if to
|
@@ -255,23 +240,21 @@ module Rewritten
|
|
255
240
|
base_from
|
256
241
|
elsif translate_partial? && base_from.count('/') > 1
|
257
242
|
parts = base_from.split('/')
|
258
|
-
base_from(parts.slice(0,parts.size-1).join('/'))
|
259
|
-
|
260
|
-
nil
|
261
|
-
end
|
243
|
+
base_from(parts.slice(0, parts.size - 1).join('/'))
|
244
|
+
end
|
262
245
|
end
|
263
246
|
|
264
247
|
def appendix(some_from)
|
265
248
|
base = base_from(some_from) || ''
|
266
|
-
result = some_from.partition(
|
249
|
+
result = some_from.partition(base).last
|
267
250
|
result.chomp('/')
|
268
251
|
end
|
269
252
|
|
270
253
|
def get_flag_string(from)
|
271
|
-
Rewritten.redis.hget("from:#{from}", :flags)||
|
254
|
+
Rewritten.redis.hget("from:#{from}", :flags) || ''
|
272
255
|
end
|
273
256
|
|
274
|
-
def
|
257
|
+
def flag?(from, c)
|
275
258
|
return false unless Rewritten.redis.exists("from:#{from}")
|
276
259
|
get_flag_string(from).index(c) != nil
|
277
260
|
end
|
@@ -279,12 +262,11 @@ module Rewritten
|
|
279
262
|
def full_line(from)
|
280
263
|
flags = get_flag_string(from)
|
281
264
|
|
282
|
-
if flags ==
|
265
|
+
if flags == ''
|
283
266
|
from
|
284
267
|
else
|
285
|
-
"#{from} [#{flags}]"
|
268
|
+
"#{from} [#{flags}]"
|
286
269
|
end
|
287
|
-
|
288
270
|
end
|
289
271
|
|
290
272
|
def exist_translation_for?(path)
|
@@ -292,26 +274,24 @@ module Rewritten
|
|
292
274
|
end
|
293
275
|
|
294
276
|
def add_hit(path, code, content_type)
|
295
|
-
h = {:
|
296
|
-
Rewritten.redis.sadd(
|
277
|
+
h = { path: path, code: code, content_type: content_type }
|
278
|
+
Rewritten.redis.sadd('hits', encode(h))
|
297
279
|
end
|
298
280
|
|
299
281
|
def all_hits
|
300
|
-
Rewritten.redis.smembers(
|
282
|
+
Rewritten.redis.smembers('hits').map { |e| decode(e) }
|
301
283
|
end
|
302
284
|
|
303
285
|
def includes?(path)
|
304
|
-
|
305
286
|
result = Rewritten.redis.hget("from:#{path.chomp('/')}", :to)
|
306
287
|
result = Rewritten.redis.hget("from:#{path.split('?')[0]}", :to) unless result
|
307
288
|
|
308
289
|
if result.nil? && translate_partial? && path.count('/') > 1
|
309
290
|
parts = path.split('/')
|
310
|
-
includes?(
|
291
|
+
includes?(parts.slice(0, parts.size - 1).join('/'))
|
311
292
|
else
|
312
293
|
result
|
313
294
|
end
|
314
|
-
|
315
295
|
end
|
316
296
|
|
317
297
|
# return the number of froms
|
@@ -325,7 +305,7 @@ module Rewritten
|
|
325
305
|
if count == 1
|
326
306
|
redis.zrange(key, start, start)[0]
|
327
307
|
else
|
328
|
-
Array(redis.zrange(key, start, start+count-1)).map do |item|
|
308
|
+
Array(redis.zrange(key, start, start + count - 1)).map do |item|
|
329
309
|
item
|
330
310
|
end
|
331
311
|
end
|
@@ -337,7 +317,7 @@ module Rewritten
|
|
337
317
|
end
|
338
318
|
|
339
319
|
# Returns an array of all known URL targets.
|
340
|
-
def targets
|
320
|
+
def targets
|
341
321
|
Array(redis.smembers(:targets))
|
342
322
|
end
|
343
323
|
|
@@ -353,29 +333,28 @@ module Rewritten
|
|
353
333
|
redis.sadd(:queues, queue.to_s)
|
354
334
|
end
|
355
335
|
|
356
|
-
|
357
336
|
#
|
358
337
|
# stats
|
359
338
|
#
|
360
339
|
|
361
340
|
# Returns a hash, similar to redis-rb's #info, of interesting stats.
|
362
341
|
def info
|
363
|
-
|
364
|
-
:
|
342
|
+
{
|
343
|
+
pending: queues.inject(0) { |m, k| m + size(k) },
|
365
344
|
#:processed => Stat[:processed],
|
366
345
|
#:queues => queues.size,
|
367
346
|
#:workers => workers.size.to_i,
|
368
347
|
#:working => working.size,
|
369
348
|
#:failed => Stat[:failed],
|
370
|
-
:
|
371
|
-
:
|
349
|
+
servers: [redis_id],
|
350
|
+
environment: ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
372
351
|
}
|
373
352
|
end
|
374
353
|
|
375
354
|
# Returns an array of all known Resque keys in Redis. Redis' KEYS operation
|
376
355
|
# is O(N) for the keyspace, so be careful - this can be slow for big databases.
|
377
356
|
def keys
|
378
|
-
redis.keys(
|
357
|
+
redis.keys('*').map do |key|
|
379
358
|
key.sub("#{redis.namespace}:", '')
|
380
359
|
end
|
381
360
|
end
|
@@ -383,7 +362,4 @@ module Rewritten
|
|
383
362
|
def per_page
|
384
363
|
20
|
385
364
|
end
|
386
|
-
|
387
|
-
|
388
365
|
end
|
389
|
-
|