hanami-router 3.0.0.rc1 → 3.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de8e82b648b6f8ca9d9962074d411fb23f01455d119fb703742999d8e11c72b4
4
- data.tar.gz: '0081e3779fa653bfcf58bd5ef06bb91b472c163082bacbdc81db08ee62d94d1c'
3
+ metadata.gz: 30cf4c77a2d61c1f8c8817c19db6bd5089627a6639dbda3f6b44441433516a67
4
+ data.tar.gz: a79a9f499cbd4746adc14e70dd9aeff68aad669cbdb3109bab7501264e5930ab
5
5
  SHA512:
6
- metadata.gz: 0fe1979c1f87763136879f17db77b9c5ca6bfc42af9916818ec70e292b2d7a86ae10c2d2c42f5e82f16406a4adf926bff9751c224a419831af0a1582c1e98c46
7
- data.tar.gz: d604701c43c8446939c4e7be8322d9384b197d1142b61fc7d01a3c96080ebd2d5c5538570d2f1af702ef7b323d5b3e2af55dabeee645f30e14d3f8cb4b0808e7
6
+ metadata.gz: d08ff095875e2e7a24d4b3663344e6aa0cb3de17bd41ed22c809588a361f28bc9f1f1ffd0ccd1933bb35c88b78a330bbfc9a4aa178cd661202657cae56ce6d13
7
+ data.tar.gz: e6ca075b83151a66a015ba99c2120ee45bd35fe338cb4f7feb6d82e772eab60a8116ea4ee4fa90629c8e6e79cd2b17c867630916b9a5c3a0ac3154eabed1be77
data/CHANGELOG.md CHANGED
@@ -1,6 +1,9 @@
1
- # Hanami::Router
1
+ # Changelog
2
2
 
