简体   繁体   English

使用cgi.FieldStorage解析multipart / form-data; 无钥匙

[英]Parse multipart/form-data using cgi.FieldStorage; None keys

The following piece of code should be able to run in Python 2.7 and Python 3.x. 以下代码应该能够在Python 2.7和Python 3.x中运行。

from __future__ import unicode_literals
from __future__ import print_function

import cgi
try:
    from StringIO import StringIO as IO
except ImportError:
    from io import BytesIO as IO

body = """
--spam
Content-Disposition: form-data; name="param1"; filename=blob
Content-Type: binary/octet-stream

value1
--spam--
"""

parsed = cgi.FieldStorage(
    IO(body.encode('utf-8')),
    headers={'content-type': 'multipart/form-data; boundary=spam'},
    environ={'REQUEST_METHOD': 'POST'})

print([key for key in parsed])

In Python 2.7 it runs fine and it outputs ['param1'] . 在Python 2.7中它运行正常并输出['param1'] In Python 3.4 however, it outputs [None] . 但是在Python 3.4中,它输出[None]

I cannot get FieldStorage to get a usable result in Python 3. I suspect something internally changed and I'm now using it wrong. 我无法让FieldStorage在Python 3中获得可用的结果。我怀疑内部发生了一些变化,我现在正在使用它。 However I can't seem to figure out what. 但是我似乎无法弄清楚是什么。 Any help is appreciated. 任何帮助表示赞赏。

These changes will make your script work identically in both Python 2.7.x and 3.4.x: 这些更改将使您的脚本在Python 2.7.x和3.4.x中的工作方式完全相同:

(I will use these abbreviations for cgi.FieldStorage() : Python 2.7.x: FS27 , Python 3.4.x: FS34 ) (我将使用cgi.FieldStorage()这些缩写:Python 2.7.x: FS27 ,Python 3.4.x: FS34

1 - While FS27 handles the newline before the boundary correctly, that is not the case with FS34 so the solution is to start with your boundary( spam ) directly. 1 -虽然FS27边界之前正确处理新行,就是不与FS34的情况下,这样的解决方案是先从你的边界( spam直接)。

body = """--spam
Content-Disposition: form-data; name="param1"; filename=blob
Content-type: binary/octet-stream

value1
--spam--
"""

2 - Quoting from cgi.py source (in FS34's definition comments): 2 - 从cgi.py 引用(在FS34的定义注释中):

Arguments, all optional: 参数,全部可选:

fp : file pointer; fp:文件指针; default: sys.stdin.buffer (not used when the request method is GET) default:sys.stdin.buffer(请求方法为GET时不使用)

  Can be : 1. a TextIOWrapper object 2. an object whose read() and readline() methods return bytes 

The grey part is not present in FS27 definition, so, most of the differences between FS27 and FS34 lie in the handling of strings(FS27) and binary streams(FS34) . FS27定义中不存在灰色部分,因此FS27FS34之间的大部分差异在于字符串(FS27)二进制流(FS34)的处理

In this context, FS34 can easily mess the semantics of the parsed object, unless it is given proper directions on how to handle this correctly. 在这种情况下, FS34很容易混淆解析对象的语义,除非给出正确处理方法的正确指示。 Apparently, the headers dictionary entry 'content-type': 'multipart/form-data; boundary=spam' 显然, headers字典条目'content-type': 'multipart/form-data; boundary=spam' 'content-type': 'multipart/form-data; boundary=spam' is not enough; 'content-type': 'multipart/form-data; boundary=spam'还不够; you have to supply the message length information. 你必须提供消息长度信息。

You can achieve this, effectively , by adding a second entry in headers : 您可以通过在headers添加第二个条目来有效地实现此目的:

headers={'content-type': 'multipart/form-data; boundary=spam;',
'content-length': len(body)}

where the value for the content-length key is the body length (including the start/end boundaries). 其中content-length body长(包括起始/结束边界)。


These modifications, combined, lead to the desired result: 这些修改结合起来,产生了预期的结果:

$ python script.py
['param1']
$ python3 script.py
['param1']

As proof-of-concept , these are the returned parsed objects from both FS27 and FS34 : 作为概念验证 ,这些是FS27FS34返回的parsed对象:

...
print(parsed)
...

yields: 收益率:

FieldStorage(None, None, [FieldStorage('param1', 'blob', 'value1')])

for FS27 , and 对于FS27 ,和

FieldStorage(None, None, [FieldStorage('param1', 'blob', b'value1')])

for FS34 . 对于FS34

In both Python 2.7 and Python 3.5 (not working in Python 3.4 for some reason), the desired output is returned by adding Content-Length to the response body: 在Python 2.7和Python 3.5中(由于某种原因在Python 3.4中不起作用),通过向响应主体添加Content-Length来返回所需的输出:

body = """
--spam
Content-Disposition: form-data; name="param1"; filename=blob
Content-Length: 6
Content-Type: binary/octet-stream

value1
--spam--
"""

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM