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.core5.http;
29  
30  import java.io.Serializable;
31  import java.net.InetAddress;
32  import java.net.URI;
33  import java.net.URISyntaxException;
34  import java.util.Objects;
35  
36  import org.apache.hc.core5.annotation.Contract;
37  import org.apache.hc.core5.annotation.ThreadingBehavior;
38  import org.apache.hc.core5.net.Host;
39  import org.apache.hc.core5.net.NamedEndpoint;
40  import org.apache.hc.core5.net.URIAuthority;
41  import org.apache.hc.core5.util.Args;
42  import org.apache.hc.core5.util.LangUtils;
43  import org.apache.hc.core5.util.TextUtils;
44  
45  /**
46   * Component that holds all details needed to describe an HTTP connection
47   * to a host. This includes remote host name, port and protocol scheme.
48   *
49   * @see org.apache.hc.core5.net.Host
50   *
51   * @since 4.0
52   * @since 5.0 For constructors that take a scheme as an argument, that argument is now the first one.
53   */
54  @Contract(threading = ThreadingBehavior.IMMUTABLE)
55  public final class HttpHost implements NamedEndpoint, Serializable {
56  
57      private static final long serialVersionUID = -7529410654042457626L;
58  
59      /** The default scheme is "http". */
60      public static final URIScheme DEFAULT_SCHEME = URIScheme.HTTP;
61  
62      private final String schemeName;
63      private final Host host;
64      private final InetAddress address;
65  
66      /**
67       * Creates a new {@link HttpHost HttpHost}, specifying all values.
68       * Constructor for HttpHost.
69       * @param scheme    the name of the scheme.
70       *                  {@code null} indicates the
71       *                  {@link #DEFAULT_SCHEME default scheme}
72       * @param address   the inet address. Can be {@code null}
73       * @param hostname   the hostname (IP or DNS name)
74       * @param port      the port number.
75       *                  {@code -1} indicates the scheme default port.
76       *
77       * @throws IllegalArgumentException
78       *             If the port parameter is outside the specified range of valid port values, which is between 0 and
79       *             65535, inclusive. {@code -1} indicates the scheme default port.
80       *
81       * @since 5.0
82       */
83      public HttpHost(final String scheme, final InetAddress address, final String hostname, final int port) {
84          Args.containsNoBlanks(hostname, "Host name");
85          this.host = new Host(hostname, port);
86          this.schemeName = scheme != null ? TextUtils.toLowerCase(scheme) : DEFAULT_SCHEME.id;
87          this.address = address;
88      }
89  
90      /**
91       * Creates {@code HttpHost} instance with the given scheme, hostname and port.
92       * @param scheme    the name of the scheme.
93       *                  {@code null} indicates the
94       *                  {@link #DEFAULT_SCHEME default scheme}
95       * @param hostname  the hostname (IP or DNS name)
96       * @param port      the port number.
97       *                  {@code -1} indicates the scheme default port.
98       *
99       * @throws IllegalArgumentException
100      *             If the port parameter is outside the specified range of valid port values, which is between 0 and
101      *             65535, inclusive. {@code -1} indicates the scheme default port.
102      */
103     public HttpHost(final String scheme, final String hostname, final int port) {
104         this(scheme, null, hostname, port);
105     }
106 
107     /**
108      * Creates {@code HttpHost} instance with the default scheme and the given hostname and port.
109      *
110      * @param hostname  the hostname (IP or DNS name)
111      * @param port      the port number.
112      *                  {@code -1} indicates the scheme default port.
113      *
114      * @throws IllegalArgumentException
115      *             If the port parameter is outside the specified range of valid port values, which is between 0 and
116      *             65535, inclusive. {@code -1} indicates the scheme default port.
117      */
118     public HttpHost(final String hostname, final int port) {
119         this(null, hostname, port);
120     }
121 
122     /**
123      * Creates {@code HttpHost} instance with the given hostname and scheme and the default port for that scheme.
124      * @param scheme    the name of the scheme.
125      *                  {@code null} indicates the
126      *                  {@link #DEFAULT_SCHEME default scheme}
127      * @param hostname  the hostname (IP or DNS name)
128      *
129      * @throws IllegalArgumentException
130      *             If the port parameter is outside the specified range of valid port values, which is between 0 and
131      *             65535, inclusive. {@code -1} indicates the scheme default port.
132      */
133     public HttpHost(final String scheme, final String hostname) {
134         this(scheme, hostname, -1);
135     }
136 
137     /**
138      * Creates {@code HttpHost} instance from a string. Text may not contain any blanks.
139      *
140      * @since 4.4
141      */
142     public static HttpHost create(final String s) throws URISyntaxException {
143         Args.notEmpty(s, "HTTP Host");
144         String text = s;
145         String scheme = null;
146         final int schemeIdx = text.indexOf("://");
147         if (schemeIdx > 0) {
148             scheme = text.substring(0, schemeIdx);
149             if (TextUtils.containsBlanks(scheme)) {
150                 throw new URISyntaxException(s, "scheme contains blanks");
151             }
152             text = text.substring(schemeIdx + 3);
153         }
154         final Host host = Host.create(text);
155         return new HttpHost(scheme, host);
156     }
157 
158     /**
159      * Creates an {@code HttpHost} instance from the scheme, host, and port from the given URI. Other URI elements are ignored.
160      *
161      * @param uri scheme, host, and port.
162      * @return a new HttpHost
163      *
164      * @since 5.0
165      */
166     public static HttpHost create(final URI uri) {
167         final String scheme = uri.getScheme();
168         return new HttpHost(scheme != null ? scheme : URIScheme.HTTP.getId(), uri.getHost(), uri.getPort());
169     }
170 
171     /**
172      * Creates {@code HttpHost} instance with the default scheme and port and the given hostname.
173      *
174      * @param hostname  the hostname (IP or DNS name)
175      *
176      * @throws IllegalArgumentException
177      *             If the port parameter is outside the specified range of valid port values, which is between 0 and
178      *             65535, inclusive. {@code -1} indicates the scheme default port.
179      */
180     public HttpHost(final String hostname) {
181         this(null, hostname, -1);
182     }
183 
184     /**
185      * Creates {@code HttpHost} instance with the given scheme, inet address and port.
186      * @param scheme    the name of the scheme.
187      *                  {@code null} indicates the
188      *                  {@link #DEFAULT_SCHEME default scheme}
189      * @param address   the inet address.
190      * @param port      the port number.
191      *                  {@code -1} indicates the scheme default port.
192      *
193      * @throws IllegalArgumentException
194      *             If the port parameter is outside the specified range of valid port values, which is between 0 and
195      *             65535, inclusive. {@code -1} indicates the scheme default port.
196      *
197      * @since 5.0
198      */
199     public HttpHost(final String scheme, final InetAddress address, final int port) {
200         this(scheme, Args.notNull(address,"Inet address"), address.getHostName(), port);
201     }
202 
203     /**
204      * Creates {@code HttpHost} instance with the default scheme and the given inet address
205      * and port.
206      *
207      * @param address   the inet address.
208      * @param port      the port number.
209      *                  {@code -1} indicates the scheme default port.
210      *
211      * @throws IllegalArgumentException
212      *             If the port parameter is outside the specified range of valid port values, which is between 0 and
213      *             65535, inclusive. {@code -1} indicates the scheme default port.
214      *
215      * @since 4.3
216      */
217     public HttpHost(final InetAddress address, final int port) {
218         this(null, address, port);
219     }
220 
221     /**
222      * Creates {@code HttpHost} instance with the default scheme and port and the given inet
223      * address.
224      *
225      * @param address   the inet address.
226      *
227      * @throws IllegalArgumentException
228      *             If the port parameter is outside the specified range of valid port values, which is between 0 and
229      *             65535, inclusive. {@code -1} indicates the scheme default port.
230      *
231      * @since 4.3
232      */
233     public HttpHost(final InetAddress address) {
234         this(null, address, -1);
235     }
236 
237     /**
238      * @throws IllegalArgumentException
239      *             If the port parameter is outside the specified range of valid port values, which is between 0 and
240      *             65535, inclusive. {@code -1} indicates the scheme default port.
241      *
242      * @since 5.0
243      */
244     public HttpHost(final String scheme, final NamedEndpoint namedEndpoint) {
245         this(scheme, Args.notNull(namedEndpoint, "Named endpoint").getHostName(), namedEndpoint.getPort());
246     }
247 
248     /**
249      * @since 5.0
250      *
251      * @deprecated Use {@link HttpHost#HttpHost(String, NamedEndpoint)}
252      */
253     @Deprecated
254     public HttpHost(final URIAuthority authority) {
255         this(null, authority);
256     }
257 
258     /**
259      * Returns the host name.
260      *
261      * @return the host name (IP or DNS name)
262      */
263     @Override
264     public String getHostName() {
265         return this.host.getHostName();
266     }
267 
268     /**
269      * Returns the port.
270      *
271      * @return the host port, or {@code -1} if not set
272      */
273     @Override
274     public int getPort() {
275         return this.host.getPort();
276     }
277 
278     /**
279      * Returns the scheme name.
280      *
281      * @return the scheme name
282      */
283     public String getSchemeName() {
284         return this.schemeName;
285     }
286 
287     /**
288      * Returns the inet address if explicitly set by a constructor,
289      *   {@code null} otherwise.
290      * @return the inet address
291      *
292      * @since 4.3
293      */
294     public InetAddress getAddress() {
295         return this.address;
296     }
297 
298     /**
299      * Return the host URI, as a string.
300      *
301      * @return the host URI
302      */
303     public String toURI() {
304         final StringBuilder buffer = new StringBuilder();
305         buffer.append(this.schemeName);
306         buffer.append("://");
307         buffer.append(this.host.toString());
308         return buffer.toString();
309     }
310 
311 
312     /**
313      * Obtains the host string, without scheme prefix.
314      *
315      * @return  the host string, for example {@code localhost:8080}
316      */
317     public String toHostString() {
318         return this.host.toString();
319     }
320 
321 
322     @Override
323     public String toString() {
324         return toURI();
325     }
326 
327 
328     @Override
329     public boolean equals(final Object obj) {
330         if (this == obj) {
331             return true;
332         }
333         if (obj instanceof HttpHost) {
334             final HttpHost that = (HttpHost) obj;
335             return this.schemeName.equals(that.schemeName) &&
336                     this.host.equals(that.host) &&
337                     Objects.equals(this.address, that.address);
338         }
339         return false;
340     }
341 
342     /**
343      * @see java.lang.Object#hashCode()
344      */
345     @Override
346     public int hashCode() {
347         int hash = LangUtils.HASH_SEED;
348         hash = LangUtils.hashCode(hash, this.schemeName);
349         hash = LangUtils.hashCode(hash, this.host);
350         hash = LangUtils.hashCode(hash, this.address);
351         return hash;
352     }
353 
354 }