openapi_first 4.0.1 → 4.2.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 +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/openapi_first/builder.rb +5 -4
- data/lib/openapi_first/child_configuration.rb +1 -0
- data/lib/openapi_first/configuration.rb +6 -1
- data/lib/openapi_first/parameters_parser.rb +14 -2
- data/lib/openapi_first/query_string_parser.rb +14 -2
- data/lib/openapi_first/request.rb +10 -1
- data/lib/openapi_first/response_parser.rb +1 -1
- data/lib/openapi_first/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 70cf5324252fd4c36421cb732127b220e45c3eefbafba7ed63ee513aea2d5b84
|
|
4
|
+
data.tar.gz: 43358cb067c765b59920160f589eb929216a9721b806a4a37b24ab039f536599
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d1b97b74dcdf98616c0f51c3e6a2c53cedb3685518f9697491eadca4110d39f12f68c54769535e6d171bf401d8d47085279124d70534fb5959c47cdf3b4d4eda
|
|
7
|
+
data.tar.gz: a27158cbd2760fa99de1f26193ce5450f5d2ef409c4a780da94ab102c24439dd1d149d6824a99cc8287617cd999cccc9de4989a33edaaaad2debfd7045a3892e
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 4.2.0
|
|
6
|
+
|
|
7
|
+
- Added `config.regexp_resolver` configuration option, `'ruby'` (default) or `'ecma'` (also as Symbol). The value is passed to json_schemer's `regexp_resolver` configuration. In OpenAPI, the pattern keyword specifies a regular expression that must conform to the ECMA-262 standard. So using `'ecma'` is recommended.
|
|
8
|
+
|
|
9
|
+
## 4.1.0
|
|
10
|
+
|
|
11
|
+
- Query and cookie parameter values with invalid encoding (like `?search=%C3`) produce a 400 response now. Before such a value passed validation or raised an `ArgumentError`. This applies to documented and undocumented query parameter, but only to documented cookie parameters.
|
|
12
|
+
- A query string with more parameters than Rack accepts (4096 by default) produces a 400 response now instead of raising `Rack::QueryParser::QueryLimitError`. See the [rack documentation](https://rack.github.io/rack/main/index.html#configuration) about how to configure this.
|
|
13
|
+
|
|
5
14
|
## 4.0.1
|
|
6
15
|
|
|
7
16
|
- Fix: Reduced memory usage with large API descriptions. Schemas no longer each deep-copy (stringify keys) the whole OAD to build a root schema. This is a json_schemer specific optimization.
|
|
@@ -27,9 +27,9 @@ module OpenapiFirst
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def initialize(contents, filepath:, config:)
|
|
30
|
+
@config = config
|
|
30
31
|
meta_schema = detect_meta_schema(contents, filepath)
|
|
31
32
|
@schemer_configuration = build_schemer_config(filepath:, meta_schema:)
|
|
32
|
-
@config = config
|
|
33
33
|
@file_loader = FileLoader.new
|
|
34
34
|
ref_resolver = RefResolver.new(file_loader:)
|
|
35
35
|
@contents = ref_resolver.for(contents, filepath:)
|
|
@@ -47,6 +47,7 @@ module OpenapiFirst
|
|
|
47
47
|
end
|
|
48
48
|
result.meta_schema = meta_schema
|
|
49
49
|
result.insert_property_defaults = true
|
|
50
|
+
result.regexp_resolver = config.regexp_resolver if config.regexp_resolver
|
|
50
51
|
result
|
|
51
52
|
end
|
|
52
53
|
|
|
@@ -126,10 +127,10 @@ module OpenapiFirst
|
|
|
126
127
|
cookie = build_parameters(grouped[:cookie])
|
|
127
128
|
ParsedParameters.new(
|
|
128
129
|
all: [*path, *query, *header, *cookie].freeze,
|
|
129
|
-
path_parser: grouped[:path] && ParametersParser.new(path),
|
|
130
|
+
path_parser: grouped[:path] && ParametersParser.new(path, check_encoding: false),
|
|
130
131
|
query_parser: QueryStringParser.new(query),
|
|
131
|
-
header_parser: grouped[:header] && ParametersParser.new(header),
|
|
132
|
-
cookie_parser: grouped[:cookie] && ParametersParser.new(cookie),
|
|
132
|
+
header_parser: grouped[:header] && ParametersParser.new(header, check_encoding: false),
|
|
133
|
+
cookie_parser: grouped[:cookie] && ParametersParser.new(cookie, check_encoding: true),
|
|
133
134
|
path_schema: build_parameter_schema(grouped[:path]),
|
|
134
135
|
query_schema: build_parameter_schema(grouped[:query]),
|
|
135
136
|
header_schema: build_parameter_schema(grouped[:header]),
|
|
@@ -16,13 +16,14 @@ module OpenapiFirst
|
|
|
16
16
|
@request_validation_error_response = OpenapiFirst.find_error_response(:default)
|
|
17
17
|
@hooks = HOOKS.to_h { [_1, Set.new] }
|
|
18
18
|
@path = nil
|
|
19
|
+
@regexp_resolver = nil
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def register(path_or_definition, as: :default)
|
|
22
23
|
OpenapiFirst.register(path_or_definition, as:)
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
attr_reader :hooks, :request_validation_error_response
|
|
26
|
+
attr_reader :hooks, :request_validation_error_response, :regexp_resolver
|
|
26
27
|
attr_accessor :path
|
|
27
28
|
|
|
28
29
|
# Return a child configuration that still receives updates of global hooks.
|
|
@@ -49,6 +50,10 @@ module OpenapiFirst
|
|
|
49
50
|
Plugins.load(name).configure(self, **)
|
|
50
51
|
end
|
|
51
52
|
|
|
53
|
+
def regexp_resolver=(resolver)
|
|
54
|
+
@regexp_resolver = resolver.is_a?(Symbol) ? resolver.to_s : resolver
|
|
55
|
+
end
|
|
56
|
+
|
|
52
57
|
def request_validation_error_response=(mod)
|
|
53
58
|
@request_validation_error_response = if mod.is_a?(Symbol)
|
|
54
59
|
OpenapiFirst.find_error_response(mod)
|
|
@@ -5,8 +5,10 @@ module OpenapiFirst
|
|
|
5
5
|
# @visibility private
|
|
6
6
|
class ParametersParser
|
|
7
7
|
# @param parameters [Array<Parameter>]
|
|
8
|
-
|
|
8
|
+
# @param check_encoding [Boolean] Raise Rack::Utils::InvalidParameterError if a value has an invalid encoding.
|
|
9
|
+
def initialize(parameters, check_encoding:)
|
|
9
10
|
@parameters = parameters
|
|
11
|
+
@check_encoding = check_encoding
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
attr_reader :parameters
|
|
@@ -16,8 +18,18 @@ module OpenapiFirst
|
|
|
16
18
|
parameters.each_with_object({}) do |parameter, result|
|
|
17
19
|
next unless parameters_hash.key?(parameter.name)
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
value = parameters_hash[parameter.name]
|
|
22
|
+
check_encoding!(value) if @check_encoding
|
|
23
|
+
result[parameter.name] = parameter.unpack_and_convert(value)
|
|
20
24
|
end
|
|
21
25
|
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def check_encoding!(value)
|
|
30
|
+
return if !value.is_a?(::String) || value.valid_encoding?
|
|
31
|
+
|
|
32
|
+
raise Rack::Utils::InvalidParameterError, "invalid encoding (#{value.inspect})"
|
|
33
|
+
end
|
|
22
34
|
end
|
|
23
35
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'rack'
|
|
4
|
+
require 'rack/query_parser'
|
|
4
5
|
require_relative 'parameters_parser'
|
|
5
6
|
|
|
6
7
|
module OpenapiFirst
|
|
@@ -10,11 +11,15 @@ module OpenapiFirst
|
|
|
10
11
|
DEEP_PROP = '\[([\w-]+)\]$'
|
|
11
12
|
private_constant :DEEP_PROP
|
|
12
13
|
|
|
14
|
+
# Rack < 3.1 does not know about Rack::BadRequest
|
|
15
|
+
BAD_REQUEST = defined?(Rack::BadRequest) ? Rack::BadRequest : Rack::QueryParser::QueryLimitError
|
|
16
|
+
private_constant :BAD_REQUEST
|
|
17
|
+
|
|
13
18
|
# @param parameters [Array<Parameter>]
|
|
14
19
|
def initialize(parameters)
|
|
15
20
|
@parameters = parameters
|
|
16
21
|
@deep_object_parameters, flat_parameters = parameters.partition(&:deep_object?)
|
|
17
|
-
@flat_parser = ParametersParser.new(flat_parameters)
|
|
22
|
+
@flat_parser = ParametersParser.new(flat_parameters, check_encoding: false)
|
|
18
23
|
@deep_object_properties = {}
|
|
19
24
|
@deep_object_regex = {}
|
|
20
25
|
@deep_object_parameters.each do |parameter|
|
|
@@ -54,16 +59,23 @@ module OpenapiFirst
|
|
|
54
59
|
return if unknown.empty?
|
|
55
60
|
|
|
56
61
|
unknown
|
|
62
|
+
rescue Rack::Utils::InvalidParameterError
|
|
63
|
+
nil
|
|
57
64
|
end
|
|
58
65
|
|
|
59
66
|
private
|
|
60
67
|
|
|
61
68
|
def parse_query(query_string)
|
|
62
69
|
Rack::Utils.parse_query(query_string) do |string|
|
|
63
|
-
Rack::Utils.unescape(string)
|
|
70
|
+
unescaped = Rack::Utils.unescape(string)
|
|
71
|
+
next unescaped if unescaped.valid_encoding?
|
|
72
|
+
|
|
73
|
+
raise Rack::Utils::InvalidParameterError, "invalid encoding (#{string})"
|
|
64
74
|
rescue ArgumentError => e
|
|
65
75
|
raise Rack::Utils::InvalidParameterError, e.message
|
|
66
76
|
end
|
|
77
|
+
rescue BAD_REQUEST => e
|
|
78
|
+
raise Rack::Utils::InvalidParameterError, e.message
|
|
67
79
|
end
|
|
68
80
|
|
|
69
81
|
def parse_deep_object(parameter, parsed_query)
|
|
@@ -61,6 +61,9 @@ module OpenapiFirst
|
|
|
61
61
|
query, query_error = parse_query(request.env[Rack::QUERY_STRING])
|
|
62
62
|
return [nil, query_error] if query_error
|
|
63
63
|
|
|
64
|
+
cookies = parse_cookies(request.env[Rack::HTTP_COOKIE])
|
|
65
|
+
return [nil, cookies] if cookies.is_a?(Failure)
|
|
66
|
+
|
|
64
67
|
body = @body_parsers&.call(request)
|
|
65
68
|
return [nil, body] if body.is_a?(Failure)
|
|
66
69
|
|
|
@@ -68,7 +71,7 @@ module OpenapiFirst
|
|
|
68
71
|
path: @path_parser&.unpack(route_params),
|
|
69
72
|
query:,
|
|
70
73
|
headers: @header_parser&.unpack(RequestHeaders.new(request.env)),
|
|
71
|
-
cookies
|
|
74
|
+
cookies:,
|
|
72
75
|
body:
|
|
73
76
|
), nil]
|
|
74
77
|
end
|
|
@@ -79,6 +82,12 @@ module OpenapiFirst
|
|
|
79
82
|
[nil, Failure.new(:invalid_query, message: 'Invalid query parameter.')]
|
|
80
83
|
end
|
|
81
84
|
|
|
85
|
+
def parse_cookies(cookie_header)
|
|
86
|
+
@cookie_parser&.unpack(Rack::Utils.parse_cookies_header(cookie_header))
|
|
87
|
+
rescue Rack::Utils::InvalidParameterError
|
|
88
|
+
Failure.new(:invalid_cookie, message: 'Invalid cookie value.')
|
|
89
|
+
end
|
|
90
|
+
|
|
82
91
|
def build_body_parser(content_type, encoding)
|
|
83
92
|
RequestBodyParsers[content_type, { encoding: encoding || {} }]
|
|
84
93
|
end
|