1 /* 2 * Copyright 2019 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static com.google.common.base.Preconditions.checkState; 21 22 import com.google.common.base.MoreObjects; 23 import com.google.common.base.Objects; 24 import java.net.InetSocketAddress; 25 import java.net.SocketAddress; 26 import javax.annotation.Nullable; 27 28 /** 29 * An {@link ProxiedSocketAddress} for making a connection to an endpoint via an HTTP CONNECT proxy. 30 */ 31 public final class HttpConnectProxiedSocketAddress extends ProxiedSocketAddress { 32 private static final long serialVersionUID = 0L; 33 34 private final SocketAddress proxyAddress; 35 private final InetSocketAddress targetAddress; 36 @Nullable 37 private final String username; 38 @Nullable 39 private final String password; 40 HttpConnectProxiedSocketAddress( SocketAddress proxyAddress, InetSocketAddress targetAddress, @Nullable String username, @Nullable String password)41 private HttpConnectProxiedSocketAddress( 42 SocketAddress proxyAddress, 43 InetSocketAddress targetAddress, 44 @Nullable String username, 45 @Nullable String password) { 46 checkNotNull(proxyAddress, "proxyAddress"); 47 checkNotNull(targetAddress, "targetAddress"); 48 // The resolution must be done by the HttpConnectProxiedSocketAddress producer, because 49 // consumers may not be allowed to do IO. 50 if (proxyAddress instanceof InetSocketAddress) { 51 checkState(!((InetSocketAddress) proxyAddress).isUnresolved(), 52 "The proxy address %s is not resolved", proxyAddress); 53 } 54 this.proxyAddress = proxyAddress; 55 this.targetAddress = targetAddress; 56 this.username = username; 57 this.password = password; 58 } 59 60 /** 61 * Returns the password used to connect to the proxy. {@code null} if there is no password. 62 */ 63 @Nullable getPassword()64 public String getPassword() { 65 return password; 66 } 67 68 /** 69 * Returns the username used to connect to the proxy. {@code null} if there is no username. 70 */ 71 @Nullable getUsername()72 public String getUsername() { 73 return username; 74 } 75 76 /** 77 * Returns the address to the proxy, which is already resolved. 78 */ getProxyAddress()79 public SocketAddress getProxyAddress() { 80 return proxyAddress; 81 } 82 83 /** 84 * Returns the address to the target server. 85 */ getTargetAddress()86 public InetSocketAddress getTargetAddress() { 87 return targetAddress; 88 } 89 90 @Override equals(Object o)91 public boolean equals(Object o) { 92 if (!(o instanceof HttpConnectProxiedSocketAddress)) { 93 return false; 94 } 95 HttpConnectProxiedSocketAddress that = (HttpConnectProxiedSocketAddress) o; 96 return Objects.equal(proxyAddress, that.proxyAddress) 97 && Objects.equal(targetAddress, that.targetAddress) 98 && Objects.equal(username, that.username) 99 && Objects.equal(password, that.password); 100 } 101 102 @Override hashCode()103 public int hashCode() { 104 return Objects.hashCode(proxyAddress, targetAddress, username, password); 105 } 106 107 @Override toString()108 public String toString() { 109 return MoreObjects.toStringHelper(this) 110 .add("proxyAddr", proxyAddress) 111 .add("targetAddr", targetAddress) 112 .add("username", username) 113 // Intentionally mask out password 114 .add("hasPassword", password != null) 115 .toString(); 116 } 117 118 /** 119 * Create a new builder. 120 */ newBuilder()121 public static Builder newBuilder() { 122 return new Builder(); 123 } 124 125 /** 126 * The builder for {@link HttpConnectProxiedSocketAddress}. 127 */ 128 public static final class Builder { 129 130 private SocketAddress proxyAddress; 131 private InetSocketAddress targetAddress; 132 @Nullable 133 private String username; 134 @Nullable 135 private String password; 136 Builder()137 private Builder() { 138 } 139 140 /** 141 * Sets the address to the proxy, which is already resolved. This is a required field. 142 */ setProxyAddress(SocketAddress proxyAddress)143 public Builder setProxyAddress(SocketAddress proxyAddress) { 144 this.proxyAddress = checkNotNull(proxyAddress, "proxyAddress"); 145 return this; 146 } 147 148 /** 149 * Sets the address to the target. This is a required field. 150 */ setTargetAddress(InetSocketAddress targetAddress)151 public Builder setTargetAddress(InetSocketAddress targetAddress) { 152 this.targetAddress = checkNotNull(targetAddress, "targetAddress"); 153 return this; 154 } 155 156 /** 157 * Sets the username used to connect to the proxy. This is an optional field and can be {@code 158 * null}. 159 */ setUsername(@ullable String username)160 public Builder setUsername(@Nullable String username) { 161 this.username = username; 162 return this; 163 } 164 165 /** 166 * Sets the password used to connect to the proxy. This is an optional field and can be {@code 167 * null}. 168 */ setPassword(@ullable String password)169 public Builder setPassword(@Nullable String password) { 170 this.password = password; 171 return this; 172 } 173 174 /** 175 * Creates an {@code HttpConnectProxiedSocketAddress}. 176 */ build()177 public HttpConnectProxiedSocketAddress build() { 178 return new HttpConnectProxiedSocketAddress(proxyAddress, targetAddress, username, password); 179 } 180 } 181 } 182