@@ -7,20 +7,15 @@ import (
77 "io"
88 "io/fs"
99 "net/http"
10- "os"
1110 "path"
12- "sync"
1311
1412 "github.com/wzshiming/ioswmr"
1513)
1614
1715type teeResponse struct {
18- fileInfo fs.FileInfo
19- swmr ioswmr.SWMR
20- tmp * os.File
21- teeCache * sync.Map
22- etag string
23- cacheFile string
16+ fileInfo fs.FileInfo
17+ swmr ioswmr.SWMR
18+ etag string
2419}
2520
2621func (t * teeResponse ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
@@ -31,91 +26,79 @@ func (t *teeResponse) ServeHTTP(w http.ResponseWriter, r *http.Request) {
3126 rs := t .swmr .NewReadSeeker (0 , int (size ))
3227 defer rs .Close ()
3328 name := path .Base (r .URL .Path )
34- w .Header ().Set ("ETag" , t .etag )
29+ if t .etag != "" {
30+ w .Header ().Set ("ETag" , t .etag )
31+ }
3532 w .Header ().Set ("Content-Type" , "application/octet-stream" )
36- w .Header ().Set ("Content-Length" , fmt .Sprint (size ))
3733 http .ServeContent (w , r , name , t .fileInfo .ModTime (), rs )
3834 } else {
3935 rs := t .swmr .NewReader (0 )
4036 defer rs .Close ()
41- w .Header ().Set ("ETag" , t .etag )
42- w .Header ().Set ("Content-Type" , "application/octet-stream" )
37+ if t .etag != "" {
38+ w .Header ().Set ("ETag" , t .etag )
39+ }
4340 w .WriteHeader (http .StatusOK )
4441 if r .Method == http .MethodGet {
4542 _ , _ = io .Copy (w , rs )
4643 }
4744 }
4845}
4946
50- func (t * teeResponse ) Close () error {
51- if ! t .swmr .IsClosed () {
52- return nil
53- }
54- if t .swmr .Using () != 0 {
55- return nil
56- }
57- t .teeCache .Delete (t .cacheFile )
58- err := t .tmp .Close ()
59- if err != nil {
60- return err
61- }
62- _ = os .Remove (t .tmp .Name ())
63- return nil
64- }
65-
6647func (m * MirrorHandler ) cacheFileTee (ctx context.Context , sourceFile , cacheFile string ) (* teeResponse , error ) {
67- resp , info , err := httpGet (ctx , m .client (), sourceFile )
48+ body , info , err := httpGet (ctx , m .client (), sourceFile , true )
6849 if err != nil {
6950 return nil , err
7051 }
7152
72- var body io.Reader = resp
73-
7453 contentLength := info .Size ()
7554 if contentLength == 0 {
76- _ = resp .Close ()
55+ _ = body .Close ()
7756 return nil , ErrNotOK
7857 }
7958
8059 if m .Logger != nil {
8160 m .Logger .Println ("Tee Cache" , cacheFile , contentLength )
8261 }
8362
84- tmp , err := os .CreateTemp ("" , "mirror-tee-*" )
85- if err != nil {
86- _ = resp .Close ()
87- return nil , err
88- }
8963 fw , err := m .RemoteCache .Writer (ctx , cacheFile )
9064 if err != nil {
9165 if m .Logger != nil {
9266 m .Logger .Println ("Cache writer error" , cacheFile , contentLength , err )
9367 }
94- _ = resp .Close ()
95- _ = tmp .Close ()
96- _ = os .Remove (tmp .Name ())
68+ _ = body .Close ()
9769 return nil , err
9870 }
9971
100- swmr := ioswmr .NewSWMR (tmp )
72+ swmr := ioswmr .NewSWMR (
73+ ioswmr .NewMemoryOrTemporaryFileBuffer (nil , nil ),
74+ ioswmr .WithAutoClose (),
75+ ioswmr .WithBeforeCloseFunc (func () {
76+ m .teeCache .Delete (cacheFile )
77+ if m .Logger != nil {
78+ m .Logger .Println ("Tee Cache closed" , cacheFile , err )
79+ }
80+ }),
81+ )
10182
10283 tee := & teeResponse {
103- fileInfo : info ,
104- swmr : swmr ,
105- tmp : tmp ,
106- etag : info .ETag (),
107- teeCache : & m .teeCache ,
108- cacheFile : cacheFile ,
84+ fileInfo : info ,
85+ swmr : swmr ,
86+ etag : info .ETag (),
10987 }
88+ sw := swmr .Writer ()
11089
11190 go func () {
112- defer tee .Close ()
113- defer resp . Close ( )
114- defer fw . Close ( )
115- defer swmr . Close ()
91+ defer body .Close ()
92+ _ , err := io . Copy ( sw , body )
93+ _ = sw . CloseWithError ( err )
94+ } ()
11695
117- w := io .MultiWriter (swmr , fw )
118- n , err := io .Copy (w , body )
96+ go func () {
97+ r := swmr .NewReader (0 )
98+ defer r .Close ()
99+
100+ defer fw .Close ()
101+ n , err := io .Copy (fw , r )
119102 if err != nil && ! errors .Is (err , io .EOF ) {
120103 if m .Logger != nil {
121104 m .Logger .Println ("SWMR copy error" , cacheFile , contentLength , n , err )
0 commit comments