1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.protocol;
29
30 import java.io.IOException;
31 import java.time.Instant;
32 import java.util.ArrayList;
33 import java.util.List;
34
35 import org.apache.hc.client5.http.RouteInfo;
36 import org.apache.hc.client5.http.config.RequestConfig;
37 import org.apache.hc.client5.http.cookie.Cookie;
38 import org.apache.hc.client5.http.cookie.CookieOrigin;
39 import org.apache.hc.client5.http.cookie.CookieSpec;
40 import org.apache.hc.client5.http.cookie.CookieSpecFactory;
41 import org.apache.hc.client5.http.cookie.CookieStore;
42 import org.apache.hc.client5.http.cookie.StandardCookieSpec;
43 import org.apache.hc.core5.annotation.Contract;
44 import org.apache.hc.core5.annotation.ThreadingBehavior;
45 import org.apache.hc.core5.http.EntityDetails;
46 import org.apache.hc.core5.http.Header;
47 import org.apache.hc.core5.http.HttpException;
48 import org.apache.hc.core5.http.HttpHeaders;
49 import org.apache.hc.core5.http.HttpRequest;
50 import org.apache.hc.core5.http.HttpRequestInterceptor;
51 import org.apache.hc.core5.http.Method;
52 import org.apache.hc.core5.http.config.Lookup;
53 import org.apache.hc.core5.http.protocol.HttpContext;
54 import org.apache.hc.core5.net.URIAuthority;
55 import org.apache.hc.core5.util.Args;
56 import org.apache.hc.core5.util.TextUtils;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60
61
62
63
64
65
66
67 @Contract(threading = ThreadingBehavior.STATELESS)
68 public class RequestAddCookies implements HttpRequestInterceptor {
69
70
71
72
73
74
75 public static final RequestAddCookies INSTANCE = new RequestAddCookies();
76
77 private static final Logger LOG = LoggerFactory.getLogger(RequestAddCookies.class);
78
79 public RequestAddCookies() {
80 super();
81 }
82
83 @Override
84 public void process(final HttpRequest request, final EntityDetails entity, final HttpContext context)
85 throws HttpException, IOException {
86 Args.notNull(request, "HTTP request");
87 Args.notNull(context, "HTTP context");
88
89 final String method = request.getMethod();
90 if (Method.CONNECT.isSame(method) || Method.TRACE.isSame(method)) {
91 return;
92 }
93
94
95 if (request.containsHeader(HttpHeaders.COOKIE)) {
96 if (LOG.isDebugEnabled()) {
97 LOG.debug("Skipping cookie addition, Cookie header already present in the request");
98 }
99
100 return;
101 }
102
103
104 final HttpClientContext clientContext = HttpClientContext.cast(context);
105 final String exchangeId = clientContext.getExchangeId();
106
107
108 final CookieStore cookieStore = clientContext.getCookieStore();
109 if (cookieStore == null) {
110 if (LOG.isDebugEnabled()) {
111 LOG.debug("{} Cookie store not specified in HTTP context", exchangeId);
112 }
113 return;
114 }
115
116
117 final Lookup<CookieSpecFactory> registry = clientContext.getCookieSpecRegistry();
118 if (registry == null) {
119 if (LOG.isDebugEnabled()) {
120 LOG.debug("{} CookieSpec registry not specified in HTTP context", exchangeId);
121 }
122 return;
123 }
124
125
126 final RouteInfo route = clientContext.getHttpRoute();
127 if (route == null) {
128 if (LOG.isDebugEnabled()) {
129 LOG.debug("{} Connection route not set in the context", exchangeId);
130 }
131 return;
132 }
133
134 final RequestConfig config = clientContext.getRequestConfigOrDefault();
135 String cookieSpecName = config.getCookieSpec();
136 if (cookieSpecName == null) {
137 cookieSpecName = StandardCookieSpec.STRICT;
138 }
139 if (LOG.isDebugEnabled()) {
140 LOG.debug("{} Cookie spec selected: {}", exchangeId, cookieSpecName);
141 }
142
143 final URIAuthority authority = request.getAuthority();
144 String path = request.getPath();
145 if (TextUtils.isEmpty(path)) {
146 path = "/";
147 }
148 String hostName = authority != null ? authority.getHostName() : null;
149 if (hostName == null) {
150 hostName = route.getTargetHost().getHostName();
151 }
152 int port = authority != null ? authority.getPort() : -1;
153 if (port < 0) {
154 port = route.getTargetHost().getPort();
155 }
156 final CookieOrigin cookieOrigin = new CookieOrigin(hostName, port, path, route.isSecure());
157
158
159 final CookieSpecFactory factory = registry.lookup(cookieSpecName);
160 if (factory == null) {
161 if (LOG.isDebugEnabled()) {
162 LOG.debug("{} Unsupported cookie spec: {}", exchangeId, cookieSpecName);
163 }
164 return;
165 }
166 final CookieSpec cookieSpec = factory.create(clientContext);
167
168 final List<Cookie> cookies = cookieStore.getCookies();
169
170 final List<Cookie> matchedCookies = new ArrayList<>();
171 final Instant now = Instant.now();
172 boolean expired = false;
173 for (final Cookie cookie : cookies) {
174 if (!cookie.isExpired(now)) {
175 if (cookieSpec.match(cookie, cookieOrigin)) {
176 if (LOG.isDebugEnabled()) {
177 LOG.debug("{} Cookie {} match {}", exchangeId, cookie, cookieOrigin);
178 }
179 matchedCookies.add(cookie);
180 }
181 } else {
182 if (LOG.isDebugEnabled()) {
183 LOG.debug("{} Cookie {} expired", exchangeId, cookie);
184 }
185 expired = true;
186 }
187 }
188
189
190
191 if (expired) {
192 cookieStore.clearExpired(now);
193 }
194
195 if (!matchedCookies.isEmpty()) {
196 final List<Header> headers = cookieSpec.formatCookies(matchedCookies);
197 for (final Header header : headers) {
198 request.addHeader(header);
199 }
200 }
201
202
203
204 clientContext.setCookieSpec(cookieSpec);
205 clientContext.setCookieOrigin(cookieOrigin);
206 }
207
208 }