rack-sanitizer 2.0.3 → 2.0.4
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/.github/workflows/ci.yml +6 -3
- data/Gemfile.lock +1 -1
- data/Rakefile +1 -1
- data/bin/bacon +488 -0
- data/lib/rack/sanitizer.rb +5 -1
- data/rack-sanitizer.gemspec +2 -2
- data/test/test_sanitizer.rb +16 -17
- metadata +4 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df0d39073134888976a11608a842c3c5de86b8bde87c8d157b133a99a7278253
|
4
|
+
data.tar.gz: 233aeb1b01a1766196206d2ce51add45b52eb1bea05565716ac46ddca27704e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 378f8675ec6d51e81cdd43b25adbe7ce2bfd02420f0d0da2f953d47d15ebd58bca9373517403d8e6c5e86f4a038e9b41a76519fcf10c26718dbac7185f00b06f
|
7
|
+
data.tar.gz: b108ed7404f5aeed13fc1582d1916fd3d21248c69cde05121225e1adccf2f26c1b3298def5f27a99f601fc665758c164b83fd91eca315674859f81b67db85e4a
|
data/.github/workflows/ci.yml
CHANGED
@@ -10,7 +10,10 @@ jobs:
|
|
10
10
|
strategy:
|
11
11
|
fail-fast: false
|
12
12
|
matrix:
|
13
|
-
ruby: ["2.5", "2.6", "2.7", "3.0", "3.1", "3.2", "3.3", ruby-head, jruby-9.2, jruby-9.3, jruby-head]
|
13
|
+
ruby: ["2.5", "2.6", "2.7", "3.0", "3.1", "3.2", "3.3", "3.4", ruby-head, jruby-9.2, jruby-9.3, jruby-head]
|
14
|
+
include:
|
15
|
+
- ruby: "3.4"
|
16
|
+
rubyopt: "--enable-frozen-string-literal --debug-frozen-string-literal"
|
14
17
|
|
15
18
|
steps:
|
16
19
|
- uses: actions/checkout@v4
|
@@ -20,5 +23,5 @@ jobs:
|
|
20
23
|
bundler-cache: true # 'bundle install' and cache gems
|
21
24
|
ruby-version: ${{ matrix.ruby }}
|
22
25
|
bundler: latest
|
23
|
-
- name: Run tests
|
24
|
-
run: bundle exec rake
|
26
|
+
- name: Run tests ${{ matrix.rubyopt }}
|
27
|
+
run: bundle exec rake RUBYOPT="${{ matrix.rubyopt }}"
|
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
data/bin/bacon
ADDED
@@ -0,0 +1,488 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# -*- ruby -*-
|
4
|
+
|
5
|
+
# Bacon -- small RSpec clone.
|
6
|
+
#
|
7
|
+
# "Truth will sooner come out from error than from confusion." ---Francis Bacon
|
8
|
+
|
9
|
+
# Copyright (C) 2007, 2008, 2012 Christian Neukirchen <purl.org/net/chneukirchen>
|
10
|
+
#
|
11
|
+
# Bacon is freely distributable under the terms of an MIT-style license.
|
12
|
+
# See COPYING or http://www.opensource.org/licenses/mit-license.php.
|
13
|
+
|
14
|
+
module Bacon
|
15
|
+
VERSION = "1.2"
|
16
|
+
|
17
|
+
Counter = Hash.new(0)
|
18
|
+
ErrorLog = +""
|
19
|
+
Shared = Hash.new { |_, name|
|
20
|
+
raise NameError, "no such context: #{name.inspect}"
|
21
|
+
}
|
22
|
+
|
23
|
+
RestrictName = // unless defined? RestrictName
|
24
|
+
RestrictContext = // unless defined? RestrictContext
|
25
|
+
|
26
|
+
Backtraces = true unless defined? Backtraces
|
27
|
+
|
28
|
+
def self.summary_on_exit
|
29
|
+
return if Counter[:installed_summary] > 0
|
30
|
+
@timer = Time.now
|
31
|
+
at_exit {
|
32
|
+
handle_summary
|
33
|
+
if $!
|
34
|
+
raise $!
|
35
|
+
elsif Counter[:errors] + Counter[:failed] > 0
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
}
|
39
|
+
Counter[:installed_summary] += 1
|
40
|
+
end
|
41
|
+
class <<self; alias summary_at_exit summary_on_exit; end
|
42
|
+
|
43
|
+
module SpecDoxOutput
|
44
|
+
def handle_specification(name)
|
45
|
+
puts spaces + name
|
46
|
+
yield
|
47
|
+
puts if Counter[:context_depth] == 1
|
48
|
+
end
|
49
|
+
|
50
|
+
def handle_requirement(description)
|
51
|
+
print "#{spaces} - #{description}"
|
52
|
+
error = yield
|
53
|
+
puts error.empty? ? "" : " [#{error}]"
|
54
|
+
end
|
55
|
+
|
56
|
+
def handle_summary
|
57
|
+
print ErrorLog if Backtraces
|
58
|
+
puts "%d specifications (%d requirements), %d failures, %d errors" %
|
59
|
+
Counter.values_at(:specifications, :requirements, :failed, :errors)
|
60
|
+
end
|
61
|
+
|
62
|
+
def spaces
|
63
|
+
" " * (Counter[:context_depth] - 1)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module TestUnitOutput
|
68
|
+
def handle_specification(name) yield end
|
69
|
+
|
70
|
+
def handle_requirement(description)
|
71
|
+
error = yield
|
72
|
+
if error.empty?
|
73
|
+
print "."
|
74
|
+
else
|
75
|
+
print error[0..0]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def handle_summary
|
80
|
+
puts "", "Finished in #{Time.now - @timer} seconds."
|
81
|
+
puts ErrorLog if Backtraces
|
82
|
+
puts "%d tests, %d assertions, %d failures, %d errors" %
|
83
|
+
Counter.values_at(:specifications, :requirements, :failed, :errors)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
module TapOutput
|
88
|
+
def handle_specification(name) yield end
|
89
|
+
|
90
|
+
def handle_requirement(description)
|
91
|
+
ErrorLog.replace ""
|
92
|
+
error = yield
|
93
|
+
if error.empty?
|
94
|
+
puts "ok %-3d - %s" % [Counter[:specifications], description]
|
95
|
+
else
|
96
|
+
puts "not ok %d - %s: %s" %
|
97
|
+
[Counter[:specifications], description, error]
|
98
|
+
puts ErrorLog.strip.gsub(/^/, '# ') if Backtraces
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def handle_summary
|
103
|
+
puts "1..#{Counter[:specifications]}"
|
104
|
+
puts "# %d tests, %d assertions, %d failures, %d errors" %
|
105
|
+
Counter.values_at(:specifications, :requirements, :failed, :errors)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
module KnockOutput
|
110
|
+
def handle_specification(name) yield end
|
111
|
+
|
112
|
+
def handle_requirement(description)
|
113
|
+
ErrorLog.replace ""
|
114
|
+
error = yield
|
115
|
+
if error.empty?
|
116
|
+
puts "ok - %s" % [description]
|
117
|
+
else
|
118
|
+
puts "not ok - %s: %s" % [description, error]
|
119
|
+
puts ErrorLog.strip.gsub(/^/, '# ') if Backtraces
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def handle_summary; end
|
124
|
+
end
|
125
|
+
|
126
|
+
extend SpecDoxOutput # default
|
127
|
+
|
128
|
+
class Error < RuntimeError
|
129
|
+
attr_accessor :count_as
|
130
|
+
|
131
|
+
def initialize(count_as, message)
|
132
|
+
@count_as = count_as
|
133
|
+
super message
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class Context
|
138
|
+
attr_reader :name, :block
|
139
|
+
|
140
|
+
def initialize(name, &block)
|
141
|
+
@name = name
|
142
|
+
@before, @after = [], []
|
143
|
+
@block = block
|
144
|
+
end
|
145
|
+
|
146
|
+
def run
|
147
|
+
return unless name =~ RestrictContext
|
148
|
+
Counter[:context_depth] += 1
|
149
|
+
Bacon.handle_specification(name) { instance_eval(&block) }
|
150
|
+
Counter[:context_depth] -= 1
|
151
|
+
self
|
152
|
+
end
|
153
|
+
|
154
|
+
def before(&block); @before << block; end
|
155
|
+
def after(&block); @after << block; end
|
156
|
+
|
157
|
+
def behaves_like(*names)
|
158
|
+
names.each { |name| instance_eval(&Shared[name]) }
|
159
|
+
end
|
160
|
+
|
161
|
+
def it(description, &block)
|
162
|
+
return unless description =~ RestrictName
|
163
|
+
block ||= lambda { should.flunk "not implemented" }
|
164
|
+
Counter[:specifications] += 1
|
165
|
+
run_requirement description, block
|
166
|
+
end
|
167
|
+
|
168
|
+
def should(*args, &block)
|
169
|
+
if Counter[:depth]==0
|
170
|
+
it('should '+args.first,&block)
|
171
|
+
else
|
172
|
+
super(*args,&block)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def run_requirement(description, spec)
|
177
|
+
Bacon.handle_requirement description do
|
178
|
+
begin
|
179
|
+
Counter[:depth] += 1
|
180
|
+
rescued = false
|
181
|
+
begin
|
182
|
+
@before.each { |block| instance_eval(&block) }
|
183
|
+
prev_req = Counter[:requirements]
|
184
|
+
instance_eval(&spec)
|
185
|
+
rescue Object => e
|
186
|
+
rescued = true
|
187
|
+
raise e
|
188
|
+
ensure
|
189
|
+
if Counter[:requirements] == prev_req and not rescued
|
190
|
+
raise Error.new(:missing,
|
191
|
+
"empty specification: #{@name} #{description}")
|
192
|
+
end
|
193
|
+
begin
|
194
|
+
@after.each { |block| instance_eval(&block) }
|
195
|
+
rescue Object => e
|
196
|
+
raise e unless rescued
|
197
|
+
end
|
198
|
+
end
|
199
|
+
rescue Object => e
|
200
|
+
ErrorLog << "#{e.class}: #{e.message}\n"
|
201
|
+
e.backtrace.find_all { |line| line !~ /bin\/bacon|\/bacon\.rb:\d+/ }.
|
202
|
+
each_with_index { |line, i|
|
203
|
+
ErrorLog << "\t#{line}#{i==0 ? ": #@name - #{description}" : ""}\n"
|
204
|
+
}
|
205
|
+
ErrorLog << "\n"
|
206
|
+
|
207
|
+
if e.kind_of? Error
|
208
|
+
Counter[e.count_as] += 1
|
209
|
+
e.count_as.to_s.upcase
|
210
|
+
else
|
211
|
+
Counter[:errors] += 1
|
212
|
+
"ERROR: #{e.class}"
|
213
|
+
end
|
214
|
+
else
|
215
|
+
""
|
216
|
+
ensure
|
217
|
+
Counter[:depth] -= 1
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def describe(*args, &block)
|
223
|
+
context = Bacon::Context.new(args.join(' '), &block)
|
224
|
+
(parent_context = self).methods(false).each {|e|
|
225
|
+
class<<context; self end.send(:define_method, e) {|*args| parent_context.send(e, *args)}
|
226
|
+
}
|
227
|
+
@before.each { |b| context.before(&b) }
|
228
|
+
@after.each { |b| context.after(&b) }
|
229
|
+
context.run
|
230
|
+
end
|
231
|
+
|
232
|
+
def raise?(*args, &block); block.raise?(*args); end
|
233
|
+
def throw?(*args, &block); block.throw?(*args); end
|
234
|
+
def change?(&block); lambda{}.change?(&block); end
|
235
|
+
end
|
236
|
+
|
237
|
+
module ColoredOutput
|
238
|
+
def handle_requirement(*args)
|
239
|
+
error = yield
|
240
|
+
|
241
|
+
print error.empty? ? color("\e[32m") : color("\e[1;31m")
|
242
|
+
super(*args) { error }
|
243
|
+
print color("\e[0m")
|
244
|
+
end
|
245
|
+
|
246
|
+
def color(escape_seq)
|
247
|
+
if $stdout.respond_to?(:tty?) && $stdout.tty?
|
248
|
+
escape_seq
|
249
|
+
else
|
250
|
+
""
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
extend ColoredOutput
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
class Object
|
260
|
+
def true?; false; end
|
261
|
+
def false?; false; end
|
262
|
+
end
|
263
|
+
|
264
|
+
class TrueClass
|
265
|
+
def true?; true; end
|
266
|
+
end
|
267
|
+
|
268
|
+
class FalseClass
|
269
|
+
def false?; true; end
|
270
|
+
end
|
271
|
+
|
272
|
+
class Proc
|
273
|
+
def raise?(*exceptions)
|
274
|
+
call
|
275
|
+
rescue *(exceptions.empty? ? RuntimeError : exceptions) => e
|
276
|
+
e
|
277
|
+
else
|
278
|
+
false
|
279
|
+
end
|
280
|
+
|
281
|
+
def throw?(sym)
|
282
|
+
catch(sym) {
|
283
|
+
call
|
284
|
+
return false
|
285
|
+
}
|
286
|
+
return true
|
287
|
+
end
|
288
|
+
|
289
|
+
def change?
|
290
|
+
pre_result = yield
|
291
|
+
call
|
292
|
+
post_result = yield
|
293
|
+
pre_result != post_result
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
class Numeric
|
298
|
+
def close?(to, delta)
|
299
|
+
(to.to_f - self).abs <= delta.to_f rescue false
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
|
304
|
+
class Object
|
305
|
+
def should(*args, &block) Should.new(self).be(*args, &block) end
|
306
|
+
end
|
307
|
+
|
308
|
+
module Kernel
|
309
|
+
private
|
310
|
+
def describe(*args, &block) Bacon::Context.new(args.join(' '), &block).run end
|
311
|
+
def shared(name, &block) Bacon::Shared[name] = block end
|
312
|
+
end
|
313
|
+
|
314
|
+
class Should
|
315
|
+
# Kills ==, ===, =~, eql?, equal?, frozen?, instance_of?, is_a?,
|
316
|
+
# kind_of?, nil?, respond_to?, tainted?
|
317
|
+
instance_methods.each { |name| undef_method name if name =~ /\?|^\W+$/ }
|
318
|
+
|
319
|
+
def initialize(object)
|
320
|
+
@object = object
|
321
|
+
@negated = false
|
322
|
+
end
|
323
|
+
|
324
|
+
def not(*args, &block)
|
325
|
+
@negated = !@negated
|
326
|
+
|
327
|
+
if args.empty?
|
328
|
+
self
|
329
|
+
else
|
330
|
+
be(*args, &block)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def be(*args, &block)
|
335
|
+
if args.empty?
|
336
|
+
self
|
337
|
+
else
|
338
|
+
block = args.shift unless block_given?
|
339
|
+
satisfy(*args, &block)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
alias a be
|
344
|
+
alias an be
|
345
|
+
|
346
|
+
def satisfy(description="", &block)
|
347
|
+
r = yield(@object)
|
348
|
+
if Bacon::Counter[:depth] > 0
|
349
|
+
Bacon::Counter[:requirements] += 1
|
350
|
+
raise Bacon::Error.new(:failed, description) unless @negated ^ r
|
351
|
+
r
|
352
|
+
else
|
353
|
+
@negated ? !r : !!r
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
def method_missing(name, *args, &block)
|
358
|
+
name = "#{name}?" if name.to_s =~ /\w[^?]\z/
|
359
|
+
|
360
|
+
desc = @negated ? "not ".dup : "".dup
|
361
|
+
desc << @object.inspect << "." << name.to_s
|
362
|
+
desc << "(" << args.map{|x|x.inspect}.join(", ") << ") failed"
|
363
|
+
|
364
|
+
satisfy(desc) { |x| x.__send__(name, *args, &block) }
|
365
|
+
end
|
366
|
+
|
367
|
+
def equal(value) self == value end
|
368
|
+
def match(value) self =~ value end
|
369
|
+
def identical_to(value) self.equal? value end
|
370
|
+
alias same_as identical_to
|
371
|
+
|
372
|
+
def flunk(reason="Flunked")
|
373
|
+
raise Bacon::Error.new(:failed, reason)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
require 'optparse'
|
378
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '../lib/')
|
379
|
+
module Bacon; end
|
380
|
+
|
381
|
+
automatic = false
|
382
|
+
output = 'SpecDoxOutput'
|
383
|
+
|
384
|
+
opts = OptionParser.new("", 24, ' ') { |opts|
|
385
|
+
opts.banner = "Usage: bacon [options] [files | -a] [-- untouched arguments]"
|
386
|
+
|
387
|
+
opts.separator ""
|
388
|
+
opts.separator "Ruby options:"
|
389
|
+
|
390
|
+
lineno = 1
|
391
|
+
opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line|
|
392
|
+
eval line, TOPLEVEL_BINDING, "-e", lineno
|
393
|
+
lineno += 1
|
394
|
+
}
|
395
|
+
|
396
|
+
opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") {
|
397
|
+
$DEBUG = true
|
398
|
+
}
|
399
|
+
opts.on("-w", "--warn", "turn warnings on for your script") {
|
400
|
+
$-w = true
|
401
|
+
}
|
402
|
+
|
403
|
+
opts.on("-I", "--include PATH",
|
404
|
+
"specify $LOAD_PATH (may be used more than once)") { |path|
|
405
|
+
$LOAD_PATH.unshift(*path.split(":"))
|
406
|
+
}
|
407
|
+
|
408
|
+
opts.on("-r", "--require LIBRARY",
|
409
|
+
"require the library, before executing your script") { |library|
|
410
|
+
require library
|
411
|
+
}
|
412
|
+
|
413
|
+
opts.separator ""
|
414
|
+
opts.separator "bacon options:"
|
415
|
+
|
416
|
+
opts.on("-s", "--specdox", "do AgileDox-like output (default)") {
|
417
|
+
output = 'SpecDoxOutput'
|
418
|
+
}
|
419
|
+
opts.on("-q", "--quiet", "do Test::Unit-like non-verbose output") {
|
420
|
+
output = 'TestUnitOutput'
|
421
|
+
}
|
422
|
+
opts.on("-p", "--tap", "do TAP (Test Anything Protocol) output") {
|
423
|
+
output = 'TapOutput'
|
424
|
+
}
|
425
|
+
opts.on("-k", "--knock", "do Knock output") {
|
426
|
+
output = 'KnockOutput'
|
427
|
+
}
|
428
|
+
|
429
|
+
opts.on("-o", "--output FORMAT",
|
430
|
+
"do FORMAT (SpecDox/TestUnit/Tap) output") { |format|
|
431
|
+
output = format + "Output"
|
432
|
+
}
|
433
|
+
opts.on("-Q", "--no-backtrace", "don't print backtraces") {
|
434
|
+
Bacon.const_set :Backtraces, false
|
435
|
+
}
|
436
|
+
|
437
|
+
opts.on("-a", "--automatic", "gather tests from ./test/, include ./lib/") {
|
438
|
+
$LOAD_PATH.unshift "lib" if File.directory? "lib"
|
439
|
+
automatic = true
|
440
|
+
}
|
441
|
+
|
442
|
+
opts.on('-n', '--name NAME', String,
|
443
|
+
"runs tests matching regexp NAME") { |n|
|
444
|
+
Bacon.const_set :RestrictName, Regexp.new(n)
|
445
|
+
}
|
446
|
+
|
447
|
+
opts.on('-t', '--testcase TESTCASE', String,
|
448
|
+
"runs tests in TestCases matching regexp TESTCASE") { |t|
|
449
|
+
Bacon.const_set :RestrictContext, Regexp.new(t)
|
450
|
+
}
|
451
|
+
|
452
|
+
opts.separator ""
|
453
|
+
opts.separator "Common options:"
|
454
|
+
|
455
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
456
|
+
puts opts
|
457
|
+
exit
|
458
|
+
end
|
459
|
+
|
460
|
+
opts.on_tail("--version", "Show version") do
|
461
|
+
require 'bacon'
|
462
|
+
puts "bacon #{Bacon::VERSION}"
|
463
|
+
exit
|
464
|
+
end
|
465
|
+
|
466
|
+
opts.parse! ARGV
|
467
|
+
}
|
468
|
+
|
469
|
+
files = ARGV
|
470
|
+
|
471
|
+
if automatic
|
472
|
+
files.concat Dir["test/**/test_*.rb"]
|
473
|
+
files.concat Dir["test/**/spec_*.rb"]
|
474
|
+
files.concat Dir["spec/**/spec_*.rb"]
|
475
|
+
files.concat Dir["spec/**/*_spec.rb"]
|
476
|
+
end
|
477
|
+
|
478
|
+
if files.empty?
|
479
|
+
puts opts.banner
|
480
|
+
exit 1
|
481
|
+
end
|
482
|
+
|
483
|
+
Bacon.extend Bacon.const_get(output) rescue abort "No such formatter: #{output}"
|
484
|
+
Bacon.summary_on_exit
|
485
|
+
|
486
|
+
files.each { |file|
|
487
|
+
load file
|
488
|
+
}
|
data/lib/rack/sanitizer.rb
CHANGED
@@ -196,7 +196,11 @@ module Rack
|
|
196
196
|
|
197
197
|
def sanitize_string(input)
|
198
198
|
if input.is_a? String
|
199
|
-
|
199
|
+
# Handle chilled strings
|
200
|
+
# Rack values aren't supposed to be frozen, but it's common in test suites.
|
201
|
+
input = +input
|
202
|
+
|
203
|
+
input.force_encoding(Encoding::UTF_8)
|
200
204
|
|
201
205
|
if input.valid_encoding?
|
202
206
|
input
|
data/rack-sanitizer.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = "rack-sanitizer"
|
5
|
-
gem.version = '2.0.
|
5
|
+
gem.version = '2.0.4'
|
6
6
|
gem.authors = ["Jean Boussier", "whitequark"]
|
7
7
|
gem.license = "MIT"
|
8
8
|
gem.email = ["jean.boussier@gmail.org"]
|
9
|
-
gem.description = %{Rack::Sanitizer is a Rack middleware which cleans up }
|
9
|
+
gem.description = %{Rack::Sanitizer is a Rack middleware which cleans up } +
|
10
10
|
%{invalid UTF8 characters in request URI and headers.}
|
11
11
|
gem.summary = "It is a mordernized and optimized fork of rack-utf8_sanitizer"
|
12
12
|
gem.homepage = "http://github.com/Shopify/rack-sanitizer"
|
data/test/test_sanitizer.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# encoding:ascii-8bit
|
2
2
|
|
3
|
-
require 'bacon/colored_output'
|
4
3
|
require 'cgi'
|
5
4
|
require 'rack/sanitizer'
|
6
5
|
|
@@ -31,7 +30,7 @@ describe Rack::Sanitizer do
|
|
31
30
|
|
32
31
|
describe "with invalid host input" do
|
33
32
|
it "sanitizes host entity (SERVER_NAME)" do
|
34
|
-
host = "host\xD0".force_encoding(
|
33
|
+
host = "host\xD0".dup.force_encoding(Encoding::UTF_8)
|
35
34
|
env = @app.({ "SERVER_NAME" => host })
|
36
35
|
result = env["SERVER_NAME"]
|
37
36
|
|
@@ -42,8 +41,8 @@ describe Rack::Sanitizer do
|
|
42
41
|
|
43
42
|
describe "with invalid UTF-8 input" do
|
44
43
|
before do
|
45
|
-
@plain_input = "foo\xe0".force_encoding(
|
46
|
-
@uri_input = "http://bar/foo%E0".force_encoding(
|
44
|
+
@plain_input = "foo\xe0".dup.force_encoding(Encoding::UTF_8)
|
45
|
+
@uri_input = "http://bar/foo%E0".dup.force_encoding(Encoding::UTF_8)
|
47
46
|
end
|
48
47
|
|
49
48
|
behaves_like :does_sanitize_plain
|
@@ -52,7 +51,7 @@ describe Rack::Sanitizer do
|
|
52
51
|
|
53
52
|
describe "with invalid, incorrectly percent-encoded UTF-8 URI input" do
|
54
53
|
before do
|
55
|
-
@uri_input = "http://bar/foo%E0\xe0".force_encoding(
|
54
|
+
@uri_input = "http://bar/foo%E0\xe0".dup.force_encoding(Encoding::UTF_8)
|
56
55
|
end
|
57
56
|
|
58
57
|
behaves_like :does_sanitize_uri
|
@@ -100,8 +99,8 @@ describe Rack::Sanitizer do
|
|
100
99
|
|
101
100
|
describe "with valid UTF-8 input" do
|
102
101
|
before do
|
103
|
-
@plain_input = "foo bar лол".force_encoding(
|
104
|
-
@uri_input = "http://bar/foo+bar+%D0%BB%D0%BE%D0%BB".force_encoding(
|
102
|
+
@plain_input = "foo bar лол".dup.force_encoding(Encoding::UTF_8)
|
103
|
+
@uri_input = "http://bar/foo+bar+%D0%BB%D0%BE%D0%BB".dup.force_encoding(Encoding::UTF_8)
|
105
104
|
end
|
106
105
|
|
107
106
|
behaves_like :identity_plain
|
@@ -109,7 +108,7 @@ describe Rack::Sanitizer do
|
|
109
108
|
|
110
109
|
describe "with URI characters from reserved range" do
|
111
110
|
before do
|
112
|
-
@uri_input = "http://bar/foo+%2F%3A+bar+%D0%BB%D0%BE%D0%BB".force_encoding(
|
111
|
+
@uri_input = "http://bar/foo+%2F%3A+bar+%D0%BB%D0%BE%D0%BB".dup.force_encoding(Encoding::UTF_8)
|
113
112
|
end
|
114
113
|
|
115
114
|
behaves_like :identity_uri
|
@@ -118,7 +117,7 @@ describe Rack::Sanitizer do
|
|
118
117
|
|
119
118
|
describe "with valid, not percent-encoded UTF-8 URI input" do
|
120
119
|
before do
|
121
|
-
@uri_input = "http://bar/foo+bar+лол".force_encoding(
|
120
|
+
@uri_input = "http://bar/foo+bar+лол".dup.force_encoding(Encoding::UTF_8)
|
122
121
|
@encoded = "http://bar/foo+bar+#{CGI.escape("лол")}"
|
123
122
|
end
|
124
123
|
|
@@ -167,7 +166,7 @@ describe Rack::Sanitizer do
|
|
167
166
|
|
168
167
|
describe "with symbols in the env" do
|
169
168
|
before do
|
170
|
-
@uri_input = "http://bar/foo%E0\xe0".force_encoding(
|
169
|
+
@uri_input = "http://bar/foo%E0\xe0".dup.force_encoding(Encoding::UTF_8)
|
171
170
|
end
|
172
171
|
|
173
172
|
it "sanitizes REQUEST_PATH with invalid UTF-8 URI input" do
|
@@ -183,7 +182,7 @@ describe Rack::Sanitizer do
|
|
183
182
|
|
184
183
|
describe "with form data" do
|
185
184
|
def request_env
|
186
|
-
@plain_input = "foo bar лол".force_encoding(
|
185
|
+
@plain_input = "foo bar лол".dup.force_encoding(Encoding::UTF_8)
|
187
186
|
{
|
188
187
|
"REQUEST_METHOD" => "POST",
|
189
188
|
"CONTENT_TYPE" => "application/x-www-form-urlencoded;foo=bar",
|
@@ -193,7 +192,7 @@ describe Rack::Sanitizer do
|
|
193
192
|
end
|
194
193
|
|
195
194
|
def sanitize_form_data(request_env = request_env())
|
196
|
-
@uri_input = "http://bar/foo+%2F%3A+bar+%D0%BB%D0%BE%D0%BB".force_encoding(
|
195
|
+
@uri_input = "http://bar/foo+%2F%3A+bar+%D0%BB%D0%BE%D0%BB".dup.force_encoding(Encoding::UTF_8)
|
197
196
|
@response_env = @app.(request_env)
|
198
197
|
sanitized_input = @response_env['rack.input'].read
|
199
198
|
|
@@ -380,7 +379,7 @@ describe Rack::Sanitizer do
|
|
380
379
|
|
381
380
|
describe "with custom content-type" do
|
382
381
|
def request_env
|
383
|
-
@plain_input = "foo bar лол".force_encoding(
|
382
|
+
@plain_input = "foo bar лол".dup.force_encoding(Encoding::UTF_8)
|
384
383
|
{
|
385
384
|
"REQUEST_METHOD" => "POST",
|
386
385
|
"CONTENT_TYPE" => "application/vnd.api+json",
|
@@ -390,7 +389,7 @@ describe Rack::Sanitizer do
|
|
390
389
|
end
|
391
390
|
|
392
391
|
def sanitize_data(request_env = request_env())
|
393
|
-
@uri_input = "http://bar/foo+%2F%3A+bar+%D0%BB%D0%BE%D0%BB".force_encoding(
|
392
|
+
@uri_input = "http://bar/foo+%2F%3A+bar+%D0%BB%D0%BE%D0%BB".dup.force_encoding(Encoding::UTF_8)
|
394
393
|
@response_env = @app.(request_env)
|
395
394
|
sanitized_input = @response_env['rack.input'].read
|
396
395
|
|
@@ -464,7 +463,7 @@ describe Rack::Sanitizer do
|
|
464
463
|
|
465
464
|
describe "with custom strategy" do
|
466
465
|
def request_env
|
467
|
-
@plain_input = "foo bar лол".force_encoding(
|
466
|
+
@plain_input = "foo bar лол".dup.force_encoding(Encoding::UTF_8)
|
468
467
|
{
|
469
468
|
"REQUEST_METHOD" => "POST",
|
470
469
|
"CONTENT_TYPE" => "application/json",
|
@@ -474,7 +473,7 @@ describe Rack::Sanitizer do
|
|
474
473
|
end
|
475
474
|
|
476
475
|
def sanitize_data(request_env = request_env())
|
477
|
-
@uri_input = "http://bar/foo+%2F%3A+bar+%D0%BB%D0%BE%D0%BB".force_encoding(
|
476
|
+
@uri_input = "http://bar/foo+%2F%3A+bar+%D0%BB%D0%BE%D0%BB".dup.force_encoding(Encoding::UTF_8)
|
478
477
|
@response_env = @app.(request_env)
|
479
478
|
sanitized_input = @response_env['rack.input'].read
|
480
479
|
|
@@ -507,7 +506,7 @@ describe Rack::Sanitizer do
|
|
507
506
|
|
508
507
|
it "accepts a proc as a strategy" do
|
509
508
|
truncate = -> (input) do
|
510
|
-
'replace'.force_encoding(Encoding::UTF_8)
|
509
|
+
'replace'.dup.force_encoding(Encoding::UTF_8)
|
511
510
|
end
|
512
511
|
|
513
512
|
@app = Rack::Sanitizer.new(-> env { env }, strategy: truncate)
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-sanitizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
- whitequark
|
9
|
-
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2025-03-12 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rack
|
@@ -92,6 +91,7 @@ files:
|
|
92
91
|
- LICENSE.txt
|
93
92
|
- README.md
|
94
93
|
- Rakefile
|
94
|
+
- bin/bacon
|
95
95
|
- lib/rack/sanitizer.rb
|
96
96
|
- rack-sanitizer.gemspec
|
97
97
|
- test/test_sanitizer.rb
|
@@ -100,7 +100,6 @@ licenses:
|
|
100
100
|
- MIT
|
101
101
|
metadata:
|
102
102
|
allowed_push_host: https://rubygems.org/
|
103
|
-
post_install_message:
|
104
103
|
rdoc_options: []
|
105
104
|
require_paths:
|
106
105
|
- lib
|
@@ -115,8 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
114
|
- !ruby/object:Gem::Version
|
116
115
|
version: '0'
|
117
116
|
requirements: []
|
118
|
-
rubygems_version: 3.5
|
119
|
-
signing_key:
|
117
|
+
rubygems_version: 3.6.5
|
120
118
|
specification_version: 4
|
121
119
|
summary: It is a mordernized and optimized fork of rack-utf8_sanitizer
|
122
120
|
test_files:
|