package com.paypal.base;
import com.paypal.base.exception.SSLConfigurationException;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.*;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
/**
* Wrapper class used for HttpsURLConnection
*
*/
public class DefaultHttpConnection extends HttpConnection {
/**
* Secure Socket Layer context
*/
private SSLContext sslContext;
public DefaultHttpConnection() {
try {
sslContext = SSLUtil.getSSLContext(null);
} catch (SSLConfigurationException e) {
throw new RuntimeException(e);
}
}
public DefaultHttpConnection(SSLContext sslContext) {
this.sslContext = sslContext;
}
@Override
public void setupClientSSL(String certPath, String certKey)
throws SSLConfigurationException {
try {
this.sslContext = SSLUtil.setupClientSSL(certPath, certKey);
} catch (Exception e) {
throw new SSLConfigurationException(e.getMessage(), e);
}
}
@Override
public void createAndconfigureHttpConnection(
HttpConfiguration clientConfiguration) throws IOException {
this.config = clientConfiguration;
URL url = new URL(this.config.getEndPointUrl());
Proxy proxy = null;
String proxyHost = this.config.getProxyHost();
int proxyPort = this.config.getProxyPort();
if ((proxyHost != null) && (proxyPort > 0)) {
SocketAddress addr = new InetSocketAddress(proxyHost, proxyPort);
proxy = new Proxy(Proxy.Type.HTTP, addr);
}
if (proxy != null) {
this.connection = (HttpURLConnection) url.openConnection(proxy);
} else {
this.connection = (HttpURLConnection) url
.openConnection(Proxy.NO_PROXY);
}
if (this.connection instanceof HttpsURLConnection) {
((HttpsURLConnection) this.connection)
.setSSLSocketFactory(this.sslContext.getSocketFactory());
}
if (this.config.getProxyUserName() != null
&& this.config.getProxyPassword() != null) {
final String username = this.config.getProxyUserName();
final String password = this.config.getProxyPassword();
Authenticator authenticator = new DefaultPasswordAuthenticator(
username, password);
Authenticator.setDefault(authenticator);
}
System.setProperty("http.maxConnections",
String.valueOf(this.config.getMaxHttpConnection()));
System.setProperty("sun.net.http.errorstream.enableBuffering", "true");
this.connection.setDoInput(true);
this.connection.setDoOutput(true);
setRequestMethodViaJreBugWorkaround(this.connection, config.getHttpMethod());
this.connection.setConnectTimeout(this.config.getConnectionTimeout());
this.connection.setReadTimeout(this.config.getReadTimeout());
}
/**
* Workaround for a bug in {@code HttpURLConnection.setRequestMethod(String)}
* The implementation of Sun/Oracle is throwing a {@code ProtocolException}
* when the method is other than the HTTP/1.1 default methods. So to use {@code PATCH}
* and others, we must apply this workaround.
*
* See issue http://java.net/jira/browse/JERSEY-639
*/
private static void setRequestMethodViaJreBugWorkaround(final HttpURLConnection httpURLConnection, final String method) {
try {
httpURLConnection.setRequestMethod(method); // Check whether we are running on a buggy JRE
} catch (final ProtocolException pe) {
try {
final Class<?> httpURLConnectionClass = httpURLConnection.getClass();
AccessController
.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws NoSuchFieldException,
IllegalAccessException {
try {
httpURLConnection.setRequestMethod(method);
// Check whether we are running on a buggy
// JRE
} catch (final ProtocolException pe) {
Class<?> connectionClass = httpURLConnection
.getClass();
Field delegateField = null;
try {
delegateField = connectionClass
.getDeclaredField("delegate");
delegateField.setAccessible(true);
HttpURLConnection delegateConnection = (HttpURLConnection) delegateField
.get(httpURLConnection);
setRequestMethodViaJreBugWorkaround(
delegateConnection, method);
} catch (NoSuchFieldException e) {
// Ignore for now, keep going
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
try {
Field methodField;
while (connectionClass != null) {
try {
methodField = connectionClass
.getDeclaredField("method");
} catch (NoSuchFieldException e) {
connectionClass = connectionClass
.getSuperclass();
continue;
}
methodField.setAccessible(true);
methodField.set(httpURLConnection,
method);
break;
}
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
return null;
}
});
} catch (final PrivilegedActionException e) {
final Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else {
throw new RuntimeException(cause);
}
}
}
}
/**
* Private class for password based authentication
*
*/
private static class DefaultPasswordAuthenticator extends Authenticator {
/**
* Username
*/
private String userName;
/**
* Password
*/
private String password;
public DefaultPasswordAuthenticator(String userName, String password) {
this.userName = userName;
this.password = password;
}
public PasswordAuthentication getPasswordAuthentication() {
return (new PasswordAuthentication(userName, password.toCharArray()));
}
}
}