-
-
Notifications
You must be signed in to change notification settings - Fork 85
fix: falcon form with application/x-www-form-urlencoded
#434
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
Conversation
Signed-off-by: Keming <kemingy94@gmail.com>
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.
Pull Request Overview
This PR fixes form validation handling in the Falcon plugin to properly support application/x-www-form-urlencoded content type. The changes differentiate between form-encoded data and multipart form data, ensuring appropriate parsing for each content type.
- Adds type hint for FalconASGIRequest import and parameter
- Implements content-type-specific form parsing logic for both sync and async validation methods
- Ensures form validation only occurs for supported MIME types
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
Works for me! >>> import requests
>>> url = 'http://localhost:8000/api/file_upload'
>>> files = {'file': open('example.bin', 'rb')}
>>> data = {'uid': 'bla'}
>>> response = requests.post(url, files=files, data=data)
>>> print(response.text)
{"filename": "example.bin", "type": "text/plain", "uid": "bla"} @spec.validate(resp=Response(HTTP_200=FileResp), tags=["file-upload"])
def on_post(self, req, resp, form: File):
"""
post multipart/form-data demo
demo for 'form'
"""
file: BodyPart = form.file
response = {}
if file:
response = {"filename": file.secure_filename, "type": file.content_type}
if form.uid:
response.update({"uid": form.uid})
resp.media = response |
Signed-off-by: Keming <kemingy94@gmail.com>
vytas7
left a comment
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.
Just a couple of late comments. 😈
| if form and req.content_type: | ||
| try: | ||
| form_data = await req.get_media() | ||
| except HTTPError as err: |
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 works, although it would be more idiomatic to catch the media-specific exceptions: MediaNotFoundError (irrelevant if you are sure you handling forms here) and, the most important, MediaMalformedError.
| req_form = {} | ||
| async for part in form_data: | ||
| if part.filename is None: | ||
| req_form[part.name] = await part.data |
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.
These async properties look a bit awkward and provided only for compatibility. I would prefer part.get_data().
| # pass the `falcon.BodyPart` if it's attached as a file | ||
| req_form[part.name] = part | ||
| # try to consume the file data, otherwise it will be lost | ||
| _ = part.data |
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.
As above, just part.get_data() should look cleaner and more obvious it performs I/O.
| # pass the `falcon.BodyPart` if it's attached as a file | ||
| req_form[part.name] = part | ||
| # try to consume the file data, otherwise it will be lost | ||
| await part.data |
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.
Note that Falcon doesn't spool data to temporary files or anything like that out of the box. part.get_text() and part.get_data() are meant as convenience methods for getting short form fields, not files. They are limited to (by default, configurable) 1 MiB.
Although maybe you are not intending to handle large files here in the OpenAPI context?
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.
Uh oh!
There was an error while loading. Please reload this page.