@@ -2,7 +2,7 @@ use crate::response::CookieEvent;
2
2
use crate :: utils:: BoxFuture ;
3
3
use crate :: { Middleware , Next , Request } ;
4
4
5
- use crate :: http:: cookies:: { Cookie , CookieJar } ;
5
+ use crate :: http:: cookies:: { Cookie , CookieJar , Delta } ;
6
6
use crate :: http:: headers;
7
7
8
8
use std:: sync:: { Arc , RwLock } ;
@@ -41,27 +41,32 @@ impl<State: Send + Sync + 'static> Middleware<State> for CookiesMiddleware {
41
41
let cookie_jar = if let Some ( cookie_data) = ctx. local :: < CookieData > ( ) {
42
42
cookie_data. content . clone ( )
43
43
} else {
44
- // no cookie data in local context, so we need to create it
45
44
let cookie_data = CookieData :: from_request ( & ctx) ;
45
+ // no cookie data in local context, so we try to create it
46
46
let content = cookie_data. content . clone ( ) ;
47
47
ctx = ctx. set_local ( cookie_data) ;
48
48
content
49
49
} ;
50
50
51
51
let mut res = next. run ( ctx) . await ?;
52
52
53
+ // Don't do anything if there are no cookies.
54
+ if res. cookie_events . is_empty ( ) {
55
+ return Ok ( res) ;
56
+ }
57
+
58
+ let jar = & mut * cookie_jar. write ( ) . unwrap ( ) ;
59
+
53
60
// add modifications from response to original
54
61
for cookie in res. cookie_events . drain ( ..) {
55
62
match cookie {
56
- CookieEvent :: Added ( cookie) => cookie_jar. write ( ) . unwrap ( ) . add ( cookie. clone ( ) ) ,
57
- CookieEvent :: Removed ( cookie) => {
58
- cookie_jar. write ( ) . unwrap ( ) . remove ( cookie. clone ( ) )
59
- }
63
+ CookieEvent :: Added ( cookie) => jar. add ( cookie. clone ( ) ) ,
64
+ CookieEvent :: Removed ( cookie) => jar. remove ( cookie. clone ( ) ) ,
60
65
}
61
66
}
62
67
63
68
// iterate over added and removed cookies
64
- for cookie in cookie_jar . read ( ) . unwrap ( ) . delta ( ) {
69
+ for cookie in jar . delta ( ) {
65
70
let encoded_cookie = cookie. encoded ( ) . to_string ( ) ;
66
71
res = res. append_header ( headers:: SET_COOKIE , encoded_cookie) ;
67
72
}
@@ -70,16 +75,48 @@ impl<State: Send + Sync + 'static> Middleware<State> for CookiesMiddleware {
70
75
}
71
76
}
72
77
73
- #[ derive( Debug , Clone ) ]
78
+ #[ derive( Debug , Default , Clone ) ]
74
79
pub ( crate ) struct CookieData {
75
- pub ( crate ) content : Arc < RwLock < CookieJar > > ,
80
+ pub ( crate ) content : Arc < RwLock < LazyJar > > ,
81
+ }
82
+
83
+ #[ derive( Debug , Default , Clone ) ]
84
+ /// Wrapper around `CookieJar`, that initializes only when actually used.
85
+ pub ( crate ) struct LazyJar ( Option < CookieJar > ) ;
86
+
87
+ impl LazyJar {
88
+ fn add ( & mut self , cookie : Cookie < ' static > ) {
89
+ self . get_jar ( ) . add ( cookie)
90
+ }
91
+
92
+ fn remove ( & mut self , cookie : Cookie < ' static > ) {
93
+ self . get_jar ( ) . remove ( cookie)
94
+ }
95
+
96
+ fn delta ( & mut self ) -> Delta < ' _ > {
97
+ self . get_jar ( ) . delta ( )
98
+ }
99
+
100
+ pub ( crate ) fn get ( & self , name : & str ) -> Option < & Cookie < ' static > > {
101
+ if let Some ( jar) = & self . 0 {
102
+ return jar. get ( name) ;
103
+ }
104
+ None
105
+ }
106
+
107
+ fn get_jar ( & mut self ) -> & mut CookieJar {
108
+ if self . 0 . is_none ( ) {
109
+ self . 0 = Some ( CookieJar :: new ( ) ) ;
110
+ }
111
+
112
+ self . 0 . as_mut ( ) . unwrap ( )
113
+ }
76
114
}
77
115
78
116
impl CookieData {
79
117
pub ( crate ) fn from_request < S > ( req : & Request < S > ) -> Self {
80
- let mut jar = CookieJar :: new ( ) ;
81
-
82
- if let Some ( cookie_headers) = req. header ( & headers:: COOKIE ) {
118
+ let jar = if let Some ( cookie_headers) = req. header ( & headers:: COOKIE ) {
119
+ let mut jar = CookieJar :: new ( ) ;
83
120
for cookie_header in cookie_headers {
84
121
// spec says there should be only one, so this is permissive
85
122
for pair in cookie_header. as_str ( ) . split ( ';' ) {
@@ -88,9 +125,13 @@ impl CookieData {
88
125
}
89
126
}
90
127
}
91
- }
92
128
93
- Self {
129
+ LazyJar ( Some ( jar) )
130
+ } else {
131
+ LazyJar :: default ( )
132
+ } ;
133
+
134
+ CookieData {
94
135
content : Arc :: new ( RwLock :: new ( jar) ) ,
95
136
}
96
137
}
0 commit comments