grape 0.1.1 → 2.4.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 +7 -0
- data/CHANGELOG.md +1167 -0
- data/CONTRIBUTING.md +156 -0
- data/LICENSE +1 -1
- data/README.md +4192 -0
- data/UPGRADING.md +1697 -0
- data/grape.gemspec +28 -105
- data/grape.png +0 -0
- data/lib/grape/api/helpers.rb +9 -0
- data/lib/grape/api/instance.rb +247 -0
- data/lib/grape/api.rb +158 -194
- data/lib/grape/content_types.rb +31 -0
- data/lib/grape/cookies.rb +50 -0
- data/lib/grape/dry_types.rb +10 -0
- data/lib/grape/dsl/api.rb +17 -0
- data/lib/grape/dsl/callbacks.rb +69 -0
- data/lib/grape/dsl/configuration.rb +15 -0
- data/lib/grape/dsl/desc.rb +124 -0
- data/lib/grape/dsl/headers.rb +21 -0
- data/lib/grape/dsl/helpers.rb +108 -0
- data/lib/grape/dsl/inside_route.rb +454 -0
- data/lib/grape/dsl/logger.rb +22 -0
- data/lib/grape/dsl/middleware.rb +54 -0
- data/lib/grape/dsl/parameters.rb +266 -0
- data/lib/grape/dsl/request_response.rb +171 -0
- data/lib/grape/dsl/routing.rb +248 -0
- data/lib/grape/dsl/settings.rb +179 -0
- data/lib/grape/dsl/validations.rb +57 -0
- data/lib/grape/endpoint.rb +398 -68
- data/lib/grape/env.rb +20 -0
- data/lib/grape/error_formatter/base.rb +68 -0
- data/lib/grape/error_formatter/json.rb +28 -0
- data/lib/grape/error_formatter/serializable_hash.rb +7 -0
- data/lib/grape/error_formatter/txt.rb +21 -0
- data/lib/grape/error_formatter/xml.rb +11 -0
- data/lib/grape/error_formatter.rb +15 -0
- data/lib/grape/exceptions/base.rb +76 -0
- data/lib/grape/exceptions/conflicting_types.rb +11 -0
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/incompatible_option_values.rb +11 -0
- data/lib/grape/exceptions/invalid_accept_header.rb +11 -0
- data/lib/grape/exceptions/invalid_formatter.rb +11 -0
- data/lib/grape/exceptions/invalid_message_body.rb +11 -0
- data/lib/grape/exceptions/invalid_parameters.rb +11 -0
- data/lib/grape/exceptions/invalid_response.rb +11 -0
- data/lib/grape/exceptions/invalid_version_header.rb +11 -0
- data/lib/grape/exceptions/invalid_versioner_option.rb +11 -0
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +11 -0
- data/lib/grape/exceptions/method_not_allowed.rb +11 -0
- data/lib/grape/exceptions/missing_group_type.rb +13 -0
- data/lib/grape/exceptions/missing_mime_type.rb +11 -0
- data/lib/grape/exceptions/missing_option.rb +11 -0
- data/lib/grape/exceptions/missing_vendor_option.rb +11 -0
- data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
- data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
- data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
- data/lib/grape/exceptions/unknown_options.rb +11 -0
- data/lib/grape/exceptions/unknown_parameter.rb +11 -0
- data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
- data/lib/grape/exceptions/unknown_validator.rb +11 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +13 -0
- data/lib/grape/exceptions/validation.rb +25 -0
- data/lib/grape/exceptions/validation_array_errors.rb +14 -0
- data/lib/grape/exceptions/validation_errors.rb +53 -0
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +24 -0
- data/lib/grape/extensions/hash.rb +27 -0
- data/lib/grape/extensions/hashie/mash.rb +24 -0
- data/lib/grape/formatter/base.rb +16 -0
- data/lib/grape/formatter/json.rb +13 -0
- data/lib/grape/formatter/serializable_hash.rb +39 -0
- data/lib/grape/formatter/txt.rb +11 -0
- data/lib/grape/formatter/xml.rb +13 -0
- data/lib/grape/formatter.rb +17 -0
- data/lib/grape/json.rb +10 -0
- data/lib/grape/locale/en.yml +59 -0
- data/lib/grape/middleware/auth/base.rb +23 -0
- data/lib/grape/middleware/auth/dsl.rb +39 -0
- data/lib/grape/middleware/auth/strategies.rb +25 -0
- data/lib/grape/middleware/auth/strategy_info.rb +15 -0
- data/lib/grape/middleware/base.rb +89 -18
- data/lib/grape/middleware/error.rb +129 -10
- data/lib/grape/middleware/filter.rb +19 -0
- data/lib/grape/middleware/formatter.rb +124 -82
- data/lib/grape/middleware/globals.rb +14 -0
- data/lib/grape/middleware/stack.rb +109 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +38 -0
- data/lib/grape/middleware/versioner/base.rb +74 -0
- data/lib/grape/middleware/versioner/header.rb +127 -0
- data/lib/grape/middleware/versioner/param.rb +32 -0
- data/lib/grape/middleware/versioner/path.rb +40 -0
- data/lib/grape/middleware/versioner.rb +21 -21
- data/lib/grape/namespace.rb +46 -0
- data/lib/grape/params_builder/base.rb +18 -0
- data/lib/grape/params_builder/hash.rb +11 -0
- data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
- data/lib/grape/params_builder/hashie_mash.rb +11 -0
- data/lib/grape/params_builder.rb +32 -0
- data/lib/grape/parser/base.rb +16 -0
- data/lib/grape/parser/json.rb +14 -0
- data/lib/grape/parser/xml.rb +14 -0
- data/lib/grape/parser.rb +15 -0
- data/lib/grape/path.rb +76 -0
- data/lib/grape/presenters/presenter.rb +11 -0
- data/lib/grape/railtie.rb +9 -0
- data/lib/grape/request.rb +190 -0
- data/lib/grape/router/base_route.rb +39 -0
- data/lib/grape/router/greedy_route.rb +20 -0
- data/lib/grape/router/pattern.rb +81 -0
- data/lib/grape/router/route.rb +62 -0
- data/lib/grape/router.rb +190 -0
- data/lib/grape/serve_stream/file_body.rb +36 -0
- data/lib/grape/serve_stream/sendfile_response.rb +21 -0
- data/lib/grape/serve_stream/stream_response.rb +23 -0
- data/lib/grape/types/invalid_value.rb +8 -0
- data/lib/grape/util/base_inheritable.rb +43 -0
- data/lib/grape/util/cache.rb +17 -0
- data/lib/grape/util/endpoint_configuration.rb +8 -0
- data/lib/grape/util/header.rb +13 -0
- data/lib/grape/util/inheritable_setting.rb +100 -0
- data/lib/grape/util/inheritable_values.rb +29 -0
- data/lib/grape/util/lazy/block.rb +29 -0
- data/lib/grape/util/lazy/value.rb +38 -0
- data/lib/grape/util/lazy/value_array.rb +21 -0
- data/lib/grape/util/lazy/value_enumerable.rb +34 -0
- data/lib/grape/util/lazy/value_hash.rb +21 -0
- data/lib/grape/util/media_type.rb +70 -0
- data/lib/grape/util/registry.rb +27 -0
- data/lib/grape/util/reverse_stackable_values.rb +15 -0
- data/lib/grape/util/stackable_values.rb +36 -0
- data/lib/grape/util/strict_hash_configuration.rb +108 -0
- data/lib/grape/validations/attributes_doc.rb +60 -0
- data/lib/grape/validations/attributes_iterator.rb +62 -0
- data/lib/grape/validations/contract_scope.rb +34 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
- data/lib/grape/validations/params_scope.rb +538 -0
- data/lib/grape/validations/single_attribute_iterator.rb +26 -0
- data/lib/grape/validations/types/array_coercer.rb +61 -0
- data/lib/grape/validations/types/custom_type_coercer.rb +164 -0
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +56 -0
- data/lib/grape/validations/types/dry_type_coercer.rb +66 -0
- data/lib/grape/validations/types/file.rb +31 -0
- data/lib/grape/validations/types/invalid_value.rb +17 -0
- data/lib/grape/validations/types/json.rb +71 -0
- data/lib/grape/validations/types/multiple_type_coercer.rb +57 -0
- data/lib/grape/validations/types/primitive_coercer.rb +73 -0
- data/lib/grape/validations/types/set_coercer.rb +35 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +51 -0
- data/lib/grape/validations/types.rb +213 -0
- data/lib/grape/validations/validator_factory.rb +15 -0
- data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
- data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
- data/lib/grape/validations/validators/as_validator.rb +14 -0
- data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
- data/lib/grape/validations/validators/base.rb +88 -0
- data/lib/grape/validations/validators/coerce_validator.rb +75 -0
- data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
- data/lib/grape/validations/validators/default_validator.rb +37 -0
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
- data/lib/grape/validations/validators/except_values_validator.rb +24 -0
- data/lib/grape/validations/validators/length_validator.rb +49 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +34 -0
- data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
- data/lib/grape/validations/validators/presence_validator.rb +15 -0
- data/lib/grape/validations/validators/regexp_validator.rb +16 -0
- data/lib/grape/validations/validators/same_as_validator.rb +29 -0
- data/lib/grape/validations/validators/values_validator.rb +60 -0
- data/lib/grape/validations.rb +21 -0
- data/lib/grape/version.rb +6 -0
- data/lib/grape/xml.rb +10 -0
- data/lib/grape.rb +81 -17
- metadata +250 -192
- data/.document +0 -5
- data/.gitignore +0 -23
- data/.rspec +0 -2
- data/.rvmrc +0 -1
- data/Gemfile +0 -21
- data/Gemfile.lock +0 -58
- data/README.markdown +0 -75
- data/Rakefile +0 -70
- data/VERSION +0 -1
- data/autotest/discover.rb +0 -1
- data/lib/grape/middleware/auth/basic.rb +0 -30
- data/lib/grape/middleware/auth/oauth2.rb +0 -55
- data/lib/grape/middleware/prefixer.rb +0 -21
- data/lib/grape/middleware_stack.rb +0 -35
- data/spec/grape/api_spec.rb +0 -343
- data/spec/grape/endpoint_spec.rb +0 -104
- data/spec/grape/middleware/auth/basic_spec.rb +0 -31
- data/spec/grape/middleware/auth/oauth2_spec.rb +0 -88
- data/spec/grape/middleware/base_spec.rb +0 -63
- data/spec/grape/middleware/error_spec.rb +0 -49
- data/spec/grape/middleware/formatter_spec.rb +0 -87
- data/spec/grape/middleware/prefixer_spec.rb +0 -30
- data/spec/grape/middleware/versioner_spec.rb +0 -40
- data/spec/grape/middleware_stack_spec.rb +0 -47
- data/spec/grape_spec.rb +0 -1
- data/spec/spec_helper.rb +0 -20
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Versioners set env['api.version'] when a version is defined on an API and
|
|
4
|
+
# on the requests. The current methods for determining version are:
|
|
5
|
+
#
|
|
6
|
+
# :header - version from HTTP Accept header.
|
|
7
|
+
# :accept_version_header - version from HTTP Accept-Version header
|
|
8
|
+
# :path - version from uri. e.g. /v1/resource
|
|
9
|
+
# :param - version from uri query string, e.g. /v1/resource?apiver=v1
|
|
10
|
+
# See individual classes for details.
|
|
3
11
|
module Grape
|
|
4
12
|
module Middleware
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if options[:versions] && !options[:versions].include?(potential_version)
|
|
17
|
-
throw :error, :status => 404, :message => "404 API Version Not Found"
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
truncated_path = "/#{pieces[2..-1].join('/')}"
|
|
21
|
-
env['api.version'] = potential_version
|
|
22
|
-
env['PATH_INFO'] = truncated_path
|
|
23
|
-
end
|
|
13
|
+
module Versioner
|
|
14
|
+
extend Grape::Util::Registry
|
|
15
|
+
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
# @param strategy [Symbol] :path, :header, :accept_version_header or :param
|
|
19
|
+
# @return a middleware class based on strategy
|
|
20
|
+
def using(strategy)
|
|
21
|
+
raise Grape::Exceptions::InvalidVersionerOption, strategy unless registry.key?(strategy)
|
|
22
|
+
|
|
23
|
+
registry[strategy]
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
|
-
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
# A container for endpoints or other namespaces, which allows for both
|
|
5
|
+
# logical grouping of endpoints as well as sharing common configuration.
|
|
6
|
+
# May also be referred to as group, segment, or resource.
|
|
7
|
+
class Namespace
|
|
8
|
+
attr_reader :space, :options
|
|
9
|
+
|
|
10
|
+
# @param space [String] the name of this namespace
|
|
11
|
+
# @param options [Hash] options hash
|
|
12
|
+
# @option options :requirements [Hash] param-regex pairs, all of which must
|
|
13
|
+
# be met by a request's params for all endpoints in this namespace, or
|
|
14
|
+
# validation will fail and return a 422.
|
|
15
|
+
def initialize(space, options)
|
|
16
|
+
@space = space.to_s
|
|
17
|
+
@options = options
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Retrieves the requirements from the options hash, if given.
|
|
21
|
+
# @return [Hash]
|
|
22
|
+
def requirements
|
|
23
|
+
options[:requirements] || {}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# (see ::joined_space_path)
|
|
27
|
+
def self.joined_space(settings)
|
|
28
|
+
settings&.map(&:space)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Join the namespaces from a list of settings to create a path prefix.
|
|
32
|
+
# @param settings [Array] list of Grape::Util::InheritableSettings.
|
|
33
|
+
def self.joined_space_path(settings)
|
|
34
|
+
JoinedSpaceCache[joined_space(settings)]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class JoinedSpaceCache < Grape::Util::Cache
|
|
38
|
+
def initialize
|
|
39
|
+
super
|
|
40
|
+
@cache = Hash.new do |h, joined_space|
|
|
41
|
+
h[joined_space] = Grape::Router.normalize_path(joined_space.join('/'))
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module ParamsBuilder
|
|
5
|
+
class Base
|
|
6
|
+
class << self
|
|
7
|
+
def call(_params)
|
|
8
|
+
raise NotImplementedError
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def inherited(klass)
|
|
12
|
+
super
|
|
13
|
+
ParamsBuilder.register(klass)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module ParamsBuilder
|
|
5
|
+
extend Grape::Util::Registry
|
|
6
|
+
|
|
7
|
+
SHORT_NAME_LOOKUP = {
|
|
8
|
+
'Grape::Extensions::Hash::ParamBuilder' => :hash,
|
|
9
|
+
'Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder' => :hash_with_indifferent_access,
|
|
10
|
+
'Grape::Extensions::Hashie::Mash::ParamBuilder' => :hashie_mash
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
def params_builder_for(short_name)
|
|
16
|
+
verified_short_name = verify_short_name!(short_name)
|
|
17
|
+
|
|
18
|
+
raise Grape::Exceptions::UnknownParamsBuilder, verified_short_name unless registry.key?(verified_short_name)
|
|
19
|
+
|
|
20
|
+
registry[verified_short_name]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def verify_short_name!(short_name)
|
|
24
|
+
return short_name if short_name.is_a?(Symbol)
|
|
25
|
+
|
|
26
|
+
class_name = short_name.name
|
|
27
|
+
SHORT_NAME_LOOKUP[class_name].tap do |real_short_name|
|
|
28
|
+
Grape.deprecator.warn "#{class_name} has been deprecated. Use short name :#{real_short_name} instead."
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Parser
|
|
5
|
+
class Json < Base
|
|
6
|
+
def self.call(object, _env)
|
|
7
|
+
::Grape::Json.load(object)
|
|
8
|
+
rescue ::Grape::Json::ParseError
|
|
9
|
+
# handle JSON parsing errors via the rescue handlers or provide error message
|
|
10
|
+
raise Grape::Exceptions::InvalidMessageBody.new('application/json')
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Parser
|
|
5
|
+
class Xml < Base
|
|
6
|
+
def self.call(object, _env)
|
|
7
|
+
::Grape::Xml.parse(object)
|
|
8
|
+
rescue ::Grape::Xml::ParseError
|
|
9
|
+
# handle XML parsing errors via the rescue handlers or provide error message
|
|
10
|
+
raise Grape::Exceptions::InvalidMessageBody.new('application/xml')
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/grape/parser.rb
ADDED
data/lib/grape/path.rb
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
# Represents a path to an endpoint.
|
|
5
|
+
class Path
|
|
6
|
+
DEFAULT_FORMAT_SEGMENT = '(/.:format)'
|
|
7
|
+
NO_VERSIONING_WITH_VALID_PATH_FORMAT_SEGMENT = '(.:format)'
|
|
8
|
+
VERSION_SEGMENT = ':version'
|
|
9
|
+
|
|
10
|
+
attr_reader :origin, :suffix
|
|
11
|
+
|
|
12
|
+
def initialize(raw_path, raw_namespace, settings)
|
|
13
|
+
@origin = PartsCache[build_parts(raw_path, raw_namespace, settings)]
|
|
14
|
+
@suffix = build_suffix(raw_path, raw_namespace, settings)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_s
|
|
18
|
+
"#{origin}#{suffix}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def build_suffix(raw_path, raw_namespace, settings)
|
|
24
|
+
if uses_specific_format?(settings)
|
|
25
|
+
"(.#{settings[:format]})"
|
|
26
|
+
elsif !uses_path_versioning?(settings) || (valid_part?(raw_namespace) || valid_part?(raw_path))
|
|
27
|
+
NO_VERSIONING_WITH_VALID_PATH_FORMAT_SEGMENT
|
|
28
|
+
else
|
|
29
|
+
DEFAULT_FORMAT_SEGMENT
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def build_parts(raw_path, raw_namespace, settings)
|
|
34
|
+
[].tap do |parts|
|
|
35
|
+
add_part(parts, settings[:mount_path])
|
|
36
|
+
add_part(parts, settings[:root_prefix])
|
|
37
|
+
parts << VERSION_SEGMENT if uses_path_versioning?(settings)
|
|
38
|
+
add_part(parts, raw_namespace)
|
|
39
|
+
add_part(parts, raw_path)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def add_part(parts, value)
|
|
44
|
+
parts << value if value && not_slash?(value)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def not_slash?(value)
|
|
48
|
+
value != '/'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def uses_specific_format?(settings)
|
|
52
|
+
return false unless settings.key?(:format) && settings.key?(:content_types)
|
|
53
|
+
|
|
54
|
+
settings[:format] && Array(settings[:content_types]).size == 1
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def uses_path_versioning?(settings)
|
|
58
|
+
return false unless settings.key?(:version) && settings[:version_options]&.key?(:using)
|
|
59
|
+
|
|
60
|
+
settings[:version] && settings[:version_options][:using] == :path
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def valid_part?(part)
|
|
64
|
+
part&.match?(/^\S/) && not_slash?(part)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class PartsCache < Grape::Util::Cache
|
|
68
|
+
def initialize
|
|
69
|
+
super
|
|
70
|
+
@cache = Hash.new do |h, parts|
|
|
71
|
+
h[parts] = Grape::Router.normalize_path(parts.join('/'))
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
class Request < Rack::Request
|
|
5
|
+
# Based on rack 3 KNOWN_HEADERS
|
|
6
|
+
# https://github.com/rack/rack/blob/4f15e7b814922af79605be4b02c5b7c3044ba206/lib/rack/headers.rb#L10
|
|
7
|
+
|
|
8
|
+
KNOWN_HEADERS = %w[
|
|
9
|
+
Accept
|
|
10
|
+
Accept-CH
|
|
11
|
+
Accept-Encoding
|
|
12
|
+
Accept-Language
|
|
13
|
+
Accept-Patch
|
|
14
|
+
Accept-Ranges
|
|
15
|
+
Accept-Version
|
|
16
|
+
Access-Control-Allow-Credentials
|
|
17
|
+
Access-Control-Allow-Headers
|
|
18
|
+
Access-Control-Allow-Methods
|
|
19
|
+
Access-Control-Allow-Origin
|
|
20
|
+
Access-Control-Expose-Headers
|
|
21
|
+
Access-Control-Max-Age
|
|
22
|
+
Age
|
|
23
|
+
Allow
|
|
24
|
+
Alt-Svc
|
|
25
|
+
Authorization
|
|
26
|
+
Cache-Control
|
|
27
|
+
Client-Ip
|
|
28
|
+
Connection
|
|
29
|
+
Content-Disposition
|
|
30
|
+
Content-Encoding
|
|
31
|
+
Content-Language
|
|
32
|
+
Content-Length
|
|
33
|
+
Content-Location
|
|
34
|
+
Content-MD5
|
|
35
|
+
Content-Range
|
|
36
|
+
Content-Security-Policy
|
|
37
|
+
Content-Security-Policy-Report-Only
|
|
38
|
+
Content-Type
|
|
39
|
+
Cookie
|
|
40
|
+
Date
|
|
41
|
+
Delta-Base
|
|
42
|
+
Dnt
|
|
43
|
+
ETag
|
|
44
|
+
Expect-CT
|
|
45
|
+
Expires
|
|
46
|
+
Feature-Policy
|
|
47
|
+
Forwarded
|
|
48
|
+
Host
|
|
49
|
+
If-Modified-Since
|
|
50
|
+
If-None-Match
|
|
51
|
+
IM
|
|
52
|
+
Last-Modified
|
|
53
|
+
Link
|
|
54
|
+
Location
|
|
55
|
+
NEL
|
|
56
|
+
P3P
|
|
57
|
+
Permissions-Policy
|
|
58
|
+
Pragma
|
|
59
|
+
Preference-Applied
|
|
60
|
+
Proxy-Authenticate
|
|
61
|
+
Public-Key-Pins
|
|
62
|
+
Range
|
|
63
|
+
Referer
|
|
64
|
+
Referrer-Policy
|
|
65
|
+
Refresh
|
|
66
|
+
Report-To
|
|
67
|
+
Retry-After
|
|
68
|
+
Sec-Fetch-Dest
|
|
69
|
+
Sec-Fetch-Mode
|
|
70
|
+
Sec-Fetch-Site
|
|
71
|
+
Sec-Fetch-User
|
|
72
|
+
Server
|
|
73
|
+
Set-Cookie
|
|
74
|
+
Status
|
|
75
|
+
Strict-Transport-Security
|
|
76
|
+
Timing-Allow-Origin
|
|
77
|
+
Tk
|
|
78
|
+
Trailer
|
|
79
|
+
Transfer-Encoding
|
|
80
|
+
Upgrade
|
|
81
|
+
Upgrade-Insecure-Requests
|
|
82
|
+
User-Agent
|
|
83
|
+
Vary
|
|
84
|
+
Version
|
|
85
|
+
Via
|
|
86
|
+
Warning
|
|
87
|
+
WWW-Authenticate
|
|
88
|
+
X-Accel-Buffering
|
|
89
|
+
X-Accel-Charset
|
|
90
|
+
X-Accel-Expires
|
|
91
|
+
X-Accel-Limit-Rate
|
|
92
|
+
X-Accel-Mapping
|
|
93
|
+
X-Accel-Redirect
|
|
94
|
+
X-Access-Token
|
|
95
|
+
X-Auth-Request-Access-Token
|
|
96
|
+
X-Auth-Request-Email
|
|
97
|
+
X-Auth-Request-Groups
|
|
98
|
+
X-Auth-Request-Preferred-Username
|
|
99
|
+
X-Auth-Request-Redirect
|
|
100
|
+
X-Auth-Request-Token
|
|
101
|
+
X-Auth-Request-User
|
|
102
|
+
X-Cascade
|
|
103
|
+
X-Client-Ip
|
|
104
|
+
X-Content-Duration
|
|
105
|
+
X-Content-Security-Policy
|
|
106
|
+
X-Content-Type-Options
|
|
107
|
+
X-Correlation-Id
|
|
108
|
+
X-Download-Options
|
|
109
|
+
X-Forwarded-Access-Token
|
|
110
|
+
X-Forwarded-Email
|
|
111
|
+
X-Forwarded-For
|
|
112
|
+
X-Forwarded-Groups
|
|
113
|
+
X-Forwarded-Host
|
|
114
|
+
X-Forwarded-Port
|
|
115
|
+
X-Forwarded-Preferred-Username
|
|
116
|
+
X-Forwarded-Proto
|
|
117
|
+
X-Forwarded-Scheme
|
|
118
|
+
X-Forwarded-Ssl
|
|
119
|
+
X-Forwarded-Uri
|
|
120
|
+
X-Forwarded-User
|
|
121
|
+
X-Frame-Options
|
|
122
|
+
X-HTTP-Method-Override
|
|
123
|
+
X-Permitted-Cross-Domain-Policies
|
|
124
|
+
X-Powered-By
|
|
125
|
+
X-Real-IP
|
|
126
|
+
X-Redirect-By
|
|
127
|
+
X-Request-Id
|
|
128
|
+
X-Requested-With
|
|
129
|
+
X-Runtime
|
|
130
|
+
X-Sendfile
|
|
131
|
+
X-Sendfile-Type
|
|
132
|
+
X-UA-Compatible
|
|
133
|
+
X-WebKit-CS
|
|
134
|
+
X-XSS-Protection
|
|
135
|
+
].each_with_object({}) do |header, response|
|
|
136
|
+
response["HTTP_#{header.upcase.tr('-', '_')}"] = header
|
|
137
|
+
end.freeze
|
|
138
|
+
|
|
139
|
+
alias rack_params params
|
|
140
|
+
alias rack_cookies cookies
|
|
141
|
+
|
|
142
|
+
def initialize(env, build_params_with: nil)
|
|
143
|
+
super(env)
|
|
144
|
+
@params_builder = Grape::ParamsBuilder.params_builder_for(build_params_with || Grape.config.param_builder)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def params
|
|
148
|
+
@params ||= make_params
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def headers
|
|
152
|
+
@headers ||= build_headers
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def cookies
|
|
156
|
+
@cookies ||= Grape::Cookies.new(-> { rack_cookies })
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# needs to be public until extensions param_builder are removed
|
|
160
|
+
def grape_routing_args
|
|
161
|
+
# preserve version from query string parameters
|
|
162
|
+
env[Grape::Env::GRAPE_ROUTING_ARGS]&.except(:version, :route_info) || {}
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
|
|
167
|
+
def make_params
|
|
168
|
+
@params_builder.call(rack_params).deep_merge!(grape_routing_args)
|
|
169
|
+
rescue EOFError
|
|
170
|
+
raise Grape::Exceptions::EmptyMessageBody.new(content_type)
|
|
171
|
+
rescue Rack::Multipart::MultipartPartLimitError, Rack::Multipart::MultipartTotalPartLimitError
|
|
172
|
+
raise Grape::Exceptions::TooManyMultipartFiles.new(Rack::Utils.multipart_part_limit)
|
|
173
|
+
rescue Rack::QueryParser::ParamsTooDeepError
|
|
174
|
+
raise Grape::Exceptions::TooDeepParameters.new(Rack::Utils.param_depth_limit)
|
|
175
|
+
rescue Rack::Utils::ParameterTypeError
|
|
176
|
+
raise Grape::Exceptions::ConflictingTypes
|
|
177
|
+
rescue Rack::Utils::InvalidParameterError
|
|
178
|
+
raise Grape::Exceptions::InvalidParameters
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def build_headers
|
|
182
|
+
each_header.with_object(Grape::Util::Header.new) do |(k, v), headers|
|
|
183
|
+
next unless k.start_with? 'HTTP_'
|
|
184
|
+
|
|
185
|
+
transformed_header = KNOWN_HEADERS.fetch(k) { -k[5..].tr('_', '-').downcase }
|
|
186
|
+
headers[transformed_header] = v
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
class Router
|
|
5
|
+
class BaseRoute
|
|
6
|
+
delegate_missing_to :@options
|
|
7
|
+
|
|
8
|
+
attr_reader :index, :pattern, :options
|
|
9
|
+
|
|
10
|
+
def initialize(options)
|
|
11
|
+
@options = options.is_a?(ActiveSupport::OrderedOptions) ? options : ActiveSupport::OrderedOptions.new.update(options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
alias attributes options
|
|
15
|
+
|
|
16
|
+
def regexp_capture_index
|
|
17
|
+
CaptureIndexCache[index]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def pattern_regexp
|
|
21
|
+
pattern.to_regexp
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_regexp(index)
|
|
25
|
+
@index = index
|
|
26
|
+
Regexp.new("(?<#{regexp_capture_index}>#{pattern_regexp})")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class CaptureIndexCache < Grape::Util::Cache
|
|
30
|
+
def initialize
|
|
31
|
+
super
|
|
32
|
+
@cache = Hash.new do |h, index|
|
|
33
|
+
h[index] = "_#{index}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Act like a Grape::Router::Route but for greedy_match
|
|
4
|
+
# see @neutral_map
|
|
5
|
+
|
|
6
|
+
module Grape
|
|
7
|
+
class Router
|
|
8
|
+
class GreedyRoute < BaseRoute
|
|
9
|
+
def initialize(pattern, options)
|
|
10
|
+
@pattern = pattern
|
|
11
|
+
super(options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Grape::Router:Route defines params as a function
|
|
15
|
+
def params(_input = nil)
|
|
16
|
+
options[:params] || {}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
class Router
|
|
5
|
+
class Pattern
|
|
6
|
+
extend Forwardable
|
|
7
|
+
|
|
8
|
+
DEFAULT_CAPTURES = %w[format version].freeze
|
|
9
|
+
|
|
10
|
+
attr_reader :origin, :path, :pattern, :to_regexp
|
|
11
|
+
|
|
12
|
+
def_delegators :pattern, :params
|
|
13
|
+
def_delegators :to_regexp, :===
|
|
14
|
+
alias match? ===
|
|
15
|
+
|
|
16
|
+
def initialize(origin, suffix, options)
|
|
17
|
+
@origin = origin
|
|
18
|
+
@path = build_path(origin, options[:anchor], suffix)
|
|
19
|
+
@pattern = build_pattern(@path, options[:params], options[:format], options[:version], options[:requirements])
|
|
20
|
+
@to_regexp = @pattern.to_regexp
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def captures_default
|
|
24
|
+
to_regexp.names
|
|
25
|
+
.delete_if { |n| DEFAULT_CAPTURES.include?(n) }
|
|
26
|
+
.to_h { |k| [k, ''] }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def build_pattern(path, params, format, version, requirements)
|
|
32
|
+
Mustermann::Grape.new(
|
|
33
|
+
path,
|
|
34
|
+
uri_decode: true,
|
|
35
|
+
params: params,
|
|
36
|
+
capture: extract_capture(format, version, requirements)
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def build_path(pattern, anchor, suffix)
|
|
41
|
+
PatternCache[[build_path_from_pattern(pattern, anchor), suffix]]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def extract_capture(format, version, requirements)
|
|
45
|
+
capture = {}.tap do |h|
|
|
46
|
+
h[:format] = map_str(format) if format.present?
|
|
47
|
+
h[:version] = map_str(version) if version.present?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
return capture if requirements.blank?
|
|
51
|
+
|
|
52
|
+
requirements.merge(capture)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def build_path_from_pattern(pattern, anchor)
|
|
56
|
+
if pattern.end_with?('*path')
|
|
57
|
+
pattern.dup.insert(pattern.rindex('/') + 1, '?')
|
|
58
|
+
elsif anchor
|
|
59
|
+
pattern
|
|
60
|
+
elsif pattern.end_with?('/')
|
|
61
|
+
"#{pattern}?*path"
|
|
62
|
+
else
|
|
63
|
+
"#{pattern}/?*path"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def map_str(value)
|
|
68
|
+
Array.wrap(value).map(&:to_s)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class PatternCache < Grape::Util::Cache
|
|
72
|
+
def initialize
|
|
73
|
+
super
|
|
74
|
+
@cache = Hash.new do |h, (pattern, suffix)|
|
|
75
|
+
h[[pattern, suffix]] = -"#{pattern}#{suffix}"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|