Skip to content

Commit db5ae3e

Browse files
remove random logs from console (#1317)
as a practice always use LogError or LogInfo instead of using `log.Println()` directly.
1 parent 8a79409 commit db5ae3e

File tree

1 file changed

+119
-149
lines changed

1 file changed

+119
-149
lines changed

restapi/user_objects.go

Lines changed: 119 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"encoding/base64"
2424
"fmt"
2525
"io"
26-
"log"
2726
"net/http"
2827
"path"
2928
"path/filepath"
@@ -274,6 +273,85 @@ func listBucketObjects(ctx context.Context, client MinioClient, bucketName strin
274273
return objects, nil
275274
}
276275

276+
type httpRange struct {
277+
Start int64
278+
Length int64
279+
}
280+
281+
// Example:
282+
// "Content-Range": "bytes 100-200/1000"
283+
// "Content-Range": "bytes 100-200/*"
284+
func getRange(start, end, total int64) string {
285+
// unknown total: -1
286+
if total == -1 {
287+
return fmt.Sprintf("bytes %d-%d/*", start, end)
288+
}
289+
290+
return fmt.Sprintf("bytes %d-%d/%d", start, end, total)
291+
}
292+
293+
// Example:
294+
// "Range": "bytes=100-200"
295+
// "Range": "bytes=-50"
296+
// "Range": "bytes=150-"
297+
// "Range": "bytes=0-0,-1"
298+
func parseRange(s string, size int64) ([]httpRange, error) {
299+
if s == "" {
300+
return nil, nil // header not present
301+
}
302+
const b = "bytes="
303+
if !strings.HasPrefix(s, b) {
304+
return nil, errors.New("invalid range")
305+
}
306+
var ranges []httpRange
307+
for _, ra := range strings.Split(s[len(b):], ",") {
308+
ra = strings.TrimSpace(ra)
309+
if ra == "" {
310+
continue
311+
}
312+
i := strings.Index(ra, "-")
313+
if i < 0 {
314+
return nil, errors.New("invalid range")
315+
}
316+
start, end := strings.TrimSpace(ra[:i]), strings.TrimSpace(ra[i+1:])
317+
var r httpRange
318+
if start == "" {
319+
// If no start is specified, end specifies the
320+
// range start relative to the end of the file.
321+
i, err := strconv.ParseInt(end, 10, 64)
322+
if err != nil {
323+
return nil, errors.New("invalid range")
324+
}
325+
if i > size {
326+
i = size
327+
}
328+
r.Start = size - i
329+
r.Length = size - r.Start
330+
} else {
331+
i, err := strconv.ParseInt(start, 10, 64)
332+
if err != nil || i >= size || i < 0 {
333+
return nil, errors.New("invalid range")
334+
}
335+
r.Start = i
336+
if end == "" {
337+
// If no end is specified, range extends to end of the file.
338+
r.Length = size - r.Start
339+
} else {
340+
i, err := strconv.ParseInt(end, 10, 64)
341+
if err != nil || r.Start > i {
342+
return nil, errors.New("invalid range")
343+
}
344+
if i >= size {
345+
i = size - 1
346+
}
347+
r.Length = i - r.Start + 1
348+
}
349+
}
350+
ranges = append(ranges, r)
351+
}
352+
return ranges, nil
353+
}
354+
277355
func getDownloadObjectResponse(session *models.Principal, params user_api.DownloadObjectParams) (middleware.Responder, *models.Error) {
278356
ctx := context.Background()
279357
var prefix string
@@ -298,30 +376,10 @@ func getDownloadObjectResponse(session *models.Principal, params user_api.Downlo
298376
return middleware.ResponderFunc(func(rw http.ResponseWriter, _ runtime.Producer) {
299377
defer resp.Close()
300378

301-
// indicate object size & content type
302-
stat, err := resp.Stat()
303-
statOk := false
304-
if err != nil {
305-
log.Println(err)
306-
} else {
307-
statOk = true
308-
}
309-
310379
isPreview := params.Preview != nil && *params.Preview
311-
312380
// indicate it's a download / inline content to the browser, and the size of the object
313-
var prefixPath string
314381
var filename string
315-
if params.Prefix != "" {
316-
encodedPrefix := SanitizeEncodedPrefix(params.Prefix)
317-
decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix)
318-
if err != nil {
319-
log.Println(err)
320-
}
321-
322-
prefixPath = string(decodedPrefix)
323-
}
324-
prefixElements := strings.Split(prefixPath, "/")
382+
prefixElements := strings.Split(prefix, "/")
325383
if len(prefixElements) > 0 {
326384
if prefixElements[len(prefixElements)-1] == "" {
327385
filename = prefixElements[len(prefixElements)-2]
@@ -330,68 +388,60 @@ func getDownloadObjectResponse(session *models.Principal, params user_api.Downlo
330388
}
331389
}
332390

333-
// if we are getting a Range Request (video) handle that specially
334-
isRange := params.HTTPRequest.Header.Get("Range")
335-
if isRange != "" {
336-
337-
rangeFrom := -1
338-
rangeTo := -1
339-
340-
parts := strings.Split(isRange, "=")
341-
if len(parts) > 1 {
342-
rangeParts := strings.Split(parts[1], "-")
343-
var err error
344-
rangeFrom, err = strconv.Atoi(rangeParts[0])
345-
if err != nil {
346-
log.Println(err)
347-
return
348-
}
349-
if rangeParts[1] != "" {
350-
rangeTo, err = strconv.Atoi(rangeParts[1])
351-
if err != nil {
352-
log.Println(err)
353-
return
354-
}
355-
}
356-
357-
}
391+
// indicate object size & content type
392+
stat, err := resp.Stat()
393+
if err != nil {
394+
LogError("Failed to get Stat() response from server for %s: %v", prefix, err)
395+
return
396+
}
358397

359-
if handleRangeRequest(rw, isRange, stat, isPreview, filename, resp, params, rangeTo, rangeFrom) {
360-
return
361-
}
398+
// if we are getting a Range Request (video) handle that specially
399+
ranges, err := parseRange(params.HTTPRequest.Header.Get("Range"), stat.Size)
400+
if err != nil {
401+
LogError("Unable to parse range header input %s: %v", params.HTTPRequest.Header.Get("Range"), err)
402+
return
362403
}
363404

364405
if isPreview {
365406
rw.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", filename))
366407
rw.Header().Set("X-Frame-Options", "SAMEORIGIN")
367408
rw.Header().Set("X-XSS-Protection", "1")
368-
369409
} else {
370410
rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
371-
rw.Header().Set("Content-Type", "application/octet-stream")
372411
}
373412

374-
// indicate object size & content type
375-
376-
if statOk {
377-
rw.Header().Set("Content-Length", fmt.Sprintf("%d", stat.Size))
413+
rw.Header().Set("Last-Modified", stat.LastModified.UTC().Format(http.TimeFormat))
378414

379-
contentType := stat.ContentType
415+
contentType := stat.ContentType
416+
if isPreview {
417+
// In case content type was uploaded as octet-stream, we double verify content type
418+
if stat.ContentType == "application/octet-stream" {
419+
contentType = mimedb.TypeByExtension(filepath.Ext(filename))
420+
}
421+
}
422+
rw.Header().Set("Content-Type", contentType)
423+
length := stat.Size
424+
if len(ranges) > 0 {
425+
start := ranges[0].Start
426+
length = ranges[0].Length
380427

381-
if isPreview {
382-
// In case content type was uploaded as octet-stream, we double verify content type
383-
if stat.ContentType == "application/octet-stream" {
384-
contentType = mimedb.TypeByExtension(filepath.Ext(filename))
385-
}
428+
_, err = resp.Seek(start, io.SeekStart)
429+
if err != nil {
430+
LogError("Unable to seek at offset %d: %v", start, err)
431+
return
386432
}
387433

388-
rw.Header().Set("Content-Type", contentType)
434+
rw.Header().Set("Accept-Ranges", "bytes")
435+
rw.Header().Set("Access-Control-Allow-Origin", "*")
436+
rw.Header().Set("Content-Range", getRange(start, start+length-1, stat.Size))
437+
rw.WriteHeader(http.StatusPartialContent)
389438
}
390439

391-
// Copy the stream
392-
_, err = io.Copy(rw, resp)
440+
rw.Header().Set("Content-Length", fmt.Sprintf("%d", length))
441+
_, err = io.Copy(rw, io.LimitReader(resp, length))
393442
if err != nil {
394-
log.Println(err)
443+
LogError("Unable to write all data to client: %v", err)
444+
return
395445
}
396446
}), nil
397447
}
@@ -451,7 +501,8 @@ func getDownloadFolderResponse(session *models.Principal, params user_api.Downlo
451501
encodedPrefix := SanitizeEncodedPrefix(params.Prefix)
452502
decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix)
453503
if err != nil {
454-
log.Println(err)
504+
LogError("Unable to parse encoded prefix %s: %v", encodedPrefix, err)
505+
return
455506
}
456507

457508
prefixPath = string(decodedPrefix)
@@ -471,7 +522,7 @@ func getDownloadFolderResponse(session *models.Principal, params user_api.Downlo
471522
// Copy the stream
472523
_, err := io.Copy(rw, resp)
473524
if err != nil {
474-
log.Println(err)
525+
LogError("Unable to write all the requested data: %v", err)
475526
}
476527
}), nil
477528
}
@@ -1033,84 +1084,3 @@ func getHost(authority string) (host string) {
10331084
}
10341085
return authority
10351086
}
1036-
1037-
func handleRangeRequest(rw http.ResponseWriter, isRange string, stat minio.ObjectInfo, isPreview bool, filename string, resp *minio.Object, params user_api.DownloadObjectParams, rangeTo int, rangeFrom int) bool {
1038-
parts := strings.Split(isRange, "=")
1039-
if len(parts) > 1 {
1040-
if parts[1] == "0-1" {
1041-
contentType := stat.ContentType
1042-
1043-
if isPreview {
1044-
// In case content type was uploaded as octet-stream, we double verify content type
1045-
if stat.ContentType == "application/octet-stream" {
1046-
contentType = mimedb.TypeByExtension(filepath.Ext(filename))
1047-
}
1048-
}
1049-
rw.Header().Set("Content-Type", contentType)
1050-
rw.Header().Set("Content-Length", "2")
1051-
rw.Header().Set("Content-Range", fmt.Sprintf("bytes 0-1/%d", stat.Size))
1052-
rw.Header().Set("Accept-Ranges", "bytes")
1053-
rw.Header().Set("Access-Control-Allow-Origin", "*")
1054-
rw.WriteHeader(206)
1055-
byts := make([]byte, 2)
1056-
t, err := resp.Read(byts)
1057-
log.Println("read", t, "bytes")
1058-
if err != nil {
1059-
log.Println(err)
1060-
}
1061-
rw.Write(byts)
1062-
return true
1063-
}
1064-
1065-
contentType := stat.ContentType
1066-
1067-
if isPreview {
1068-
// In case content type was uploaded as octet-stream, we double verify content type
1069-
if stat.ContentType == "application/octet-stream" {
1070-
contentType = mimedb.TypeByExtension(filepath.Ext(filename))
1071-
}
1072-
}
1073-
rw.Header().Set("Content-Type", contentType)
1074-
isFirefox := false
1075-
if strings.Contains(params.HTTPRequest.UserAgent(), "Firefox") {
1076-
isFirefox = true
1077-
}
1078-
if !isFirefox {
1079-
rw.Header().Set("Content-Length", fmt.Sprintf("%d", stat.Size))
1080-
}
1081-
1082-
if rangeTo > -1 {
1083-
rw.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", rangeFrom, rangeTo, stat.Size))
1084-
if isFirefox {
1085-
rw.Header().Set("Content-Length", fmt.Sprintf("%d", rangeTo-rangeFrom+1))
1086-
}
1087-
} else {
1088-
rw.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", rangeFrom, stat.Size-1, stat.Size))
1089-
if isFirefox {
1090-
rw.Header().Set("Content-Length", fmt.Sprintf("%d", stat.Size-int64(rangeFrom)))
1091-
}
1092-
}
1093-
rw.Header().Set("Accept-Ranges", "bytes")
1094-
rw.Header().Set("Access-Control-Allow-Origin", "*")
1095-
rw.WriteHeader(206)
1096-
if rangeTo > -1 {
1097-
byts := make([]byte, rangeTo+1)
1098-
t, err := resp.ReadAt(byts, int64(rangeFrom))
1099-
log.Println("0 read", t, "bytes")
1100-
if err != nil {
1101-
log.Println(err)
1102-
}
1103-
rw.Write(byts)
1104-
} else {
1105-
byts := make([]byte, stat.Size-int64(rangeFrom))
1106-
t, err := resp.ReadAt(byts, int64(rangeFrom))
1107-
log.Println("1 read", t, "bytes")
1108-
if err != nil {
1109-
log.Println(err)
1110-
}
1111-
rw.Write(byts)
1112-
}
1113-
1114-
}
1115-
return false
1116-
}

0 commit comments

Comments
 (0)