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. 21
      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
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
setCommonHeaders(w)
@ -147,15 +147,26 @@ func setObjectHeaders(w http.ResponseWriter, objInfo ObjectInfo, rs *HTTPRangeSp
}
}
var start, rangeLen int64
totalObjectSize, err := objInfo.GetActualSize()
if err != nil {
return err
}
// for providing ranged content
start, rangeLen, err := rs.GetOffsetLength(totalObjectSize)
if err != nil {
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
start, rangeLen, err = rs.GetOffsetLength(totalObjectSize)
if err != nil {
return err
}
}
// Set content length.

@ -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()) (
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
// with error
defer func() {

@ -378,6 +378,22 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
rangeHeader := r.Header.Get(xhttp.Range)
if 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.
@ -393,16 +409,6 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
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
}
@ -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))
return
}
@ -459,7 +465,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
statusCodeWritten := false
httpWriter := ioutil.WriteOnClose(w)
if rs != nil {
if rs != nil || opts.PartNumber > 0 {
statusCodeWritten = true
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
if objectAPI.IsEncryptionSupported() {
if crypto.IsEncrypted(objInfo.UserDefined) {
@ -632,7 +644,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
}
// 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))
return
}
@ -646,7 +658,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
setHeadGetRespHeaders(w, r.URL.Query())
// Successful response.
if rs != nil {
if rs != nil || opts.PartNumber > 0 {
w.WriteHeader(http.StatusPartialContent)
} else {
w.WriteHeader(http.StatusOK)

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

Loading…
Cancel
Save