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 }