2015-10-01 19 views
6

La seguente parte di codice dovrebbe essere in grado di essere eseguita in Python 2.7 e Python 3.x.Parse multipart/form-data using cgi.FieldStorage; Nessuna chiave

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 funziona benissimo ed uscite ['param1']. In Python 3.4, tuttavia, produce [None].

Non riesco a ottenere FieldStorage per ottenere un risultato utilizzabile in Python 3. Sospetto che qualcosa sia cambiato internamente e che ora lo stia usando male. Comunque non riesco a capire cosa. Qualsiasi aiuto è apprezzato.

risposta

3

Questi cambiamenti renderanno il vostro lavoro lo script in modo identico sia 2.7.x Python e 3.4.x:

(userò queste abbreviazioni per cgi.FieldStorage(): 2.7.x Python: FS27, Python 3.4.x: FS34)

- Mentre FS27 gestisce il ritorno a capo prima del confine in modo corretto, che non è il caso di FS34 quindi la soluzione è quella di iniziare con il confine (spam) direttamente.

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

value1 
--spam-- 
""" 

- Citando cgi.pysource (in commenti di FS34 definizione):

Argomenti, tutti opzionali:

fp: puntatore al file; predefinito: sys.stdin.buffer (non utilizzato quando il metodo di richiesta è GET)

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

La parte grigia non c'è FS27 definizione, quindi, la maggior parte delle differenze tra FS27 eFS34 si trovano nella gestione di stringhe (FS27) e flussi binari (FS34).

In questo contesto, FS34 può facilmente confondere la semantica dell'oggetto analizzato, a meno che non vengano fornite le istruzioni corrette su come gestirlo correttamente. Apparentemente, la voce del dizionario 'content-type': 'multipart/form-data; boundary=spam' non è sufficiente; devi fornire le informazioni sulla lunghezza del messaggio.

È possibile raggiungere questo obiettivo, efficace, con l'aggiunta di una seconda voce in headers:

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

in cui il valoreper la content-lengthchiave è la lunghezza body (comprese le start/confini finali).


Tali modifiche, combinati, portare al risultato desiderato:

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

Come prova-di-concetto, questi sono gli restituiti parsed oggetti provenienti sia FS27 e FS34:

... 
print(parsed) 
... 

rendimenti:

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

per FS27, e

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

per FS34.

0

Sia in Python 2.7 e Python 3.5 (non funziona in Python 3.4 per qualche motivo), l'uscita desiderata viene restituita con l'aggiunta Content-Length nel corpo della risposta:

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

value1 
--spam-- 
"""