/
sendFile.go
92 lines (88 loc) · 2.34 KB
/
sendFile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package http
import (
"crypto/sha1"
"fmt"
"io"
"log"
"net/http"
"os"
"strconv"
"strings"
)
// SendFile 分段传输文件
func SendFile(writer http.ResponseWriter, request *http.Request, f *os.File, buf_n ...int) {
defer f.Close()
info, err := f.Stat()
if err != nil {
log.Println("sendFile1", err.Error())
http.NotFound(writer, request)
return
}
SetHeader(writer.Header(), "Accept-Ranges", "bytes")
SetHeader(writer.Header(), "Content-Disposition", "attachment; filename="+info.Name())
etag := sha1.New()
etag.Write([]byte(strconv.FormatInt(info.ModTime().UnixNano(), 10)))
SetHeader(writer.Header(), "ETag", fmt.Sprintf("%x", etag.Sum(nil)))
var start, end int64
IfRange := request.Header.Get("If-Range")
// fmt.Println(request.Header,"\n")
if r := request.Header.Get("Range"); r != "" && (IfRange == fmt.Sprintf("%x", etag.Sum(nil)) || IfRange == "") {
if strings.Contains(r, "bytes=") && strings.Contains(r, "-") {
fmt.Sscanf(r, "bytes=%d-%d", &start, &end)
if end == 0 {
end = info.Size() - 1
}
if start > end || start < 0 || end < 0 || end >= info.Size() {
writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
log.Println("sendFile2 start:", start, "end:", end, "size:", info.Size())
return
}
writer.Header().Set("Content-Length", strconv.FormatInt(end-start+1, 10))
writer.Header().Set("Content-Range", fmt.Sprintf("bytes %v-%v/%v", start, end, info.Size()))
writer.WriteHeader(http.StatusPartialContent)
} else {
writer.WriteHeader(http.StatusBadRequest)
return
}
} else {
writer.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10))
start = 0
end = info.Size() - 1
}
_, err = f.Seek(start, 0)
if err != nil {
log.Println("sendFile3", err.Error())
writer.WriteHeader(http.StatusInternalServerError)
return
}
var buf_size int
if len(buf_n) != 0 {
buf_size = buf_n[0]
} else {
buf_size = 512
}
buf := make([]byte, buf_size)
for {
if end-start+1 < int64(buf_size) {
buf_size = int(end - start + 1)
}
_, err := f.Read(buf[:buf_size])
if err != nil {
log.Println("1:", err)
if err != io.EOF {
log.Println("error:", err)
}
return
}
err = nil
_, err = writer.Write(buf[:buf_size])
if err != nil {
// log.Println(err, start, end, info.Size(), n)
return
}
start += int64(buf_size)
if start >= end+1 {
return
}
}
}