2014-10-15 15 views
7

Desidero consentire il caricamento dei file. Go viene utilizzato lato server per gestire le richieste. Vorrei inviare una risposta "File troppo grande" ogni volta che il file che stanno cercando di caricare è troppo grande. Vorrei farlo, prima dello l'intero file viene caricato (larghezza di banda).Caricamento file Golang: connessione chiusa se il file è troppo grande

Sto utilizzando il seguente snippet, ma è solo l'invio di una risposta dopo il caricamento del client. Salva un file da 5 kB.

const MaxFileSize = 5 * 1024 
// This feels like a bad hack... 
if r.ContentLength > MaxFileSize { 
    if flusher, ok := w.(http.Flusher); ok { 
     response := []byte("Request too large") 
     w.Header().Set("Connection", "close") 
     w.Header().Set("Content-Length", fmt.Sprintf("%d", len(response))) 
     w.WriteHeader(http.StatusExpectationFailed) 
     w.Write(response) 
     flusher.Flush() 
    } 
    conn, _, _ := w.(http.Hijacker).Hijack() 
    conn.Close() 
    return 
} 

r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize) 

err := r.ParseMultipartForm(1024) 
if err != nil { 
    w.Write([]byte("File too large")); 
    return 
} 

file, header, err := r.FormFile("file") 
if err != nil { 
    panic(err) 
} 

dst, err := os.Create("upload/" + header.Filename) 
defer dst.Close() 
if err != nil { 
    panic(err) 
} 

written, err := io.Copy(dst, io.LimitReader(file, MaxFileSize)) 
if err != nil { 
    panic(err) 
} 

if written == MaxFileSize { 
    w.Write([]byte("File too large")) 
    return 
} 
w.Write([]byte("Success...")) 
+2

Ingannevole. Forse potresti usare io.CopyN per leggere 'MaxFileSize + 1' byte. Se "err! = EOF', il limite è stato superato o c'era qualche altro problema. Non sono sicuro di quale comportamento l'utente vedrà nel browser se lo fai, però - provalo e guarda. Inoltre, capisco che questo è un codice di test, ma passare da 'panic's a error return è una buona idea per il tuo codice di produzione. – twotwotwo

+1

Grazie per il suggerimento. Sostituire 'Copia' con' CopiaN' e leggere 'MaxFileSize + 1' byte non ha aiutato (alla fine del browser). Per quanto riguarda il panico, di solito ho uno speciale 'RecoverHandler', che recupera dal panico e si traduce in una bella pagina di errore 400. Grazie per aver notato però. –

risposta

13

La maggior parte dei client non legge la risposta finché non ha terminato di scrivere la richiesta. La risposta a un errore dal server non causerà la fine della scrittura di questi client.

Il server net/http supporta 100 continue status. Per utilizzare questa funzione, l'applicazione server dovrebbe rispondere con un errore prima di leggere il corpo della richiesta:

func handler(w http.ResponseWriter, r *http.Request) { 
    if r.ContentLength > MaxFileSize { 
    http.Error(w, "request too large", http.StatusExpectationFailed) 
    return 
    } 
    r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize) 
    err := r.ParseMultipartForm(1024) 

    // ... continue as before 

Se il cliente ha inviato il "Expect: 100-continue" intestazione, il client deve attendere per il 100 continua di stato prima di scrivere il corpo della richiesta. Il server net/http invia automaticamente il 100 stato di continuazione quando l'applicazione server legge il corpo della richiesta. Il server può impedire al client di scrivere il corpo della richiesta rispondendo con un errore prima di leggere la richiesta.

Il client net/http does not support the 100 continue status.

Se il client non ha inviato l'header expect e l'applicazione server restituisce dal gestore richieste senza leggere il corpo della richiesta completa, il server net/http legge e scarta fino a 256 < < 10 byte del corpo della richiesta. Il server chiuderà la connessione se l'intero corpo della richiesta non è stato letto.

+1

C'è un modo per "chiedere" al client di inviare l'intestazione "Aspettarsi: 100-continua"? Il modo in cui l'ho risolto ora (modifica in questione), sembra un po 'hacky. Grazie per la risposta però! –

+0

Come hai risolto questo? puoi condividere una soluzione? AFAICT http.ServeHTTP (r, w) risponde automaticamente con 100-continue e impedisce a un server di farlo. – jrwren

+0

Il server risponde automaticamente con 100 continue su [prima lettura del corpo della richiesta] (https://github.com/golang/go/blob/023556c07166be15a914d1f828d8c7b20a59a804/src/net/http/server.go#L790-L804). Non leggere il corpo della richiesta prima di rispondere con StatusExpectationFailed. –

Problemi correlati