Come invia il file internamente?
Il formato viene chiamato multipart/form-data
, come richiesto in: Cosa significa enctype = 'multipart / form-data'?
Sto andando a:
- aggiungi altri riferimenti HTML5
- spiega perché ha ragione con un modulo invia un esempio
Riferimenti HTML5
Esistono tre possibilità per enctype
:
Come generare gli esempi
Una volta che vedi un esempio di ciascun metodo, diventa ovvio come funzionano e quando dovresti usarli.
Puoi produrre esempi usando:
Salvare il modulo in un .html
file minimo :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>upload</title>
</head>
<body>
<form action="http://localhost:8000" method="post" enctype="multipart/form-data">
<p><input type="text" name="text1" value="text default">
<p><input type="text" name="text2" value="aωb">
<p><input type="file" name="file1">
<p><input type="file" name="file2">
<p><input type="file" name="file3">
<p><button type="submit">Submit</button>
</form>
</body>
</html>
Impostiamo il valore di testo predefinito su aωb
, il che significa aωb
perché ω
è U+03C9
, che sono i byte 61 CF 89 62
in UTF-8.
Crea file da caricare:
echo 'Content of a.txt.' > a.txt
echo '<!DOCTYPE html><title>Content of a.html.</title>' > a.html
# Binary file containing 4 bytes: 'a', 1, 2 and 'b'.
printf 'a\xCF\x89b' > binary
Esegui il nostro piccolo server echo:
while true; do printf '' | nc -l 8000 localhost; done
Apri l'HTML sul tuo browser, seleziona i file e fai clic su Invia e controlla il terminale.
nc
stampa la richiesta ricevuta.
Testato su: Ubuntu 14.04.3, nc
BSD 1.105, Firefox 40.
multipart / form-data
Firefox inviato:
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 834
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text1"
text default
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text2"
aωb
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
<!DOCTYPE html><title>Content of a.html.</title>
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream
aωb
-----------------------------735323031399963166993862150--
Per il file binario e il campo di testo, i byte 61 CF 89 62
( aωb
in UTF-8) vengono inviati letteralmente. Puoi verificarlo con nc -l localhost 8000 | hd
, che dice che i byte:
61 CF 89 62
sono stati inviati ( 61
== 'a' e 62
== 'b').
Pertanto è chiaro che:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
imposta il tipo di contenuto su multipart/form-data
e dice che i campi sono separati dal datoboundary
stringa .
Ma nota che:
boundary=---------------------------735323031399963166993862150
ha due paphes in meno --
rispetto alla barriera reale
-----------------------------735323031399963166993862150
Questo perché lo standard richiede che il limite inizi con due trattini --
. Gli altri trattini sembrano essere proprio come Firefox ha scelto di implementare il confine arbitrario. RFC 7578 menziona chiaramente che --
sono necessari quei due trattini principali :
4.1. Parametro "Boundary" di multipart / form-data
Come con altri tipi multipart, le parti sono delimitate da un delimitatore di limite, costruito usando CRLF, "-" e il valore del parametro "limite".
ogni campo ottiene alcuni sottotitoli prima dei suoi dati:, Content-Disposition: form-data;
il campo name
, il filename
, seguito dai dati.
Il server legge i dati fino alla stringa di limite successiva. Il browser deve scegliere un limite che non verrà visualizzato in nessuno dei campi, quindi è per questo che il limite può variare tra le richieste.
Poiché abbiamo il limite univoco, non è necessaria alcuna codifica dei dati: i dati binari vengono inviati così come sono.
TODO: qual è la dimensione del limite ottimale ( log(N)
scommetto) e il nome / tempo di esecuzione dell'algoritmo che lo trova? Chiesto a: /cs/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences
Content-Type
viene determinato automaticamente dal browser.
Come viene determinato esattamente è stato chiesto a: Come viene determinato il tipo mime di un file caricato dal browser?
application / x-www-form-urlencoded
Ora modifica il enctype
in application/x-www-form-urlencoded
, ricarica il browser e reinvia.
Firefox inviato:
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: application/x-www-form-urlencoded
Content-Length: 51
text1=text+default&text2=a%CF%89b&file1=a.txt&file2=a.html&file3=binary
Chiaramente i dati del file non sono stati inviati, solo i nomi di base. Quindi questo non può essere usato per i file.
Per quanto riguarda il campo di testo, vediamo che al solito i caratteri stampabili come a
e b
sono stati inviati in un byte, mentre quelli non stampabili come 0xCF
e 0x89
presero 3 byte ciascuno: %CF%89
!
Confronto
I caricamenti di file contengono spesso molti caratteri non stampabili (ad esempio immagini), mentre i moduli di testo non lo fanno quasi mai.
Dagli esempi abbiamo visto che:
multipart/form-data
: aggiunge alcuni byte di sovraccarico al confine al messaggio e deve impiegare del tempo per calcolarlo, ma invia ogni byte in un byte.
application/x-www-form-urlencoded
: ha un limite di byte singolo per campo ( &
), ma aggiunge un fattore di sovraccarico lineare di 3x per ogni carattere non stampabile.
Pertanto, anche se potessimo inviare file con application/x-www-form-urlencoded
, non vorremmo, perché è così inefficiente.
Ma per i caratteri stampabili che si trovano nei campi di testo, non importa e genera meno sovraccarico, quindi lo usiamo e basta.