Comments (10)
Looking at the source code a bit more, it looks like perhaps I could utilize the "on_finish" function to split the individual values? I'm assuming that will be called each time a value is "stored" to the target. Is that an appropriate use of the function?
from streaming-form-data.
Do you have an example of what the request body looks like on the server side in such cases?
Depending on what the server sees, I would also probably suggest some variation of ValueTarget
. If there's a fixed delimiter that's known before hand, you could watch for it inside on_data_received
and adapt the values collection. But an example would be helpful before I can recommend something.
from streaming-form-data.
Sure, I'll put together a minimal working example. It's a fairly common case, however: for example checkboxes in a HTML form where you could have one or more checked, and should get a list of checked values as a result. Said form is designed by simply giving each checkbox in the set the same "name" attribute. (see https://html5-tutorial.net/forms/checkboxes/ under the section of "multiple choices", for example).
Like I said though, I'll go ahead and put together a minimal working example so you can see not only the HTML, but also what the server gets in the body. May take a couple of days.
from streaming-form-data.
So using the example HTML from the link above, I get a very simple request body (as retrieved by calling flask.request.stream.read()
:
favorite_pet=Cats&favorite_pet=Dogs&favorite_pet=Birds
Assuming I check all three boxes. Obviously if I only check two of them, then I only get two values, not all three as shown here :-)
Of course, my actual form is much more complicated, including file uploads and many more fields - I can flesh out this example if needed to more closely match the actual use case. However, this should (I think) demonstrate the portion of the body related to multi-valued fields.
The code I used to test this, if interested, is the following:
import flask
app = flask.Flask(__name__)
@app.route('/')
def index():
html = """
<form method="post" action="/testPost">
<fieldset>
<legend>What is Your Favorite Pet?</legend>
<input type="checkbox" name="favorite_pet" value="Cats">Cats<br>
<input type="checkbox" name="favorite_pet" value="Dogs">Dogs<br>
<input type="checkbox" name="favorite_pet" value="Birds">Birds<br>
<br>
<input type="submit" value="Submit now" />
</fieldset>
</form>
"""
return html
@app.route('/testPost', methods = ["POST"])
def test_post():
body = flask.request.stream.read()
print(body)
return ''
app.run()
from streaming-form-data.
I realized just now that the body content is a bit different if using multipart/form-data encoding on the form (as will be the case if uploading any files), so I modified the HTML portion as such:
<form method="post" action="/testPost", enctype="multipart/form-data">
<legend>What is Your Favorite Pet?</legend>
<input type="checkbox" name="favorite_pet" value="Cats">Cats<br>
<input type="checkbox" name="favorite_pet" value="Dogs">Dogs<br>
<input type="checkbox" name="favorite_pet" value="Birds">Birds<br>
<br>
Upload a photo of your pet: <input type=file name=fileUpload>
<br>
<input type="submit" value="Submit now" />
</form>
with the following resulting body:
b'------WebKitFormBoundaryM31StAfyAYukZZNw\r\nContent-Disposition: form-data; name="favorite_pet"\r\n\r\nCats\r\n------WebKitFormBoundaryM31StAfyAYukZZNw\r\nContent-Disposition: form-data; name="favorite_pet"\r\n\r\nBirds\r\n------WebKitFormBoundaryM31StAfyAYukZZNw\r\nContent-Disposition: form-data; name="fileUpload"; filename=""\r\nContent-Type: application/octet-stream\r\n\r\n\r\n------WebKitFormBoundaryM31StAfyAYukZZNw--\r\n'
So, basically it appears to treat each "instance" of the field as a separate field, which just happens to have the same name.
from streaming-form-data.
Interesting. Thanks for sending the form body.
One solution could be to implement a target that can "collect" values? Something along the lines of ValueCollectorTarget
. Similar to ValueTarget
but if you're expecting multiple values for a given field then we put all of them inside a in-memory list or something inside the class.
from streaming-form-data.
Agreed. The question is at what point to "collect" the individual values - presumably you can't do it at the "on_data_received" level, because a chunk may only be a partial value (presumably). As such, I'm thinking the on_finish function is the correct location, but as I don't know what triggers that function, I'm not completely confidant in that solution. I have implemented this that appears to work in testing:
class ListTarget(BaseTarget):
"""ValueTarget stores the input in an in-memory list of bytes.
This is useful in case you'd like to have the value contained in an
in-memory string.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._temp_value = []
self._values = []
def on_data_received(self, chunk: bytes):
self._temp_value.append(chunk)
def on_finish(self):
value = b''.join(self._temp_value)
self._values.append(value)
self._temp_value = []
@property
def value(self):
return self._values
... but as I mentioned, not being sure what triggers the on_finish function means I'm not sure that won't break if, for example, the value is long enough to span multiple chunks.
from streaming-form-data.
on_finish
is called by target.finish
which in turn is called by Part.finish
which signifies the end of a "part" of the form-data encoded bytes. So when on_finish
is called, we should be done with a single part. So it should be the right place to do the value collection.
Although we should also be able to use the data you provided in the earlier comment and write a test case for testing such a ListTarget
.
from streaming-form-data.
Agreed. I can try to get around to writing such a test case in the next week or two, depending on how things go at work.
from streaming-form-data.
Awesome, thanks!
from streaming-form-data.
Related Issues (20)
- No wheels deployed HOT 3
- Build fails without Python2 headers HOT 5
- Ubuntu Server slow speed HOT 1
- How do you read file name? HOT 2
- Support for AsyncIO HOT 2
- Install failure with pip 20 and setuptools 46 HOT 8
- __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) A wheel is created for you to put on pypi. HOT 6
- Any ideas how to deal with excel files in streaming ? HOT 1
- Get file name HOT 2
- Parser won't get registered and receive chunk data as a flask_appbuilder app in airflow webserver ui HOT 5
- How to use to read image file? HOT 2
- Move C declarations to a .pxd file to be available to other Cython modules. HOT 7
- Question: Does it support to parse raw multipart/form-data bodies ? HOT 5
- handler _parser.data_received failed with delimiting multipart stream into parts HOT 1
- `cgi` is being deprecated in 3.13 HOT 1
- smart-open as an optional dependency HOT 3
- How to validate content-type? HOT 7
- Question: Is it possible to raise an error when data for a non-registered target is parsed? HOT 7
- Fails to install with PyPy 3.10 on Windows HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from streaming-form-data.