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 final Header cookieHeader = request.getHeader(HttpHeaders.COOKIE);
95
96 if (cookieHeader != null) {
97 if (LOG.isDebugEnabled()) {
98 LOG.debug("Skipping cookie addition, Cookie header already present in the request");
99 }
100
101 return;
102 }
103
104
105 final HttpClientContext clientContext = HttpClientContext.cast(context);
106 final String exchangeId = clientContext.getExchangeId();
107
108
109 final CookieStore cookieStore = clientContext.getCookieStore();
110 if (cookieStore == null) {
111 if (LOG.isDebugEnabled()) {
112 LOG.debug("{} Cookie store not specified in HTTP context", exchangeId);
113 }
114 return;
115 }
116
117
118 final Lookup<CookieSpecFactory> registry = clientContext.getCookieSpecRegistry();
119 if (registry == null) {
120 if (LOG.isDebugEnabled()) {
121 LOG.debug("{} CookieSpec registry not specified in HTTP context", exchangeId);
122 }
123 return;
124 }
125
126
127 final RouteInfo route = clientContext.getHttpRoute();
128 if (route == null) {
129 if (LOG.isDebugEnabled()) {
130 LOG.debug("{} Connection route not set in the context", exchangeId);
131 }
132 return;
133 }
134
135 final RequestConfig config = clientContext.getRequestConfigOrDefault();
136 String cookieSpecName = config.getCookieSpec();
137 if (cookieSpecName == null) {
138 cookieSpecName = StandardCookieSpec.STRICT;
139 }
140 if (LOG.isDebugEnabled()) {
141 LOG.debug("{} Cookie spec selected: {}", exchangeId, cookieSpecName);
142 }
143
144 final URIAuthority authority = request.getAuthority();
145 String path = request.getPath();
146 if (TextUtils.isEmpty(path)) {
147 path = "/";
148 }
149 String hostName = authority != null ? authority.getHostName() : null;
150 if (hostName == null) {
151 hostName = route.getTargetHost().getHostName();
152 }
153 int port = authority != null ? authority.getPort() : -1;
154 if (port < 0) {
155 port = route.getTargetHost().getPort();
156 }
157 final CookieOrigin cookieOrigin = new CookieOrigin(hostName, port, path, route.isSecure());
158
159
160 final CookieSpecFactory factory = registry.lookup(cookieSpecName);
161 if (factory == null) {
162 if (LOG.isDebugEnabled()) {
163 LOG.debug("{} Unsupported cookie spec: {}", exchangeId, cookieSpecName);
164 }
165 return;
166 }
167 final CookieSpec cookieSpec = factory.create(clientContext);
168
169 final List<Cookie> cookies = cookieStore.getCookies();
170
171 final List<Cookie> matchedCookies = new ArrayList<>();
172 final Instant now = Instant.now();
173 boolean expired = false;
174 for (final Cookie cookie : cookies) {
175 if (!cookie.isExpired(now)) {
176 if (cookieSpec.match(cookie, cookieOrigin)) {
177 if (LOG.isDebugEnabled()) {
178 LOG.debug("{} Cookie {} match {}", exchangeId, cookie, cookieOrigin);
179 }
180 matchedCookies.add(cookie);
181 }
182 } else {
183 if (LOG.isDebugEnabled()) {
184 LOG.debug("{} Cookie {} expired", exchangeId, cookie);
185 }
186 expired = true;
187 }
188 }
189
190
191
192 if (expired) {
193 cookieStore.clearExpired(now);
194 }
195
196 if (!matchedCookies.isEmpty()) {
197 final List<Header> headers = cookieSpec.formatCookies(matchedCookies);
198 for (final Header header : headers) {
199 request.addHeader(header);
200 }
201 }
202
203
204
205 clientContext.setCookieSpec(cookieSpec);
206 clientContext.setCookieOrigin(cookieOrigin);
207 }
208
209 }