001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027 028package org.apache.http; 029 030import java.io.Serializable; 031import java.net.InetAddress; 032import java.util.Locale; 033 034import org.apache.http.annotation.ThreadingBehavior; 035import org.apache.http.annotation.Contract; 036import org.apache.http.util.Args; 037import org.apache.http.util.LangUtils; 038 039/** 040 * Holds all of the variables needed to describe an HTTP connection to a host. 041 * This includes remote host name, port and scheme. 042 * 043 * @since 4.0 044 */ 045@Contract(threading = ThreadingBehavior.IMMUTABLE) 046public final class HttpHost implements Cloneable, Serializable { 047 048 private static final long serialVersionUID = -7529410654042457626L; 049 050 /** The default scheme is "http". */ 051 public static final String DEFAULT_SCHEME_NAME = "http"; 052 053 /** The host to use. */ 054 protected final String hostname; 055 056 /** The lowercase host, for {@link #equals} and {@link #hashCode}. */ 057 protected final String lcHostname; 058 059 060 /** The port to use, defaults to -1 if not set. */ 061 protected final int port; 062 063 /** The scheme (lowercased) */ 064 protected final String schemeName; 065 066 protected final InetAddress address; 067 068 /** 069 * Creates {@code HttpHost} instance with the given scheme, hostname and port. 070 * 071 * @param hostname the hostname (IP or DNS name) 072 * @param port the port number. 073 * {@code -1} indicates the scheme default port. 074 * @param scheme the name of the scheme. 075 * {@code null} indicates the 076 * {@link #DEFAULT_SCHEME_NAME default scheme} 077 */ 078 public HttpHost(final String hostname, final int port, final String scheme) { 079 super(); 080 this.hostname = Args.containsNoBlanks(hostname, "Host name"); 081 this.lcHostname = hostname.toLowerCase(Locale.ROOT); 082 if (scheme != null) { 083 this.schemeName = scheme.toLowerCase(Locale.ROOT); 084 } else { 085 this.schemeName = DEFAULT_SCHEME_NAME; 086 } 087 this.port = port; 088 this.address = null; 089 } 090 091 /** 092 * Creates {@code HttpHost} instance with the default scheme and the given hostname and port. 093 * 094 * @param hostname the hostname (IP or DNS name) 095 * @param port the port number. 096 * {@code -1} indicates the scheme default port. 097 */ 098 public HttpHost(final String hostname, final int port) { 099 this(hostname, port, null); 100 } 101 102 /** 103 * Creates {@code HttpHost} instance from string. Text may not contain any blanks. 104 * 105 * @since 4.4 106 */ 107 public static HttpHost create(final String s) { 108 Args.containsNoBlanks(s, "HTTP Host"); 109 String text = s; 110 String scheme = null; 111 final int schemeIdx = text.indexOf("://"); 112 if (schemeIdx > 0) { 113 scheme = text.substring(0, schemeIdx); 114 text = text.substring(schemeIdx + 3); 115 } 116 int port = -1; 117 final int portIdx = text.lastIndexOf(":"); 118 if (portIdx > 0) { 119 try { 120 port = Integer.parseInt(text.substring(portIdx + 1)); 121 } catch (final NumberFormatException ex) { 122 throw new IllegalArgumentException("Invalid HTTP host: " + text); 123 } 124 text = text.substring(0, portIdx); 125 } 126 return new HttpHost(text, port, scheme); 127 } 128 129 /** 130 * Creates {@code HttpHost} instance with the default scheme and port and the given hostname. 131 * 132 * @param hostname the hostname (IP or DNS name) 133 */ 134 public HttpHost(final String hostname) { 135 this(hostname, -1, null); 136 } 137 138 /** 139 * Creates {@code HttpHost} instance with the given scheme, inet address and port. 140 * 141 * @param address the inet address. 142 * @param port the port number. 143 * {@code -1} indicates the scheme default port. 144 * @param scheme the name of the scheme. 145 * {@code null} indicates the 146 * {@link #DEFAULT_SCHEME_NAME default scheme} 147 * 148 * @since 4.3 149 */ 150 public HttpHost(final InetAddress address, final int port, final String scheme) { 151 this(Args.notNull(address,"Inet address"), address.getHostName(), port, scheme); 152 } 153 /** 154 * Creates a new {@link HttpHost HttpHost}, specifying all values. 155 * Constructor for HttpHost. 156 * 157 * @param address the inet address. 158 * @param hostname the hostname (IP or DNS name) 159 * @param port the port number. 160 * {@code -1} indicates the scheme default port. 161 * @param scheme the name of the scheme. 162 * {@code null} indicates the 163 * {@link #DEFAULT_SCHEME_NAME default scheme} 164 * 165 * @since 4.4 166 */ 167 public HttpHost(final InetAddress address, final String hostname, final int port, final String scheme) { 168 super(); 169 this.address = Args.notNull(address, "Inet address"); 170 this.hostname = Args.notNull(hostname, "Hostname"); 171 this.lcHostname = this.hostname.toLowerCase(Locale.ROOT); 172 if (scheme != null) { 173 this.schemeName = scheme.toLowerCase(Locale.ROOT); 174 } else { 175 this.schemeName = DEFAULT_SCHEME_NAME; 176 } 177 this.port = port; 178 } 179 180 /** 181 * Creates {@code HttpHost} instance with the default scheme and the given inet address 182 * and port. 183 * 184 * @param address the inet address. 185 * @param port the port number. 186 * {@code -1} indicates the scheme default port. 187 * 188 * @since 4.3 189 */ 190 public HttpHost(final InetAddress address, final int port) { 191 this(address, port, null); 192 } 193 194 /** 195 * Creates {@code HttpHost} instance with the default scheme and port and the given inet 196 * address. 197 * 198 * @param address the inet address. 199 * 200 * @since 4.3 201 */ 202 public HttpHost(final InetAddress address) { 203 this(address, -1, null); 204 } 205 206 /** 207 * Copy constructor for {@link HttpHost HttpHost}. 208 * 209 * @param httphost the HTTP host to copy details from 210 */ 211 public HttpHost (final HttpHost httphost) { 212 super(); 213 Args.notNull(httphost, "HTTP host"); 214 this.hostname = httphost.hostname; 215 this.lcHostname = httphost.lcHostname; 216 this.schemeName = httphost.schemeName; 217 this.port = httphost.port; 218 this.address = httphost.address; 219 } 220 221 /** 222 * Returns the host name. 223 * 224 * @return the host name (IP or DNS name) 225 */ 226 public String getHostName() { 227 return this.hostname; 228 } 229 230 /** 231 * Returns the port. 232 * 233 * @return the host port, or {@code -1} if not set 234 */ 235 public int getPort() { 236 return this.port; 237 } 238 239 /** 240 * Returns the scheme name. 241 * 242 * @return the scheme name 243 */ 244 public String getSchemeName() { 245 return this.schemeName; 246 } 247 248 /** 249 * Returns the inet address if explicitly set by a constructor, 250 * {@code null} otherwise. 251 * @return the inet address 252 * 253 * @since 4.3 254 */ 255 public InetAddress getAddress() { 256 return this.address; 257 } 258 259 /** 260 * Return the host URI, as a string. 261 * 262 * @return the host URI 263 */ 264 public String toURI() { 265 final StringBuilder buffer = new StringBuilder(); 266 buffer.append(this.schemeName); 267 buffer.append("://"); 268 buffer.append(this.hostname); 269 if (this.port != -1) { 270 buffer.append(':'); 271 buffer.append(Integer.toString(this.port)); 272 } 273 return buffer.toString(); 274 } 275 276 277 /** 278 * Obtains the host string, without scheme prefix. 279 * 280 * @return the host string, for example {@code localhost:8080} 281 */ 282 public String toHostString() { 283 if (this.port != -1) { 284 //the highest port number is 65535, which is length 6 with the addition of the colon 285 final StringBuilder buffer = new StringBuilder(this.hostname.length() + 6); 286 buffer.append(this.hostname); 287 buffer.append(":"); 288 buffer.append(Integer.toString(this.port)); 289 return buffer.toString(); 290 } else { 291 return this.hostname; 292 } 293 } 294 295 296 @Override 297 public String toString() { 298 return toURI(); 299 } 300 301 302 @Override 303 public boolean equals(final Object obj) { 304 if (this == obj) { 305 return true; 306 } 307 if (obj instanceof HttpHost) { 308 final HttpHost that = (HttpHost) obj; 309 return this.lcHostname.equals(that.lcHostname) 310 && this.port == that.port 311 && this.schemeName.equals(that.schemeName) 312 && (this.address==null ? that.address== null : this.address.equals(that.address)); 313 } else { 314 return false; 315 } 316 } 317 318 /** 319 * @see java.lang.Object#hashCode() 320 */ 321 @Override 322 public int hashCode() { 323 int hash = LangUtils.HASH_SEED; 324 hash = LangUtils.hashCode(hash, this.lcHostname); 325 hash = LangUtils.hashCode(hash, this.port); 326 hash = LangUtils.hashCode(hash, this.schemeName); 327 if (address!=null) { 328 hash = LangUtils.hashCode(hash, address); 329 } 330 return hash; 331 } 332 333 @Override 334 public Object clone() throws CloneNotSupportedException { 335 return super.clone(); 336 } 337 338}