16
16
17
17
package org .springframework .web .context .request ;
18
18
19
+ import java .util .Enumeration ;
20
+ import java .util .HashMap ;
21
+ import java .util .Map ;
22
+
19
23
import io .micrometer .context .ThreadLocalAccessor ;
24
+ import jakarta .servlet .http .HttpServletRequest ;
20
25
21
26
import org .springframework .lang .Nullable ;
22
27
26
31
* {@link RequestAttributes} propagation.
27
32
*
28
33
* @author Tadaya Tsuyukubo
34
+ * @author Rossen Stoyanchev
29
35
* @since 6.2
30
36
*/
31
37
public class RequestAttributesThreadLocalAccessor implements ThreadLocalAccessor <RequestAttributes > {
@@ -44,7 +50,11 @@ public Object key() {
44
50
@ Override
45
51
@ Nullable
46
52
public RequestAttributes getValue () {
47
- return RequestContextHolder .getRequestAttributes ();
53
+ RequestAttributes request = RequestContextHolder .getRequestAttributes ();
54
+ if (request instanceof ServletRequestAttributes sra && !(sra instanceof SnapshotServletRequestAttributes )) {
55
+ request = new SnapshotServletRequestAttributes (sra );
56
+ }
57
+ return request ;
48
58
}
49
59
50
60
@ Override
@@ -57,4 +67,82 @@ public void setValue() {
57
67
RequestContextHolder .resetRequestAttributes ();
58
68
}
59
69
70
+
71
+ /**
72
+ * ServletRequestAttributes that takes another instance, and makes a copy of the
73
+ * request attributes at present to provides extended read access during async
74
+ * handling when the DispatcherServlet has exited from the initial REQUEST dispatch
75
+ * and marked the request {@link ServletRequestAttributes#requestCompleted()}.
76
+ * <p>Note that beyond access to request attributes, here is no attempt to support
77
+ * setting or removing request attributes, nor to access session attributes after
78
+ * the initial REQUEST dispatch has exited.
79
+ */
80
+ private static final class SnapshotServletRequestAttributes extends ServletRequestAttributes {
81
+
82
+ private final ServletRequestAttributes delegate ;
83
+
84
+ private final Map <String , Object > attributeMap ;
85
+
86
+ public SnapshotServletRequestAttributes (ServletRequestAttributes requestAttributes ) {
87
+ super (requestAttributes .getRequest (), requestAttributes .getResponse ());
88
+ this .delegate = requestAttributes ;
89
+ this .attributeMap = getAttributes (requestAttributes .getRequest ());
90
+ }
91
+
92
+ private static Map <String , Object > getAttributes (HttpServletRequest request ) {
93
+ Map <String , Object > map = new HashMap <>();
94
+ Enumeration <String > names = request .getAttributeNames ();
95
+ while (names .hasMoreElements ()) {
96
+ String name = names .nextElement ();
97
+ map .put (name , request .getAttribute (name ));
98
+ }
99
+ return map ;
100
+ }
101
+
102
+ // Delegate methods that check isRequestActive()
103
+
104
+ @ Nullable
105
+ @ Override
106
+ public Object getAttribute (String name , int scope ) {
107
+ if (scope == RequestAttributes .SCOPE_REQUEST && !this .delegate .isRequestActive ()) {
108
+ return this .attributeMap .get (name );
109
+ }
110
+ try {
111
+ return this .delegate .getAttribute (name , scope );
112
+ }
113
+ catch (IllegalStateException ex ) {
114
+ if (scope == RequestAttributes .SCOPE_REQUEST ) {
115
+ return this .attributeMap .get (name );
116
+ }
117
+ throw ex ;
118
+ }
119
+ }
120
+
121
+ @ Override
122
+ public String [] getAttributeNames (int scope ) {
123
+ if (scope == RequestAttributes .SCOPE_REQUEST && !this .delegate .isRequestActive ()) {
124
+ return this .attributeMap .keySet ().toArray (new String [0 ]);
125
+ }
126
+ try {
127
+ return this .delegate .getAttributeNames (scope );
128
+ }
129
+ catch (IllegalStateException ex ) {
130
+ if (scope == RequestAttributes .SCOPE_REQUEST ) {
131
+ return this .attributeMap .keySet ().toArray (new String [0 ]);
132
+ }
133
+ throw ex ;
134
+ }
135
+ }
136
+
137
+ @ Override
138
+ public void setAttribute (String name , Object value , int scope ) {
139
+ this .delegate .setAttribute (name , value , scope );
140
+ }
141
+
142
+ @ Override
143
+ public void removeAttribute (String name , int scope ) {
144
+ this .delegate .removeAttribute (name , scope );
145
+ }
146
+ }
147
+
60
148
}
0 commit comments