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  package org.apache.hc.client5.http.fluent;
28  
29  import java.io.IOException;
30  import java.net.URISyntaxException;
31  
32  import org.apache.hc.client5.http.auth.AuthCache;
33  import org.apache.hc.client5.http.auth.AuthScope;
34  import org.apache.hc.client5.http.auth.Credentials;
35  import org.apache.hc.client5.http.auth.CredentialsStore;
36  import org.apache.hc.client5.http.auth.NTCredentials;
37  import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
38  import org.apache.hc.client5.http.cookie.CookieStore;
39  import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
40  import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
41  import org.apache.hc.client5.http.impl.auth.BasicScheme;
42  import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
43  import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
44  import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
45  import org.apache.hc.client5.http.protocol.HttpClientContext;
46  import org.apache.hc.core5.http.HttpHost;
47  import org.apache.hc.core5.util.TimeValue;
48  
49  /**
50   * Executor for {@link Request}s.
51   * <p>
52   * A connection pool with maximum 100 connections per route and
53   * a total maximum of 200 connections is used internally.
54   *
55   * @since 4.2
56   */
57  public class Executor {
58  
59      final static CloseableHttpClient CLIENT;
60  
61      static {
62          CLIENT = HttpClientBuilder.create()
63                  .setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create()
64                          .useSystemProperties()
65                          .setMaxConnPerRoute(100)
66                          .setMaxConnTotal(200)
67                          .setValidateAfterInactivity(TimeValue.ofSeconds(10))
68                          .build())
69                  .useSystemProperties()
70                  .evictExpiredConnections()
71                  .evictIdleConnections(TimeValue.ofMinutes(1))
72                  .build();
73      }
74  
75      public static Executor newInstance() {
76          return new Executor(CLIENT);
77      }
78  
79      public static Executor newInstance(final CloseableHttpClient httpclient) {
80          return new Executor(httpclient != null ? httpclient : CLIENT);
81      }
82  
83      private final CloseableHttpClient httpclient;
84      private final AuthCache authCache;
85      private volatile CredentialsStore credentialsStore;
86      private volatile CookieStore cookieStore;
87  
88      Executor(final CloseableHttpClient httpclient) {
89          super();
90          this.httpclient = httpclient;
91          this.authCache = new BasicAuthCache();
92      }
93  
94      /**
95       * @since 4.5
96       */
97      public Executor use(final CredentialsStore credentialsStore) {
98          this.credentialsStore = credentialsStore;
99          return this;
100     }
101 
102     public Executor auth(final AuthScope authScope, final Credentials credentials) {
103         if (this.credentialsStore == null) {
104             this.credentialsStore = new BasicCredentialsProvider();
105         }
106         this.credentialsStore.setCredentials(authScope, credentials);
107         return this;
108     }
109 
110     public Executor auth(final HttpHost host, final Credentials credentials) {
111         return auth(new AuthScope(host), credentials);
112     }
113 
114     /**
115      * @since 4.4
116      */
117     public Executor auth(final String host, final Credentials credentials) {
118         final HttpHost httpHost;
119         try {
120             httpHost = HttpHost.create(host);
121         } catch (final URISyntaxException ex) {
122             throw new IllegalArgumentException("Invalid host: " + host);
123         }
124         return auth(httpHost, credentials);
125     }
126 
127     public Executor authPreemptive(final HttpHost host) {
128         if (this.credentialsStore != null) {
129             final Credentials credentials = this.credentialsStore.getCredentials(new AuthScope(host), null);
130             if (credentials == null) {
131                 final BasicSchemeauth/BasicScheme.html#BasicScheme">BasicScheme basicScheme = new BasicScheme();
132                 basicScheme.initPreemptive(credentials);
133                 this.authCache.put(host, basicScheme);
134             }
135         }
136         return this;
137     }
138 
139     /**
140      * @since 4.4
141      */
142     public Executor authPreemptive(final String host) {
143         final HttpHost httpHost;
144         try {
145             httpHost = HttpHost.create(host);
146         } catch (final URISyntaxException ex) {
147             throw new IllegalArgumentException("Invalid host: " + host);
148         }
149         return authPreemptive(httpHost);
150     }
151 
152     public Executor authPreemptiveProxy(final HttpHost proxy) {
153         if (this.credentialsStore != null) {
154             final Credentials credentials = this.credentialsStore.getCredentials(new AuthScope(proxy), null);
155             if (credentials == null) {
156                 final BasicSchemeauth/BasicScheme.html#BasicScheme">BasicScheme basicScheme = new BasicScheme();
157                 basicScheme.initPreemptive(credentials);
158                 this.authCache.put(proxy, basicScheme);
159             }
160         }
161         return this;
162     }
163 
164     /**
165      * @since 4.4
166      */
167     public Executor authPreemptiveProxy(final String proxy) {
168         final HttpHost httpHost;
169         try {
170             httpHost = HttpHost.create(proxy);
171         } catch (final URISyntaxException ex) {
172             throw new IllegalArgumentException("Invalid host: " + proxy);
173         }
174         return authPreemptiveProxy(httpHost);
175     }
176 
177     public Executor auth(final HttpHost host,
178             final String username, final char[] password) {
179         return auth(host, new UsernamePasswordCredentials(username, password));
180     }
181 
182     public Executor auth(final HttpHost host,
183             final String username, final char[] password,
184             final String workstation, final String domain) {
185         return auth(host, new NTCredentials(username, password, workstation, domain));
186     }
187 
188     public Executor clearAuth() {
189         if (this.credentialsStore != null) {
190             this.credentialsStore.clear();
191         }
192         return this;
193     }
194 
195     /**
196      * @since 4.5
197      */
198     public Executor use(final CookieStore cookieStore) {
199         this.cookieStore = cookieStore;
200         return this;
201     }
202 
203     public Executor clearCookies() {
204         if (this.cookieStore != null) {
205             this.cookieStore.clear();
206         }
207         return this;
208     }
209 
210     /**
211      * Executes the request. Please Note that response content must be processed
212      * or discarded using {@link Response#discardContent()}, otherwise the
213      * connection used for the request might not be released to the pool.
214      *
215      * @see Response#handleResponse(org.apache.hc.core5.http.io.HttpClientResponseHandler)
216      * @see Response#discardContent()
217      */
218     public Response execute(
219             final Request request) throws IOException {
220         final HttpClientContext localContext = HttpClientContext.create();
221         if (this.credentialsStore != null) {
222             localContext.setAttribute(HttpClientContext.CREDS_PROVIDER, this.credentialsStore);
223         }
224         if (this.authCache != null) {
225             localContext.setAttribute(HttpClientContext.AUTH_CACHE, this.authCache);
226         }
227         if (this.cookieStore != null) {
228             localContext.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
229         }
230         return new Response(request.internalExecute(this.httpclient, localContext));
231     }
232 
233 }