fix: zip error races in WebDownload (#12086)

When an error is reported it is ignored and zipping continues with the next object.

However, if there is an error it will write a response to `writeWebErrorResponse(w, err)`, but responses are still being built.

Fixes #12082

Bonus: Exclude common compressed image types.
This commit is contained in:
Klaus Post
2021-04-19 17:44:18 +02:00
committed by GitHub
parent 49b7923309
commit 3d685b7fff
2 changed files with 12 additions and 21 deletions

View File

@@ -1688,6 +1688,9 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) {
respElements := extractRespElements(w)
for i, object := range args.Objects {
if contextCanceled(ctx) {
return
}
// Writes compressed object file to the response.
zipit := func(objectName string) error {
var opts ObjectOptions
@@ -1706,38 +1709,26 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) {
return err
}
header := &zip.FileHeader{
Name: strings.TrimPrefix(objectName, args.Prefix),
Method: zip.Deflate,
Flags: 1 << 11,
Modified: info.ModTime,
Name: strings.TrimPrefix(objectName, args.Prefix),
Method: zip.Deflate,
Flags: 1 << 11,
Modified: info.ModTime,
UncompressedSize64: uint64(info.Size),
}
if hasStringSuffixInSlice(info.Name, standardExcludeCompressExtensions) || hasPattern(standardExcludeCompressContentTypes, info.ContentType) {
if info.Size < 20 || hasStringSuffixInSlice(info.Name, standardExcludeCompressExtensions) || hasPattern(standardExcludeCompressContentTypes, info.ContentType) {
// We strictly disable compression for standard extensions/content-types.
header.Method = zip.Store
}
writer, err := archive.CreateHeader(header)
if err != nil {
writeWebErrorResponse(w, errUnexpected)
return err
}
httpWriter := ioutil.WriteOnClose(writer)
// Write object content to response body
if _, err = io.Copy(httpWriter, gr); err != nil {
httpWriter.Close()
if !httpWriter.HasWritten() { // write error response only if no data or headers has been written to client yet
writeWebErrorResponse(w, err)
}
if _, err = io.Copy(writer, gr); err != nil {
return err
}
if err = httpWriter.Close(); err != nil {
if !httpWriter.HasWritten() { // write error response only if no data has been written to client yet
writeWebErrorResponse(w, err)
return err
}
}
// Notify object accessed via a GET request.
sendEvent(eventArgs{
EventName: event.ObjectAccessedGet,