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