View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.client5.http.protocol;
29  
30  import java.util.HashMap;
31  import java.util.Map;
32  
33  import javax.net.ssl.SSLSession;
34  
35  import org.apache.hc.client5.http.HttpRoute;
36  import org.apache.hc.client5.http.RouteInfo;
37  import org.apache.hc.client5.http.auth.AuthCache;
38  import org.apache.hc.client5.http.auth.AuthExchange;
39  import org.apache.hc.client5.http.auth.AuthScheme;
40  import org.apache.hc.client5.http.auth.AuthSchemeFactory;
41  import org.apache.hc.client5.http.auth.CredentialsProvider;
42  import org.apache.hc.client5.http.config.RequestConfig;
43  import org.apache.hc.client5.http.cookie.CookieOrigin;
44  import org.apache.hc.client5.http.cookie.CookieSpec;
45  import org.apache.hc.client5.http.cookie.CookieSpecFactory;
46  import org.apache.hc.client5.http.cookie.CookieStore;
47  import org.apache.hc.core5.annotation.Internal;
48  import org.apache.hc.core5.http.EndpointDetails;
49  import org.apache.hc.core5.http.HttpHost;
50  import org.apache.hc.core5.http.HttpRequest;
51  import org.apache.hc.core5.http.HttpResponse;
52  import org.apache.hc.core5.http.ProtocolVersion;
53  import org.apache.hc.core5.http.config.Lookup;
54  import org.apache.hc.core5.http.protocol.HttpContext;
55  import org.apache.hc.core5.http.protocol.HttpCoreContext;
56  
57  /**
58   * Client execution {@link HttpContext}. This class can be re-used for
59   * multiple consecutive logically related request executions that represent
60   * a single communication session. This context may not be used concurrently.
61   * <p>
62   * IMPORTANT: This class is NOT thread-safe and MUST NOT be used concurrently by
63   * multiple message exchanges.
64   *
65   * @since 4.3
66   */
67  public class HttpClientContext extends HttpCoreContext {
68  
69      /**
70       * @deprecated Use getter methods
71       */
72      @Deprecated
73      public static final String HTTP_ROUTE = "http.route";
74  
75      /**
76       * @deprecated Use getter methods
77       */
78      @Deprecated
79      public static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";
80  
81      /**
82       * @deprecated Use getter methods
83       */
84      @Deprecated
85      public static final String COOKIESPEC_REGISTRY = "http.cookiespec-registry";
86  
87      /**
88       * @deprecated Use getter methods
89       */
90      @Deprecated
91      public static final String COOKIE_SPEC = "http.cookie-spec";
92  
93      /**
94       * @deprecated Use getter methods
95       */
96      @Deprecated
97      public static final String COOKIE_ORIGIN = "http.cookie-origin";
98  
99      /**
100      * @deprecated Use getter methods
101      */
102     @Deprecated
103     public static final String COOKIE_STORE = "http.cookie-store";
104 
105     /**
106      * @deprecated Use getter methods
107      */
108     @Deprecated
109     public static final String CREDS_PROVIDER = "http.auth.credentials-provider";
110 
111     /**
112      * @deprecated Use getter methods
113      */
114     @Deprecated
115     public static final String AUTH_CACHE = "http.auth.auth-cache";
116 
117     /**
118      * @deprecated Use getter methods
119      */
120     @Deprecated
121     public static final String AUTH_EXCHANGE_MAP = "http.auth.exchanges";
122 
123     /**
124      * @deprecated Use getter methods
125      */
126     @Deprecated
127     public static final String USER_TOKEN = "http.user-token";
128 
129     /**
130      * @deprecated Use getter methods
131      */
132     @Deprecated
133     public static final String AUTHSCHEME_REGISTRY = "http.authscheme-registry";
134 
135     /**
136      * @deprecated Use getter methods
137      */
138     @Deprecated
139     public static final String REQUEST_CONFIG = "http.request-config";
140 
141     /**
142      * @deprecated Use getter methods
143      */
144     @Deprecated
145     public static final String EXCHANGE_ID = "http.exchange-id";
146 
147     /**
148      * @deprecated Use {@link #castOrCreate(HttpContext)}.
149      */
150     @Deprecated
151     public static HttpClientContext adapt(final HttpContext context) {
152         if (context == null) {
153             return new HttpClientContext();
154         }
155         if (context instanceof HttpClientContext) {
156             return (HttpClientContext) context;
157         }
158         return new HttpClientContext(context);
159     }
160 
161     /**
162      * Casts the given generic {@link HttpContext} as {@link HttpClientContext}.
163      *
164      * @since 5.4
165      */
166     public static HttpClientContext cast(final HttpContext context) {
167         if (context == null) {
168             return null;
169         }
170         if (context instanceof HttpClientContext) {
171             return (HttpClientContext) context;
172         }
173         return new Delegate(context);
174     }
175 
176     /**
177      * Casts the given generic {@link HttpContext} as {@link HttpClientContext} or
178      * creates new {@link HttpClientContext} if the given context is null.
179      *
180      * @since 5.4
181      */
182     public static HttpClientContext castOrCreate(final HttpContext context) {
183         return context != null ? cast(context) : create();
184     }
185 
186     public static HttpClientContext create() {
187         return new HttpClientContext();
188     }
189 
190     private HttpRoute route;
191     private RedirectLocations redirectLocations;
192     private CookieSpec cookieSpec;
193     private CookieOrigin cookieOrigin;
194     private Map<HttpHost, AuthExchange> authExchangeMap;
195     private String exchangeId;
196 
197     private Lookup<CookieSpecFactory> cookieSpecFactoryLookup;
198     private Lookup<AuthSchemeFactory> authSchemeFactoryLookup;
199     private CookieStore cookieStore;
200     private CredentialsProvider credentialsProvider;
201     private AuthCache authCache;
202     private Object userToken;
203     private RequestConfig requestConfig;
204 
205     /**
206      * Stores the {@code nextnonce} value provided by the server in an HTTP response.
207      * <p>
208      * In the context of HTTP Digest Access Authentication, the {@code nextnonce} parameter
209      * is used by the client in subsequent requests to ensure one-time or session-bound usage
210      * of nonce values, enhancing security by preventing replay attacks.
211      * </p>
212      * <p>
213      * This field is set by an interceptor or other component that processes the server's
214      * response containing the {@code Authentication-Info} header. Once used, this value
215      * may be cleared from the context to avoid reuse.
216      * </p>
217      *
218      * @since 5.5
219      */
220     private String nextNonce;
221 
222     public HttpClientContext(final HttpContext context) {
223         super(context);
224     }
225 
226     public HttpClientContext() {
227         super();
228     }
229 
230     /**
231      * Represents current route used to execute message exchanges.
232      * <p>
233      * This context attribute is expected to be populated by the protocol handler.
234      */
235     public RouteInfo getHttpRoute() {
236         return route;
237     }
238 
239     /**
240      * @since 5.4
241      */
242     @Internal
243     public void setRoute(final HttpRoute route) {
244         this.route = route;
245     }
246 
247     /**
248      * Represents a collection of all redirects executed in the context of request execution.
249      * <p>
250      * This context attribute is expected to be populated by the protocol handler.
251      */
252     public RedirectLocations getRedirectLocations() {
253         if (this.redirectLocations == null) {
254             this.redirectLocations = new RedirectLocations();
255         }
256         return this.redirectLocations;
257     }
258 
259     /**
260      * @since 5.4
261      */
262     @Internal
263     public void setRedirectLocations(final RedirectLocations redirectLocations) {
264         this.redirectLocations = redirectLocations;
265     }
266 
267     /**
268      * Represents a {@link CookieStore} used in the context of the request execution.
269      * <p>
270      * This context attribute can be set by the caller.
271      */
272     public CookieStore getCookieStore() {
273         return cookieStore;
274     }
275 
276     public void setCookieStore(final CookieStore cookieStore) {
277         this.cookieStore = cookieStore;
278     }
279 
280     /**
281      * Represents a {@link CookieSpec} chosen in the context of request execution.
282      * <p>
283      * This context attribute is expected to be populated by the protocol handler.
284      */
285     public CookieSpec getCookieSpec() {
286         return cookieSpec;
287     }
288 
289     /**
290      * @since 5.4
291      */
292     @Internal
293     public void setCookieSpec(final CookieSpec cookieSpec) {
294         this.cookieSpec = cookieSpec;
295     }
296 
297     /**
298      * Represents a {@link CookieOrigin} produced in the context of request execution.
299      * <p>
300      * This context attribute is expected to be populated by the protocol handler.
301      */
302     public CookieOrigin getCookieOrigin() {
303         return cookieOrigin;
304     }
305 
306     /**
307      * @since 5.4
308      */
309     @Internal
310     public void setCookieOrigin(final CookieOrigin cookieOrigin) {
311         this.cookieOrigin = cookieOrigin;
312     }
313 
314     /**
315      * Represents a {@link CookieSpecFactory} registry used in the context of the request execution.
316      * <p>
317      * This context attribute can be set by the caller.
318      */
319     public Lookup<CookieSpecFactory> getCookieSpecRegistry() {
320         return cookieSpecFactoryLookup;
321     }
322 
323     public void setCookieSpecRegistry(final Lookup<CookieSpecFactory> lookup) {
324         this.cookieSpecFactoryLookup = lookup;
325     }
326 
327     /**
328      * Represents a {@link AuthSchemeFactory} registry used in the context of the request execution.
329      * <p>
330      * This context attribute can be set by the caller.
331      */
332     public Lookup<AuthSchemeFactory> getAuthSchemeRegistry() {
333         return authSchemeFactoryLookup;
334     }
335 
336     public void setAuthSchemeRegistry(final Lookup<AuthSchemeFactory> lookup) {
337         this.authSchemeFactoryLookup = lookup;
338     }
339 
340     /**
341      * Represents a {@link CredentialsProvider} registry used in the context of the request execution.
342      * <p>
343      * This context attribute can be set by the caller.
344      */
345     public CredentialsProvider getCredentialsProvider() {
346         return credentialsProvider;
347     }
348 
349     public void setCredentialsProvider(final CredentialsProvider credentialsProvider) {
350         this.credentialsProvider = credentialsProvider;
351     }
352 
353     /**
354      * Represents a {@link AuthCache} used in the context of the request execution.
355      * <p>
356      * This context attribute can be set by the caller.
357      */
358     public AuthCache getAuthCache() {
359         return authCache;
360     }
361 
362     public void setAuthCache(final AuthCache authCache) {
363         this.authCache = authCache;
364     }
365 
366     /**
367      * Represents a map of {@link AuthExchange}s performed in the context of the request
368      * execution.
369      * <p>
370      * This context attribute is expected to be populated by the protocol handler.
371      *
372      * @since 5.0
373      */
374     public Map<HttpHost, AuthExchange> getAuthExchanges() {
375         if (authExchangeMap == null) {
376             authExchangeMap = new HashMap<>();
377         }
378         return authExchangeMap;
379     }
380 
381     /**
382      * @since 5.0
383      */
384     public AuthExchange getAuthExchange(final HttpHost host) {
385         return getAuthExchanges().computeIfAbsent(host, k -> new AuthExchange());
386     }
387 
388     /**
389      * @since 5.0
390      */
391     public void setAuthExchange(final HttpHost host, final AuthExchange authExchange) {
392         getAuthExchanges().put(host, authExchange);
393     }
394 
395     /**
396      * @since 5.0
397      */
398     public void resetAuthExchange(final HttpHost host, final AuthScheme authScheme) {
399         final AuthExchange authExchange = new AuthExchange();
400         authExchange.select(authScheme);
401         getAuthExchanges().put(host, authExchange);
402     }
403 
404     /**
405      * @deprecated Use {@link #getUserToken()}
406      */
407     @Deprecated
408     @SuppressWarnings("unchecked")
409     public <T> T getUserToken(final Class<T> clazz) {
410         return (T) getUserToken();
411     }
412 
413     /**
414      * Represents an arbitrary user token that identifies the user in the context
415      * of the request execution.
416      * <p>
417      * This context attribute can be set by the caller.
418      */
419     public Object getUserToken() {
420         return userToken;
421     }
422 
423     public void setUserToken(final Object userToken) {
424         this.userToken = userToken;
425     }
426 
427     /**
428      * Represents an {@link RequestConfig used} in the context of the request execution.
429      * <p>
430      * This context attribute can be set by the caller.
431      */
432     public RequestConfig getRequestConfig() {
433         return requestConfig;
434     }
435 
436     /**
437      * Returns {@link RequestConfig} set in the context or {@link RequestConfig#DEFAULT}
438      * if not explicitly set in the context.
439      *
440      * @since 5.4
441      */
442     public final RequestConfig getRequestConfigOrDefault() {
443         final RequestConfig requestConfig = getRequestConfig();
444         return requestConfig != null ? requestConfig : RequestConfig.DEFAULT;
445     }
446 
447     public void setRequestConfig(final RequestConfig requestConfig) {
448         this.requestConfig = requestConfig;
449     }
450 
451     /**
452      * Represents an identifier generated for the current message exchange executed
453      * in the given context.
454      * <p>
455      * This context attribute is expected to be populated by the protocol handler.
456      * @since 5.1
457      */
458     public String getExchangeId() {
459         return exchangeId;
460     }
461 
462     /**
463      * @since 5.1
464      */
465     public void setExchangeId(final String exchangeId) {
466         this.exchangeId = exchangeId;
467     }
468 
469     /**
470      * Retrieves the stored {@code nextnonce} value.
471      *
472      * @return the {@code nextnonce} parameter value, or {@code null} if not set
473      * @since 5.5
474      */
475     @Internal
476     public String getNextNonce() {
477         return nextNonce;
478     }
479 
480     /**
481      * Sets the {@code nextnonce} value directly as an instance attribute.
482      *
483      * @param nextNonce the nonce value to set
484      * @since 5.5
485      */
486     @Internal
487     public void setNextNonce(final String nextNonce) {
488         this.nextNonce = nextNonce;
489     }
490 
491     /**
492      * Internal adaptor class that delegates all its method calls to a plain {@link HttpContext}.
493      * To be removed in the future.
494      */
495     @SuppressWarnings("deprecation")
496     @Internal
497     static class Delegate extends HttpClientContext {
498 
499         private final HttpContext httpContext;
500 
501         Delegate(final HttpContext httpContext) {
502             super(null);
503             this.httpContext = httpContext;
504         }
505 
506         <T> T getAttr(final String id, final Class<T> clazz) {
507             final Object obj = httpContext.getAttribute(id);
508             if (obj == null) {
509                 return null;
510             }
511             return clazz.cast(obj);
512         }
513 
514         @Override
515         public RouteInfo getHttpRoute() {
516             return getAttr(HTTP_ROUTE, RouteInfo.class);
517         }
518 
519         @Override
520         public void setRoute(final HttpRoute route) {
521             httpContext.setAttribute(HTTP_ROUTE, route);
522         }
523 
524         @Override
525         public RedirectLocations getRedirectLocations() {
526             RedirectLocations redirectLocations = getAttr(REDIRECT_LOCATIONS, RedirectLocations.class);
527             if (redirectLocations == null) {
528                 redirectLocations = new RedirectLocations();
529                 httpContext.setAttribute(REDIRECT_LOCATIONS, redirectLocations);
530             }
531             return redirectLocations;
532         }
533 
534         @Override
535         public void setRedirectLocations(final RedirectLocations redirectLocations) {
536             httpContext.setAttribute(REDIRECT_LOCATIONS, redirectLocations);
537         }
538 
539         @Override
540         public CookieStore getCookieStore() {
541             return getAttr(COOKIE_STORE, CookieStore.class);
542         }
543 
544         @Override
545         public void setCookieStore(final CookieStore cookieStore) {
546             httpContext.setAttribute(COOKIE_STORE, cookieStore);
547         }
548 
549         @Override
550         public CookieSpec getCookieSpec() {
551             return getAttr(COOKIE_SPEC, CookieSpec.class);
552         }
553 
554         @Override
555         public void setCookieSpec(final CookieSpec cookieSpec) {
556             httpContext.setAttribute(COOKIE_SPEC, cookieSpec);
557         }
558 
559         @Override
560         public CookieOrigin getCookieOrigin() {
561             return getAttr(COOKIE_ORIGIN, CookieOrigin.class);
562         }
563 
564         @Override
565         public void setCookieOrigin(final CookieOrigin cookieOrigin) {
566             httpContext.setAttribute(COOKIE_ORIGIN, cookieOrigin);
567         }
568 
569         @Override
570         public Lookup<CookieSpecFactory> getCookieSpecRegistry() {
571             return getAttr(COOKIESPEC_REGISTRY, Lookup.class);
572         }
573 
574         @Override
575         public void setCookieSpecRegistry(final Lookup<CookieSpecFactory> lookup) {
576             httpContext.setAttribute(COOKIESPEC_REGISTRY, lookup);
577         }
578 
579         @Override
580         public Lookup<AuthSchemeFactory> getAuthSchemeRegistry() {
581             return getAttr(AUTHSCHEME_REGISTRY, Lookup.class);
582         }
583 
584         @Override
585         public void setAuthSchemeRegistry(final Lookup<AuthSchemeFactory> lookup) {
586             httpContext.setAttribute(AUTHSCHEME_REGISTRY, lookup);
587         }
588 
589         @Override
590         public CredentialsProvider getCredentialsProvider() {
591             return getAttr(CREDS_PROVIDER, CredentialsProvider.class);
592         }
593 
594         @Override
595         public void setCredentialsProvider(final CredentialsProvider credentialsProvider) {
596             httpContext.setAttribute(CREDS_PROVIDER, credentialsProvider);
597         }
598 
599         @Override
600         public AuthCache getAuthCache() {
601             return getAttr(AUTH_CACHE, AuthCache.class);
602         }
603 
604         @Override
605         public void setAuthCache(final AuthCache authCache) {
606             httpContext.setAttribute(AUTH_CACHE, authCache);
607         }
608 
609         @Override
610         public Map<HttpHost, AuthExchange> getAuthExchanges() {
611             Map<HttpHost, AuthExchange> map = getAttr(AUTH_EXCHANGE_MAP, Map.class);
612             if (map == null) {
613                 map = new HashMap<>();
614                 httpContext.setAttribute(AUTH_EXCHANGE_MAP, map);
615             }
616             return map;
617         }
618 
619         @Override
620         public Object getUserToken() {
621             return httpContext.getAttribute(USER_TOKEN);
622         }
623 
624         @Override
625         public void setUserToken(final Object userToken) {
626             httpContext.setAttribute(USER_TOKEN, userToken);
627         }
628 
629         @Override
630         public RequestConfig getRequestConfig() {
631             return getAttr(REQUEST_CONFIG, RequestConfig.class);
632         }
633 
634         @Override
635         public void setRequestConfig(final RequestConfig requestConfig) {
636             httpContext.setAttribute(REQUEST_CONFIG, requestConfig);
637         }
638 
639         @Override
640         public String getExchangeId() {
641             return getAttr(EXCHANGE_ID, String.class);
642         }
643 
644         @Override
645         public void setExchangeId(final String exchangeId) {
646             httpContext.setAttribute(EXCHANGE_ID, exchangeId);
647         }
648 
649         @Override
650         public HttpRequest getRequest() {
651             return getAttr(HttpCoreContext.HTTP_REQUEST, HttpRequest.class);
652         }
653 
654         @Override
655         public void setRequest(final HttpRequest request) {
656             httpContext.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
657         }
658 
659         @Override
660         public HttpResponse getResponse() {
661             return getAttr(HttpCoreContext.HTTP_RESPONSE, HttpResponse.class);
662         }
663 
664         @Override
665         public void setResponse(final HttpResponse response) {
666             httpContext.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
667         }
668 
669         @Override
670         public EndpointDetails getEndpointDetails() {
671             return getAttr(HttpCoreContext.CONNECTION_ENDPOINT, EndpointDetails.class);
672         }
673 
674         @Override
675         public void setEndpointDetails(final EndpointDetails endpointDetails) {
676             httpContext.setAttribute(CONNECTION_ENDPOINT, endpointDetails);
677         }
678 
679         @Override
680         public SSLSession getSSLSession() {
681             return getAttr(HttpCoreContext.SSL_SESSION, SSLSession.class);
682         }
683 
684         @Override
685         public void setSSLSession(final SSLSession sslSession) {
686             httpContext.setAttribute(HttpCoreContext.SSL_SESSION, sslSession);
687         }
688 
689         @Override
690         public ProtocolVersion getProtocolVersion() {
691             return httpContext.getProtocolVersion();
692         }
693 
694         @Override
695         public void setProtocolVersion(final ProtocolVersion version) {
696             httpContext.setProtocolVersion(version);
697         }
698 
699         @Override
700         public Object getAttribute(final String id) {
701             return httpContext.getAttribute(id);
702         }
703 
704         @Override
705         public Object setAttribute(final String id, final Object obj) {
706             return httpContext.setAttribute(id, obj);
707         }
708 
709         @Override
710         public Object removeAttribute(final String id) {
711             return httpContext.removeAttribute(id);
712         }
713 
714         @Override
715         public <T> T getAttribute(final String id, final Class<T> clazz) {
716             return getAttr(id, clazz);
717         }
718 
719         @Override
720         public String toString() {
721             return httpContext.toString();
722         }
723 
724     }
725 
726 }