@@ -480,25 +480,114 @@ def parseable_data?
480480 PARSEABLE_DATA_MEDIA_TYPES . include? ( media_type )
481481 end
482482
483- # Returns the data received in the query string.
484- def GET
485- if get_header ( RACK_REQUEST_QUERY_STRING ) == query_string
486- if query_hash = get_header ( RACK_REQUEST_QUERY_HASH )
487- return query_hash
483+ # Given a current input value, and a validity key, check if the cache
484+ # is valid, and if so, return the cached value. If not, yield the
485+ # current value to the block, and set the cache to the result.
486+ #
487+ # This method does not use cache_key, so it is shared between all
488+ # instance of Rack::Request and it's sub-classes.
489+ private def cache_for ( key , validity_key , current_value )
490+ # Get the current value of the validity key and compare it with the input value:
491+ if get_header ( validity_key ) . equal? ( current_value )
492+ # If the values are the same, then the cache is valid, so return the cached value.
493+ if has_header? ( key )
494+ value = get_header ( key )
495+ # If the cached value is an exception, then re-raise it.
496+ if value . is_a? ( Exception )
497+ raise value . class , value . message , cause : value . cause
498+ else
499+ # Otherwise, return the cached value.
500+ return value
501+ end
488502 end
489503 end
490504
491- set_header ( RACK_REQUEST_QUERY_HASH , expand_params ( query_param_list ) )
505+ # If the cache is not valid, then yield the current value to the block:
506+ value = yield ( current_value )
507+
508+ # Set the validity key to the current value so that we can detect changes:
509+ set_header ( validity_key , current_value )
510+
511+ # Set the cache to the result of the block, and return the result:
512+ set_header ( key , value )
513+ rescue => error
514+ # If an exception is raised, then set the cache to the exception, and re-raise it:
515+ set_header ( validity_key , current_value )
516+ set_header ( key , error )
517+ raise
518+ end
519+
520+ # This cache key is used by cached values generated by class_cache_for,
521+ # specfically GET and POST. This is to ensure that the cache is not
522+ # shared between instances of different classes which have different
523+ # behaviour. This includes sub-classes that override query_parser or
524+ # expand_params.
525+ def cache_key
526+ query_parser . class
527+ end
528+
529+ # Given a current input value, and a validity key, check if the cache
530+ # is valid, and if so, return the cached value. If not, yield the
531+ # current value to the block, and set the cache to the result.
532+ #
533+ # This method uses cache_key to ensure that the cache is not shared
534+ # between instances of different classes which have different
535+ # behaviour of the cached operations.
536+ private def class_cache_for ( key , validity_key , current_value )
537+ # The cache is organised in the env as:
538+ # env[key][cache_key] = value
539+ # and is valid as long as env[validity_key].equal?(current_value)
540+
541+ cache_key = self . cache_key
542+
543+ # Get the current value of the validity key and compare it with the input value:
544+ if get_header ( validity_key ) . equal? ( current_value )
545+ # Lookup the cache for the current cache key:
546+ if cache = get_header ( key )
547+ if cache . key? ( cache_key )
548+ # If the cache is valid, then return the cached value.
549+ value = cache [ cache_key ]
550+ if value . is_a? ( Exception )
551+ # If the cached value is an exception, then re-raise it.
552+ raise value . class , value . message , cause : value . cause
553+ else
554+ # Otherwise, return the cached value.
555+ return value
556+ end
557+ end
558+ end
559+ end
560+
561+ # If the cache was not defined for this cache key, then create a new cache:
562+ unless cache
563+ set_header ( key , cache = { } )
564+ end
565+
566+ begin
567+ # Yield the current value to the block to generate an updated value:
568+ value = yield ( current_value )
569+
570+ # Only set this after generating the value, so that if an error or other cache depending on the same key, it will be invalidated correctly:
571+ set_header ( validity_key , current_value )
572+ return cache [ cache_key ] = value
573+ rescue => error
574+ set_header ( validity_key , current_value )
575+ cache [ cache_key ] = error
576+ raise
577+ end
578+ end
579+
580+ # Returns the data received in the query string.
581+ def GET
582+ class_cache_for ( RACK_REQUEST_QUERY_HASH , RACK_REQUEST_QUERY_STRING , query_string ) do
583+ expand_params ( query_param_list )
584+ end
492585 end
493586
494587 def query_param_list
495- if get_header ( RACK_REQUEST_QUERY_STRING ) == query_string
496- get_header ( RACK_REQUEST_QUERY_PAIRS )
497- else
498- query_pairs = split_query ( query_string , '&' )
499- set_header RACK_REQUEST_QUERY_STRING , query_string
500- set_header RACK_REQUEST_QUERY_HASH , nil
501- set_header ( RACK_REQUEST_QUERY_PAIRS , query_pairs )
588+ cache_for ( RACK_REQUEST_QUERY_PAIRS , RACK_REQUEST_QUERY_STRING , query_string ) do
589+ set_header ( RACK_REQUEST_QUERY_HASH , nil )
590+ split_query ( query_string , '&' )
502591 end
503592 end
504593
@@ -507,33 +596,13 @@ def query_param_list
507596 # This method support both application/x-www-form-urlencoded and
508597 # multipart/form-data.
509598 def POST
510- if get_header ( RACK_REQUEST_FORM_INPUT ) . equal? ( get_header ( RACK_INPUT ) )
511- if form_hash = get_header ( RACK_REQUEST_FORM_HASH )
512- return form_hash
513- end
599+ class_cache_for ( RACK_REQUEST_FORM_HASH , RACK_REQUEST_FORM_INPUT , get_header ( RACK_INPUT ) ) do
600+ expand_params ( body_param_list )
514601 end
515-
516- set_header ( RACK_REQUEST_FORM_HASH , expand_params ( body_param_list ) )
517602 end
518603
519604 def body_param_list
520- if error = get_header ( RACK_REQUEST_FORM_ERROR )
521- raise error . class , error . message , cause : error . cause
522- end
523-
524- begin
525- rack_input = get_header ( RACK_INPUT )
526-
527- form_pairs = nil
528-
529- # If the form data has already been memoized from the same
530- # input:
531- if get_header ( RACK_REQUEST_FORM_INPUT ) . equal? ( rack_input )
532- if form_pairs = get_header ( RACK_REQUEST_FORM_PAIRS )
533- return form_pairs
534- end
535- end
536-
605+ cache_for ( RACK_REQUEST_FORM_PAIRS , RACK_REQUEST_FORM_INPUT , get_header ( RACK_INPUT ) ) do |rack_input |
537606 if rack_input . nil?
538607 form_pairs = [ ]
539608 elsif form_data? || parseable_data?
@@ -544,19 +613,16 @@ def body_param_list
544613 # form_vars.sub!(/\0\z/, '') # performance replacement:
545614 form_vars . slice! ( -1 ) if form_vars . end_with? ( "\0 " )
546615
547- set_header RACK_REQUEST_FORM_VARS , form_vars
616+ # Removing this line breaks Rail test "test_filters_rack_request_form_vars"!
617+ set_header ( RACK_REQUEST_FORM_VARS , form_vars )
618+
548619 form_pairs = split_query ( form_vars , '&' )
549620 end
550621 else
551622 form_pairs = [ ]
552623 end
553-
554- set_header RACK_REQUEST_FORM_INPUT , rack_input
555- set_header RACK_REQUEST_FORM_HASH , nil
556- set_header ( RACK_REQUEST_FORM_PAIRS , form_pairs )
557- rescue => error
558- set_header ( RACK_REQUEST_FORM_ERROR , error )
559- raise
624+
625+ form_pairs
560626 end
561627 end
562628
0 commit comments