@@ -17,12 +17,13 @@ def initialize(app)
17
17
class LintError < RuntimeError ; end
18
18
module Assertion
19
19
def assert ( message )
20
+ warn ( "Rack::Lint::Assertion#assert is deprecated as it is inherently inefficient. " \
21
+ "Use `raise Rack::Lint::LintError, 'msg' unless condition` instead" , uplevel : 1 )
20
22
unless yield
21
23
raise LintError , message
22
24
end
23
25
end
24
26
end
25
- include Assertion
26
27
27
28
## This specification aims to formalize the Rack protocol. You
28
29
## can (and should) use Rack::Lint to enforce it.
@@ -40,20 +41,16 @@ def call(env = nil)
40
41
41
42
def _call ( env )
42
43
## It takes exactly one argument, the *environment*
43
- assert ( "No env given" ) { env }
44
+ raise LintError , "No env given" unless env
44
45
check_env env
45
46
46
47
env [ RACK_INPUT ] = InputWrapper . new ( env [ RACK_INPUT ] )
47
48
env [ RACK_ERRORS ] = ErrorWrapper . new ( env [ RACK_ERRORS ] )
48
49
49
50
## and returns an Array of exactly three values:
50
51
ary = @app . call ( env )
51
- assert ( "response is not an Array, but #{ ary . class } " ) {
52
- ary . kind_of? Array
53
- }
54
- assert ( "response array has #{ ary . size } elements instead of 3" ) {
55
- ary . size == 3
56
- }
52
+ raise LintError , "response is not an Array, but #{ ary . class } " unless ary . kind_of? Array
53
+ raise LintError , "response array has #{ ary . size } elements instead of 3" unless ary . size == 3
57
54
58
55
status , headers , @body = ary
59
56
## The *status*,
@@ -78,12 +75,8 @@ def check_env(env)
78
75
## The environment must be an unfrozen instance of Hash that includes
79
76
## CGI-like headers. The application is free to modify the
80
77
## environment.
81
- assert ( "env #{ env . inspect } is not a Hash, but #{ env . class } " ) {
82
- env . kind_of? Hash
83
- }
84
- assert ( "env should not be frozen, but is" ) {
85
- !env . frozen?
86
- }
78
+ raise LintError , "env #{ env . inspect } is not a Hash, but #{ env . class } " unless env . kind_of? Hash
79
+ raise LintError , "env should not be frozen, but is" if env . frozen?
87
80
88
81
##
89
82
## The environment is required to include these variables
@@ -195,73 +188,73 @@ def check_env(env)
195
188
## The store must implement:
196
189
if session = env [ RACK_SESSION ]
197
190
## store(key, value) (aliased as []=);
198
- assert ( "session #{ session . inspect } must respond to store and []=" ) {
199
- session . respond_to? ( : store) && session . respond_to? ( : []=)
200
- }
191
+ unless session . respond_to? ( : store) && session . respond_to? ( : []=)
192
+ raise LintError , " session #{ session . inspect } must respond to store and []="
193
+ end
201
194
202
195
## fetch(key, default = nil) (aliased as []);
203
- assert ( "session #{ session . inspect } must respond to fetch and []" ) {
204
- session . respond_to? ( : fetch) && session . respond_to? ( :[] )
205
- }
196
+ unless session . respond_to? ( : fetch) && session . respond_to? ( :[] )
197
+ raise LintError , " session #{ session . inspect } must respond to fetch and []"
198
+ end
206
199
207
200
## delete(key);
208
- assert ( "session #{ session . inspect } must respond to delete" ) {
209
- session . respond_to? ( : delete)
210
- }
201
+ unless session . respond_to? ( : delete)
202
+ raise LintError , " session #{ session . inspect } must respond to delete"
203
+ end
211
204
212
205
## clear;
213
- assert ( "session #{ session . inspect } must respond to clear" ) {
214
- session . respond_to? ( : clear)
215
- }
206
+ unless session . respond_to? ( : clear)
207
+ raise LintError , " session #{ session . inspect } must respond to clear"
208
+ end
216
209
217
210
## to_hash (returning unfrozen Hash instance);
218
- assert ( "session #{ session . inspect } must respond to to_hash and return unfrozen Hash instance" ) {
219
- session . respond_to? ( :to_hash ) && session . to_hash . kind_of? ( Hash ) && ! session . to_hash . frozen?
220
- }
211
+ unless session . respond_to? ( : to_hash) && session . to_hash . kind_of? ( Hash ) && ! session . to_hash . frozen?
212
+ raise LintError , " session #{ session . inspect } must respond to to_hash and return unfrozen Hash instance"
213
+ end
221
214
end
222
215
223
216
## <tt>rack.logger</tt>:: A common object interface for logging messages.
224
217
## The object must implement:
225
218
if logger = env [ RACK_LOGGER ]
226
219
## info(message, &block)
227
- assert ( "logger #{ logger . inspect } must respond to info" ) {
228
- logger . respond_to? ( : info)
229
- }
220
+ unless logger . respond_to? ( : info)
221
+ raise LintError , " logger #{ logger . inspect } must respond to info"
222
+ end
230
223
231
224
## debug(message, &block)
232
- assert ( "logger #{ logger . inspect } must respond to debug" ) {
233
- logger . respond_to? ( : debug)
234
- }
225
+ unless logger . respond_to? ( : debug)
226
+ raise LintError , " logger #{ logger . inspect } must respond to debug"
227
+ end
235
228
236
229
## warn(message, &block)
237
- assert ( "logger #{ logger . inspect } must respond to warn" ) {
238
- logger . respond_to? ( : warn)
239
- }
230
+ unless logger . respond_to? ( : warn)
231
+ raise LintError , " logger #{ logger . inspect } must respond to warn"
232
+ end
240
233
241
234
## error(message, &block)
242
- assert ( "logger #{ logger . inspect } must respond to error" ) {
243
- logger . respond_to? ( : error)
244
- }
235
+ unless logger . respond_to? ( : error)
236
+ raise LintError , " logger #{ logger . inspect } must respond to error"
237
+ end
245
238
246
239
## fatal(message, &block)
247
- assert ( "logger #{ logger . inspect } must respond to fatal" ) {
248
- logger . respond_to? ( : fatal)
249
- }
240
+ unless logger . respond_to? ( : fatal)
241
+ raise LintError , " logger #{ logger . inspect } must respond to fatal"
242
+ end
250
243
end
251
244
252
245
## <tt>rack.multipart.buffer_size</tt>:: An Integer hint to the multipart parser as to what chunk size to use for reads and writes.
253
246
if bufsize = env [ RACK_MULTIPART_BUFFER_SIZE ]
254
- assert ( "rack.multipart.buffer_size must be an Integer > 0 if specified" ) {
255
- bufsize . is_a? ( Integer ) && bufsize > 0
256
- }
247
+ unless bufsize . is_a? ( Integer ) && bufsize > 0
248
+ raise LintError , "rack.multipart.buffer_size must be an Integer > 0 if specified"
249
+ end
257
250
end
258
251
259
252
## <tt>rack.multipart.tempfile_factory</tt>:: An object responding to #call with two arguments, the filename and content_type given for the multipart form field, and returning an IO-like object that responds to #<< and optionally #rewind. This factory will be used to instantiate the tempfile for each multipart form file upload field, rather than the default class of Tempfile.
260
253
if tempfile_factory = env [ RACK_MULTIPART_TEMPFILE_FACTORY ]
261
- assert ( "rack.multipart.tempfile_factory must respond to #call" ) { tempfile_factory . respond_to? ( :call ) }
254
+ raise LintError , "rack.multipart.tempfile_factory must respond to #call" unless tempfile_factory . respond_to? ( :call )
262
255
env [ RACK_MULTIPART_TEMPFILE_FACTORY ] = lambda do |filename , content_type |
263
256
io = tempfile_factory . call ( filename , content_type )
264
- assert ( "rack.multipart.tempfile_factory return value must respond to #<<" ) { io . respond_to? ( :<< ) }
257
+ raise LintError , "rack.multipart.tempfile_factory return value must respond to #<<" unless io . respond_to? ( :<< )
265
258
io
266
259
end
267
260
end
@@ -276,58 +269,58 @@ def check_env(env)
276
269
%w[ REQUEST_METHOD SERVER_NAME QUERY_STRING
277
270
rack.version rack.input rack.errors
278
271
rack.multithread rack.multiprocess rack.run_once ] . each { |header |
279
- assert ( "env missing required key #{ header } " ) { env . include? header }
272
+ raise LintError , "env missing required key #{ header } " unless env . include? header
280
273
}
281
274
282
275
## The <tt>SERVER_PORT</tt> must be an Integer if set.
283
- assert ( " env[SERVER_PORT] is not an Integer" ) do
284
- server_port = env [ "SERVER_PORT" ]
285
- server_port . nil? || ( Integer ( server_port ) rescue false )
276
+ server_port = env [ " SERVER_PORT" ]
277
+ unless server_port . nil? || ( Integer ( server_port ) rescue false )
278
+ raise LintError , "env[SERVER_PORT] is not an Integer"
286
279
end
287
280
288
281
## The <tt>SERVER_NAME</tt> must be a valid authority as defined by RFC7540.
289
- assert ( " #{ env [ SERVER_NAME ] } must be a valid authority ") do
290
- URI . parse ( "http:// #{ env [ SERVER_NAME ] } /" ) rescue false
282
+ unless ( URI . parse ( "http:// #{ env [ SERVER_NAME ] } / ") rescue false )
283
+ raise LintError , " #{ env [ SERVER_NAME ] } must be a valid authority"
291
284
end
292
285
293
286
## The <tt>HTTP_HOST</tt> must be a valid authority as defined by RFC7540.
294
- assert ( " #{ env [ HTTP_HOST ] } must be a valid authority ") do
295
- URI . parse ( "http:// #{ env [ HTTP_HOST ] } /" ) rescue false
287
+ unless ( URI . parse ( "http:// #{ env [ HTTP_HOST ] } / ") rescue false )
288
+ raise LintError , " #{ env [ HTTP_HOST ] } must be a valid authority"
296
289
end
297
290
298
291
## The environment must not contain the keys
299
292
## <tt>HTTP_CONTENT_TYPE</tt> or <tt>HTTP_CONTENT_LENGTH</tt>
300
293
## (use the versions without <tt>HTTP_</tt>).
301
294
%w[ HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH ] . each { |header |
302
- assert ( " env contains #{ header } , must use #{ header [ 5 , - 1 ] } " ) {
303
- not env . include? header
304
- }
295
+ if env . include? header
296
+ raise LintError , " env contains #{ header } , must use #{ header [ 5 , - 1 ] } "
297
+ end
305
298
}
306
299
307
300
## The CGI keys (named without a period) must have String values.
308
301
## If the string values for CGI keys contain non-ASCII characters,
309
302
## they should use ASCII-8BIT encoding.
310
303
env . each { |key , value |
311
304
next if key . include? "." # Skip extensions
312
- assert ( "env variable #{ key } has non-string value #{ value . inspect } " ) {
313
- value . kind_of? String
314
- }
305
+ unless value . kind_of? String
306
+ raise LintError , "env variable #{ key } has non-string value #{ value . inspect } "
307
+ end
315
308
next if value . encoding == Encoding ::ASCII_8BIT
316
- assert ( "env variable #{ key } has value containing non-ASCII characters and has non-ASCII-8BIT encoding #{ value . inspect } encoding: #{ value . encoding } " ) {
317
- value . b !~ /[ \x80 - \xff ]/n
318
- }
309
+ unless value . b !~ /[ \x80 - \xff ]/n
310
+ raise LintError , "env variable #{ key } has value containing non-ASCII characters and has non-ASCII-8BIT encoding #{ value . inspect } encoding: #{ value . encoding } "
311
+ end
319
312
}
320
313
321
314
## There are the following restrictions:
322
315
323
316
## * <tt>rack.version</tt> must be an array of Integers.
324
- assert ( "rack.version must be an Array, was #{ env [ RACK_VERSION ] . class } " ) {
325
- env [ RACK_VERSION ] . kind_of? Array
326
- }
317
+ unless env [ RACK_VERSION ] . kind_of? Array
318
+ raise LintError , "rack.version must be an Array, was #{ env [ RACK_VERSION ] . class } "
319
+ end
327
320
## * <tt>rack.url_scheme</tt> must either be +http+ or +https+.
328
- assert ( "rack.url_scheme unknown: #{ env [ RACK_URL_SCHEME ] . inspect } " ) {
329
- %w[ http https ] . include? ( env [ RACK_URL_SCHEME ] )
330
- }
321
+ unless %w[ http https ] . include? ( env [ RACK_URL_SCHEME ] )
322
+ raise LintError , "rack.url_scheme unknown: #{ env [ RACK_URL_SCHEME ] . inspect } "
323
+ end
331
324
332
325
## * There must be a valid input stream in <tt>rack.input</tt>.
333
326
check_input env [ RACK_INPUT ]
@@ -337,37 +330,33 @@ def check_env(env)
337
330
check_hijack env
338
331
339
332
## * The <tt>REQUEST_METHOD</tt> must be a valid token.
340
- assert ( "REQUEST_METHOD unknown: #{ env [ REQUEST_METHOD ] } " ) {
341
- env [ REQUEST_METHOD ] =~ / \A [0-9A-Za-z! \# $%&'*+.^_`|~-]+ \z /
342
- }
333
+ unless env [ REQUEST_METHOD ] =~ / \A [0-9A-Za-z! \# $%&'*+.^_`|~-]+ \z /
334
+ raise LintError , " REQUEST_METHOD unknown: #{ env [ REQUEST_METHOD ] } "
335
+ end
343
336
344
337
## * The <tt>SCRIPT_NAME</tt>, if non-empty, must start with <tt>/</tt>
345
- assert ( "SCRIPT_NAME must start with /" ) {
346
- !env . include? ( SCRIPT_NAME ) ||
347
- env [ SCRIPT_NAME ] == "" ||
348
- env [ SCRIPT_NAME ] =~ /\A \/ /
349
- }
338
+ if env . include? ( SCRIPT_NAME ) && env [ SCRIPT_NAME ] != "" && env [ SCRIPT_NAME ] !~ /\A \/ /
339
+ raise LintError , "SCRIPT_NAME must start with /"
340
+ end
350
341
## * The <tt>PATH_INFO</tt>, if non-empty, must start with <tt>/</tt>
351
- assert ( "PATH_INFO must start with /" ) {
352
- !env . include? ( PATH_INFO ) ||
353
- env [ PATH_INFO ] == "" ||
354
- env [ PATH_INFO ] =~ /\A \/ /
355
- }
342
+ if env . include? ( PATH_INFO ) && env [ PATH_INFO ] != "" && env [ PATH_INFO ] !~ /\A \/ /
343
+ raise LintError , "PATH_INFO must start with /"
344
+ end
356
345
## * The <tt>CONTENT_LENGTH</tt>, if given, must consist of digits only.
357
- assert ( "Invalid CONTENT_LENGTH: #{ env [ "CONTENT_LENGTH" ] } " ) {
358
- ! env . include? ( " CONTENT_LENGTH" ) || env [ "CONTENT_LENGTH" ] =~ / \A \d + \z /
359
- }
346
+ if env . include? ( " CONTENT_LENGTH" ) && env [ "CONTENT_LENGTH" ] !~ / \A \d + \z /
347
+ raise LintError , "Invalid CONTENT_LENGTH: #{ env [ "CONTENT_LENGTH" ] } "
348
+ end
360
349
361
350
## * One of <tt>SCRIPT_NAME</tt> or <tt>PATH_INFO</tt> must be
362
351
## set. <tt>PATH_INFO</tt> should be <tt>/</tt> if
363
352
## <tt>SCRIPT_NAME</tt> is empty.
364
- assert ( "One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)" ) {
365
- env [ SCRIPT_NAME ] || env [ PATH_INFO ]
366
- }
353
+ unless env [ SCRIPT_NAME ] || env [ PATH_INFO ]
354
+ raise LintError , "One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)"
355
+ end
367
356
## <tt>SCRIPT_NAME</tt> never should be <tt>/</tt>, but instead be empty.
368
- assert ( " SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'" ) {
369
- env [ SCRIPT_NAME ] != "/ "
370
- }
357
+ unless env [ SCRIPT_NAME ] != "/"
358
+ raise LintError , "SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/' "
359
+ end
371
360
end
372
361
373
362
## === The Input Stream
@@ -377,36 +366,34 @@ def check_env(env)
377
366
def check_input ( input )
378
367
## When applicable, its external encoding must be "ASCII-8BIT" and it
379
368
## must be opened in binary mode, for Ruby 1.9 compatibility.
380
- assert ( "rack.input #{ input } does not have ASCII-8BIT as its external encoding" ) {
381
- input . external_encoding == Encoding :: ASCII_8BIT
382
- } if input . respond_to? ( :external_encoding )
383
- assert ( "rack.input #{ input } is not opened in binary mode" ) {
384
- input . binmode?
385
- } if input . respond_to? ( :binmode? )
369
+ if input . respond_to? ( :external_encoding ) && input . external_encoding != Encoding :: ASCII_8BIT
370
+ raise LintError , "rack.input #{ input } does not have ASCII-8BIT as its external encoding"
371
+ end
372
+ if input . respond_to? ( :binmode? ) && ! input . binmode?
373
+ raise LintError , "rack.input #{ input } is not opened in binary mode"
374
+ end
386
375
387
376
## The input stream must respond to +gets+, +each+, +read+ and +rewind+.
388
377
[ :gets , :each , :read , :rewind ] . each { |method |
389
- assert ( "rack.input #{ input } does not respond to # #{ method } " ) {
390
- input . respond_to? method
391
- }
378
+ unless input . respond_to? method
379
+ raise LintError , "rack.input #{ input } does not respond to # #{ method } "
380
+ end
392
381
}
393
382
end
394
383
395
384
class InputWrapper
396
- include Assertion
397
-
398
385
def initialize ( input )
399
386
@input = input
400
387
end
401
388
402
389
## * +gets+ must be called without arguments and return a string,
403
390
## or +nil+ on EOF.
404
391
def gets ( *args )
405
- assert ( "rack.input#gets called with arguments" ) { args . size == 0 }
392
+ raise LintError , "rack.input#gets called with arguments" unless args . size == 0
406
393
v = @input . gets
407
- assert ( "rack.input#gets didn't return a String" ) {
408
- v . nil? or v . kind_of? String
409
- }
394
+ unless v . nil? or v . kind_of? String
395
+ raise LintError , "rack.input#gets didn't return a String"
396
+ end
410
397
v
411
398
end
412
399
@@ -428,44 +415,44 @@ def gets(*args)
428
415
## If +buffer+ is given, then the read data will be placed
429
416
## into +buffer+ instead of a newly created String object.
430
417
def read ( *args )
431
- assert ( "rack.input#read called with too many arguments" ) {
432
- args . size <= 2
433
- }
418
+ unless args . size <= 2
419
+ raise LintError , "rack.input#read called with too many arguments"
420
+ end
434
421
if args . size >= 1
435
- assert ( "rack.input#read called with non-integer and non- nil length" ) {
436
- args . first . kind_of? ( Integer ) || args . first . nil?
437
- }
438
- assert ( "rack.input#read called with a negative length" ) {
439
- args . first . nil? || args . first >= 0
440
- }
422
+ unless args . first . kind_of? ( Integer ) || args . first . nil?
423
+ raise LintError , "rack.input#read called with non-integer and non- nil length"
424
+ end
425
+ unless args . first . nil? || args . first >= 0
426
+ raise LintError , "rack.input#read called with a negative length"
427
+ end
441
428
end
442
429
if args . size >= 2
443
- assert ( "rack.input#read called with non- String buffer" ) {
444
- args [ 1 ] . kind_of? ( String )
445
- }
430
+ unless args [ 1 ] . kind_of? ( String )
431
+ raise LintError , "rack.input#read called with non- String buffer"
432
+ end
446
433
end
447
434
448
435
v = @input . read ( *args )
449
436
450
- assert ( "rack.input#read didn't return nil or a String" ) {
451
- v . nil? or v . kind_of? String
452
- }
437
+ unless v . nil? or v . kind_of? String
438
+ raise LintError , "rack.input#read didn't return nil or a String"
439
+ end
453
440
if args [ 0 ] . nil?
454
- assert ( "rack.input#read( nil) returned nil on EOF" ) {
455
- ! v . nil?
456
- }
441
+ unless ! v . nil?
442
+ raise LintError , "rack.input#read( nil) returned nil on EOF"
443
+ end
457
444
end
458
445
459
446
v
460
447
end
461
448
462
449
## * +each+ must be called without arguments and only yield Strings.
463
450
def each ( *args )
464
- assert ( "rack.input#each called with arguments" ) { args . size == 0 }
451
+ raise LintError , "rack.input#each called with arguments" unless args . size == 0
465
452
@input . each { |line |
466
- assert ( "rack.input#each didn't yield a String" ) {
467
- line . kind_of? String
468
- }
453
+ unless line . kind_of? String
454
+ raise LintError , "rack.input#each didn't yield a String"
455
+ end
469
456
yield line
470
457
}
471
458
end
@@ -476,36 +463,32 @@ def each(*args)
476
463
## developers must buffer the input data into some rewindable object
477
464
## if the underlying input stream is not rewindable.
478
465
def rewind ( *args )
479
- assert ( "rack.input#rewind called with arguments" ) { args . size == 0 }
480
- assert ( "rack.input#rewind raised Errno::ESPIPE" ) {
481
- begin
482
- @input . rewind
483
- true
484
- rescue Errno ::ESPIPE
485
- false
486
- end
487
- }
466
+ raise LintError , "rack.input#rewind called with arguments" unless args . size == 0
467
+ begin
468
+ @input . rewind
469
+ true
470
+ rescue Errno ::ESPIPE
471
+ raise LintError , "rack.input#rewind raised Errno::ESPIPE"
472
+ end
488
473
end
489
474
490
475
## * +close+ must never be called on the input stream.
491
476
def close ( *args )
492
- assert ( "rack.input#close must not be called" ) { false }
477
+ raise LintError , "rack.input#close must not be called"
493
478
end
494
479
end
495
480
496
481
## === The Error Stream
497
482
def check_error ( error )
498
483
## The error stream must respond to +puts+, +write+ and +flush+.
499
484
[ :puts , :write , :flush ] . each { |method |
500
- assert ( "rack.error #{ error } does not respond to # #{ method } " ) {
501
- error . respond_to? method
502
- }
485
+ unless error . respond_to? method
486
+ raise LintError , "rack.error #{ error } does not respond to # #{ method } "
487
+ end
503
488
}
504
489
end
505
490
506
491
class ErrorWrapper
507
- include Assertion
508
-
509
492
def initialize ( error )
510
493
@error = error
511
494
end
@@ -517,7 +500,7 @@ def puts(str)
517
500
518
501
## * +write+ must be called with a single argument that is a String.
519
502
def write ( str )
520
- assert ( "rack.errors#write not called with a String" ) { str . kind_of? String }
503
+ raise LintError , "rack.errors#write not called with a String" unless str . kind_of? String
521
504
@error . write str
522
505
end
523
506
@@ -529,12 +512,11 @@ def flush
529
512
530
513
## * +close+ must never be called on the error stream.
531
514
def close ( *args )
532
- assert ( "rack.errors#close must not be called" ) { false }
515
+ raise LintError , "rack.errors#close must not be called"
533
516
end
534
517
end
535
518
536
519
class HijackWrapper
537
- include Assertion
538
520
extend Forwardable
539
521
540
522
REQUIRED_METHODS = [
@@ -547,7 +529,7 @@ class HijackWrapper
547
529
def initialize ( io )
548
530
@io = io
549
531
REQUIRED_METHODS . each do |meth |
550
- assert ( "rack.hijack_io must respond to #{ meth } " ) { io . respond_to? meth }
532
+ raise LintError , "rack.hijack_io must respond to #{ meth } " unless io . respond_to? meth
551
533
end
552
534
end
553
535
end
@@ -563,7 +545,7 @@ def check_hijack(env)
563
545
if env [ RACK_IS_HIJACK ]
564
546
## If rack.hijack? is true then rack.hijack must respond to #call.
565
547
original_hijack = env [ RACK_HIJACK ]
566
- assert ( "rack.hijack must respond to call" ) { original_hijack . respond_to? ( :call ) }
548
+ raise LintError , "rack.hijack must respond to call" unless original_hijack . respond_to? ( :call )
567
549
env [ RACK_HIJACK ] = proc do
568
550
## rack.hijack must return the io that will also be assigned (or is
569
551
## already present, in rack.hijack_io.
@@ -596,10 +578,10 @@ def check_hijack(env)
596
578
else
597
579
##
598
580
## If rack.hijack? is false, then rack.hijack should not be set.
599
- assert ( "rack.hijack? is false, but rack.hijack is present" ) { env [ RACK_HIJACK ] . nil? }
581
+ raise LintError , "rack.hijack? is false, but rack.hijack is present" unless env [ RACK_HIJACK ] . nil?
600
582
##
601
583
## If rack.hijack? is false, then rack.hijack_io should not be set.
602
- assert ( "rack.hijack? is false, but rack.hijack_io is present" ) { env [ RACK_HIJACK_IO ] . nil? }
584
+ raise LintError , "rack.hijack? is false, but rack.hijack_io is present" unless env [ RACK_HIJACK_IO ] . nil?
603
585
end
604
586
end
605
587
@@ -630,9 +612,9 @@ def check_hijack_response(headers, env)
630
612
## the <tt>rack.hijack</tt> response API is in use.
631
613
632
614
if env [ RACK_IS_HIJACK ] && headers [ RACK_HIJACK ]
633
- assert ( 'rack.hijack header must respond to # call' ) {
634
- headers [ RACK_HIJACK ] . respond_to? : call
635
- }
615
+ unless headers [ RACK_HIJACK ] . respond_to? : call
616
+ raise LintError , 'rack.hijack header must respond to # call'
617
+ end
636
618
original_hijack = headers [ RACK_HIJACK ]
637
619
proc do |io |
638
620
original_hijack . call HijackWrapper . new ( io )
@@ -641,9 +623,9 @@ def check_hijack_response(headers, env)
641
623
##
642
624
## The special response header <tt>rack.hijack</tt> must only be set
643
625
## if the request env has <tt>rack.hijack?</tt> <tt>true</tt>.
644
- assert ( 'rack.hijack header must not be present if server does not support hijacking' ) {
645
- headers [ RACK_HIJACK ] . nil?
646
- }
626
+ unless headers [ RACK_HIJACK ] . nil?
627
+ raise LintError , 'rack.hijack header must not be present if server does not support hijacking'
628
+ end
647
629
648
630
nil
649
631
end
@@ -661,44 +643,45 @@ def check_hijack_response(headers, env)
661
643
def check_status ( status )
662
644
## This is an HTTP status. It must be an Integer greater than or equal to
663
645
## 100.
664
- assert ( "Status must be an Integer >=100" ) {
665
- status . is_a? ( Integer ) && status >= 100
666
- }
646
+ unless status . is_a? ( Integer ) && status >= 100
647
+ raise LintError , "Status must be an Integer >= 100"
648
+ end
667
649
end
668
650
669
651
## === The Headers
670
652
def check_headers ( header )
671
653
## The header must respond to +each+, and yield values of key and value.
672
- assert ( "headers object should respond to #each, but doesn't (got #{ header . class } as headers)" ) {
673
- header . respond_to? :each
674
- }
654
+ unless header . respond_to? :each
655
+ raise LintError , "headers object should respond to #each, but doesn't (got #{ header . class } as headers)"
656
+ end
675
657
676
658
header . each { |key , value |
677
659
## The header keys must be Strings.
678
- assert ( "header key must be a string, was #{ key . class } " ) {
679
- key . kind_of? String
680
- }
660
+ unless key . kind_of? String
661
+ raise LintError , "header key must be a string, was #{ key . class } "
662
+ end
681
663
682
664
## Special headers starting "rack." are for communicating with the
683
665
## server, and must not be sent back to the client.
684
666
next if key =~ /^rack\. .+$/
685
667
686
668
## The header must not contain a +Status+ key.
687
- assert ( "header must not contain Status" ) { key . downcase != "status" }
669
+ raise LintError , "header must not contain Status" if key . downcase == "status"
688
670
## The header must conform to RFC7230 token specification, i.e. cannot
689
671
## contain non-printable ASCII, DQUOTE or "(),/:;<=>?@[\]{}".
690
- assert ( "invalid header name: #{ key } " ) { key ! ~ /[\( \) ,\/ :;<=>\? @\[ \\ \] {}[:cntrl:]]/ }
672
+ raise LintError , "invalid header name: #{ key } " if key = ~ /[\( \) ,\/ :;<=>\? @\[ \\ \] {}[:cntrl:]]/
691
673
692
674
## The values of the header must be Strings,
693
- assert ( "a header value must be a String, but the value of " +
694
- "'#{ key } ' is a #{ value . class } " ) { value . kind_of? String }
675
+ unless value . kind_of? String
676
+ raise LintError , "a header value must be a String, but the value of '#{ key } ' is a #{ value . class } "
677
+ end
695
678
## consisting of lines (for multiple header values, e.g. multiple
696
679
## <tt>Set-Cookie</tt> values) separated by "\\n".
697
680
value . split ( "\n " ) . each { |item |
698
681
## The lines must not contain characters below 037.
699
- assert ( "invalid header value #{ key } : #{ item . inspect } " ) {
700
- item !~ /[ \000 - \037 ]/
701
- }
682
+ if item =~ /[ \000 - \037 ]/
683
+ raise LintError , "invalid header value #{ key } : #{ item . inspect } "
684
+ end
702
685
}
703
686
}
704
687
end
@@ -709,9 +692,9 @@ def check_content_type(status, headers)
709
692
## There must not be a <tt>Content-Type</tt>, when the +Status+ is 1xx,
710
693
## 204 or 304.
711
694
if key . downcase == "content-type"
712
- assert ( "Content-Type header found in #{ status } response, not allowed" ) {
713
- not Rack :: Utils :: STATUS_WITH_NO_ENTITY_BODY . key? status . to_i
714
- }
695
+ if Rack :: Utils :: STATUS_WITH_NO_ENTITY_BODY . key? status . to_i
696
+ raise LintError , "Content-Type header found in #{ status } response, not allowed"
697
+ end
715
698
return
716
699
end
717
700
}
@@ -723,23 +706,23 @@ def check_content_length(status, headers)
723
706
if key . downcase == 'content-length'
724
707
## There must not be a <tt>Content-Length</tt> header when the
725
708
## +Status+ is 1xx, 204 or 304.
726
- assert ( "Content-Length header found in #{ status } response, not allowed" ) {
727
- not Rack :: Utils :: STATUS_WITH_NO_ENTITY_BODY . key? status . to_i
728
- }
709
+ if Rack :: Utils :: STATUS_WITH_NO_ENTITY_BODY . key? status . to_i
710
+ raise LintError , "Content-Length header found in #{ status } response, not allowed"
711
+ end
729
712
@content_length = value
730
713
end
731
714
}
732
715
end
733
716
734
717
def verify_content_length ( bytes )
735
718
if @head_request
736
- assert ( "Response body was given for HEAD request, but should be empty" ) {
737
- bytes == 0
738
- }
719
+ unless bytes == 0
720
+ raise LintError , "Response body was given for HEAD request, but should be empty"
721
+ end
739
722
elsif @content_length
740
- assert ( "Content-Length header was #{ @content_length } , but should be #{ bytes } " ) {
741
- @content_length == bytes . to_s
742
- }
723
+ unless @content_length == bytes . to_s
724
+ raise LintError , "Content-Length header was #{ @content_length } , but should be #{ bytes } "
725
+ end
743
726
end
744
727
end
745
728
@@ -749,15 +732,15 @@ def each
749
732
bytes = 0
750
733
751
734
## The Body must respond to +each+
752
- assert ( "Response body must respond to each" ) do
753
- @ body. respond_to? ( : each)
735
+ unless @ body. respond_to? ( : each)
736
+ raise LintError , "Response body must respond to each"
754
737
end
755
738
756
739
@body . each { |part |
757
740
## and must only yield String values.
758
- assert ( "Body yielded non-string value #{ part . inspect } " ) {
759
- part . kind_of? String
760
- }
741
+ unless part . kind_of? String
742
+ raise LintError , "Body yielded non-string value #{ part . inspect } "
743
+ end
761
744
bytes += part . bytesize
762
745
yield part
763
746
}
@@ -770,7 +753,7 @@ def each
770
753
## If the Body responds to +close+, it will be called after iteration. If
771
754
## the body is replaced by a middleware after action, the original body
772
755
## must be closed first, if it responds to close.
773
- # XXX howto: assert( "Body has not been closed") { @closed }
756
+ # XXX howto: raise LintError, "Body has not been closed" unless @closed
774
757
775
758
776
759
##
@@ -781,9 +764,9 @@ def each
781
764
## transport the response.
782
765
783
766
if @body . respond_to? ( :to_path )
784
- assert ( "The file identified by body.to_path does not exist" ) {
785
- :: File . exist? @ body. to_path
786
- }
767
+ unless :: File . exist? @ body. to_path
768
+ raise LintError , "The file identified by body.to_path does not exist"
769
+ end
787
770
end
788
771
789
772
##
0 commit comments