3
- Rack compatible HTTP router for Ruby.
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Break Versioning](https://www.taoensso.com/break-versioning).
4
7
 
5
8
  ## [Unreleased]
6
9
 
@@ -16,7 +19,26 @@ Rack compatible HTTP router for Ruby.
16
19
 
17
20
  ### Security
18
21
 
19
- [Unreleased]: http://github.com/hanami/hanami-router/compare/v3.0.0.rc1...HEAD
22
+ [Unreleased]: http://github.com/hanami/hanami-router/compare/v3.0.0...HEAD
23
+
24
+ ## [3.0.0] - 2026-06-30
25
+
26
+ ### Added
27
+
28
+ - Add `#permanent_redirect` and `#temporary_redirect` helpers for 301 and 302 responses. (@cllns in #302)
29
+
30
+ ### Changed
31
+
32
+ - **BREAKING:** `#redirect` now requires an explicit `code:` argument. Use `#permanent_redirect` or `#temporary_redirect` for the common cases, and pass `code:` to `#redirect` for less common codes (e.g. `303`, `307`, `308`). (@cllns in #302)
33
+ - Upgrade mustermann to 3.1 and remove mustermann-contrib dependency. (@rkh in #300)
34
+ - Require Ruby 3.3 or newer.
35
+
36
+ ### Fixed
37
+
38
+ - Only parse the request body into params when the content type is `application/x-www-form-urlencoded`. Previously, with no body parser middleware in use, posting a multipart upload (or other non-form body) could raise `Rack::QueryParser::InvalidParameterError`. (@cllns and @timriley in #305)
39
+ - Allow URL generation (via `#path`) to work with array variables. (@inouire in #304)
40
+
41
+ [3.0.0]: http://github.com/hanami/hanami-router/compare/v2.3.1...v3.0.0
20
42
 
21
43
  ## [3.0.0.rc1] - 2026-06-16
22
44
 
@@ -2,8 +2,10 @@
2
2
 
3
3
  module Hanami
4
4
  class Router
5
+ # Rack env key containing the request body as parsed by the body parser middleware. Signals that
6
+ # the body has already been parsed, so the router should not attempt to parse it again.
7
+ #
5
8
  # @api private
6
- # @since 2.0.0
7
9
  ROUTER_PARSED_BODY = "router.parsed_body"
8
10
  end
9
11
  end
@@ -7,6 +7,6 @@ module Hanami
7
7
  # @return [String]
8
8
  #
9
9
  # @api public
10
- VERSION = "3.0.0.rc1"
10
+ VERSION = "3.0.0"
11
11
  end
12
12
  end
data/lib/hanami/router.rb CHANGED
@@ -113,9 +113,7 @@ module Hanami
113
113
  env[::Rack::RACK_INPUT] = Rack::RewindableInput.new(input)
114
114
  end
115
115
 
116
- endpoint.call(
117
- _params(env, params)
118
- ).to_a
116
+ endpoint.call(_env_with_params(env, params)).to_a
119
117
  end
120
118
 
121
119
  # Defines a named root route (a GET route for "/")
@@ -684,7 +682,7 @@ module Hanami
684
682
  env = env_for(env, params, options)
685
683
  endpoint, params = lookup(env)
686
684
 
687
- RecognizedRoute.new(endpoint, _params(env, params))
685
+ RecognizedRoute.new(endpoint, _env_with_params(env, params))
688
686
  end
689
687
 
690
688
  # @since 2.0.0
@@ -777,7 +775,6 @@ module Hanami
777
775
  # @api private
778
776
  PREFIXED_NAME_SEPARATOR = "_"
779
777
 
780
- # @since x.x.x
781
778
  # @api private
782
779
  UNDERSCORED_NAME_REGEXP = /[-+~.]/
783
780
 
@@ -789,6 +786,9 @@ module Hanami
789
786
  # @api private
790
787
  EMPTY_STRING = ""
791
788
 
789
+ # @api private
790
+ EMPTY_HASH = {}.freeze
791
+
792
792
  # @since 2.0.0
793
793
  # @api private
794
794
  DEFAULT_RESOLVER = ->(_, to) { to }
@@ -841,6 +841,15 @@ module Hanami
841
841
  # @api private
842
842
  PARAMS = "router.params"
843
843
 
844
+ # @api private
845
+ CONTENT_TYPE = "CONTENT_TYPE"
846
+
847
+ # @api private
848
+ FORM_URLENCODED_MEDIA_TYPE = "application/x-www-form-urlencoded"
849
+
850
+ # @api private
851
+ FORM_URLENCODED_MEDIA_TYPE_PREFIX = "#{FORM_URLENCODED_MEDIA_TYPE};".freeze
852
+
844
853
  # @since 2.0.0
845
854
  # @api private
846
855
  ROUTE_VARIABLE_MATCHER = /:/
@@ -1034,17 +1043,12 @@ module Hanami
1034
1043
  Redirect.new(destination, code, ->(*) { [code, {HTTP_HEADER_LOCATION => destination}, [body]] })
1035
1044
  end
1036
1045
 
1037
- # @since 2.0.0
1038
1046
  # @api private
1039
- def _params(env, params)
1047
+ def _env_with_params(env, params)
1040
1048
  params ||= {}
1041
1049
  env[PARAMS] ||= {}
1042
1050
 
1043
- if !env.key?(ROUTER_PARSED_BODY) && (input = env[::Rack::RACK_INPUT]) and input.rewind
1044
- env[PARAMS].merge!(::Rack::Utils.parse_nested_query(input.read))
1045
- input.rewind
1046
- end
1047
-
1051
+ env[PARAMS].merge!(_form_urlencoded_body(env))
1048
1052
  env[PARAMS].merge!(::Rack::Utils.parse_nested_query(env[::Rack::QUERY_STRING]))
1049
1053
  env[PARAMS].merge!(params)
1050
1054
  env[PARAMS] = Params.deep_symbolize(env[PARAMS])
@@ -1052,6 +1056,28 @@ module Hanami
1052
1056
  env
1053
1057
  end
1054
1058
 
1059
+ # @api private
1060
+ def _form_urlencoded_body(env)
1061
+ return EMPTY_HASH if env.key?(ROUTER_PARSED_BODY)
1062
+ return EMPTY_HASH unless _form_urlencoded?(env)
1063
+ return EMPTY_HASH unless (input = env[::Rack::RACK_INPUT])
1064
+
1065
+ input.rewind
1066
+ body = ::Rack::Utils.parse_nested_query(input.read)
1067
+ input.rewind # leave the stream readable for downstream consumers
1068
+ body
1069
+ end
1070
+
1071
+ # @api private
1072
+ def _form_urlencoded?(env)
1073
+ content_type = env[CONTENT_TYPE]
1074
+ return false unless content_type
1075
+
1076
+ content_type = content_type.downcase
1077
+ content_type == FORM_URLENCODED_MEDIA_TYPE ||
1078
+ content_type.start_with?(FORM_URLENCODED_MEDIA_TYPE_PREFIX)
1079
+ end
1080
+
1055
1081
  # @since 2.0.0
1056
1082
  # @api private
1057
1083
  def _not_allowed_fixed(env)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-router
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.rc1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hanakai team