hanami-action 3.0.0.rc1
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 +985 -0
- data/LICENSE +20 -0
- data/README.md +873 -0
- data/hanami-action.gemspec +39 -0
- data/lib/hanami/action/body_parser/json.rb +20 -0
- data/lib/hanami/action/body_parser/multipart_form.rb +22 -0
- data/lib/hanami/action/body_parser.rb +109 -0
- data/lib/hanami/action/cache/cache_control.rb +84 -0
- data/lib/hanami/action/cache/conditional_get.rb +101 -0
- data/lib/hanami/action/cache/directives.rb +126 -0
- data/lib/hanami/action/cache/expires.rb +84 -0
- data/lib/hanami/action/cache.rb +29 -0
- data/lib/hanami/action/config/formats.rb +256 -0
- data/lib/hanami/action/config.rb +172 -0
- data/lib/hanami/action/constants.rb +283 -0
- data/lib/hanami/action/cookie_jar.rb +214 -0
- data/lib/hanami/action/cookies.rb +27 -0
- data/lib/hanami/action/csrf_protection.rb +217 -0
- data/lib/hanami/action/errors.rb +109 -0
- data/lib/hanami/action/flash.rb +176 -0
- data/lib/hanami/action/halt.rb +18 -0
- data/lib/hanami/action/mime/request_mime_weight.rb +66 -0
- data/lib/hanami/action/mime.rb +438 -0
- data/lib/hanami/action/params.rb +342 -0
- data/lib/hanami/action/rack/file.rb +41 -0
- data/lib/hanami/action/rack_utils.rb +11 -0
- data/lib/hanami/action/request/session.rb +68 -0
- data/lib/hanami/action/request.rb +141 -0
- data/lib/hanami/action/response.rb +481 -0
- data/lib/hanami/action/session.rb +47 -0
- data/lib/hanami/action/validatable.rb +166 -0
- data/lib/hanami/action/version.rb +13 -0
- data/lib/hanami/action/view_name_inferrer.rb +56 -0
- data/lib/hanami/action.rb +672 -0
- data/lib/hanami/http/status.rb +149 -0
- data/lib/hanami-action.rb +3 -0
- metadata +153 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/utils/kernel"
|
|
4
|
+
require "dry/core"
|
|
5
|
+
|
|
6
|
+
module Hanami
|
|
7
|
+
class Action
|
|
8
|
+
class Config
|
|
9
|
+
# Action format configuration.
|
|
10
|
+
#
|
|
11
|
+
# @since 2.0.0
|
|
12
|
+
# @api private
|
|
13
|
+
class Formats
|
|
14
|
+
include Dry.Equalizer(:accepted, :mapping)
|
|
15
|
+
|
|
16
|
+
# @since 2.0.0
|
|
17
|
+
# @api private
|
|
18
|
+
attr_reader :mapping
|
|
19
|
+
|
|
20
|
+
# The array of formats to accept requests by.
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# config.formats.accepted = [:html, :json]
|
|
24
|
+
# config.formats.accepted # => [:html, :json]
|
|
25
|
+
#
|
|
26
|
+
# @since 2.0.0
|
|
27
|
+
# @api public
|
|
28
|
+
attr_reader :accepted
|
|
29
|
+
|
|
30
|
+
# The registered body parsers, as a hash mapping content types to callable parsers.
|
|
31
|
+
#
|
|
32
|
+
# @return [Hash{String => #call}]
|
|
33
|
+
#
|
|
34
|
+
# @since x.x.x
|
|
35
|
+
# @api public
|
|
36
|
+
attr_reader :body_parsers
|
|
37
|
+
|
|
38
|
+
# Returns the default format name.
|
|
39
|
+
#
|
|
40
|
+
# When a request is received that cannot
|
|
41
|
+
#
|
|
42
|
+
# @return [Symbol, nil] the default format name, if any
|
|
43
|
+
#
|
|
44
|
+
# @example
|
|
45
|
+
# @config.formats.default # => :json
|
|
46
|
+
#
|
|
47
|
+
# @since 2.0.0
|
|
48
|
+
# @api public
|
|
49
|
+
attr_reader :default
|
|
50
|
+
|
|
51
|
+
# @since 2.0.0
|
|
52
|
+
# @api private
|
|
53
|
+
def initialize(accepted: [], default: nil, mapping: {})
|
|
54
|
+
@accepted = accepted
|
|
55
|
+
@default = default
|
|
56
|
+
@mapping = mapping
|
|
57
|
+
@body_parsers = {}
|
|
58
|
+
|
|
59
|
+
register_default_body_parsers
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @since 2.0.0
|
|
63
|
+
# @api private
|
|
64
|
+
private def initialize_copy(original)
|
|
65
|
+
super
|
|
66
|
+
@accepted = original.accepted.dup
|
|
67
|
+
@default = original.default
|
|
68
|
+
@mapping = original.mapping.dup
|
|
69
|
+
@body_parsers = original.body_parsers.dup
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# !@attribute [w] accepted
|
|
73
|
+
# @since 2.3.0
|
|
74
|
+
# @api public
|
|
75
|
+
def accepted=(formats)
|
|
76
|
+
@accepted = formats.map { |f| Hanami::Utils::Kernel.Symbol(f) }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @since 2.3.0
|
|
80
|
+
def accept(*formats)
|
|
81
|
+
self.default = formats.first if default.nil?
|
|
82
|
+
self.accepted = accepted | formats
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# @api private
|
|
86
|
+
def accepted_formats(standard_formats = {})
|
|
87
|
+
accepted.to_h { |format|
|
|
88
|
+
[
|
|
89
|
+
format,
|
|
90
|
+
mapping.fetch(format) { standard_formats[format] }
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @since 2.3.0
|
|
96
|
+
def default=(format)
|
|
97
|
+
@default = format.to_sym
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Registers a format and its associated media types.
|
|
101
|
+
#
|
|
102
|
+
# @param format [Symbol] the format name
|
|
103
|
+
# @param media_type [String] the format's media type
|
|
104
|
+
# @param accept_types [Array<String>] media types to accept in request `Accept` headers
|
|
105
|
+
# @param content_types [Array<String>] media types to accept in request `Content-Type` headers
|
|
106
|
+
#
|
|
107
|
+
# @example
|
|
108
|
+
# config.formats.register(:scim, media_type: "application/json+scim")
|
|
109
|
+
#
|
|
110
|
+
# config.formats.register(
|
|
111
|
+
# :jsonapi,
|
|
112
|
+
# "application/vnd.api+json",
|
|
113
|
+
# accept_types: ["application/vnd.api+json", "application/json"],
|
|
114
|
+
# content_types: ["application/vnd.api+json", "application/json"]
|
|
115
|
+
# )
|
|
116
|
+
#
|
|
117
|
+
# @return [self]
|
|
118
|
+
#
|
|
119
|
+
# @since 2.3.0
|
|
120
|
+
# @api public
|
|
121
|
+
def register(format, media_type, accept_types: [media_type], content_types: [media_type], parser: nil)
|
|
122
|
+
mapping[format] = Mime::Format.new(
|
|
123
|
+
name: format.to_sym,
|
|
124
|
+
media_type: media_type,
|
|
125
|
+
accept_types: accept_types,
|
|
126
|
+
content_types: content_types
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if parser
|
|
130
|
+
Array(content_types).each do |ct|
|
|
131
|
+
@body_parsers[ct.downcase] = parser
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
self
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# @since 2.0.0
|
|
139
|
+
# @api private
|
|
140
|
+
def empty?
|
|
141
|
+
accepted.empty?
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @since 2.0.0
|
|
145
|
+
# @api private
|
|
146
|
+
def any?
|
|
147
|
+
@accepted.any?
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# @since 2.0.0
|
|
151
|
+
# @api private
|
|
152
|
+
def map(&blk)
|
|
153
|
+
@accepted.map(&blk)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Clears any previously added mappings and format values.
|
|
157
|
+
#
|
|
158
|
+
# @return [self]
|
|
159
|
+
#
|
|
160
|
+
# @since 2.0.0
|
|
161
|
+
# @api public
|
|
162
|
+
def clear
|
|
163
|
+
@accepted = []
|
|
164
|
+
@default = nil
|
|
165
|
+
@mapping = {}
|
|
166
|
+
|
|
167
|
+
self
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Returns an array of all accepted media types.
|
|
171
|
+
#
|
|
172
|
+
# @since 2.3.0
|
|
173
|
+
# @api public
|
|
174
|
+
def accept_types
|
|
175
|
+
accepted.map { |format| mapping[format]&.accept_types }.flatten(1).compact
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Retrieve the format name associated with the given media type
|
|
179
|
+
#
|
|
180
|
+
# @param media_type [String] the media Type
|
|
181
|
+
#
|
|
182
|
+
# @return [Symbol,NilClass] the associated format name, if any
|
|
183
|
+
#
|
|
184
|
+
# @example
|
|
185
|
+
# @config.formats.format_for("application/json") # => :json
|
|
186
|
+
#
|
|
187
|
+
# @see #mime_type_for
|
|
188
|
+
#
|
|
189
|
+
# @since 2.0.0
|
|
190
|
+
# @api public
|
|
191
|
+
def format_for(media_type)
|
|
192
|
+
mapping.values.reverse.find { |format| format.media_type == media_type }&.name
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Returns the media type associated with the given format.
|
|
196
|
+
#
|
|
197
|
+
# @param format [Symbol] the format name
|
|
198
|
+
#
|
|
199
|
+
# @return [String, nil] the associated media type, if any
|
|
200
|
+
#
|
|
201
|
+
# @example
|
|
202
|
+
# @config.formats.media_type_for(:json) # => "application/json"
|
|
203
|
+
#
|
|
204
|
+
# @see #format_for
|
|
205
|
+
#
|
|
206
|
+
# @since 2.3.0
|
|
207
|
+
# @api public
|
|
208
|
+
def media_type_for(format)
|
|
209
|
+
mapping[format]&.media_type
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# @api private
|
|
213
|
+
def accept_types_for(format)
|
|
214
|
+
mapping[format]&.accept_types || []
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# @api private
|
|
218
|
+
def content_types_for(format)
|
|
219
|
+
mapping[format]&.content_types || []
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# @see #media_type_for
|
|
223
|
+
# @since 2.0.0
|
|
224
|
+
# @api public
|
|
225
|
+
alias_method :mime_type_for, :media_type_for
|
|
226
|
+
|
|
227
|
+
# @see #media_type_for
|
|
228
|
+
# @since 2.0.0
|
|
229
|
+
# @api public
|
|
230
|
+
alias_method :mime_types_for, :accept_types_for
|
|
231
|
+
|
|
232
|
+
# Finds the parser for a content type.
|
|
233
|
+
#
|
|
234
|
+
# @param content_type [String] the content type
|
|
235
|
+
#
|
|
236
|
+
# @return [#call, nil] the parser callable, if registered
|
|
237
|
+
#
|
|
238
|
+
# @api private
|
|
239
|
+
def body_parser_for(content_type)
|
|
240
|
+
@body_parsers[content_type&.downcase]
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
private
|
|
244
|
+
|
|
245
|
+
def register_default_body_parsers
|
|
246
|
+
# Multipart forms (ordinary urlencoded forms are handled by Rack automatically)
|
|
247
|
+
@body_parsers["multipart/form-data"] = BodyParser::MultipartForm
|
|
248
|
+
|
|
249
|
+
# JSON
|
|
250
|
+
@body_parsers["application/json"] = BodyParser::JSON
|
|
251
|
+
@body_parsers["application/vnd.api+json"] = BodyParser::JSON
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/configurable"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
class Action
|
|
7
|
+
# Config for `Hanami::Action` classes.
|
|
8
|
+
#
|
|
9
|
+
# @see Hanami::Action.config
|
|
10
|
+
#
|
|
11
|
+
# @api public
|
|
12
|
+
# @since 2.0.0
|
|
13
|
+
class Config < Dry::Configurable::Config
|
|
14
|
+
# Default public directory
|
|
15
|
+
#
|
|
16
|
+
# This serves as the root directory for file downloads
|
|
17
|
+
#
|
|
18
|
+
# @since 1.0.0
|
|
19
|
+
#
|
|
20
|
+
# @api private
|
|
21
|
+
DEFAULT_PUBLIC_DIRECTORY = "public"
|
|
22
|
+
|
|
23
|
+
# @!attribute [rw] handled_exceptions
|
|
24
|
+
#
|
|
25
|
+
# Specifies how to handle exceptions with an HTTP status.
|
|
26
|
+
#
|
|
27
|
+
# Raised exceptions will return the corresponding HTTP status.
|
|
28
|
+
#
|
|
29
|
+
# @return [Hash{Exception=>Integer}] exception classes as keys and HTTP statuses as values
|
|
30
|
+
#
|
|
31
|
+
# @example
|
|
32
|
+
# config.handled_exceptions = {ArgumentError => 400}
|
|
33
|
+
#
|
|
34
|
+
# @since 0.2.0
|
|
35
|
+
|
|
36
|
+
# Specifies how to handle exceptions with an HTTP status
|
|
37
|
+
#
|
|
38
|
+
# Raised exceptions will return the corresponding HTTP status
|
|
39
|
+
#
|
|
40
|
+
# The specified exceptions will be merged with any previously configured
|
|
41
|
+
# exceptions
|
|
42
|
+
#
|
|
43
|
+
# @param exceptions [Hash{Exception=>Integer}] exception classes as keys
|
|
44
|
+
# and HTTP statuses as values
|
|
45
|
+
#
|
|
46
|
+
# @return [void]
|
|
47
|
+
#
|
|
48
|
+
# @example
|
|
49
|
+
# config.handle_exceptions(ArgumentError => 400}
|
|
50
|
+
#
|
|
51
|
+
# @see handled_exceptions
|
|
52
|
+
#
|
|
53
|
+
# @since 0.2.0
|
|
54
|
+
def handle_exception(exceptions)
|
|
55
|
+
self.handled_exceptions = handled_exceptions
|
|
56
|
+
.merge(exceptions)
|
|
57
|
+
.sort do |(ex1, _), (ex2, _)|
|
|
58
|
+
next 0 if [ex1, ex2].any?(String)
|
|
59
|
+
|
|
60
|
+
ex1.ancestors.include?(ex2) ? -1 : 1
|
|
61
|
+
end
|
|
62
|
+
.to_h
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @!attribute [r] formats
|
|
66
|
+
# Returns the format config for the action.
|
|
67
|
+
#
|
|
68
|
+
# @return [Config::Formats]
|
|
69
|
+
#
|
|
70
|
+
# @since 2.0.0
|
|
71
|
+
# @api public
|
|
72
|
+
|
|
73
|
+
# @!attribute [rw] default_charset
|
|
74
|
+
#
|
|
75
|
+
# Sets a charset (character set) as default fallback for all the requests
|
|
76
|
+
# without a strict requirement for the charset.
|
|
77
|
+
#
|
|
78
|
+
# By default, this value is nil.
|
|
79
|
+
#
|
|
80
|
+
# @return [String]
|
|
81
|
+
#
|
|
82
|
+
# @see Hanami::Action::Mime
|
|
83
|
+
#
|
|
84
|
+
# @since 0.3.0
|
|
85
|
+
|
|
86
|
+
# @!attribute [rw] default_headers
|
|
87
|
+
#
|
|
88
|
+
# Sets default headers for all responses.
|
|
89
|
+
#
|
|
90
|
+
# By default, this is an empty hash.
|
|
91
|
+
#
|
|
92
|
+
# @return [Hash{String=>String}] the headers
|
|
93
|
+
#
|
|
94
|
+
# @example
|
|
95
|
+
# config.default_headers = {"X-Frame-Options" => "DENY"}
|
|
96
|
+
#
|
|
97
|
+
# @see default_headers
|
|
98
|
+
#
|
|
99
|
+
# @since 0.4.0
|
|
100
|
+
|
|
101
|
+
# @!attribute [rw] default_tld_length
|
|
102
|
+
#
|
|
103
|
+
# Sets the default TLD length for host names. It is used to extract the
|
|
104
|
+
# subdomain(s) in `Request#subdomains`.
|
|
105
|
+
#
|
|
106
|
+
# Defaults to 1.
|
|
107
|
+
#
|
|
108
|
+
# @example
|
|
109
|
+
# # For *.example.com
|
|
110
|
+
# config.default_tld_length = 1
|
|
111
|
+
#
|
|
112
|
+
# # Or for *.example.co.uk
|
|
113
|
+
# config.default_tld_length = 2
|
|
114
|
+
#
|
|
115
|
+
# @return [Integer] the number of subdomains
|
|
116
|
+
#
|
|
117
|
+
# @since 2.3.0
|
|
118
|
+
|
|
119
|
+
# @!attribute [rw] cookies
|
|
120
|
+
#
|
|
121
|
+
# Sets default cookie options for all responses.
|
|
122
|
+
#
|
|
123
|
+
# By default this, is an empty hash.
|
|
124
|
+
#
|
|
125
|
+
# @return [Hash{Symbol=>String}] the cookie options
|
|
126
|
+
#
|
|
127
|
+
# @example
|
|
128
|
+
# config.cookies = {
|
|
129
|
+
# domain: "hanamirb.org",
|
|
130
|
+
# path: "/action",
|
|
131
|
+
# secure: true,
|
|
132
|
+
# httponly: true
|
|
133
|
+
# }
|
|
134
|
+
#
|
|
135
|
+
# @since 0.4.0
|
|
136
|
+
|
|
137
|
+
# @!attribute [rw] root_directory
|
|
138
|
+
#
|
|
139
|
+
# Sets the the for the public directory, which is used for file downloads.
|
|
140
|
+
# This must be an existent directory.
|
|
141
|
+
#
|
|
142
|
+
# Defaults to the current working directory.
|
|
143
|
+
#
|
|
144
|
+
# @return [String] the directory path
|
|
145
|
+
#
|
|
146
|
+
# @api private
|
|
147
|
+
#
|
|
148
|
+
# @since 1.0.0
|
|
149
|
+
|
|
150
|
+
# @!attribute [rw] public_directory
|
|
151
|
+
#
|
|
152
|
+
# Sets the path to public directory. This directory is used for file downloads.
|
|
153
|
+
#
|
|
154
|
+
# This given directory will be appended onto the root directory.
|
|
155
|
+
#
|
|
156
|
+
# By default, the public directory is `"public"`.
|
|
157
|
+
# @return [String] the public directory path
|
|
158
|
+
#
|
|
159
|
+
# @example
|
|
160
|
+
# config.public_directory = "public"
|
|
161
|
+
# config.public_directory # => "/path/to/root/public"
|
|
162
|
+
#
|
|
163
|
+
# @see root_directory
|
|
164
|
+
#
|
|
165
|
+
# @since 2.0.0
|
|
166
|
+
def public_directory
|
|
167
|
+
# This must be a string, for Rack compatibility
|
|
168
|
+
root_directory.join(super).to_s
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rack"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
class Action
|
|
7
|
+
# Rack SPEC response code
|
|
8
|
+
#
|
|
9
|
+
# @since 1.0.0
|
|
10
|
+
# @api private
|
|
11
|
+
RESPONSE_CODE = 0
|
|
12
|
+
|
|
13
|
+
# Rack SPEC response headers
|
|
14
|
+
#
|
|
15
|
+
# @since 1.0.0
|
|
16
|
+
# @api private
|
|
17
|
+
RESPONSE_HEADERS = 1
|
|
18
|
+
|
|
19
|
+
# Rack SPEC response body
|
|
20
|
+
#
|
|
21
|
+
# @since 1.0.0
|
|
22
|
+
# @api private
|
|
23
|
+
RESPONSE_BODY = 2
|
|
24
|
+
|
|
25
|
+
# @since 1.0.0
|
|
26
|
+
# @api private
|
|
27
|
+
DEFAULT_ERROR_CODE = 500
|
|
28
|
+
|
|
29
|
+
# Status codes that by RFC must not include a message body
|
|
30
|
+
#
|
|
31
|
+
# @since 0.3.2
|
|
32
|
+
# @api private
|
|
33
|
+
HTTP_STATUSES_WITHOUT_BODY = Set.new((100..199).to_a << 204 << 205 << 304).freeze
|
|
34
|
+
|
|
35
|
+
# Not Found
|
|
36
|
+
#
|
|
37
|
+
# @since 1.0.0
|
|
38
|
+
# @api private
|
|
39
|
+
NOT_FOUND = 404
|
|
40
|
+
|
|
41
|
+
# Entity headers allowed in blank body responses, according to
|
|
42
|
+
# RFC 2616 - Section 10 (HTTP 1.1).
|
|
43
|
+
#
|
|
44
|
+
# "The response MAY include new or updated metainformation in the form
|
|
45
|
+
# of entity-headers".
|
|
46
|
+
#
|
|
47
|
+
# @since 0.4.0
|
|
48
|
+
# @api private
|
|
49
|
+
#
|
|
50
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5
|
|
51
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html
|
|
52
|
+
ENTITY_HEADERS = {
|
|
53
|
+
"allow" => true,
|
|
54
|
+
"content-encoding" => true,
|
|
55
|
+
"content-language" => true,
|
|
56
|
+
"content-location" => true,
|
|
57
|
+
"content-md5" => true,
|
|
58
|
+
"content-range" => true,
|
|
59
|
+
"expires" => true,
|
|
60
|
+
"last-modified" => true,
|
|
61
|
+
"extension-header" => true
|
|
62
|
+
}.freeze
|
|
63
|
+
|
|
64
|
+
# The request relative path
|
|
65
|
+
#
|
|
66
|
+
# @since 2.0.0
|
|
67
|
+
# @api private
|
|
68
|
+
PATH_INFO = ::Rack::PATH_INFO
|
|
69
|
+
|
|
70
|
+
# The request content type (env key, CGI-style uppercase). Rack exposes a `CONTENT_TYPE`
|
|
71
|
+
# constant but it refers to the response header (lowercase in Rack 3), not the env key.
|
|
72
|
+
#
|
|
73
|
+
# @api private
|
|
74
|
+
CONTENT_TYPE = "CONTENT_TYPE"
|
|
75
|
+
|
|
76
|
+
# The request method
|
|
77
|
+
#
|
|
78
|
+
# @since 0.3.2
|
|
79
|
+
# @api private
|
|
80
|
+
REQUEST_METHOD = ::Rack::REQUEST_METHOD
|
|
81
|
+
|
|
82
|
+
# The Content-Length HTTP header
|
|
83
|
+
#
|
|
84
|
+
# @since 1.0.0
|
|
85
|
+
# @api private
|
|
86
|
+
CONTENT_LENGTH = ::Rack::CONTENT_LENGTH
|
|
87
|
+
|
|
88
|
+
# The non-standard HTTP header to pass the control over when a resource
|
|
89
|
+
# cannot be found by the current endpoint
|
|
90
|
+
#
|
|
91
|
+
# @since 1.0.0
|
|
92
|
+
# @api private
|
|
93
|
+
X_CASCADE = "X-Cascade"
|
|
94
|
+
|
|
95
|
+
# HEAD request
|
|
96
|
+
#
|
|
97
|
+
# @since 0.3.2
|
|
98
|
+
# @api private
|
|
99
|
+
HEAD = ::Rack::HEAD
|
|
100
|
+
|
|
101
|
+
# GET request
|
|
102
|
+
#
|
|
103
|
+
# @since 2.0.0
|
|
104
|
+
# @api private
|
|
105
|
+
GET = ::Rack::GET
|
|
106
|
+
|
|
107
|
+
# TRACE request
|
|
108
|
+
#
|
|
109
|
+
# @since 2.0.0
|
|
110
|
+
# @api private
|
|
111
|
+
TRACE = ::Rack::TRACE
|
|
112
|
+
|
|
113
|
+
# OPTIONS request
|
|
114
|
+
#
|
|
115
|
+
# @since 2.0.0
|
|
116
|
+
# @api private
|
|
117
|
+
OPTIONS = ::Rack::OPTIONS
|
|
118
|
+
|
|
119
|
+
# The key that returns accepted mime types from the Rack env
|
|
120
|
+
#
|
|
121
|
+
# @since 0.1.0
|
|
122
|
+
# @api private
|
|
123
|
+
HTTP_ACCEPT = "HTTP_ACCEPT"
|
|
124
|
+
|
|
125
|
+
# The default mime type for an incoming HTTP request
|
|
126
|
+
#
|
|
127
|
+
# @since 0.1.0
|
|
128
|
+
# @api private
|
|
129
|
+
DEFAULT_ACCEPT = "*/*"
|
|
130
|
+
|
|
131
|
+
# The default mime type that is returned in the response
|
|
132
|
+
#
|
|
133
|
+
# @since 0.1.0
|
|
134
|
+
# @api private
|
|
135
|
+
DEFAULT_CONTENT_TYPE = "application/octet-stream"
|
|
136
|
+
|
|
137
|
+
# @since 0.2.0
|
|
138
|
+
# @api private
|
|
139
|
+
RACK_ERRORS = ::Rack::RACK_ERRORS
|
|
140
|
+
|
|
141
|
+
# The HTTP header for Cache-Control
|
|
142
|
+
#
|
|
143
|
+
# @since 2.0.0
|
|
144
|
+
# @api private
|
|
145
|
+
CACHE_CONTROL = ::Rack::CACHE_CONTROL
|
|
146
|
+
|
|
147
|
+
# @since 2.0.0
|
|
148
|
+
# @api private
|
|
149
|
+
IF_NONE_MATCH = "HTTP_IF_NONE_MATCH"
|
|
150
|
+
|
|
151
|
+
# The HTTP header for ETag
|
|
152
|
+
#
|
|
153
|
+
# @since 2.0.0
|
|
154
|
+
# @api private
|
|
155
|
+
ETAG = ::Rack::ETAG
|
|
156
|
+
|
|
157
|
+
# @since 2.0.0
|
|
158
|
+
# @api private
|
|
159
|
+
IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE"
|
|
160
|
+
|
|
161
|
+
# The HTTP header for Expires
|
|
162
|
+
#
|
|
163
|
+
# @since 2.0.0
|
|
164
|
+
# @api private
|
|
165
|
+
EXPIRES = ::Rack::EXPIRES
|
|
166
|
+
|
|
167
|
+
# The HTTP header for Last-Modified
|
|
168
|
+
#
|
|
169
|
+
# @since 0.3.0
|
|
170
|
+
# @api private
|
|
171
|
+
LAST_MODIFIED = "Last-Modified"
|
|
172
|
+
|
|
173
|
+
# This isn't part of Rack SPEC
|
|
174
|
+
#
|
|
175
|
+
# Exception notifiers use <tt>rack.exception</tt> instead of
|
|
176
|
+
# <tt>rack.errors</tt>, so we need to support it.
|
|
177
|
+
#
|
|
178
|
+
# @since 0.5.0
|
|
179
|
+
# @api private
|
|
180
|
+
#
|
|
181
|
+
# @see Hanami::Action::Throwable::RACK_ERRORS
|
|
182
|
+
# @see http://www.rubydoc.info/github/rack/rack/file/SPEC#The_Error_Stream
|
|
183
|
+
# @see https://github.com/hanami/hanami-action/issues/133
|
|
184
|
+
RACK_EXCEPTION = "rack.exception"
|
|
185
|
+
|
|
186
|
+
# The HTTP header for redirects
|
|
187
|
+
#
|
|
188
|
+
# @since 0.2.0
|
|
189
|
+
# @api private
|
|
190
|
+
LOCATION = "Location"
|
|
191
|
+
|
|
192
|
+
# The key that returns Rack session params from the Rack env
|
|
193
|
+
# Please note that this is used only when an action is unit tested.
|
|
194
|
+
#
|
|
195
|
+
# @since 2.0.0
|
|
196
|
+
# @api private
|
|
197
|
+
#
|
|
198
|
+
# @example
|
|
199
|
+
# # action unit test
|
|
200
|
+
# action.call("rack.session" => { "foo" => "bar" })
|
|
201
|
+
# action.session[:foo] # => "bar"
|
|
202
|
+
#
|
|
203
|
+
# @api private
|
|
204
|
+
RACK_SESSION = ::Rack::RACK_SESSION
|
|
205
|
+
|
|
206
|
+
# @since 2.0.0
|
|
207
|
+
# @api private
|
|
208
|
+
REQUEST_ID = "hanami.request_id"
|
|
209
|
+
|
|
210
|
+
# @since 2.0.0
|
|
211
|
+
# @api private
|
|
212
|
+
DEFAULT_ID_LENGTH = 16
|
|
213
|
+
|
|
214
|
+
# The key that returns raw cookies from the Rack env
|
|
215
|
+
#
|
|
216
|
+
# @since 2.0.0
|
|
217
|
+
# @api private
|
|
218
|
+
HTTP_COOKIE = ::Rack::HTTP_COOKIE
|
|
219
|
+
|
|
220
|
+
# The key used by Rack to set the cookies as an Hash in the env
|
|
221
|
+
#
|
|
222
|
+
# @since 2.0.0
|
|
223
|
+
# @api private
|
|
224
|
+
COOKIE_HASH_KEY = ::Rack::RACK_REQUEST_COOKIE_HASH
|
|
225
|
+
|
|
226
|
+
# The key used by Rack to set the cookies as a String in the env
|
|
227
|
+
#
|
|
228
|
+
# @since 2.0.0
|
|
229
|
+
# @api private
|
|
230
|
+
COOKIE_STRING_KEY = ::Rack::RACK_REQUEST_COOKIE_STRING
|
|
231
|
+
|
|
232
|
+
# The key that returns raw input from the Rack env
|
|
233
|
+
#
|
|
234
|
+
# @since 2.0.0
|
|
235
|
+
# @api private
|
|
236
|
+
RACK_INPUT = ::Rack::RACK_INPUT
|
|
237
|
+
|
|
238
|
+
# The key that returns a request body parsed by Hanami Action.
|
|
239
|
+
#
|
|
240
|
+
# This is the canonical key for body parsing.
|
|
241
|
+
#
|
|
242
|
+
# @since x.x.x
|
|
243
|
+
# @api private
|
|
244
|
+
ACTION_PARSED_BODY = "hanami.action.parsed_body"
|
|
245
|
+
|
|
246
|
+
# The key that returns params from a parsed body by Hanami Action.
|
|
247
|
+
#
|
|
248
|
+
# This is the canonical key for parsed body params.
|
|
249
|
+
#
|
|
250
|
+
# @since x.x.x
|
|
251
|
+
# @api private
|
|
252
|
+
ACTION_BODY_PARAMS = "hanami.action.body_params"
|
|
253
|
+
|
|
254
|
+
# The key that returns a request body parsed by Hanami Router.
|
|
255
|
+
#
|
|
256
|
+
# This is maintained for backward compatibility with Hanami Router.
|
|
257
|
+
#
|
|
258
|
+
# @api private
|
|
259
|
+
ROUTER_PARSED_BODY = "router.parsed_body"
|
|
260
|
+
|
|
261
|
+
# The key that returns router params from the Rack env.
|
|
262
|
+
#
|
|
263
|
+
# This is maintained for backward compatibility with Hanami Router.
|
|
264
|
+
#
|
|
265
|
+
# @since 2.0.0
|
|
266
|
+
# @api private
|
|
267
|
+
ROUTER_PARAMS = "router.params"
|
|
268
|
+
|
|
269
|
+
# Default HTTP request method for Rack env
|
|
270
|
+
#
|
|
271
|
+
# @since 2.0.0
|
|
272
|
+
# @api private
|
|
273
|
+
DEFAULT_REQUEST_METHOD = GET
|
|
274
|
+
|
|
275
|
+
# @since 2.0.0
|
|
276
|
+
# @api private
|
|
277
|
+
DEFAULT_CHARSET = "utf-8"
|
|
278
|
+
|
|
279
|
+
# @since 2.2.0
|
|
280
|
+
# @api private
|
|
281
|
+
ACTION_INSTANCE = "hanami.action_instance"
|
|
282
|
+
end
|
|
283
|
+
end
|