-
-
Notifications
You must be signed in to change notification settings - Fork 948
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
feat(multipart): add max_length to secure_filename() #2421
base: master
Are you sure you want to change the base?
Conversation
Krishn1412
commented
Dec 12, 2024
- adding max_length parameter which truncates the file but includes the ext.
- This is presently set to None but can be set 255 characters.
1) adding max_length parameter which truncates the file but includes the ext. 2) This is presently set to None but can be set 255 characters.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #2421 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 64 64
Lines 7728 7737 +9
Branches 1071 1073 +2
=========================================
+ Hits 7728 7737 +9 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this PR @Krishn1412!
In order to speed up the review process though, it is usually more efficient if you make sure that at least tox
passes locally for you first. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Provided implementation suggestions in-line.
Also, you still need to make all the tox
tests pass. To that end, you'll also need to add new unit tests verifying the proposed behaviour.
the file extension. Defaults to ``None`` for backward compatibility. | ||
|
||
.. note:: | ||
Starting from Falcon 5.0, this will default to 255 characters. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest a smaller default value. On some systems, e.g., Windows, the max possible path length is around 255-260, so likely we will want to make the file name part of the path shorter than that.
Maybe 64 could be a sane default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
64 may be a bit small as default, but 96/128 is likely ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I think 64 ought to be enough for the basename, since secure_filename()
is mangling the name in any case, so there is no guarantee to get exactly the same string as submitted in the form anyway. But 96 works for me as well.
I have changed the logic as suggested in the review. For the unit tests, I have made direct function call to test the logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
other than the max length for v5 the rest looks fine, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, the algorithm itself looks good now!
It seems that you forgot to actually forgot to wire the new option into the actual implementation of the BodyPart.secure_filename
property though.
See also other comments inline.
@@ -592,6 +592,15 @@ class MultipartParseOptions: | |||
If the body part headers size exceeds this value, an instance of | |||
:class:`.MultipartParseError` will be raised. | |||
""" | |||
max_filename_length: Optional[int] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new length is not passed to the actual invocation of secure_filename()
when referencing the corresponding part property.
Also add tests (make sure to parametrize on both WSGI/ASGI) for actually modifying this parsing option, and verifying that it is respected when referencing the said property.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to add a newsfragment for this improvement.
falcon/util/misc.py
Outdated
@@ -357,6 +358,8 @@ def secure_filename(filename: str) -> str: | |||
Args: | |||
filename (str): Arbitrary filename input from the request, such as a | |||
multipart form filename field. | |||
max_length (int, optional): Maximum length of the sanitized filename, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This (int, optional)
looks a bit unconventional. I think you can simply remove this type from here altogether, and let Sphinx pick it up from the type annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to pass the max_length as a parameter in the BodyPart.secure_filename function or set it as an instance or class variable and reference it from there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want us to actually use the new option in BodyPart.secure_filename()
, i.e.:
@property
def secure_filename(self) -> str:
"""The sanitized version of `filename` using only the most common ASCII
<...>
""" # noqa: D205
try:
return misc.secure_filename(self.filename or '')
except ValueError as ex:
raise MultipartParseError(description=str(ex)) from ex
⬇️
@property
def secure_filename(self) -> str:
"""The sanitized version of `filename` using only the most common ASCII
<...>
""" # noqa: D205
try:
return misc.secure_filename(self.filename or '', max_length=self._parse_options.max_secure_filename_length)
except ValueError as ex:
raise MultipartParseError(description=str(ex)) from ex
(untested)