fix: consider partNumber in GET/HEAD requests (#10618)

master
Anis Elleuch 4 years ago committed by GitHub
parent f28d02b7f2
commit 71403be912
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      cmd/api-headers.go
  2. 9
      cmd/object-api-utils.go
  3. 40
      cmd/object-handlers.go
  4. 2
      cmd/web-handlers.go

@ -84,7 +84,7 @@ func setPartsCountHeaders(w http.ResponseWriter, objInfo ObjectInfo) {
} }
// Write object header // Write object header
func setObjectHeaders(w http.ResponseWriter, objInfo ObjectInfo, rs *HTTPRangeSpec) (err error) { func setObjectHeaders(w http.ResponseWriter, objInfo ObjectInfo, rs *HTTPRangeSpec, opts ObjectOptions) (err error) {
// set common headers // set common headers
setCommonHeaders(w) setCommonHeaders(w)
@ -147,16 +147,27 @@ func setObjectHeaders(w http.ResponseWriter, objInfo ObjectInfo, rs *HTTPRangeSp
} }
} }
var start, rangeLen int64
totalObjectSize, err := objInfo.GetActualSize() totalObjectSize, err := objInfo.GetActualSize()
if err != nil { if err != nil {
return err return err
} }
if opts.PartNumber > 0 {
var start, end int64
for i := 0; i < len(objInfo.Parts) && i < opts.PartNumber; i++ {
start = end
end = start + objInfo.Parts[i].ActualSize - 1
}
rs = &HTTPRangeSpec{Start: start, End: end}
rangeLen = end - start + 1
} else {
// for providing ranged content // for providing ranged content
start, rangeLen, err := rs.GetOffsetLength(totalObjectSize) start, rangeLen, err = rs.GetOffsetLength(totalObjectSize)
if err != nil { if err != nil {
return err return err
} }
}
// Set content length. // Set content length.
w.Header().Set(xhttp.ContentLength, strconv.FormatInt(rangeLen, 10)) w.Header().Set(xhttp.ContentLength, strconv.FormatInt(rangeLen, 10))

@ -562,6 +562,15 @@ type ObjReaderFn func(inputReader io.Reader, h http.Header, pcfn CheckPreconditi
func NewGetObjectReader(rs *HTTPRangeSpec, oi ObjectInfo, opts ObjectOptions, cleanUpFns ...func()) ( func NewGetObjectReader(rs *HTTPRangeSpec, oi ObjectInfo, opts ObjectOptions, cleanUpFns ...func()) (
fn ObjReaderFn, off, length int64, err error) { fn ObjReaderFn, off, length int64, err error) {
if rs == nil && opts.PartNumber > 0 {
var start, end int64
for i := 0; i < len(oi.Parts) && i < opts.PartNumber; i++ {
start = end
end = start + oi.Parts[i].ActualSize - 1
}
rs = &HTTPRangeSpec{Start: start, End: end}
}
// Call the clean-up functions immediately in case of exit // Call the clean-up functions immediately in case of exit
// with error // with error
defer func() { defer func() {

@ -378,6 +378,22 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
rangeHeader := r.Header.Get(xhttp.Range) rangeHeader := r.Header.Get(xhttp.Range)
if rangeHeader != "" { if rangeHeader != "" {
rs, rangeErr = parseRequestRangeSpec(rangeHeader) rs, rangeErr = parseRequestRangeSpec(rangeHeader)
// Handle only errInvalidRange. Ignore other
// parse error and treat it as regular Get
// request like Amazon S3.
if rangeErr == errInvalidRange {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidRange), r.URL, guessIsBrowserReq(r))
return
}
if rangeErr != nil {
logger.LogIf(ctx, rangeErr, logger.Application)
}
}
// Both 'bytes' and 'partNumber' cannot be specified at the same time
if rs != nil && opts.PartNumber > 0 {
writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrBadRequest))
return
} }
// Validate pre-conditions if any. // Validate pre-conditions if any.
@ -393,16 +409,6 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
return true return true
} }
// Handle only errInvalidRange. Ignore other
// parse error and treat it as regular Get
// request like Amazon S3.
if rangeErr == errInvalidRange {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidRange), r.URL, guessIsBrowserReq(r))
return true
}
if rangeErr != nil {
logger.LogIf(ctx, rangeErr, logger.Application)
}
return false return false
} }
@ -445,7 +451,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
} }
} }
if err = setObjectHeaders(w, objInfo, rs); err != nil { if err = setObjectHeaders(w, objInfo, rs, opts); err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
return return
} }
@ -459,7 +465,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
statusCodeWritten := false statusCodeWritten := false
httpWriter := ioutil.WriteOnClose(w) httpWriter := ioutil.WriteOnClose(w)
if rs != nil { if rs != nil || opts.PartNumber > 0 {
statusCodeWritten = true statusCodeWritten = true
w.WriteHeader(http.StatusPartialContent) w.WriteHeader(http.StatusPartialContent)
} }
@ -613,6 +619,12 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
} }
} }
// Both 'bytes' and 'partNumber' cannot be specified at the same time
if rs != nil && opts.PartNumber > 0 {
writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrBadRequest))
return
}
// Set encryption response headers // Set encryption response headers
if objectAPI.IsEncryptionSupported() { if objectAPI.IsEncryptionSupported() {
if crypto.IsEncrypted(objInfo.UserDefined) { if crypto.IsEncrypted(objInfo.UserDefined) {
@ -632,7 +644,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
} }
// Set standard object headers. // Set standard object headers.
if err = setObjectHeaders(w, objInfo, rs); err != nil { if err = setObjectHeaders(w, objInfo, rs, opts); err != nil {
writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) writeErrorResponseHeadersOnly(w, toAPIError(ctx, err))
return return
} }
@ -646,7 +658,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
setHeadGetRespHeaders(w, r.URL.Query()) setHeadGetRespHeaders(w, r.URL.Query())
// Successful response. // Successful response.
if rs != nil { if rs != nil || opts.PartNumber > 0 {
w.WriteHeader(http.StatusPartialContent) w.WriteHeader(http.StatusPartialContent)
} else { } else {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)

@ -1330,7 +1330,7 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
setPartsCountHeaders(w, objInfo) setPartsCountHeaders(w, objInfo)
} }
if err = setObjectHeaders(w, objInfo, nil); err != nil { if err = setObjectHeaders(w, objInfo, nil, opts); err != nil {
writeWebErrorResponse(w, err) writeWebErrorResponse(w, err)
return return
} }

Loading…
Cancel
Save