bottlepy / bottle

bottle.py is a fast and simple micro-framework for python web-applications.
http://bottlepy.org/
MIT License
8.33k stars 1.46k forks source link

request.params not always filled in #1343

Closed andopaju closed 3 years ago

andopaju commented 3 years ago

Multipart request in the form of

Content-Disposition: form-data; name="confirmation_file"; filename="" (notice empty filename) will have no attribute params: AttributeError: Attribute 'params' not defined while dir(bottle.request) has it listed.

Content-Disposition: form-data; name="confirmation_file"; filename="filename" will work as usual.

Maybe some confusion with https://github.com/bottlepy/bottle/blob/f9b1849db4dd724e36a93a1032be592193fba581/bottle.py#L1420 ?

defnull commented 3 years ago

Not sure how an empty filename header field is possible and not a bug on the client side for file uploads.

andopaju commented 3 years ago

No idea, I stumbled upon it while uploading a form via js when no file was yet selected. I can force extra checks client side, but thought to report it here as well.

defnull commented 3 years ago

What happens here: If the multipart part has no valid filename header field, it is expected to be a text field, not a file upload. These end up in request.forms and request.params as plain python strings, and strings obviously do not have a filename attribute. Items in request.params are always strings, asking for item.filename should never work. If you are looking for (valid) file uploads, look into request.files.

andopaju commented 3 years ago

I can access files via .files alright and other data via forms. Just seemed weird not having request.params attribute (as other POST data has it and also other file uploads if filename is supplied).

defnull commented 3 years ago

The request.params property should always be there, but it might be empty. Please show the code that triggers the attribute error.

andopaju commented 3 years ago

Took some time to unwrap this. Apparently I was using a customized bottle code that overwrote params method. The method expected value in for key, value in self.forms.allitems() to be a str instance if not self.forms.recode_unicode.

It raised AttributeError because bytes obj didn't have the expected method. AttributeError: 'bytes' object has no attribute 'encode' Because it was not caught, it made it to __getattr__code and ate the original exception making debugging difficult:

  File "[.......]/bottle.py", line 1618, in __getattr__
    var = self.environ['bottle.request.ext.%s' % name]
KeyError: 'bottle.request.ext.params'

-> AttributeError: Attribute 'params' not defined

Sorry for the confusion, only one question remains: should bottle always ensure forms items are str instances even in weird input cases and never bytes? I know I can use decode or getunicode methods.

defnull commented 3 years ago

should bottle always ensure forms items are str instances even in weird input cases and never bytes? I know I can use decode or getunicode methods.

You triggered a wierd edge case here. The file upload had an empty filename field in the Content-Disposition header, which caused cgi.FieldStorage to think it is a file (and item.value to contain bytes) but bottle to think this is a text field (because item.filename was empty and thus false). This should never happen with a well behaved client, but yes, this could and should be fixed in bottle.