@@ -2,8 +2,10 @@ package middleware
22
33import (
44 "bytes"
5+ "fmt"
56 "net/http"
67 "strconv"
8+ "strings"
79 "sync"
810
911 "github.com/darkweak/go-esi/esi"
@@ -85,6 +87,59 @@ func (r *CustomWriter) Write(b []byte) (int, error) {
8587 return len (b ), nil
8688}
8789
90+ type rangeValue struct {
91+ from , to int64
92+ }
93+
94+ const separator = "--SOUIN-HTTP-CACHE-SEPARATOR"
95+
96+ func parseRange (rangeHeaders []string , contentRange string ) ([]rangeValue , rangeValue , int64 ) {
97+ if len (rangeHeaders ) == 0 {
98+ return nil , rangeValue {}, - 1
99+ }
100+
101+ crv := rangeValue {from : 0 , to : 0 }
102+ var total int64 = - 1
103+ if contentRange != "" {
104+ crVal := strings .Split (strings .TrimPrefix (contentRange , "bytes " ), "/" )
105+ total , _ = strconv .ParseInt (crVal [1 ], 10 , 64 )
106+ total --
107+
108+ crSplit := strings .Split (crVal [0 ], "-" )
109+ crv .from , _ = strconv .ParseInt (crSplit [0 ], 10 , 64 )
110+ crv .to , _ = strconv .ParseInt (crSplit [1 ], 10 , 64 )
111+ }
112+
113+ values := make ([]rangeValue , len (rangeHeaders ))
114+
115+ for idx , header := range rangeHeaders {
116+ ranges := strings .Split (header , "-" )
117+ rv := rangeValue {from : - 1 , to : total }
118+
119+ // e.g. Range: -5
120+ if len (ranges ) == 2 && ranges [0 ] == "" {
121+ ranges [0 ] = "-" + ranges [1 ]
122+ from , _ := strconv .ParseInt (ranges [0 ], 10 , 64 )
123+ rv .from = total + from
124+
125+ values [idx ] = rv
126+
127+ continue
128+ }
129+
130+ rv .from , _ = strconv .ParseInt (ranges [0 ], 10 , 64 )
131+
132+ if ranges [1 ] != "" {
133+ rv .to , _ = strconv .ParseInt (ranges [1 ], 10 , 64 )
134+ rv .to ++
135+ }
136+
137+ values [idx ] = rv
138+ }
139+
140+ return values , crv , total + 1
141+ }
142+
88143// Send delays the response to handle Cache-Status
89144func (r * CustomWriter ) Send () (int , error ) {
90145 defer r .handleBuffer (func (b * bytes.Buffer ) {
@@ -94,10 +149,72 @@ func (r *CustomWriter) Send() (int, error) {
94149 if storedLength != "" {
95150 r .Header ().Set ("Content-Length" , storedLength )
96151 }
97- b := esi .Parse (r .Buf .Bytes (), r .Req )
98- if len (b ) != 0 {
99- r .Header ().Set ("Content-Length" , strconv .Itoa (len (b )))
152+
153+ result := r .Buf .Bytes ()
154+
155+ result = esi .Parse (result , r .Req )
156+
157+ if r .Headers .Get ("Range" ) != "" {
158+
159+ var bufStr string
160+ mimeType := r .Header ().Get ("Content-Type" )
161+
162+ r .WriteHeader (http .StatusPartialContent )
163+
164+ rangeHeader , contentRangeValue , total := parseRange (
165+ strings .Split (strings .TrimPrefix (r .Headers .Get ("Range" ), "bytes=" ), ", " ),
166+ r .Header ().Get ("Content-Range" ),
167+ )
168+ bodyBytes := r .Buf .Bytes ()
169+ bufLen := int64 (r .Buf .Len ())
170+ if total > 0 {
171+ bufLen = total
172+ }
173+
174+ if len (rangeHeader ) == 1 {
175+ header := rangeHeader [0 ]
176+ internalFrom := (header .from - contentRangeValue .from ) % bufLen
177+ internalTo := (header .to - contentRangeValue .from ) % bufLen
178+
179+ content := bodyBytes [internalFrom :]
180+
181+ r .Header ().Set ("Content-Range" , fmt .Sprintf ("bytes %d-%d/%d" , contentRangeValue .from , contentRangeValue .to , bufLen ))
182+
183+ if internalTo >= 0 {
184+ content = content [:internalTo - internalFrom ]
185+ r .Header ().Set ("Content-Range" , fmt .Sprintf ("bytes %d-%d/%d" , header .from , header .to , bufLen ))
186+ }
187+
188+ result = content
189+ }
190+
191+ if len (rangeHeader ) > 1 {
192+ r .Header ().Set ("Content-Type" , "multipart/byteranges; boundary=" + separator )
193+
194+ for _ , header := range rangeHeader {
195+
196+ content := bodyBytes [header .from :]
197+ if header .to >= 0 {
198+ content = content [:header .to - header .from ]
199+ }
200+
201+ bufStr += fmt .Sprintf (`
202+ %s
203+ Content-Type: %s
204+ Content-Range: bytes %d-%d/%d
205+
206+ %s
207+ ` , separator , mimeType , header .from , header .to , r .Buf .Len (), content )
208+ }
209+
210+ result = []byte (bufStr + separator + "--" )
211+ }
212+ }
213+
214+ if len (result ) != 0 {
215+ r .Header ().Set ("Content-Length" , strconv .Itoa (len (result )))
100216 }
217+
101218 r .Header ().Del (rfc .StoredLengthHeader )
102219 r .Header ().Del (rfc .StoredTTLHeader )
103220
@@ -106,5 +223,5 @@ func (r *CustomWriter) Send() (int, error) {
106223 r .headersSent = true
107224 }
108225
109- return r .Rw .Write (b )
226+ return r .Rw .Write (result )
110227}
0 commit comments