-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nested parameters parsing error in rack 3.0.8 #2128
Comments
I believe the format we accept is:
@jeremyevans WDYT? |
As I mentioned above, this is the standard format for generating forms in Rails, and it works fine with rack version 2.2.8. "body"=>{"answer1"=>""}, In the html code it looks like this.
name="article_version[body[answer1]]" At least not like this, anyway. --> "body[answer1"=>{"]"=>""}, |
No, it is not. I'm very surprised that format has ever parsed predictably. I guess we'll need to dig into history to figure out whether it was totally accidental, or deliberately accommodated as a variant format. The lack of tests suggests the former, though it honestly seems hard to accidentally write code that would handle it. |
Hi, @matthewd I won't insist, but it is quite logical to use this format for some fields. It is especially useful for various JSON fields, when the value for each required key is output separately. Some additional. >> p.parse_query(qs)
=>
{"authenticity_token"=>"cATU9VIIozE3HDwS_kVfbyJpRkDlHUhJH3pfZllA-CSPm6L7fkOF-fQFByLv75mFP1uCgW64JyCi5Z4YTloaIg",
"commit"=>"Создать версию статьи",
"article_version[title]"=>"",
"article_version[article_code_prefix]"=>"ZDR_",
"article_version[classifier_ids][]"=>"",
"article_version[questionnaire_id]"=>"",
"article_version[record_type_id]"=>"",
"article_version[tag_plus]"=>["0", "1"],
"article_version[comment]"=>"",
"article_version[body[answer1]]"=>"",
"article_version[virtual_linked_articles_codes][]"=>"",
"article_version[double_linked_codes][]"=>"",
"article_version[questions][]"=>""}
>> p.parse_nested_query(qs)
=>
{"authenticity_token"=>"cATU9VIIozE3HDwS_kVfbyJpRkDlHUhJH3pfZllA-CSPm6L7fkOF-fQFByLv75mFP1uCgW64JyCi5Z4YTloaIg",
"commit"=>"Создать версию статьи",
"article_version"=>
{"title"=>"",
"article_code_prefix"=>"ZDR_",
"classifier_ids"=>[""],
"questionnaire_id"=>"",
"record_type_id"=>"",
"tag_plus"=>"1",
"comment"=>"",
"body[answer1"=>{"]"=>""},
"virtual_linked_articles_codes"=>[""],
"double_linked_codes"=>[""],
"questions"=>[""]}} |
https://guides.rubyonrails.org/form_helpers.html#understanding-parameter-naming-conventions
|
Inside view <div class='answer_body' data-controller='tinymce'>
<%= form.text_area "body[#{k}]", class: 'tinymce', placeholder: t(:body_prompt), value: @article_version.body[k], data: { add_field_target: 'answer', tinymce_target: 'input' } %> |
This is a bug in the application that needs to be fixed, not a bug in Rack. That it worked in older versions of Rack is accidental. |
I draw my conclusions based on the fact that TWO methods in rack (see above) produce DIFFERENT results for the same input data. |
The whole point of having the two methods is the fact that they do different things. You can already see that happening with |
Thank you for the detailed explanations of the difference in the objectives of the methods. |
We could change However, I'm not sure trying to support |
Another way leads to increased complexity of forms, when there is a layout of nested elements of standard arrays and hash into simple names, which leads to an additional "layer" of processing and errors. |
To reiterate for clarity, we aren't going to support parsing If you do not want to change the parameter keys you are using, please switch from using |
As I said, we are using rails 7.0.8, which in turn uses rack 2.2.8, and everything is working fine. The option you suggested is possible, but it is not the right way to customise Rails. If you solve the problem with at least the correct field name - I will consider how to better solve the overall problem. The last thing I want to do is to make any custom solutions for docking two gems. The option of changing the design of forms is also possible, as I said, the problem is that we have a lot of these forms, we actively use arrays and hashes. Leaving rack in version 2.2.8 is also a possible option, but also not very correct from my point of view for further update of the stack, because the next updates may require the current version of rack. |
If you use the correct parameter name, I'm sorry if you have a lot of forms that are doing things incorrectly. It would have better if older Rack did not unexpectedly handle the format you are using by accident. However, there is nothing we can do about that now. Your best approach forward is to fix the parameter names in all of your forms. |
Yes, I understand your position very well. The field is a hash. If you use a direct normal reference - it will look like the usual In case of at least some parsing of the field name from your side, I will try to implement the logic at least at the controller or model level. I hope, I have clearly explained the essence of the problems arising from the lack of such parsing. I was very happy when in version 2.2.8 the construction with the field name as a direct reference to the hash value worked. It really removes a lot of problems when working with arrays and hash in any forms. And your words that it was nothing more than an accident made me very sad. |
I'm sorry to hear that. I realize this is disappointing to you, and could result in a lot of additional work. |
Don't worry, nobody cancelled monkeypath :-) I actually really like the existing solution in 2.2.8. Anyway, if you somehow fix the output of the parsing results as the correct field name, there will be an opportunity to think about the problem again from all sides. Thanks for participating in solving our problems, although I believe we are not the only ones with such problems :-) |
Yeah, that would be a fully new feature, and I don't think that's worth the huge slowdown it would impose on all parameter parsing. If there were evidence that the previous behaviour was undocumented-but-originally-intended, then I might be inclined to re-support it for a while, with a gentler deprecation path. That would at least [presumably] still be possible with simple (regex) splits. |
Seems omniauth may have been relying on this behavior as well. Not totally sure if it's the same, but see referenced issue cookpad/omniauth-rails_csrf_protection#15. |
For reference, this change is caused by this PR: #1797 |
In Rack 3 the wrongly formatted `option_values_hash` stopped working. It was an accident that this ever worked in Rack 1 and 2 See rack/rack#2128
We had a wrongly formatted input field name and fixed it to the correct one See: https://github.com/solidusio-contrib/solidus_prototypes/pull/65/files TL;DR Use |
I personally believe it would be advantageous to define a proper grammar for parameter parsing (ideally using Ragel). In fact, I already did that: https://github.com/socketry/xrb/blob/main/parsers/xrb/query.rl This grammar would not parse nested square brackets: XRB::Query.parse(XRB::Buffer "a[b]=c")
# => {:a=>{:b=>"c"}}
XRB::Query.parse(XRB::Buffer "a[b[c]]=x")
# /Users/samuel/.gem/ruby/3.3.0/gems/xrb-0.6.1/lib/xrb/query.rb:15:in `parse_query': <string>[1:3]: could not parse all input (XRB::ParseError) Unfortunately, Rack's parser was too loose, and we see another instance of Hyrum's Law. The question now is do we officially support such a format?
We can see from the "standard":
Unfortunately the guidance from Falling back to the time-tested PHP: php > parse_str("a[b[c]]=x", $params);
php > print_r($params);
Array
(
[a] => Array
(
[b[c] => x
)
)
php > parse_str("a[b][c]=x", $params);
php > print_r($params);
Array
(
[a] => Array
(
[b] => Array
(
[c] => x
)
)
) It does something even more weird when faced with In summary:
In other words, I would be in favour of Rack::Utils.parse_nested_query("a[b[c]]=x")
# => {"a"=>{"b[c"=>{"]"=>"x"}}} Raising an error instead. |
Rack's parameter parsing has always had the idea of never raising an error based on the format of the parameter name. I'm on the fence regarding changing the parsing to make it strict, but it's a big change and I think could only be done in a major version upgrade. |
On the face of it, all of these look a bit wrong to me:
Of course, our interpretation of the key and value is up to us, and the specification for the query part of the URL is unfortunately loose. In other words, you are asserting that:
is the best we can do? Okay, what about introducing a strict mode to the parser and defining a formal grammar/structure? Then, we can start off making it opt-in. |
I think it's best unless we want to start rejecting parameter name formats, which we've never done in the past.
I'm open to that. |
I just encountered this issue after upgrading to Rack 3 and it took me a bit of time to understand why. Apparently I've been doing nested forms wrong for the past 12 years :) I'll change my forms no problem, but overall I fear this problem will be quite comon as people are starting to upgrade to Rack 3, and the way it's silently giving a different parsing now will be quite surprising. My 2 cents 🪙 : I understand the desire to never raise argument parsing in production (I'm not against that), but I would definitely have prefered a strict mode at least for test, development and staging env (so if this option existed, I would enable it in these env). Also I think this gotcha could be added to the Migration Guide: https://github.com/rack/rack/blob/main/UPGRADE-GUIDE.md because it's gonna hit a lot of apps (even though it's not "standard syntax" apparently we're not the only one using it). I read the guide first so it would have saved me some investigation time had I read about this first :) Thanks ! |
Do you want to make a PR? |
Following the discussion in rack#2128 about nested parameters parsing change in rack 3, here is a suggestion PR to mention it in the upgrade guide.
Sure, I just made a draft here: #2260 let me know what you think. |
Thanks, the documentation (upgrade guide) is updated. I don't believe we are going to change the behaviour here, so I'm going to close the issue. My apologies in advance for everyone and anyone who is affected by this... but I think this is the best course of action at this time. |
Btw. I have hit this in various Rails apps also. Isn't previous behaviour suggested in some Rails guides or most common tutorials? It seems pretty common to me. |
@ioquatix No link, I have realised all usage of wrong behaviour is coming from custom code (not from any gem). Fix was as simple as not passing field name around, but pass array if nested like |
Thanks for reporting back. In any case, even if it was in your own code, it's good to know it existed and that the fix was easy. |
When running with Rack 2.x, Rails 8.0 should report a deprecation warning in this case -- rails/rails#53471 |
Looks good for basic usages, but the problem here is actually when you already upgraded to Rack 3 (in our case it was Rails 7.1) with no idea about this "change" which will not print any deprecation warning currently if I understand it well. |
Problem description
We are planning an upgrade to Rails 7.1.1.
The upgrade involves updating the rack version to the current one (3.0.8)
However, some of the ours forms that use POST request stopped working.
Investigating this issue led to the fact that the parsing of parameters passed by the form to rack is not done correctly.
When using rack version 2.2.8 everything works fine.
The error occurs when using field names of the field_name[index] type in the form, which is used to work with JSON arrays.
A test example to reproduce the error.
Reproduce error
The same example for rack version 3.0.8
Note the "body[answer1"=>{"]"=>""}, - this is a field parsed with error.
It would be appreciated if this error could be fixed
The text was updated successfully, but these errors were encountered: