-
Notifications
You must be signed in to change notification settings - Fork 410
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
Raise OutOfRangeError for page input below min #102
Comments
How comes that |
Because it's user input from querystring ( |
The Again, how comes that a user can set the input to a string like |
It's a querystring so the user can input anything they want in the URL. It's also an API so API clients can have a bug that they ask for page 0 or a string. Regardless a client side constraint, which can be bypassed, would still leave the backend open to resulting in a server error. |
Not really. No (final) user is supposed to enter anything in the query-string directly. It's the app that should handle the query-string. And if the "user" is the developer, then s/he is supposed to handle it correctly, i.e. ensuring it is a integer (or a "strigyfied" integer) and not a string, or (for easy handling) just passing the param straight and getting the default in case of blank param.
The goal of Pagy is not fixing the bugs of any API clients. If that is a goal of the app that implements the API (and it would be a silly goal IMO), the app itself could fix the API call before passing the wrong value to Pagy. Again, not a Pagy concern.
If the client side constraint gets bypassed, than it means that the final user is tampering with the UI. Fixing a tampering attempt is not a concern of Pagy and indeed it is handled with a proper
Indeed passing a string instead of an expected integer (or a stringyfied integer) IS resulting in a server error. Specifically a In conclusion I guess that the core of your concern is that you would like to have a The Strictly speaking that is a poor naming choice. I just realize that something like Also, the error feedback should report the value of the I will open a new issue to rename it and fix the feedback. |
If needed, please, continue the discussion in #103. |
I disagree with many statements here. To sum up my view:
IMHO ArgumentError should be a result of a developer using invalid argument in the code. Dynamic user input is not a developer argument error. This should raise The way it is now there is no way to catch this error without catching the generic ArgumentError. So the best case is to make a wrapper method that does input validation. I think that should be handled by the gem due to arguments listed above. |
Thanks for this, because you save me the time to answer you point by point. As you just wrote, the whole discussion is focused on the only 2 possible cause of that kind of error: bugs and malicious behaviour, and both of them are VERY worth an exception.
The gem offers the |
What is the difference between a user inputting an invalid page integer and a string input? Both are invalid and should result in an manageable error. But only the integer is possible to handle with the current error raising. Also only the invalid integer is handled internally by pagy. There is not only bugs and malicious behaviour but also user errors (for example the pagy_nav_compact gives an input which the user can enter any page). Now this will result in a logged error which will cause error reporting based on user input - this should not be the case. How do you suggest this should be handled when implementing pagy? |
The string or integer is not a problem with Pagy IF the string actually contains the page number.
As you can understand if the user enters It's not true that "the user can enter any page" with the
Indeed it is absolutely NOT the case! There will be no |
If you rely on the browser restrictions and validations. Which on the backend you shouldn't. For any high usage web-app this will be an issue. If every gem resulted in ArgumentError for invalid user input then error logs would be full of errors. Let's for example take a CMS which would have crawlers and bots doing all sort of things to forms - this would lead to many variations of user input.
The are two problems with this approach:
What? It surely is. User input is "foo" and it will result in an error. We obviously disagree on this. But I don't think I am the only one you would disagree with. This is not an issue in other gems. If I for example supply an invalid date to a gem handling dates it would either result in a specific error (ie InvalidDateError) or it will just silently "fail" and yield nil. How do you suggest this should be handled when implementing pagy? |
... if you are protecting Fort Knox and data that will get stored. In input that is only related to displaying stuff on the screen browser side restrictions and validation are good enough! Besides, I don't give a hut if a tampered input get an exception, and you should do the same. Did you read my previous answers?
Nope. It's not a quantitative problem: it's a qualitative problem, and the trigger of errors could only be bugs or malicious behaviour so, again I don't give a hut about those generating an exception or one million exceptions, and you should do the same.
so what?
If you have a paranoid problem for input that just decides the display of a page, then write a
Seriously? ...
rescue ArgumentError => e
if e.message.match(/....../)
do_something
else
raise
end
end And BTW, rescue-ing is a bad idea when instead you could use the constructor properly by sanitizing/normalizing the input before using it.
User input is "foo" only for that 2 causes that I already explained endless times and you seems confused with, and that indeed must raise an exception.
Sanitize/normalize your input before passing it to the constructor either in your code (best option) or propose a change in the backend (that will very likely be rejected) or write a I am afraid I exhausted myself and the time I can dedicate to this thread, so if you are still not convinced, please, submit some code. Thanks. |
I read all the discussion, and, actually, don't think it is a problem. But, I do understand @espen 's point of view(had similar issue with "Postgres integer out of range"). ArgumentError is not nice. If Because, if user somehow managed to enter "foo", it seems that he wants to brake the logic and not to receive real data. So this case may be ignored by the programmer. Unless it is requirement of a customer. If you care about serializing user input for @pagy, @collection = pagy(scope, page: (params[:page].to_i rescue 1)) This is "bullet proof" handling of user input, including floating numbers. Such example may be mentioned in "FAQ", and it will be enough. |
@workgena: |
Perhaps draft implementation of paranoid-extra might "open our eyes"(in a good way) on this use-case? |
Very low priority IMO. It is still better to implement param normalization in the specific app code, if you really need that, and again, you would need that only for "ideological" reasons. :) |
def normalized_current_page
page = current_page.to_i rescue 1
return 1 if page == 0
max_pages = records.count.fdiv(per_page).ceil
if page > max_pages
max_pages
else
page
end
end This could help |
@espen, @workgena FYI: from version 3.3.1 all the exceptions are The IMO that's not a dramatic improvement, but it will be simpler to rescue even very specific errors, even for the most pointless reasons :) HTH |
I think the issue should be handled by pagy gem. If my url asks for page > available, give me the last page. The amount of records can change between when the page gets generated and the 'next' page is requested. This is very likely with a multi-user system. Also by the way if any other bad parameter is passed... just return page 1 Otherwise I have to rescue all calls to pagy. If you want the option to raise error, you can make it an option. |
I don't believe that is true for out of bounds page number. The number of pages can change in another session/thread and now i have to check the the page is within range. Page is already checking, why should I rewrite code. |
@weiserma you don't have to rewrite any code nor check if the page is within range. Pagy does it for you, you can use the Overflow extra and/or go deeper at any level of detail by handling exceptions |
# config/initializers/pagy.rb
require 'page/extras/overflow'
Pagy::DEFAULT[:overflow] = :empty_page
# controllers
@pagy, @collection = pagy(scope, page: [params[:page].to_i, 1].max) I prefer this. |
OutOfRangeError
works great when page input is larger than max page (page=11 when max is 10). But when setting page input to 0 (as will happen when input is not a number) it results inArgumentError
when callingpagy()
which is not so easy to work with.page=0
=>ArgumentError: expected :page >= 1; got 0
The text was updated successfully, but these errors were encountered: