in src/main/java/com/microsoft/azure/proton/transport/proxy/impl/ProxyImpl.java [274:361]
public void process() throws TransportException {
if (!getIsHandshakeInProgress()) {
underlyingInput.process();
return;
}
switch (proxyState) {
case PN_PROXY_CONNECTING:
inputBuffer.flip();
final ProxyResponse connectResponse = readProxyResponse(inputBuffer);
if (connectResponse == null || connectResponse.isMissingContent()) {
LOGGER.info("Request is missing content. Waiting for more bytes.");
break;
}
// Clean up response to prepare for challenge
proxyResponse.set(null);
final boolean isSuccess = proxyHandler.validateProxyResponse(connectResponse);
// When connecting to proxy, it does not challenge us for authentication. If the user has specified
// a configuration, and it is not NONE, then we fail due to misconfiguration.
if (isSuccess) {
if (proxyConfiguration == null || proxyConfiguration.authentication() == ProxyAuthenticationType.NONE) {
proxyState = ProxyState.PN_PROXY_CONNECTED;
} else {
if (LOGGER.isErrorEnabled()) {
LOGGER.error("ProxyConfiguration mismatch. User configured: '{}', but authentication is not required",
proxyConfiguration.authentication());
}
closeTailProxyError(PROXY_CONNECT_USER_ERROR);
}
break;
}
final Map<String, List<String>> headers = connectResponse.getHeaders();
final Set<ProxyAuthenticationType> supportedTypes = getAuthenticationTypes(headers);
// The proxy did not successfully connect, user has specified that they want a particular
// authentication method, but it is not in list of supported authentication methods.
if (proxyConfiguration != null && !supportedTypes.contains(proxyConfiguration.authentication())) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error("Proxy authentication required. User configured: '{}', but supported proxy authentication methods are: {}",
proxyConfiguration.authentication(),
supportedTypes.stream().map(type -> type.toString()).collect(Collectors.joining(",")));
}
closeTailProxyError(PROXY_CONNECT_USER_ERROR + PROXY_CONNECT_FAILED
+ connectResponse);
break;
}
final List<String> challenges = headers.getOrDefault(PROXY_AUTHENTICATE, new ArrayList<>());
final ProxyChallengeProcessor processor = proxyConfiguration != null
? getChallengeProcessor(host, challenges, proxyConfiguration.authentication())
: getChallengeProcessor(host, challenges, supportedTypes);
if (processor != null) {
proxyState = ProxyState.PN_PROXY_CHALLENGE;
ProxyImpl.this.headers = processor.getHeader();
} else {
LOGGER.warn("Could not get ProxyChallengeProcessor for challenges.");
closeTailProxyError(PROXY_CONNECT_FAILED + String.join(";", challenges));
}
break;
case PN_PROXY_CHALLENGE_RESPONDED:
inputBuffer.flip();
final ProxyResponse challengeResponse = readProxyResponse(inputBuffer);
if (challengeResponse == null || challengeResponse.isMissingContent()) {
LOGGER.warn("Request is missing content. Waiting for more bytes.");
break;
}
//Clean up
proxyResponse.set(null);
final boolean result = proxyHandler.validateProxyResponse(challengeResponse);
if (result) {
proxyState = ProxyState.PN_PROXY_CONNECTED;
} else {
closeTailProxyError(PROXY_CONNECT_FAILED + challengeResponse);
}
break;
default:
underlyingInput.process();
}
}