rack-sanitizer 2.0.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0963cd5d478e19917c2fec66f99bc1a9f49f436ece2e39a27a533e6b4eecc8fc'
4
- data.tar.gz: a91279934039be5176b8538d77c4c44a2e442e14514d7f63316f1254dcbc91d1
3
+ metadata.gz: df0d39073134888976a11608a842c3c5de86b8bde87c8d157b133a99a7278253
4
+ data.tar.gz: 233aeb1b01a1766196206d2ce51add45b52eb1bea05565716ac46ddca27704e8
5
5
  SHA512:
6
- metadata.gz: 1b9665b889004365211cbdfb62429bd3ae014bc1e99c5781cf4ed4b4ad94973efa650261f8922ce9b70d54286fe02b149e6c09e787dfc3b8252d8530b79bcccf
7
- data.tar.gz: 5e2e5555c2eccaca2755cfd727cd16fe726b5200a141853f40b55c4732a2f030742e33e511b39ba5f23ef22905fe65e1da38c0f7dc05896067ad7a70c9291f7f
6
+ metadata.gz: 378f8675ec6d51e81cdd43b25adbe7ce2bfd02420f0d0da2f953d47d15ebd58bca9373517403d8e6c5e86f4a038e9b41a76519fcf10c26718dbac7185f00b06f
7
+ data.tar.gz: b108ed7404f5aeed13fc1582d1916fd3d21248c69cde05121225e1adccf2f26c1b3298def5f27a99f601fc665758c164b83fd91eca315674859f81b67db85e4a
@@ -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", 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
@@ -19,5 +22,6 @@ jobs:
19
22
  with:
20
23
  bundler-cache: true # 'bundle install' and cache gems
21
24
  ruby-version: ${{ matrix.ruby }}
22
- - name: Run tests
23
- run: bundle exec rake
25
+ bundler: latest
26
+ - name: Run tests ${{ matrix.rubyopt }}
27
+ run: bundle exec rake RUBYOPT="${{ matrix.rubyopt }}"
data/.gitignore CHANGED
@@ -3,7 +3,6 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
- Gemfile.lock
7
6
  InstalledFiles
8
7
  _yardoc
9
8
  coverage
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.0
data/Gemfile.lock ADDED
@@ -0,0 +1,26 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rack-sanitizer (2.0.4)
5
+ rack (>= 1.0, < 4.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ bacon (1.2.0)
11
+ bacon-colored_output (1.1.1)
12
+ bacon
13
+ rack (3.0.10)
14
+ rake (13.1.0)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ bacon
21
+ bacon-colored_output
22
+ rack-sanitizer!
23
+ rake
24
+
25
+ BUNDLED WITH
26
+ 2.5.7
data/Rakefile CHANGED
@@ -4,5 +4,5 @@ task :default => :spec
4
4
 
5
5
  desc "Run tests"
6
6
  task :spec do
7
- sh 'bacon -a'
7
+ sh 'bin/bacon -a'
8
8
  end
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
+ }
@@ -180,6 +180,8 @@ module Rack
180
180
  end
181
181
  end
182
182
 
183
+ URI_PARSER = defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::RFC2396_Parser.new
184
+
183
185
  # Performs the reverse function of `unescape_unreserved`. Unlike
184
186
  # the previous function, we can reuse the logic in URI#encode
185
187
  def escape_unreserved(input)
@@ -189,12 +191,16 @@ module Rack
189
191
  # `unescape_unreserved` invocation.
190
192
  #
191
193
  # See also URI::REGEXP::PATTERN::{UNRESERVED,RESERVED}.
192
- URI::DEFAULT_PARSER.escape(input, /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]%]/)
194
+ URI_PARSER.escape(input, /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]%]/)
193
195
  end
194
196
 
195
197
  def sanitize_string(input)
196
198
  if input.is_a? String
197
- input = input.force_encoding(Encoding::UTF_8)
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)
198
204
 
199
205
  if input.valid_encoding?
200
206
  input
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = "rack-sanitizer"
5
- gem.version = '2.0.2'
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"
@@ -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('UTF-8')
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('UTF-8')
46
- @uri_input = "http://bar/foo%E0".force_encoding('UTF-8')
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('UTF-8')
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('UTF-8')
104
- @uri_input = "http://bar/foo+bar+%D0%BB%D0%BE%D0%BB".force_encoding('UTF-8')
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('UTF-8')
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('UTF-8')
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('UTF-8')
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('UTF-8')
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('UTF-8')
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('UTF-8')
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('UTF-8')
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('UTF-8')
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('UTF-8')
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.2
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: 2024-04-12 00:00:00.000000000 Z
11
+ date: 2025-03-12 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rack
@@ -86,10 +85,13 @@ files:
86
85
  - ".github/workflows/ci.yml"
87
86
  - ".github/workflows/cla.yml"
88
87
  - ".gitignore"
88
+ - ".ruby-version"
89
89
  - Gemfile
90
+ - Gemfile.lock
90
91
  - LICENSE.txt
91
92
  - README.md
92
93
  - Rakefile
94
+ - bin/bacon
93
95
  - lib/rack/sanitizer.rb
94
96
  - rack-sanitizer.gemspec
95
97
  - test/test_sanitizer.rb
@@ -98,7 +100,6 @@ licenses:
98
100
  - MIT
99
101
  metadata:
100
102
  allowed_push_host: https://rubygems.org/
101
- post_install_message:
102
103
  rdoc_options: []
103
104
  require_paths:
104
105
  - lib
@@ -113,8 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
114
  - !ruby/object:Gem::Version
114
115
  version: '0'
115
116
  requirements: []
116
- rubygems_version: 3.5.8
117
- signing_key:
117
+ rubygems_version: 3.6.5
118
118
  specification_version: 4
119
119
  summary: It is a mordernized and optimized fork of rack-utf8_sanitizer
120
120
  test_files: