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.
Files changed (197) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1167 -0
  3. data/CONTRIBUTING.md +156 -0
  4. data/LICENSE +1 -1
  5. data/README.md +4192 -0
  6. data/UPGRADING.md +1697 -0
  7. data/grape.gemspec +28 -105
  8. data/grape.png +0 -0
  9. data/lib/grape/api/helpers.rb +9 -0
  10. data/lib/grape/api/instance.rb +247 -0
  11. data/lib/grape/api.rb +158 -194
  12. data/lib/grape/content_types.rb +31 -0
  13. data/lib/grape/cookies.rb +50 -0
  14. data/lib/grape/dry_types.rb +10 -0
  15. data/lib/grape/dsl/api.rb +17 -0
  16. data/lib/grape/dsl/callbacks.rb +69 -0
  17. data/lib/grape/dsl/configuration.rb +15 -0
  18. data/lib/grape/dsl/desc.rb +124 -0
  19. data/lib/grape/dsl/headers.rb +21 -0
  20. data/lib/grape/dsl/helpers.rb +108 -0
  21. data/lib/grape/dsl/inside_route.rb +454 -0
  22. data/lib/grape/dsl/logger.rb +22 -0
  23. data/lib/grape/dsl/middleware.rb +54 -0
  24. data/lib/grape/dsl/parameters.rb +266 -0
  25. data/lib/grape/dsl/request_response.rb +171 -0
  26. data/lib/grape/dsl/routing.rb +248 -0
  27. data/lib/grape/dsl/settings.rb +179 -0
  28. data/lib/grape/dsl/validations.rb +57 -0
  29. data/lib/grape/endpoint.rb +398 -68
  30. data/lib/grape/env.rb +20 -0
  31. data/lib/grape/error_formatter/base.rb +68 -0
  32. data/lib/grape/error_formatter/json.rb +28 -0
  33. data/lib/grape/error_formatter/serializable_hash.rb +7 -0
  34. data/lib/grape/error_formatter/txt.rb +21 -0
  35. data/lib/grape/error_formatter/xml.rb +11 -0
  36. data/lib/grape/error_formatter.rb +15 -0
  37. data/lib/grape/exceptions/base.rb +76 -0
  38. data/lib/grape/exceptions/conflicting_types.rb +11 -0
  39. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  40. data/lib/grape/exceptions/incompatible_option_values.rb +11 -0
  41. data/lib/grape/exceptions/invalid_accept_header.rb +11 -0
  42. data/lib/grape/exceptions/invalid_formatter.rb +11 -0
  43. data/lib/grape/exceptions/invalid_message_body.rb +11 -0
  44. data/lib/grape/exceptions/invalid_parameters.rb +11 -0
  45. data/lib/grape/exceptions/invalid_response.rb +11 -0
  46. data/lib/grape/exceptions/invalid_version_header.rb +11 -0
  47. data/lib/grape/exceptions/invalid_versioner_option.rb +11 -0
  48. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +11 -0
  49. data/lib/grape/exceptions/method_not_allowed.rb +11 -0
  50. data/lib/grape/exceptions/missing_group_type.rb +13 -0
  51. data/lib/grape/exceptions/missing_mime_type.rb +11 -0
  52. data/lib/grape/exceptions/missing_option.rb +11 -0
  53. data/lib/grape/exceptions/missing_vendor_option.rb +11 -0
  54. data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
  55. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  56. data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
  57. data/lib/grape/exceptions/unknown_options.rb +11 -0
  58. data/lib/grape/exceptions/unknown_parameter.rb +11 -0
  59. data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
  60. data/lib/grape/exceptions/unknown_validator.rb +11 -0
  61. data/lib/grape/exceptions/unsupported_group_type.rb +13 -0
  62. data/lib/grape/exceptions/validation.rb +25 -0
  63. data/lib/grape/exceptions/validation_array_errors.rb +14 -0
  64. data/lib/grape/exceptions/validation_errors.rb +53 -0
  65. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +24 -0
  66. data/lib/grape/extensions/hash.rb +27 -0
  67. data/lib/grape/extensions/hashie/mash.rb +24 -0
  68. data/lib/grape/formatter/base.rb +16 -0
  69. data/lib/grape/formatter/json.rb +13 -0
  70. data/lib/grape/formatter/serializable_hash.rb +39 -0
  71. data/lib/grape/formatter/txt.rb +11 -0
  72. data/lib/grape/formatter/xml.rb +13 -0
  73. data/lib/grape/formatter.rb +17 -0
  74. data/lib/grape/json.rb +10 -0
  75. data/lib/grape/locale/en.yml +59 -0
  76. data/lib/grape/middleware/auth/base.rb +23 -0
  77. data/lib/grape/middleware/auth/dsl.rb +39 -0
  78. data/lib/grape/middleware/auth/strategies.rb +25 -0
  79. data/lib/grape/middleware/auth/strategy_info.rb +15 -0
  80. data/lib/grape/middleware/base.rb +89 -18
  81. data/lib/grape/middleware/error.rb +129 -10
  82. data/lib/grape/middleware/filter.rb +19 -0
  83. data/lib/grape/middleware/formatter.rb +124 -82
  84. data/lib/grape/middleware/globals.rb +14 -0
  85. data/lib/grape/middleware/stack.rb +109 -0
  86. data/lib/grape/middleware/versioner/accept_version_header.rb +38 -0
  87. data/lib/grape/middleware/versioner/base.rb +74 -0
  88. data/lib/grape/middleware/versioner/header.rb +127 -0
  89. data/lib/grape/middleware/versioner/param.rb +32 -0
  90. data/lib/grape/middleware/versioner/path.rb +40 -0
  91. data/lib/grape/middleware/versioner.rb +21 -21
  92. data/lib/grape/namespace.rb +46 -0
  93. data/lib/grape/params_builder/base.rb +18 -0
  94. data/lib/grape/params_builder/hash.rb +11 -0
  95. data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
  96. data/lib/grape/params_builder/hashie_mash.rb +11 -0
  97. data/lib/grape/params_builder.rb +32 -0
  98. data/lib/grape/parser/base.rb +16 -0
  99. data/lib/grape/parser/json.rb +14 -0
  100. data/lib/grape/parser/xml.rb +14 -0
  101. data/lib/grape/parser.rb +15 -0
  102. data/lib/grape/path.rb +76 -0
  103. data/lib/grape/presenters/presenter.rb +11 -0
  104. data/lib/grape/railtie.rb +9 -0
  105. data/lib/grape/request.rb +190 -0
  106. data/lib/grape/router/base_route.rb +39 -0
  107. data/lib/grape/router/greedy_route.rb +20 -0
  108. data/lib/grape/router/pattern.rb +81 -0
  109. data/lib/grape/router/route.rb +62 -0
  110. data/lib/grape/router.rb +190 -0
  111. data/lib/grape/serve_stream/file_body.rb +36 -0
  112. data/lib/grape/serve_stream/sendfile_response.rb +21 -0
  113. data/lib/grape/serve_stream/stream_response.rb +23 -0
  114. data/lib/grape/types/invalid_value.rb +8 -0
  115. data/lib/grape/util/base_inheritable.rb +43 -0
  116. data/lib/grape/util/cache.rb +17 -0
  117. data/lib/grape/util/endpoint_configuration.rb +8 -0
  118. data/lib/grape/util/header.rb +13 -0
  119. data/lib/grape/util/inheritable_setting.rb +100 -0
  120. data/lib/grape/util/inheritable_values.rb +29 -0
  121. data/lib/grape/util/lazy/block.rb +29 -0
  122. data/lib/grape/util/lazy/value.rb +38 -0
  123. data/lib/grape/util/lazy/value_array.rb +21 -0
  124. data/lib/grape/util/lazy/value_enumerable.rb +34 -0
  125. data/lib/grape/util/lazy/value_hash.rb +21 -0
  126. data/lib/grape/util/media_type.rb +70 -0
  127. data/lib/grape/util/registry.rb +27 -0
  128. data/lib/grape/util/reverse_stackable_values.rb +15 -0
  129. data/lib/grape/util/stackable_values.rb +36 -0
  130. data/lib/grape/util/strict_hash_configuration.rb +108 -0
  131. data/lib/grape/validations/attributes_doc.rb +60 -0
  132. data/lib/grape/validations/attributes_iterator.rb +62 -0
  133. data/lib/grape/validations/contract_scope.rb +34 -0
  134. data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
  135. data/lib/grape/validations/params_scope.rb +538 -0
  136. data/lib/grape/validations/single_attribute_iterator.rb +26 -0
  137. data/lib/grape/validations/types/array_coercer.rb +61 -0
  138. data/lib/grape/validations/types/custom_type_coercer.rb +164 -0
  139. data/lib/grape/validations/types/custom_type_collection_coercer.rb +56 -0
  140. data/lib/grape/validations/types/dry_type_coercer.rb +66 -0
  141. data/lib/grape/validations/types/file.rb +31 -0
  142. data/lib/grape/validations/types/invalid_value.rb +17 -0
  143. data/lib/grape/validations/types/json.rb +71 -0
  144. data/lib/grape/validations/types/multiple_type_coercer.rb +57 -0
  145. data/lib/grape/validations/types/primitive_coercer.rb +73 -0
  146. data/lib/grape/validations/types/set_coercer.rb +35 -0
  147. data/lib/grape/validations/types/variant_collection_coercer.rb +51 -0
  148. data/lib/grape/validations/types.rb +213 -0
  149. data/lib/grape/validations/validator_factory.rb +15 -0
  150. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  151. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  152. data/lib/grape/validations/validators/as_validator.rb +14 -0
  153. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  154. data/lib/grape/validations/validators/base.rb +88 -0
  155. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  156. data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
  157. data/lib/grape/validations/validators/default_validator.rb +37 -0
  158. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  159. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  160. data/lib/grape/validations/validators/length_validator.rb +49 -0
  161. data/lib/grape/validations/validators/multiple_params_base.rb +34 -0
  162. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  163. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  164. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  165. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  166. data/lib/grape/validations/validators/values_validator.rb +60 -0
  167. data/lib/grape/validations.rb +21 -0
  168. data/lib/grape/version.rb +6 -0
  169. data/lib/grape/xml.rb +10 -0
  170. data/lib/grape.rb +81 -17
  171. metadata +250 -192
  172. data/.document +0 -5
  173. data/.gitignore +0 -23
  174. data/.rspec +0 -2
  175. data/.rvmrc +0 -1
  176. data/Gemfile +0 -21
  177. data/Gemfile.lock +0 -58
  178. data/README.markdown +0 -75
  179. data/Rakefile +0 -70
  180. data/VERSION +0 -1
  181. data/autotest/discover.rb +0 -1
  182. data/lib/grape/middleware/auth/basic.rb +0 -30
  183. data/lib/grape/middleware/auth/oauth2.rb +0 -55
  184. data/lib/grape/middleware/prefixer.rb +0 -21
  185. data/lib/grape/middleware_stack.rb +0 -35
  186. data/spec/grape/api_spec.rb +0 -343
  187. data/spec/grape/endpoint_spec.rb +0 -104
  188. data/spec/grape/middleware/auth/basic_spec.rb +0 -31
  189. data/spec/grape/middleware/auth/oauth2_spec.rb +0 -88
  190. data/spec/grape/middleware/base_spec.rb +0 -63
  191. data/spec/grape/middleware/error_spec.rb +0 -49
  192. data/spec/grape/middleware/formatter_spec.rb +0 -87
  193. data/spec/grape/middleware/prefixer_spec.rb +0 -30
  194. data/spec/grape/middleware/versioner_spec.rb +0 -40
  195. data/spec/grape/middleware_stack_spec.rb +0 -47
  196. data/spec/grape_spec.rb +0 -1
  197. data/spec/spec_helper.rb +0 -20
@@ -1,27 +1,27 @@
1
- require 'grape/middleware/base'
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
- class Versioner < Base
6
- def default_options
7
- {
8
- :pattern => /.*/i
9
- }
10
- end
11
-
12
- def before
13
- pieces = env['PATH_INFO'].split('/')
14
- potential_version = pieces[1]
15
- if potential_version =~ options[:pattern]
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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module ParamsBuilder
5
+ class Hash < Base
6
+ def self.call(params)
7
+ params.deep_symbolize_keys
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module ParamsBuilder
5
+ class HashWithIndifferentAccess < Base
6
+ def self.call(params)
7
+ params.with_indifferent_access
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module ParamsBuilder
5
+ class HashieMash < Base
6
+ def self.call(params)
7
+ ::Hashie::Mash.new(params)
8
+ end
9
+ end
10
+ end
11
+ 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,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Parser
5
+ class Base
6
+ def self.call(_object, _env)
7
+ raise NotImplementedError
8
+ end
9
+
10
+ def self.inherited(klass)
11
+ super
12
+ Parser.register(klass)
13
+ end
14
+ end
15
+ end
16
+ 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
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Parser
5
+ extend Grape::Util::Registry
6
+
7
+ module_function
8
+
9
+ def parser_for(format, parsers = nil)
10
+ return parsers[format] if parsers&.key?(format)
11
+
12
+ registry[format]
13
+ end
14
+ end
15
+ end
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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Presenters
5
+ class Presenter
6
+ def self.represent(object, **_options)
7
+ object
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ class Railtie < ::Rails::Railtie
5
+ initializer 'grape.deprecator' do |app|
6
+ app.deprecators[:grape] = Grape.deprecator
7
+ end
8
+ end
9
+ 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