11package scs
22
33import (
4- "bufio"
5- "bytes"
64 "context"
75 "log"
8- "net"
96 "net/http"
107 "time"
118
@@ -131,6 +128,8 @@ func NewSession() *SessionManager {
131128// the client in a cookie.
132129func (s * SessionManager ) LoadAndSave (next http.Handler ) http.Handler {
133130 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
131+ w .Header ().Add ("Vary" , "Cookie" )
132+
134133 var token string
135134 cookie , err := r .Cookie (s .Cookie .Name )
136135 if err == nil {
@@ -144,33 +143,36 @@ func (s *SessionManager) LoadAndSave(next http.Handler) http.Handler {
144143 }
145144
146145 sr := r .WithContext (ctx )
147- bw := & bufferedResponseWriter {ResponseWriter : w }
148- next .ServeHTTP (bw , sr )
149146
150- if sr .MultipartForm != nil {
151- sr .MultipartForm .RemoveAll ()
147+ sw := & sessionResponseWriter {
148+ ResponseWriter : w ,
149+ request : sr ,
150+ sessionManager : s ,
152151 }
153152
154- switch s .Status (ctx ) {
155- case Modified :
156- token , expiry , err := s .Commit (ctx )
157- if err != nil {
158- s .ErrorFunc (w , r , err )
159- return
160- }
161-
162- s .WriteSessionCookie (ctx , w , token , expiry )
163- case Destroyed :
164- s .WriteSessionCookie (ctx , w , "" , time.Time {})
153+ next .ServeHTTP (sw , sr )
154+
155+ if ! sw .written {
156+ s .commitAndWriteSessionCookie (w , sr )
165157 }
158+ })
159+ }
166160
167- w .Header ().Add ("Vary" , "Cookie" )
161+ func (s * SessionManager ) commitAndWriteSessionCookie (w http.ResponseWriter , r * http.Request ) {
162+ ctx := r .Context ()
168163
169- if bw .code != 0 {
170- w .WriteHeader (bw .code )
164+ switch s .Status (ctx ) {
165+ case Modified :
166+ token , expiry , err := s .Commit (ctx )
167+ if err != nil {
168+ s .ErrorFunc (w , r , err )
169+ return
171170 }
172- w .Write (bw .buf .Bytes ())
173- })
171+
172+ s .WriteSessionCookie (ctx , w , token , expiry )
173+ case Destroyed :
174+ s .WriteSessionCookie (ctx , w , "" , time.Time {})
175+ }
174176}
175177
176178// WriteSessionCookie writes a cookie to the HTTP response with the provided
@@ -211,32 +213,31 @@ func defaultErrorFunc(w http.ResponseWriter, r *http.Request, err error) {
211213 http .Error (w , http .StatusText (http .StatusInternalServerError ), http .StatusInternalServerError )
212214}
213215
214- type bufferedResponseWriter struct {
216+ type sessionResponseWriter struct {
215217 http.ResponseWriter
216- buf bytes. Buffer
217- code int
218- wroteHeader bool
218+ request * http. Request
219+ sessionManager * SessionManager
220+ written bool
219221}
220222
221- func (bw * bufferedResponseWriter ) Write (b []byte ) (int , error ) {
222- return bw .buf .Write (b )
223+ func (sw * sessionResponseWriter ) Write (b []byte ) (int , error ) {
224+ if ! sw .written {
225+ sw .sessionManager .commitAndWriteSessionCookie (sw .ResponseWriter , sw .request )
226+ sw .written = true
227+ }
228+
229+ return sw .ResponseWriter .Write (b )
223230}
224231
225- func (bw * bufferedResponseWriter ) WriteHeader (code int ) {
226- if ! bw . wroteHeader {
227- bw . code = code
228- bw . wroteHeader = true
232+ func (sw * sessionResponseWriter ) WriteHeader (code int ) {
233+ if ! sw . written {
234+ sw . sessionManager . commitAndWriteSessionCookie ( sw . ResponseWriter , sw . request )
235+ sw . written = true
229236 }
230- }
231237
232- func (bw * bufferedResponseWriter ) Hijack () (net.Conn , * bufio.ReadWriter , error ) {
233- hj := bw .ResponseWriter .(http.Hijacker )
234- return hj .Hijack ()
238+ sw .ResponseWriter .WriteHeader (code )
235239}
236240
237- func (bw * bufferedResponseWriter ) Push (target string , opts * http.PushOptions ) error {
238- if pusher , ok := bw .ResponseWriter .(http.Pusher ); ok {
239- return pusher .Push (target , opts )
240- }
241- return http .ErrNotSupported
241+ func (sw * sessionResponseWriter ) Unwrap () http.ResponseWriter {
242+ return sw .ResponseWriter
242243}
0 commit comments