HTTPURLConnection.java [plain text]
package gnu.java.net.protocol.http;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ProtocolException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.cert.Certificate;
import java.util.Date;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocketFactory;
public class HTTPURLConnection
extends HttpsURLConnection
implements HandshakeCompletedListener
{
private static final Map connectionPool = new LinkedHashMap();
private HTTPConnection connection;
private String proxyHostname;
private int proxyPort;
private String agent;
private boolean keepAlive;
private int maxConnections;
private Request request;
private Headers requestHeaders;
private ByteArrayOutputStream requestSink;
private boolean requestMethodSetExplicitly;
private Response response;
private ByteArrayInputStream responseSink;
private HandshakeCompletedEvent handshakeEvent;
public HTTPURLConnection(URL url)
throws IOException
{
super(url);
requestHeaders = new Headers();
AccessController.doPrivileged(this.new GetHTTPPropertiesAction());
}
class GetHTTPPropertiesAction
implements PrivilegedAction
{
public Object run()
{
proxyHostname = System.getProperty("http.proxyHost");
if (proxyHostname != null && proxyHostname.length() > 0)
{
String port = System.getProperty("http.proxyPort");
if (port != null && port.length() > 0)
{
proxyPort = Integer.parseInt(port);
}
else
{
proxyHostname = null;
proxyPort = -1;
}
}
agent = System.getProperty("http.agent");
String ka = System.getProperty("http.keepAlive");
keepAlive = !(ka != null && "false".equals(ka));
String mc = System.getProperty("http.maxConnections");
maxConnections = (mc != null && mc.length() > 0) ?
Math.max(Integer.parseInt(mc), 1) : 5;
return null;
}
}
public void connect()
throws IOException
{
if (connected)
{
return;
}
String protocol = url.getProtocol();
boolean secure = "https".equals(protocol);
String host = url.getHost();
int port = url.getPort();
if (port < 0)
{
port = secure ? HTTPConnection.HTTPS_PORT :
HTTPConnection.HTTP_PORT;
}
String file = url.getFile();
String username = url.getUserInfo();
String password = null;
if (username != null)
{
int ci = username.indexOf(':');
if (ci != -1)
{
password = username.substring(ci + 1);
username = username.substring(0, ci);
}
}
final Credentials creds = (username == null) ? null :
new Credentials (username, password);
boolean retry;
do
{
retry = false;
if (connection == null)
{
connection = getConnection(host, port, secure);
if (secure)
{
SSLSocketFactory factory = getSSLSocketFactory();
HostnameVerifier verifier = getHostnameVerifier();
if (factory != null)
{
connection.setSSLSocketFactory(factory);
}
connection.addHandshakeCompletedListener(this);
}
}
if (proxyHostname != null)
{
if (proxyPort < 0)
{
proxyPort = secure ? HTTPConnection.HTTPS_PORT :
HTTPConnection.HTTP_PORT;
}
connection.setProxy(proxyHostname, proxyPort);
}
request = connection.newRequest(method, file);
if (!keepAlive)
{
request.setHeader("Connection", "close");
}
if (agent != null)
{
request.setHeader("User-Agent", agent);
}
request.getHeaders().putAll(requestHeaders);
if (requestSink != null)
{
byte[] content = requestSink.toByteArray();
RequestBodyWriter writer = new ByteArrayRequestBodyWriter(content);
request.setRequestBodyWriter(writer);
}
ByteArrayResponseBodyReader reader = new ByteArrayResponseBodyReader();
request.setResponseBodyReader(reader);
if (creds != null)
{
request.setAuthenticator(new Authenticator() {
public Credentials getCredentials(String realm, int attempts)
{
return (attempts < 2) ? creds : null;
}
});
}
response = request.dispatch();
if (response.getCodeClass() == 3 && getInstanceFollowRedirects())
{
String location = response.getHeader("Location");
String connectionUri = connection.getURI();
int start = connectionUri.length();
if (location.startsWith(connectionUri) &&
location.charAt(start) == '/')
{
file = location.substring(start);
retry = true;
}
else if (location.startsWith("http:"))
{
connection.close();
connection = null;
secure = false;
start = 7;
int end = location.indexOf('/', start);
host = location.substring(start, end);
int ci = host.lastIndexOf(':');
if (ci != -1)
{
port = Integer.parseInt(host.substring (ci + 1));
host = host.substring(0, ci);
}
else
{
port = HTTPConnection.HTTP_PORT;
}
file = location.substring(end);
retry = true;
}
else if (location.startsWith("https:"))
{
connection.close();
connection = null;
secure = true;
start = 8;
int end = location.indexOf('/', start);
host = location.substring(start, end);
int ci = host.lastIndexOf(':');
if (ci != -1)
{
port = Integer.parseInt(host.substring (ci + 1));
host = host.substring(0, ci);
}
else
{
port = HTTPConnection.HTTPS_PORT;
}
file = location.substring(end);
retry = true;
}
}
else
{
responseSink = new ByteArrayInputStream(reader.toByteArray ());
}
}
while (retry);
connected = true;
}
HTTPConnection getConnection(String host, int port, boolean secure)
throws IOException
{
HTTPConnection connection;
if (keepAlive)
{
StringBuffer buf = new StringBuffer(secure ? "https://" : "http://");
buf.append(host);
buf.append(':');
buf.append(port);
String key = buf.toString();
synchronized (connectionPool)
{
connection = (HTTPConnection) connectionPool.get(key);
if (connection == null)
{
connection = new HTTPConnection(host, port, secure);
if (connectionPool.size() == maxConnections)
{
Object lru = connectionPool.keySet().iterator().next();
connectionPool.remove(lru);
}
connectionPool.put(key, connection);
}
}
}
else
{
connection = new HTTPConnection(host, port, secure);
}
return connection;
}
public void disconnect()
{
if (connection != null)
{
try
{
connection.close();
}
catch (IOException e)
{
}
}
}
public boolean usingProxy()
{
return (proxyHostname != null);
}
public void setRequestMethod(String method)
throws ProtocolException
{
if (connected)
{
throw new ProtocolException("Already connected");
}
method = method.toUpperCase();
int len = method.length();
if (len == 0)
{
throw new ProtocolException("Empty method name");
}
for (int i = 0; i < len; i++)
{
char c = method.charAt(i);
if (c < 0x41 || c > 0x5a)
{
throw new ProtocolException("Illegal character '" + c +
"' at index " + i);
}
}
this.method = method;
requestMethodSetExplicitly = true;
}
public String getRequestProperty(String key)
{
return requestHeaders.getValue(key);
}
public Map getRequestProperties()
{
return requestHeaders;
}
public void setRequestProperty(String key, String value)
{
requestHeaders.put(key, value);
}
public void addRequestProperty(String key, String value)
{
String old = requestHeaders.getValue(key);
if (old == null)
{
requestHeaders.put(key, value);
}
else
{
requestHeaders.put(key, old + "," + value);
}
}
public OutputStream getOutputStream()
throws IOException
{
if (connected)
{
throw new ProtocolException("Already connected");
}
if (!doOutput)
{
throw new ProtocolException("doOutput is false");
}
else if (!requestMethodSetExplicitly)
{
method = "POST";
}
if (requestSink == null)
{
requestSink = new ByteArrayOutputStream();
}
return requestSink;
}
public InputStream getInputStream()
throws IOException
{
if (!connected)
{
connect();
}
if (!doInput)
{
throw new ProtocolException("doInput is false");
}
return responseSink;
}
public Map getHeaderFields()
{
if (!connected)
{
try
{
connect();
}
catch (IOException e)
{
return null;
}
}
Map headers = response.getHeaders();
Map ret = new LinkedHashMap();
ret.put("", Collections.singletonList(getStatusLine(response)));
for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
{
Map.Entry entry = (Map.Entry) i.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
ret.put(key, Collections.singletonList(value));
}
return ret;
}
String getStatusLine(Response response)
{
return "HTTP/" + response.getMajorVersion() +
"." + response.getMinorVersion() +
" " + response.getCode() +
" " + response.getMessage();
}
public String getHeaderField(int index)
{
if (!connected)
{
try
{
connect();
}
catch (IOException e)
{
return null;
}
}
if (index == 0)
{
return getStatusLine(response);
}
Iterator i = response.getHeaders().entrySet().iterator();
Map.Entry entry;
int count = 1;
do
{
if (!i.hasNext())
{
return null;
}
entry = (Map.Entry) i.next();
count++;
}
while (count <= index);
return (String) entry.getValue();
}
public String getHeaderFieldKey(int index)
{
if (!connected)
{
try
{
connect();
}
catch (IOException e)
{
return null;
}
}
if (index == 0)
{
return null;
}
Iterator i = response.getHeaders().entrySet().iterator();
Map.Entry entry;
int count = 1;
do
{
entry = (Map.Entry) i.next();
count++;
}
while (count <= index);
return (String) entry.getKey();
}
public String getHeaderField(String name)
{
if (!connected)
{
try
{
connect();
}
catch (IOException e)
{
return null;
}
}
return (String) response.getHeader(name);
}
public long getHeaderFieldDate(String name, long def)
{
if (!connected)
{
try
{
connect();
}
catch (IOException e)
{
return def;
}
}
Date date = response.getDateHeader(name);
return (date == null) ? def : date.getTime();
}
public String getContentType()
{
return getHeaderField("Content-Type");
}
public int getResponseCode()
throws IOException
{
if (!connected)
{
connect();
}
return response.getCode();
}
public String getResponseMessage()
throws IOException
{
if (!connected)
{
connect();
}
return response.getMessage();
}
public String getCipherSuite()
{
if (!connected)
{
throw new IllegalStateException("not connected");
}
return handshakeEvent.getCipherSuite();
}
public Certificate[] getLocalCertificates()
{
if (!connected)
{
throw new IllegalStateException("not connected");
}
return handshakeEvent.getLocalCertificates();
}
public Certificate[] getServerCertificates()
throws SSLPeerUnverifiedException
{
if (!connected)
{
throw new IllegalStateException("not connected");
}
return handshakeEvent.getPeerCertificates();
}
public void handshakeCompleted(HandshakeCompletedEvent event)
{
handshakeEvent = event;
}
}