hanami-controller 2.0.0.beta1 → 2.0.0.beta4
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 +19 -0
- data/README.md +1 -1
- data/lib/hanami/action/config.rb +262 -0
- data/lib/hanami/action/constants.rb +6 -12
- data/lib/hanami/action/csrf_protection.rb +1 -0
- data/lib/hanami/action/error.rb +41 -0
- data/lib/hanami/action/mime.rb +65 -31
- data/lib/hanami/action/params.rb +5 -12
- data/lib/hanami/action/request.rb +21 -2
- data/lib/hanami/action/response.rb +20 -22
- data/lib/hanami/action/session.rb +4 -0
- data/lib/hanami/action.rb +106 -103
- data/lib/hanami/controller/version.rb +1 -1
- metadata +5 -4
- data/lib/hanami/action/configuration.rb +0 -436
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a363029b7df3ddc560e2975862f72548788a2a2910c2d32519f073556b4bfbb2
|
4
|
+
data.tar.gz: e7d67505e3b0161a656d24e1ff634bd02c11d4fad1e217a1ee482271be6dbbd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a9aeb4ea44db1fe6f137dee8f3e5e05bda318a8c53f1f57c30204a0077b5dcfd82aefab569fd7169c2c728de2331fcaa52f1fcdec2e3adb6d4679c38791edf6
|
7
|
+
data.tar.gz: 726de07b87cd8055da9973ea0365c00bde1f8808a1593ef3830051e196c722f001f6dc13615182f067542c605c9437259d1d36028031867edf3abd8d9612e817
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,25 @@
|
|
2
2
|
|
3
3
|
Complete, fast and testable actions for Rack
|
4
4
|
|
5
|
+
## v2.0.0.beta4 - 2022-10-24
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- [Tim Riley] Add `Response#flash`, and delgate to request object for both `Response#session` and `Response#flash`, ensuring the same objects are used when accessed via either request or response (#399)
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
|
13
|
+
- [Benjamin Klotz] When a params validation schema is provided (in a `params do` block), only return the validated params from `request.params` (#375)
|
14
|
+
- [Sean Collins] Handle dry-schema's messages hash now being frozen by default (#391)
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
|
18
|
+
- [Tim Riley] When `Action.accept` is declared (or `Action::Config.accepted_formats` configured), return a 406 error if an `Accept` request header is present but is not acceptable. In the absence of an `Accept` header, return a 415 error if a `Content-Type` header is present but not acceptable. If neither header is provided, accept the request. (#396)
|
19
|
+
- [Tim Riley] Add `Action.handle_exception` class method as a shortcut for `Hanami::Action::Config#handle_exception` (#394)
|
20
|
+
- [Tim Riley] Significantly reduce memory usage by leveraging recent dry-configurable changes, and relocating `accepted_formats`, `before_callbacks`, `after_callbacks` inheritable attributes to `config` (#392)
|
21
|
+
- [Tim Riley] Make params validation schemas (defined in `params do` block) inheritable to subclasses (#394)
|
22
|
+
- [Benhamin Klotz, Tim Riley] Raise `Hanami::Action::MissingSessionError` with a friendly message if `Request#session`, `Request#flash`, `Response#session` or `Response#flash` are called for an action that does not already include `Hanami::Action:Session` mixin (#379 via #395)
|
23
|
+
|
5
24
|
## v2.0.0.beta1 - 2022-07-20
|
6
25
|
|
7
26
|
### Fixed
|
data/README.md
CHANGED
@@ -771,7 +771,7 @@ end
|
|
771
771
|
# When called with "\*/\*" => 200
|
772
772
|
# When called with "text/html" => 200
|
773
773
|
# When called with "application/json" => 200
|
774
|
-
# When called with "application/xml" =>
|
774
|
+
# When called with "application/xml" => 415
|
775
775
|
```
|
776
776
|
|
777
777
|
You can check if the requested MIME type is accepted by the client.
|
@@ -0,0 +1,262 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/configurable"
|
4
|
+
require_relative "mime"
|
5
|
+
|
6
|
+
module Hanami
|
7
|
+
class Action
|
8
|
+
class Config < Dry::Configurable::Config
|
9
|
+
# Default MIME type to format mapping
|
10
|
+
#
|
11
|
+
# @since 0.2.0
|
12
|
+
# @api private
|
13
|
+
DEFAULT_FORMATS = {
|
14
|
+
"application/octet-stream" => :all,
|
15
|
+
"*/*" => :all,
|
16
|
+
"text/html" => :html
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
# Default public directory
|
20
|
+
#
|
21
|
+
# This serves as the root directory for file downloads
|
22
|
+
#
|
23
|
+
# @since 1.0.0
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
DEFAULT_PUBLIC_DIRECTORY = "public"
|
27
|
+
|
28
|
+
# @!attribute [rw] handled_exceptions
|
29
|
+
#
|
30
|
+
# Specifies how to handle exceptions with an HTTP status.
|
31
|
+
#
|
32
|
+
# Raised exceptions will return the corresponding HTTP status.
|
33
|
+
#
|
34
|
+
# @return [Hash{Exception=>Integer}] exception classes as keys and HTTP statuses as values
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# config.handled_exceptions = {ArgumentError => 400}
|
38
|
+
#
|
39
|
+
# @since 0.2.0
|
40
|
+
|
41
|
+
# Specifies how to handle exceptions with an HTTP status
|
42
|
+
#
|
43
|
+
# Raised exceptions will return the corresponding HTTP status
|
44
|
+
#
|
45
|
+
# The specified exceptions will be merged with any previously configured
|
46
|
+
# exceptions
|
47
|
+
#
|
48
|
+
# @param exceptions [Hash{Exception=>Integer}] exception classes as keys
|
49
|
+
# and HTTP statuses as values
|
50
|
+
#
|
51
|
+
# @return [void]
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# config.handle_exceptions(ArgumentError => 400}
|
55
|
+
#
|
56
|
+
# @see handled_exceptions
|
57
|
+
#
|
58
|
+
# @since 0.2.0
|
59
|
+
def handle_exception(exceptions)
|
60
|
+
self.handled_exceptions = handled_exceptions
|
61
|
+
.merge(exceptions)
|
62
|
+
.sort { |(ex1, _), (ex2, _)| ex1.ancestors.include?(ex2) ? -1 : 1 }
|
63
|
+
.to_h
|
64
|
+
end
|
65
|
+
|
66
|
+
# @!attribute [rw] formats
|
67
|
+
#
|
68
|
+
# Specifies the MIME type to format mapping
|
69
|
+
#
|
70
|
+
# @return [Hash{String=>Symbol}] MIME type strings as keys and format symbols as values
|
71
|
+
#
|
72
|
+
# @see format
|
73
|
+
# @see Hanami::Action::Mime
|
74
|
+
#
|
75
|
+
# @example
|
76
|
+
# config.formats = {"text/html" => :html}
|
77
|
+
#
|
78
|
+
# @since 0.2.0
|
79
|
+
|
80
|
+
# Registers a MIME type to format mapping
|
81
|
+
#
|
82
|
+
# @param hash [Hash{Symbol=>String}] format symbols as keys and the MIME
|
83
|
+
# type strings must as values
|
84
|
+
#
|
85
|
+
# @return [void]
|
86
|
+
#
|
87
|
+
# @see formats
|
88
|
+
# @see Hanami::Action::Mime
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# config.format html: "text/html"
|
92
|
+
#
|
93
|
+
# @since 0.2.0
|
94
|
+
def format(hash)
|
95
|
+
symbol, mime_type = *Utils::Kernel.Array(hash)
|
96
|
+
formats[Utils::Kernel.String(mime_type)] = Utils::Kernel.Symbol(symbol)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the configured format for the given MIME type
|
100
|
+
#
|
101
|
+
# @param mime_type [#to_s,#to_str] A mime type
|
102
|
+
#
|
103
|
+
# @return [Symbol,nil] the corresponding format, nil if not found
|
104
|
+
#
|
105
|
+
# @see format
|
106
|
+
#
|
107
|
+
# @since 0.2.0
|
108
|
+
# @api private
|
109
|
+
def format_for(mime_type)
|
110
|
+
formats[mime_type]
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns the configured format's MIME types
|
114
|
+
#
|
115
|
+
# @return [Array<String>] the format's MIME types
|
116
|
+
#
|
117
|
+
# @see formats=
|
118
|
+
# @see format
|
119
|
+
#
|
120
|
+
# @since 0.8.0
|
121
|
+
#
|
122
|
+
# @api private
|
123
|
+
def mime_types
|
124
|
+
# FIXME: this isn't efficient. speed it up!
|
125
|
+
((formats.keys - DEFAULT_FORMATS.keys) +
|
126
|
+
Hanami::Action::Mime::TYPES.values).freeze
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns a MIME type for the given format
|
130
|
+
#
|
131
|
+
# @param format [#to_sym] a format
|
132
|
+
#
|
133
|
+
# @return [String,nil] the corresponding MIME type, if present
|
134
|
+
#
|
135
|
+
# @since 0.2.0
|
136
|
+
# @api private
|
137
|
+
def mime_type_for(format)
|
138
|
+
formats.key(format)
|
139
|
+
end
|
140
|
+
|
141
|
+
# @since 2.0.0
|
142
|
+
# @api private
|
143
|
+
def accepted_mime_types
|
144
|
+
accepted_formats.any? ? Mime.restrict_mime_types(self) : mime_types
|
145
|
+
end
|
146
|
+
|
147
|
+
# @!attribute [rw] default_request_format
|
148
|
+
#
|
149
|
+
# Sets a format as default fallback for all the requests without a strict
|
150
|
+
# requirement for the MIME type.
|
151
|
+
#
|
152
|
+
# The given format must be coercible to a symbol, and be a valid MIME
|
153
|
+
# type alias. If it isn't, at runtime the framework will raise an
|
154
|
+
# `Hanami::Controller::UnknownFormatError`.
|
155
|
+
#
|
156
|
+
# By default, this value is nil.
|
157
|
+
#
|
158
|
+
# @return [Symbol]
|
159
|
+
#
|
160
|
+
# @see Hanami::Action::Mime
|
161
|
+
#
|
162
|
+
# @since 0.5.0
|
163
|
+
|
164
|
+
# @!attribute [rw] default_response_format
|
165
|
+
#
|
166
|
+
# Sets a format to be used for all responses regardless of the request
|
167
|
+
# type.
|
168
|
+
#
|
169
|
+
# The given format must be coercible to a symbol, and be a valid MIME
|
170
|
+
# type alias. If it isn't, at the runtime the framework will raise an
|
171
|
+
# `Hanami::Controller::UnknownFormatError`.
|
172
|
+
#
|
173
|
+
# By default, this value is nil.
|
174
|
+
#
|
175
|
+
# @return [Symbol]
|
176
|
+
#
|
177
|
+
# @see Hanami::Action::Mime
|
178
|
+
#
|
179
|
+
# @since 0.5.0
|
180
|
+
|
181
|
+
# @!attribute [rw] default_charset
|
182
|
+
#
|
183
|
+
# Sets a charset (character set) as default fallback for all the requests
|
184
|
+
# without a strict requirement for the charset.
|
185
|
+
#
|
186
|
+
# By default, this value is nil.
|
187
|
+
#
|
188
|
+
# @return [String]
|
189
|
+
#
|
190
|
+
# @see Hanami::Action::Mime
|
191
|
+
#
|
192
|
+
# @since 0.3.0
|
193
|
+
|
194
|
+
# @!attribute [rw] default_headers
|
195
|
+
#
|
196
|
+
# Sets default headers for all responses.
|
197
|
+
#
|
198
|
+
# By default, this is an empty hash.
|
199
|
+
#
|
200
|
+
# @return [Hash{String=>String}] the headers
|
201
|
+
#
|
202
|
+
# @example
|
203
|
+
# config.default_headers = {"X-Frame-Options" => "DENY"}
|
204
|
+
#
|
205
|
+
# @see default_headers
|
206
|
+
#
|
207
|
+
# @since 0.4.0
|
208
|
+
|
209
|
+
# @!attribute [rw] cookies
|
210
|
+
#
|
211
|
+
# Sets default cookie options for all responses.
|
212
|
+
#
|
213
|
+
# By default this, is an empty hash.
|
214
|
+
#
|
215
|
+
# @return [Hash{Symbol=>String}] the cookie options
|
216
|
+
#
|
217
|
+
# @example
|
218
|
+
# config.cookies = {
|
219
|
+
# domain: "hanamirb.org",
|
220
|
+
# path: "/controller",
|
221
|
+
# secure: true,
|
222
|
+
# httponly: true
|
223
|
+
# }
|
224
|
+
#
|
225
|
+
# @since 0.4.0
|
226
|
+
|
227
|
+
# @!attribute [rw] root_directory
|
228
|
+
#
|
229
|
+
# Sets the the for the public directory, which is used for file downloads.
|
230
|
+
# This must be an existent directory.
|
231
|
+
#
|
232
|
+
# Defaults to the current working directory.
|
233
|
+
#
|
234
|
+
# @return [String] the directory path
|
235
|
+
#
|
236
|
+
# @api private
|
237
|
+
#
|
238
|
+
# @since 1.0.0
|
239
|
+
|
240
|
+
# @!attribute [rw] public_directory
|
241
|
+
#
|
242
|
+
# Sets the path to public directory. This directory is used for file downloads.
|
243
|
+
#
|
244
|
+
# This given directory will be appended onto the root directory.
|
245
|
+
#
|
246
|
+
# By default, the public directory is `"public"`.
|
247
|
+
# @return [String] the public directory path
|
248
|
+
#
|
249
|
+
# @example
|
250
|
+
# config.public_directory = "public"
|
251
|
+
# config.public_directory # => "/path/to/root/public"
|
252
|
+
#
|
253
|
+
# @see root_directory
|
254
|
+
#
|
255
|
+
# @since 2.0.0
|
256
|
+
def public_directory
|
257
|
+
# This must be a string, for Rack compatibility
|
258
|
+
root_directory.join(super).to_s
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
@@ -114,13 +114,13 @@ module Hanami
|
|
114
114
|
#
|
115
115
|
# @since 0.1.0
|
116
116
|
# @api private
|
117
|
-
HTTP_ACCEPT
|
117
|
+
HTTP_ACCEPT = "HTTP_ACCEPT"
|
118
118
|
|
119
119
|
# The header key to set the mime type of the response
|
120
120
|
#
|
121
121
|
# @since 0.1.0
|
122
122
|
# @api private
|
123
|
-
CONTENT_TYPE
|
123
|
+
CONTENT_TYPE = ::Rack::CONTENT_TYPE
|
124
124
|
|
125
125
|
# The default mime type for an incoming HTTP request
|
126
126
|
#
|
@@ -152,7 +152,7 @@ module Hanami
|
|
152
152
|
#
|
153
153
|
# @since 2.0.0
|
154
154
|
# @api private
|
155
|
-
ETAG
|
155
|
+
ETAG = ::Rack::ETAG
|
156
156
|
|
157
157
|
# @since 2.0.0
|
158
158
|
# @api private
|
@@ -221,7 +221,7 @@ module Hanami
|
|
221
221
|
#
|
222
222
|
# @since 2.0.0
|
223
223
|
# @api private
|
224
|
-
COOKIE_HASH_KEY
|
224
|
+
COOKIE_HASH_KEY = ::Rack::RACK_REQUEST_COOKIE_HASH
|
225
225
|
|
226
226
|
# The key used by Rack to set the cookies as a String in the env
|
227
227
|
#
|
@@ -233,7 +233,7 @@ module Hanami
|
|
233
233
|
#
|
234
234
|
# @since 2.0.0
|
235
235
|
# @api private
|
236
|
-
RACK_INPUT
|
236
|
+
RACK_INPUT = ::Rack::RACK_INPUT
|
237
237
|
|
238
238
|
# The key that returns router params from the Rack env
|
239
239
|
# This is a builtin integration for Hanami::Router
|
@@ -250,12 +250,6 @@ module Hanami
|
|
250
250
|
|
251
251
|
# @since 2.0.0
|
252
252
|
# @api private
|
253
|
-
DEFAULT_CHARSET
|
254
|
-
|
255
|
-
# The key that returns content mime type from the Rack env
|
256
|
-
#
|
257
|
-
# @since 2.0.0
|
258
|
-
# @api private
|
259
|
-
HTTP_CONTENT_TYPE = "CONTENT_TYPE"
|
253
|
+
DEFAULT_CHARSET = "utf-8"
|
260
254
|
end
|
261
255
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
class Action
|
5
|
+
# @since 2.0.0
|
6
|
+
class Error < ::StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
# Missing session error
|
10
|
+
#
|
11
|
+
# This error is raised when `session` or `flash` is accessed/set on request/response objects
|
12
|
+
# in actions which do not include `Hanami::Action::Session`.
|
13
|
+
#
|
14
|
+
# @since 2.0.0
|
15
|
+
#
|
16
|
+
# @see Hanami::Action::Session
|
17
|
+
# @see Hanami::Action::Request#session
|
18
|
+
# @see Hanami::Action::Response#session
|
19
|
+
# @see Hanami::Action::Response#flash
|
20
|
+
class MissingSessionError < Error
|
21
|
+
def initialize(session_method)
|
22
|
+
super(<<~TEXT)
|
23
|
+
Sessions are not enabled. To use `#{session_method}`:
|
24
|
+
|
25
|
+
Configure sessions in your Hanami app, e.g.
|
26
|
+
|
27
|
+
module MyApp
|
28
|
+
class App < Hanami::App
|
29
|
+
# See Rack::Session::Cookie for options
|
30
|
+
config.sessions = :cookie, {**cookie_session_options}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Or include session support directly in your action class:
|
35
|
+
|
36
|
+
include Hanami::Action::Session
|
37
|
+
TEXT
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/hanami/action/mime.rb
CHANGED
@@ -84,13 +84,13 @@ module Hanami
|
|
84
84
|
#
|
85
85
|
# @since 2.0.0
|
86
86
|
# @api private
|
87
|
-
def self.content_type(
|
87
|
+
def self.content_type(config, request, accepted_mime_types)
|
88
88
|
if request.accept_header?
|
89
89
|
type = best_q_match(request.accept, accepted_mime_types)
|
90
90
|
return type if type
|
91
91
|
end
|
92
92
|
|
93
|
-
default_response_type(
|
93
|
+
default_response_type(config) || default_content_type(config) || Action::DEFAULT_CONTENT_TYPE
|
94
94
|
end
|
95
95
|
|
96
96
|
# @since 2.0.0
|
@@ -101,22 +101,22 @@ module Hanami
|
|
101
101
|
|
102
102
|
# @since 2.0.0
|
103
103
|
# @api private
|
104
|
-
def self.default_response_type(
|
105
|
-
format_to_mime_type(
|
104
|
+
def self.default_response_type(config)
|
105
|
+
format_to_mime_type(config.default_response_format, config)
|
106
106
|
end
|
107
107
|
|
108
108
|
# @since 2.0.0
|
109
109
|
# @api private
|
110
|
-
def self.default_content_type(
|
111
|
-
format_to_mime_type(
|
110
|
+
def self.default_content_type(config)
|
111
|
+
format_to_mime_type(config.default_request_format, config)
|
112
112
|
end
|
113
113
|
|
114
114
|
# @since 2.0.0
|
115
115
|
# @api private
|
116
|
-
def self.format_to_mime_type(format,
|
116
|
+
def self.format_to_mime_type(format, config)
|
117
117
|
return if format.nil?
|
118
118
|
|
119
|
-
|
119
|
+
config.mime_type_for(format) ||
|
120
120
|
TYPES.fetch(format) { raise Hanami::Controller::UnknownFormatError.new(format) }
|
121
121
|
end
|
122
122
|
|
@@ -125,17 +125,17 @@ module Hanami
|
|
125
125
|
#
|
126
126
|
# @see Hanami::Action::Mime#finish
|
127
127
|
# @example
|
128
|
-
# detect_format("text/html; charset=utf-8",
|
128
|
+
# detect_format("text/html; charset=utf-8", config) #=> :html
|
129
129
|
#
|
130
130
|
# @return [Symbol, nil]
|
131
131
|
#
|
132
132
|
# @since 2.0.0
|
133
133
|
# @api private
|
134
|
-
def self.detect_format(content_type,
|
134
|
+
def self.detect_format(content_type, config)
|
135
135
|
return if content_type.nil?
|
136
136
|
|
137
137
|
ct = content_type.split(";").first
|
138
|
-
|
138
|
+
config.format_for(ct) || format_for(ct)
|
139
139
|
end
|
140
140
|
|
141
141
|
# @since 2.0.0
|
@@ -146,7 +146,7 @@ module Hanami
|
|
146
146
|
|
147
147
|
# Transforms symbols to MIME Types
|
148
148
|
# @example
|
149
|
-
# restrict_mime_types(
|
149
|
+
# restrict_mime_types(config, [:json]) #=> ["application/json"]
|
150
150
|
#
|
151
151
|
# @return [Array<String>, nil]
|
152
152
|
#
|
@@ -154,35 +154,71 @@ module Hanami
|
|
154
154
|
#
|
155
155
|
# @since 2.0.0
|
156
156
|
# @api private
|
157
|
-
def self.restrict_mime_types(
|
158
|
-
return if accepted_formats.empty?
|
157
|
+
def self.restrict_mime_types(config)
|
158
|
+
return if config.accepted_formats.empty?
|
159
159
|
|
160
|
-
mime_types = accepted_formats.map do |format|
|
161
|
-
format_to_mime_type(format,
|
160
|
+
mime_types = config.accepted_formats.map do |format|
|
161
|
+
format_to_mime_type(format, config)
|
162
162
|
end
|
163
163
|
|
164
|
-
accepted_mime_types = mime_types &
|
164
|
+
accepted_mime_types = mime_types & config.mime_types
|
165
165
|
|
166
166
|
return if accepted_mime_types.empty?
|
167
167
|
|
168
168
|
accepted_mime_types
|
169
169
|
end
|
170
170
|
|
171
|
-
#
|
172
|
-
#
|
171
|
+
# Yields if an action is configured with `accepted_formats`, the request has an `Accept`
|
172
|
+
# header, and none of the Accept types matches the accepted formats. The given block is
|
173
|
+
# expected to halt the request handling.
|
173
174
|
#
|
174
|
-
# If
|
175
|
+
# If any of these conditions are not met, then the request is acceptable and the method
|
176
|
+
# returns without yielding.
|
175
177
|
#
|
176
|
-
# @
|
178
|
+
# @see Action#enforce_accepted_mime_types
|
179
|
+
# @see Action.accept
|
180
|
+
# @see Config#accepted_formats
|
177
181
|
#
|
178
182
|
# @since 2.0.0
|
179
183
|
# @api private
|
180
|
-
def self.
|
181
|
-
|
182
|
-
default_content_type(configuration) ||
|
183
|
-
Action::DEFAULT_CONTENT_TYPE
|
184
|
+
def self.enforce_accept(request, config)
|
185
|
+
return unless request.accept_header?
|
184
186
|
|
185
|
-
|
187
|
+
accept_types = ::Rack::Utils.q_values(request.accept).map(&:first)
|
188
|
+
return if accept_types.any? { |mime_type| accepted_mime_type?(mime_type, config) }
|
189
|
+
|
190
|
+
yield
|
191
|
+
end
|
192
|
+
|
193
|
+
# Yields if an action is configured with `accepted_formats`, the request has a `Content-Type`
|
194
|
+
# header (or a `default_requst_format` is configured), and the content type does not match the
|
195
|
+
# accepted formats. The given block is expected to halt the request handling.
|
196
|
+
#
|
197
|
+
# If any of these conditions are not met, then the request is acceptable and the method
|
198
|
+
# returns without yielding.
|
199
|
+
#
|
200
|
+
# @see Action#enforce_accepted_mime_types
|
201
|
+
# @see Action.accept
|
202
|
+
# @see Config#accepted_formats
|
203
|
+
#
|
204
|
+
# @since 2.0.0
|
205
|
+
# @api private
|
206
|
+
def self.enforce_content_type(request, config)
|
207
|
+
content_type = request.content_type || default_content_type(config)
|
208
|
+
|
209
|
+
return if content_type.nil?
|
210
|
+
|
211
|
+
return if accepted_mime_type?(content_type, config)
|
212
|
+
|
213
|
+
yield
|
214
|
+
end
|
215
|
+
|
216
|
+
# @since 2.0.0
|
217
|
+
# @api private
|
218
|
+
def self.accepted_mime_type?(mime_type, config)
|
219
|
+
config.accepted_mime_types.any? { |accepted_mime_type|
|
220
|
+
::Rack::Mime.match?(accepted_mime_type, mime_type)
|
221
|
+
}
|
186
222
|
end
|
187
223
|
|
188
224
|
# Use for setting the content_type and charset if the response
|
@@ -193,14 +229,12 @@ module Hanami
|
|
193
229
|
#
|
194
230
|
# @since 2.0.0
|
195
231
|
# @api private
|
196
|
-
def self.calculate_content_type_with_charset(
|
197
|
-
charset
|
198
|
-
content_type = self.content_type(
|
232
|
+
def self.calculate_content_type_with_charset(config, request, accepted_mime_types)
|
233
|
+
charset = self.charset(config.default_charset)
|
234
|
+
content_type = self.content_type(config, request, accepted_mime_types)
|
199
235
|
content_type_with_charset(content_type, charset)
|
200
236
|
end
|
201
237
|
|
202
|
-
# private
|
203
|
-
|
204
238
|
# Patched version of <tt>Rack::Utils.best_q_match</tt>.
|
205
239
|
#
|
206
240
|
# @since 2.0.0
|
data/lib/hanami/action/params.rb
CHANGED
@@ -25,7 +25,7 @@ module Hanami
|
|
25
25
|
# @since 1.1.0
|
26
26
|
# @api private
|
27
27
|
def initialize(errors = {})
|
28
|
-
super(errors)
|
28
|
+
super(errors.dup)
|
29
29
|
end
|
30
30
|
|
31
31
|
# Add an error to the param validations
|
@@ -160,9 +160,9 @@ module Hanami
|
|
160
160
|
def initialize(env)
|
161
161
|
@env = env
|
162
162
|
super(_extract_params)
|
163
|
-
|
164
|
-
@params =
|
165
|
-
@errors = Errors.new(
|
163
|
+
validation = validate
|
164
|
+
@params = validation.to_h
|
165
|
+
@errors = Errors.new(validation.messages)
|
166
166
|
freeze
|
167
167
|
end
|
168
168
|
|
@@ -235,7 +235,7 @@ module Hanami
|
|
235
235
|
errors.empty?
|
236
236
|
end
|
237
237
|
|
238
|
-
# Serialize params to Hash
|
238
|
+
# Serialize validated params to Hash
|
239
239
|
#
|
240
240
|
# @return [::Hash]
|
241
241
|
#
|
@@ -244,13 +244,6 @@ module Hanami
|
|
244
244
|
@params
|
245
245
|
end
|
246
246
|
alias_method :to_hash, :to_h
|
247
|
-
|
248
|
-
private
|
249
|
-
|
250
|
-
# @api private
|
251
|
-
def _params
|
252
|
-
_router_params.merge(@result.output)
|
253
|
-
end
|
254
247
|
end
|
255
248
|
end
|
256
249
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "hanami/action/flash"
|
4
4
|
require "rack/mime"
|
5
5
|
require "rack/request"
|
6
|
+
require "rack/utils"
|
6
7
|
require "securerandom"
|
7
8
|
|
8
9
|
module Hanami
|
@@ -16,9 +17,11 @@ module Hanami
|
|
16
17
|
class Request < ::Rack::Request
|
17
18
|
attr_reader :params
|
18
19
|
|
19
|
-
def initialize(env
|
20
|
+
def initialize(env:, params:, sessions_enabled: false)
|
20
21
|
super(env)
|
22
|
+
|
21
23
|
@params = params
|
24
|
+
@sessions_enabled = sessions_enabled
|
22
25
|
end
|
23
26
|
|
24
27
|
def id
|
@@ -26,6 +29,22 @@ module Hanami
|
|
26
29
|
@id ||= @env[Action::REQUEST_ID] = SecureRandom.hex(Action::DEFAULT_ID_LENGTH)
|
27
30
|
end
|
28
31
|
|
32
|
+
def session
|
33
|
+
unless @sessions_enabled
|
34
|
+
raise Hanami::Action::MissingSessionError.new("Hanami::Action::Request#session")
|
35
|
+
end
|
36
|
+
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def flash
|
41
|
+
unless @sessions_enabled
|
42
|
+
raise Hanami::Action::MissingSessionError.new("Hanami::Action::Request#flash")
|
43
|
+
end
|
44
|
+
|
45
|
+
@flash ||= Flash.new(session[Flash::KEY])
|
46
|
+
end
|
47
|
+
|
29
48
|
def accept?(mime_type)
|
30
49
|
!!::Rack::Utils.q_values(accept).find do |mime, _|
|
31
50
|
::Rack::Mime.match?(mime_type, mime)
|