|
Java example source code file (HttpURLConnection.java)
The HttpURLConnection.java Java example source code
/*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www.protocol.http;
import java.util.Arrays;
import java.net.URL;
import java.net.URLConnection;
import java.net.ProtocolException;
import java.net.HttpRetryException;
import java.net.PasswordAuthentication;
import java.net.Authenticator;
import java.net.HttpCookie;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.SocketTimeoutException;
import java.net.SocketPermission;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.net.InetSocketAddress;
import java.net.CookieHandler;
import java.net.ResponseCache;
import java.net.CacheResponse;
import java.net.SecureCacheResponse;
import java.net.CacheRequest;
import java.net.URLPermission;
import java.net.Authenticator.RequestorType;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.Iterator;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Set;
import sun.net.*;
import sun.net.www.*;
import sun.net.www.http.HttpClient;
import sun.net.www.http.PosterOutputStream;
import sun.net.www.http.ChunkedInputStream;
import sun.net.www.http.ChunkedOutputStream;
import sun.util.logging.PlatformLogger;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.net.MalformedURLException;
import java.nio.ByteBuffer;
import static sun.net.www.protocol.http.AuthScheme.BASIC;
import static sun.net.www.protocol.http.AuthScheme.DIGEST;
import static sun.net.www.protocol.http.AuthScheme.NTLM;
import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
import static sun.net.www.protocol.http.AuthScheme.UNKNOWN;
/**
* A class to represent an HTTP connection to a remote object.
*/
public class HttpURLConnection extends java.net.HttpURLConnection {
static String HTTP_CONNECT = "CONNECT";
static final String version;
public static final String userAgent;
/* max # of allowed re-directs */
static final int defaultmaxRedirects = 20;
static final int maxRedirects;
/* Not all servers support the (Proxy)-Authentication-Info headers.
* By default, we don't require them to be sent
*/
static final boolean validateProxy;
static final boolean validateServer;
private StreamingOutputStream strOutputStream;
private final static String RETRY_MSG1 =
"cannot retry due to proxy authentication, in streaming mode";
private final static String RETRY_MSG2 =
"cannot retry due to server authentication, in streaming mode";
private final static String RETRY_MSG3 =
"cannot retry due to redirection, in streaming mode";
/*
* System properties related to error stream handling:
*
* sun.net.http.errorstream.enableBuffering = <boolean>
*
* With the above system property set to true (default is false),
* when the response code is >=400, the HTTP handler will try to
* buffer the response body (up to a certain amount and within a
* time limit). Thus freeing up the underlying socket connection
* for reuse. The rationale behind this is that usually when the
* server responds with a >=400 error (client error or server
* error, such as 404 file not found), the server will send a
* small response body to explain who to contact and what to do to
* recover. With this property set to true, even if the
* application doesn't call getErrorStream(), read the response
* body, and then call close(), the underlying socket connection
* can still be kept-alive and reused. The following two system
* properties provide further control to the error stream
* buffering behaviour.
*
* sun.net.http.errorstream.timeout = <int>
* the timeout (in millisec) waiting the error stream
* to be buffered; default is 300 ms
*
* sun.net.http.errorstream.bufferSize = <int>
* the size (in bytes) to use for the buffering the error stream;
* default is 4k
*/
/* Should we enable buffering of error streams? */
private static boolean enableESBuffer = false;
/* timeout waiting for read for buffered error stream;
*/
private static int timeout4ESBuffer = 0;
/* buffer size for buffered error stream;
*/
private static int bufSize4ES = 0;
/*
* Restrict setting of request headers through the public api
* consistent with JavaScript XMLHttpRequest2 with a few
* exceptions. Disallowed headers are silently ignored for
* backwards compatibility reasons rather than throwing a
* SecurityException. For example, some applets set the
* Host header since old JREs did not implement HTTP 1.1.
* Additionally, any header starting with Sec- is
* disallowed.
*
* The following headers are allowed for historical reasons:
*
* Accept-Charset, Accept-Encoding, Cookie, Cookie2, Date,
* Referer, TE, User-Agent, headers beginning with Proxy-.
*
* The following headers are allowed in a limited form:
*
* Connection: close
*
* See http://www.w3.org/TR/XMLHttpRequest2.
*/
private static final boolean allowRestrictedHeaders;
private static final Set<String> restrictedHeaderSet;
private static final String[] restrictedHeaders = {
/* Restricted by XMLHttpRequest2 */
//"Accept-Charset",
//"Accept-Encoding",
"Access-Control-Request-Headers",
"Access-Control-Request-Method",
"Connection", /* close is allowed */
"Content-Length",
//"Cookie",
//"Cookie2",
"Content-Transfer-Encoding",
//"Date",
//"Expect",
"Host",
"Keep-Alive",
"Origin",
// "Referer",
// "TE",
"Trailer",
"Transfer-Encoding",
"Upgrade",
//"User-Agent",
"Via"
};
static {
maxRedirects = java.security.AccessController.doPrivileged(
new sun.security.action.GetIntegerAction(
"http.maxRedirects", defaultmaxRedirects)).intValue();
version = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("java.version"));
String agent = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("http.agent"));
if (agent == null) {
agent = "Java/"+version;
} else {
agent = agent + " Java/"+version;
}
userAgent = agent;
validateProxy = java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction(
"http.auth.digest.validateProxy")).booleanValue();
validateServer = java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction(
"http.auth.digest.validateServer")).booleanValue();
enableESBuffer = java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction(
"sun.net.http.errorstream.enableBuffering")).booleanValue();
timeout4ESBuffer = java.security.AccessController.doPrivileged(
new sun.security.action.GetIntegerAction(
"sun.net.http.errorstream.timeout", 300)).intValue();
if (timeout4ESBuffer <= 0) {
timeout4ESBuffer = 300; // use the default
}
bufSize4ES = java.security.AccessController.doPrivileged(
new sun.security.action.GetIntegerAction(
"sun.net.http.errorstream.bufferSize", 4096)).intValue();
if (bufSize4ES <= 0) {
bufSize4ES = 4096; // use the default
}
allowRestrictedHeaders = java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction(
"sun.net.http.allowRestrictedHeaders")).booleanValue();
if (!allowRestrictedHeaders) {
restrictedHeaderSet = new HashSet<String>(restrictedHeaders.length);
for (int i=0; i < restrictedHeaders.length; i++) {
restrictedHeaderSet.add(restrictedHeaders[i].toLowerCase());
}
} else {
restrictedHeaderSet = null;
}
}
static final String httpVersion = "HTTP/1.1";
static final String acceptString =
"text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2";
// the following http request headers should NOT have their values
// returned for security reasons.
private static final String[] EXCLUDE_HEADERS = {
"Proxy-Authorization",
"Authorization"
};
// also exclude system cookies when any might be set
private static final String[] EXCLUDE_HEADERS2= {
"Proxy-Authorization",
"Authorization",
"Cookie",
"Cookie2"
};
protected HttpClient http;
protected Handler handler;
protected Proxy instProxy;
private CookieHandler cookieHandler;
private final ResponseCache cacheHandler;
// the cached response, and cached response headers and body
protected CacheResponse cachedResponse;
private MessageHeader cachedHeaders;
private InputStream cachedInputStream;
/* output stream to server */
protected PrintStream ps = null;
/* buffered error stream */
private InputStream errorStream = null;
/* User set Cookies */
private boolean setUserCookies = true;
private String userCookies = null;
private String userCookies2 = null;
/* We only have a single static authenticator for now.
* REMIND: backwards compatibility with JDK 1.1. Should be
* eliminated for JDK 2.0.
*/
@Deprecated
private static HttpAuthenticator defaultAuth;
/* all the headers we send
* NOTE: do *NOT* dump out the content of 'requests' in the
* output or stacktrace since it may contain security-sensitive
* headers such as those defined in EXCLUDE_HEADERS.
*/
private MessageHeader requests;
/* The headers actually set by the user are recorded here also
*/
private MessageHeader userHeaders;
/* Headers and request method cannot be changed
* once this flag is set in :-
* - getOutputStream()
* - getInputStream())
* - connect()
* Access synchronized on this.
*/
private boolean connecting = false;
/* The following two fields are only used with Digest Authentication */
String domain; /* The list of authentication domains */
DigestAuthentication.Parameters digestparams;
/* Current credentials in use */
AuthenticationInfo currentProxyCredentials = null;
AuthenticationInfo currentServerCredentials = null;
boolean needToCheck = true;
private boolean doingNTLM2ndStage = false; /* doing the 2nd stage of an NTLM server authentication */
private boolean doingNTLMp2ndStage = false; /* doing the 2nd stage of an NTLM proxy authentication */
/* try auth without calling Authenticator. Used for transparent NTLM authentication */
private boolean tryTransparentNTLMServer = true;
private boolean tryTransparentNTLMProxy = true;
/* Used by Windows specific code */
private Object authObj;
/* Set if the user is manually setting the Authorization or Proxy-Authorization headers */
boolean isUserServerAuth;
boolean isUserProxyAuth;
String serverAuthKey, proxyAuthKey;
/* Progress source */
protected ProgressSource pi;
/* all the response headers we get back */
private MessageHeader responses;
/* the stream _from_ the server */
private InputStream inputStream = null;
/* post stream _to_ the server, if any */
private PosterOutputStream poster = null;
/* Indicates if the std. request headers have been set in requests. */
private boolean setRequests=false;
/* Indicates whether a request has already failed or not */
private boolean failedOnce=false;
/* Remembered Exception, we will throw it again if somebody
calls getInputStream after disconnect */
private Exception rememberedException = null;
/* If we decide we want to reuse a client, we put it here */
private HttpClient reuseClient = null;
/* Tunnel states */
public enum TunnelState {
/* No tunnel */
NONE,
/* Setting up a tunnel */
SETUP,
/* Tunnel has been successfully setup */
TUNNELING
}
private TunnelState tunnelState = TunnelState.NONE;
/* Redefine timeouts from java.net.URLConnection as we need -1 to mean
* not set. This is to ensure backward compatibility.
*/
private int connectTimeout = NetworkClient.DEFAULT_CONNECT_TIMEOUT;
private int readTimeout = NetworkClient.DEFAULT_READ_TIMEOUT;
/* A permission converted from a URLPermission */
private SocketPermission socketPermission;
/* Logging support */
private static final PlatformLogger logger =
PlatformLogger.getLogger("sun.net.www.protocol.http.HttpURLConnection");
/*
* privileged request password authentication
*
*/
private static PasswordAuthentication
privilegedRequestPasswordAuthentication(
final String host,
final InetAddress addr,
final int port,
final String protocol,
final String prompt,
final String scheme,
final URL url,
final RequestorType authType) {
return java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<PasswordAuthentication>() {
public PasswordAuthentication run() {
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("Requesting Authentication: host =" + host + " url = " + url);
}
PasswordAuthentication pass = Authenticator.requestPasswordAuthentication(
host, addr, port, protocol,
prompt, scheme, url, authType);
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("Authentication returned: " + (pass != null ? pass.toString() : "null"));
}
return pass;
}
});
}
private boolean isRestrictedHeader(String key, String value) {
if (allowRestrictedHeaders) {
return false;
}
key = key.toLowerCase();
if (restrictedHeaderSet.contains(key)) {
/*
* Exceptions to restricted headers:
*
* Allow "Connection: close".
*/
if (key.equals("connection") && value.equalsIgnoreCase("close")) {
return false;
}
return true;
} else if (key.startsWith("sec-")) {
return true;
}
return false;
}
/*
* Checks the validity of http message header and whether the header
* is restricted and throws IllegalArgumentException if invalid or
* restricted.
*/
private boolean isExternalMessageHeaderAllowed(String key, String value) {
checkMessageHeader(key, value);
if (!isRestrictedHeader(key, value)) {
return true;
}
return false;
}
/* Logging support */
public static PlatformLogger getHttpLogger() {
return logger;
}
/* Used for Windows NTLM implementation */
public Object authObj() {
return authObj;
}
public void authObj(Object authObj) {
this.authObj = authObj;
}
/*
* checks the validity of http message header and throws
* IllegalArgumentException if invalid.
*/
private void checkMessageHeader(String key, String value) {
char LF = '\n';
int index = key.indexOf(LF);
if (index != -1) {
throw new IllegalArgumentException(
"Illegal character(s) in message header field: " + key);
}
else {
if (value == null) {
return;
}
index = value.indexOf(LF);
while (index != -1) {
index++;
if (index < value.length()) {
char c = value.charAt(index);
if ((c==' ') || (c=='\t')) {
// ok, check the next occurrence
index = value.indexOf(LF, index);
continue;
}
}
throw new IllegalArgumentException(
"Illegal character(s) in message header value: " + value);
}
}
}
public synchronized void setRequestMethod(String method)
throws ProtocolException {
if (connecting) {
throw new IllegalStateException("connect in progress");
}
super.setRequestMethod(method);
}
/* adds the standard key/val pairs to reqests if necessary & write to
* given PrintStream
*/
private void writeRequests() throws IOException {
/* print all message headers in the MessageHeader
* onto the wire - all the ones we've set and any
* others that have been set
*/
// send any pre-emptive authentication
if (http.usingProxy && tunnelState() != TunnelState.TUNNELING) {
setPreemptiveProxyAuthentication(requests);
}
if (!setRequests) {
/* We're very particular about the order in which we
* set the request headers here. The order should not
* matter, but some careless CGI programs have been
* written to expect a very particular order of the
* standard headers. To name names, the order in which
* Navigator3.0 sends them. In particular, we make *sure*
* to send Content-type: <> and Content-length:<> second
* to last and last, respectively, in the case of a POST
* request.
*/
if (!failedOnce) {
checkURLFile();
requests.prepend(method + " " + getRequestURI()+" " +
httpVersion, null);
}
if (!getUseCaches()) {
requests.setIfNotSet ("Cache-Control", "no-cache");
requests.setIfNotSet ("Pragma", "no-cache");
}
requests.setIfNotSet("User-Agent", userAgent);
int port = url.getPort();
String host = url.getHost();
if (port != -1 && port != url.getDefaultPort()) {
host += ":" + String.valueOf(port);
}
String reqHost = requests.findValue("Host");
if (reqHost == null ||
(!reqHost.equalsIgnoreCase(host) && !checkSetHost()))
{
requests.set("Host", host);
}
requests.setIfNotSet("Accept", acceptString);
/*
* For HTTP/1.1 the default behavior is to keep connections alive.
* However, we may be talking to a 1.0 server so we should set
* keep-alive just in case, except if we have encountered an error
* or if keep alive is disabled via a system property
*/
// Try keep-alive only on first attempt
if (!failedOnce && http.getHttpKeepAliveSet()) {
if (http.usingProxy && tunnelState() != TunnelState.TUNNELING) {
requests.setIfNotSet("Proxy-Connection", "keep-alive");
} else {
requests.setIfNotSet("Connection", "keep-alive");
}
} else {
/*
* RFC 2616 HTTP/1.1 section 14.10 says:
* HTTP/1.1 applications that do not support persistent
* connections MUST include the "close" connection option
* in every message
*/
requests.setIfNotSet("Connection", "close");
}
// Set modified since if necessary
long modTime = getIfModifiedSince();
if (modTime != 0 ) {
Date date = new Date(modTime);
//use the preferred date format according to RFC 2068(HTTP1.1),
// RFC 822 and RFC 1123
SimpleDateFormat fo =
new SimpleDateFormat ("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
fo.setTimeZone(TimeZone.getTimeZone("GMT"));
requests.setIfNotSet("If-Modified-Since", fo.format(date));
}
// check for preemptive authorization
AuthenticationInfo sauth = AuthenticationInfo.getServerAuth(url);
if (sauth != null && sauth.supportsPreemptiveAuthorization() ) {
// Sets "Authorization"
requests.setIfNotSet(sauth.getHeaderName(), sauth.getHeaderValue(url,method));
currentServerCredentials = sauth;
}
if (!method.equals("PUT") && (poster != null || streaming())) {
requests.setIfNotSet ("Content-type",
"application/x-www-form-urlencoded");
}
boolean chunked = false;
if (streaming()) {
if (chunkLength != -1) {
requests.set ("Transfer-Encoding", "chunked");
chunked = true;
} else { /* fixed content length */
if (fixedContentLengthLong != -1) {
requests.set ("Content-Length",
String.valueOf(fixedContentLengthLong));
} else if (fixedContentLength != -1) {
requests.set ("Content-Length",
String.valueOf(fixedContentLength));
}
}
} else if (poster != null) {
/* add Content-Length & POST/PUT data */
synchronized (poster) {
/* close it, so no more data can be added */
poster.close();
requests.set("Content-Length",
String.valueOf(poster.size()));
}
}
if (!chunked) {
if (requests.findValue("Transfer-Encoding") != null) {
requests.remove("Transfer-Encoding");
if (logger.isLoggable(PlatformLogger.Level.WARNING)) {
logger.warning(
"use streaming mode for chunked encoding");
}
}
}
// get applicable cookies based on the uri and request headers
// add them to the existing request headers
setCookieHeader();
setRequests=true;
}
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine(requests.toString());
}
http.writeRequests(requests, poster, streaming());
if (ps.checkError()) {
String proxyHost = http.getProxyHostUsed();
int proxyPort = http.getProxyPortUsed();
disconnectInternal();
if (failedOnce) {
throw new IOException("Error writing to server");
} else { // try once more
failedOnce=true;
if (proxyHost != null) {
setProxiedClient(url, proxyHost, proxyPort);
} else {
setNewClient (url);
}
ps = (PrintStream) http.getOutputStream();
connected=true;
responses = new MessageHeader();
setRequests=false;
writeRequests();
}
}
}
private boolean checkSetHost() {
SecurityManager s = System.getSecurityManager();
if (s != null) {
String name = s.getClass().getName();
if (name.equals("sun.plugin2.applet.AWTAppletSecurityManager") ||
name.equals("sun.plugin2.applet.FXAppletSecurityManager") ||
name.equals("com.sun.javaws.security.JavaWebStartSecurity") ||
name.equals("sun.plugin.security.ActivatorSecurityManager"))
{
int CHECK_SET_HOST = -2;
try {
s.checkConnect(url.toExternalForm(), CHECK_SET_HOST);
} catch (SecurityException ex) {
return false;
}
}
}
return true;
}
private void checkURLFile() {
SecurityManager s = System.getSecurityManager();
if (s != null) {
String name = s.getClass().getName();
if (name.equals("sun.plugin2.applet.AWTAppletSecurityManager") ||
name.equals("sun.plugin2.applet.FXAppletSecurityManager") ||
name.equals("com.sun.javaws.security.JavaWebStartSecurity") ||
name.equals("sun.plugin.security.ActivatorSecurityManager"))
{
int CHECK_SUBPATH = -3;
try {
s.checkConnect(url.toExternalForm(), CHECK_SUBPATH);
} catch (SecurityException ex) {
throw new SecurityException("denied access outside a permitted URL subpath", ex);
}
}
}
}
/**
* Create a new HttpClient object, bypassing the cache of
* HTTP client objects/connections.
*
* @param url the URL being accessed
*/
protected void setNewClient (URL url)
throws IOException {
setNewClient(url, false);
}
/**
* Obtain a HttpsClient object. Use the cached copy if specified.
*
* @param url the URL being accessed
* @param useCache whether the cached connection should be used
* if present
*/
protected void setNewClient (URL url, boolean useCache)
throws IOException {
http = HttpClient.New(url, null, -1, useCache, connectTimeout, this);
http.setReadTimeout(readTimeout);
}
/**
* Create a new HttpClient object, set up so that it uses
* per-instance proxying to the given HTTP proxy. This
* bypasses the cache of HTTP client objects/connections.
*
* @param url the URL being accessed
* @param proxyHost the proxy host to use
* @param proxyPort the proxy port to use
*/
protected void setProxiedClient (URL url, String proxyHost, int proxyPort)
throws IOException {
setProxiedClient(url, proxyHost, proxyPort, false);
}
/**
* Obtain a HttpClient object, set up so that it uses per-instance
* proxying to the given HTTP proxy. Use the cached copy of HTTP
* client objects/connections if specified.
*
* @param url the URL being accessed
* @param proxyHost the proxy host to use
* @param proxyPort the proxy port to use
* @param useCache whether the cached connection should be used
* if present
*/
protected void setProxiedClient (URL url,
String proxyHost, int proxyPort,
boolean useCache)
throws IOException {
proxiedConnect(url, proxyHost, proxyPort, useCache);
}
protected void proxiedConnect(URL url,
String proxyHost, int proxyPort,
boolean useCache)
throws IOException {
http = HttpClient.New (url, proxyHost, proxyPort, useCache,
connectTimeout, this);
http.setReadTimeout(readTimeout);
}
protected HttpURLConnection(URL u, Handler handler)
throws IOException {
// we set proxy == null to distinguish this case with the case
// when per connection proxy is set
this(u, null, handler);
}
public HttpURLConnection(URL u, String host, int port) {
this(u, new Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved(host, port)));
}
/** this constructor is used by other protocol handlers such as ftp
that want to use http to fetch urls on their behalf.*/
public HttpURLConnection(URL u, Proxy p) {
this(u, p, new Handler());
}
protected HttpURLConnection(URL u, Proxy p, Handler handler) {
super(u);
requests = new MessageHeader();
responses = new MessageHeader();
userHeaders = new MessageHeader();
this.handler = handler;
instProxy = p;
if (instProxy instanceof sun.net.ApplicationProxy) {
/* Application set Proxies should not have access to cookies
* in a secure environment unless explicitly allowed. */
try {
cookieHandler = CookieHandler.getDefault();
} catch (SecurityException se) { /* swallow exception */ }
} else {
cookieHandler = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<CookieHandler>() {
public CookieHandler run() {
return CookieHandler.getDefault();
}
});
}
cacheHandler = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<ResponseCache>() {
public ResponseCache run() {
return ResponseCache.getDefault();
}
});
}
/**
* @deprecated. Use java.net.Authenticator.setDefault() instead.
*/
@Deprecated
public static void setDefaultAuthenticator(HttpAuthenticator a) {
defaultAuth = a;
}
/**
* opens a stream allowing redirects only to the same host.
*/
public static InputStream openConnectionCheckRedirects(URLConnection c)
throws IOException
{
boolean redir;
int redirects = 0;
InputStream in;
do {
if (c instanceof HttpURLConnection) {
((HttpURLConnection) c).setInstanceFollowRedirects(false);
}
// We want to open the input stream before
// getting headers, because getHeaderField()
// et al swallow IOExceptions.
in = c.getInputStream();
redir = false;
if (c instanceof HttpURLConnection) {
HttpURLConnection http = (HttpURLConnection) c;
int stat = http.getResponseCode();
if (stat >= 300 && stat <= 307 && stat != 306 &&
stat != HttpURLConnection.HTTP_NOT_MODIFIED) {
URL base = http.getURL();
String loc = http.getHeaderField("Location");
URL target = null;
if (loc != null) {
target = new URL(base, loc);
}
http.disconnect();
if (target == null
|| !base.getProtocol().equals(target.getProtocol())
|| base.getPort() != target.getPort()
|| !hostsEqual(base, target)
|| redirects >= 5)
{
throw new SecurityException("illegal URL redirect");
}
redir = true;
c = target.openConnection();
redirects++;
}
}
} while (redir);
return in;
}
//
// Same as java.net.URL.hostsEqual
//
private static boolean hostsEqual(URL u1, URL u2) {
final String h1 = u1.getHost();
final String h2 = u2.getHost();
if (h1 == null) {
return h2 == null;
} else if (h2 == null) {
return false;
} else if (h1.equalsIgnoreCase(h2)) {
return true;
}
// Have to resolve addresses before comparing, otherwise
// names like tachyon and tachyon.eng would compare different
final boolean result[] = {false};
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
try {
InetAddress a1 = InetAddress.getByName(h1);
InetAddress a2 = InetAddress.getByName(h2);
result[0] = a1.equals(a2);
} catch(UnknownHostException | SecurityException e) {
}
return null;
}
});
return result[0];
}
// overridden in HTTPS subclass
public void connect() throws IOException {
synchronized (this) {
connecting = true;
}
plainConnect();
}
private boolean checkReuseConnection () {
if (connected) {
return true;
}
if (reuseClient != null) {
http = reuseClient;
http.setReadTimeout(getReadTimeout());
http.reuse = false;
reuseClient = null;
connected = true;
return true;
}
return false;
}
private String getHostAndPort(URL url) {
String host = url.getHost();
final String hostarg = host;
try {
// lookup hostname and use IP address if available
host = AccessController.doPrivileged(
new PrivilegedExceptionAction<String>() {
public String run() throws IOException {
InetAddress addr = InetAddress.getByName(hostarg);
return addr.getHostAddress();
}
}
);
} catch (PrivilegedActionException e) {}
int port = url.getPort();
if (port == -1) {
String scheme = url.getProtocol();
if ("http".equals(scheme)) {
return host + ":80";
} else { // scheme must be https
return host + ":443";
}
}
return host + ":" + Integer.toString(port);
}
protected void plainConnect() throws IOException {
synchronized (this) {
if (connected) {
return;
}
}
SocketPermission p = URLtoSocketPermission(this.url);
if (p != null) {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>() {
public Void run() throws IOException {
plainConnect0();
return null;
}
}, null, p
);
} catch (PrivilegedActionException e) {
throw (IOException) e.getException();
}
} else {
// run without additional permission
plainConnect0();
}
}
/**
* if the caller has a URLPermission for connecting to the
* given URL, then return a SocketPermission which permits
* access to that destination. Return null otherwise. The permission
* is cached in a field (which can only be changed by redirects)
*/
SocketPermission URLtoSocketPermission(URL url) throws IOException {
if (socketPermission != null) {
return socketPermission;
}
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
return null;
}
// the permission, which we might grant
SocketPermission newPerm = new SocketPermission(
getHostAndPort(url), "connect"
);
String actions = getRequestMethod()+":" +
getUserSetHeaders().getHeaderNamesInList();
String urlstring = url.getProtocol() + "://" + url.getAuthority()
+ url.getPath();
URLPermission p = new URLPermission(urlstring, actions);
try {
sm.checkPermission(p);
socketPermission = newPerm;
return socketPermission;
} catch (SecurityException e) {
// fall thru
}
return null;
}
protected void plainConnect0() throws IOException {
// try to see if request can be served from local cache
if (cacheHandler != null && getUseCaches()) {
try {
URI uri = ParseUtil.toURI(url);
if (uri != null) {
cachedResponse = cacheHandler.get(uri, getRequestMethod(), requests.getHeaders(EXCLUDE_HEADERS));
if ("https".equalsIgnoreCase(uri.getScheme())
&& !(cachedResponse instanceof SecureCacheResponse)) {
cachedResponse = null;
}
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("Cache Request for " + uri + " / " + getRequestMethod());
logger.finest("From cache: " + (cachedResponse != null ? cachedResponse.toString() : "null"));
}
if (cachedResponse != null) {
cachedHeaders = mapToMessageHeader(cachedResponse.getHeaders());
cachedInputStream = cachedResponse.getBody();
}
}
} catch (IOException ioex) {
// ignore and commence normal connection
}
if (cachedHeaders != null && cachedInputStream != null) {
connected = true;
return;
} else {
cachedResponse = null;
}
}
try {
/* Try to open connections using the following scheme,
* return on the first one that's successful:
* 1) if (instProxy != null)
* connect to instProxy; raise exception if failed
* 2) else use system default ProxySelector
* 3) is 2) fails, make direct connection
*/
if (instProxy == null) { // no instance Proxy is set
/**
* Do we have to use a proxy?
*/
ProxySelector sel =
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<ProxySelector>() {
public ProxySelector run() {
return ProxySelector.getDefault();
}
});
if (sel != null) {
URI uri = sun.net.www.ParseUtil.toURI(url);
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("ProxySelector Request for " + uri);
}
Iterator<Proxy> it = sel.select(uri).iterator();
Proxy p;
while (it.hasNext()) {
p = it.next();
try {
if (!failedOnce) {
http = getNewHttpClient(url, p, connectTimeout);
http.setReadTimeout(readTimeout);
} else {
// make sure to construct new connection if first
// attempt failed
http = getNewHttpClient(url, p, connectTimeout, false);
http.setReadTimeout(readTimeout);
}
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
if (p != null) {
logger.finest("Proxy used: " + p.toString());
}
}
break;
} catch (IOException ioex) {
if (p != Proxy.NO_PROXY) {
sel.connectFailed(uri, p.address(), ioex);
if (!it.hasNext()) {
// fallback to direct connection
http = getNewHttpClient(url, null, connectTimeout, false);
http.setReadTimeout(readTimeout);
break;
}
} else {
throw ioex;
}
continue;
}
}
} else {
// No proxy selector, create http client with no proxy
if (!failedOnce) {
http = getNewHttpClient(url, null, connectTimeout);
http.setReadTimeout(readTimeout);
} else {
// make sure to construct new connection if first
// attempt failed
http = getNewHttpClient(url, null, connectTimeout, false);
http.setReadTimeout(readTimeout);
}
}
} else {
if (!failedOnce) {
http = getNewHttpClient(url, instProxy, connectTimeout);
http.setReadTimeout(readTimeout);
} else {
// make sure to construct new connection if first
// attempt failed
http = getNewHttpClient(url, instProxy, connectTimeout, false);
http.setReadTimeout(readTimeout);
}
}
ps = (PrintStream)http.getOutputStream();
} catch (IOException e) {
throw e;
}
// constructor to HTTP client calls openserver
connected = true;
}
// subclass HttpsClient will overwrite & return an instance of HttpsClient
protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout)
throws IOException {
return HttpClient.New(url, p, connectTimeout, this);
}
// subclass HttpsClient will overwrite & return an instance of HttpsClient
protected HttpClient getNewHttpClient(URL url, Proxy p,
int connectTimeout, boolean useCache)
throws IOException {
return HttpClient.New(url, p, connectTimeout, useCache, this);
}
private void expect100Continue() throws IOException {
// Expect: 100-Continue was set, so check the return code for
// Acceptance
int oldTimeout = http.getReadTimeout();
boolean enforceTimeOut = false;
boolean timedOut = false;
if (oldTimeout <= 0) {
// 5s read timeout in case the server doesn't understand
// Expect: 100-Continue
http.setReadTimeout(5000);
enforceTimeOut = true;
}
try {
http.parseHTTP(responses, pi, this);
} catch (SocketTimeoutException se) {
if (!enforceTimeOut) {
throw se;
}
timedOut = true;
http.setIgnoreContinue(true);
}
if (!timedOut) {
// Can't use getResponseCode() yet
String resp = responses.getValue(0);
// Parse the response which is of the form:
// HTTP/1.1 417 Expectation Failed
// HTTP/1.1 100 Continue
if (resp != null && resp.startsWith("HTTP/")) {
String[] sa = resp.split("\\s+");
responseCode = -1;
try {
// Response code is 2nd token on the line
if (sa.length > 1)
responseCode = Integer.parseInt(sa[1]);
} catch (NumberFormatException numberFormatException) {
}
}
if (responseCode != 100) {
throw new ProtocolException("Server rejected operation");
}
}
http.setReadTimeout(oldTimeout);
responseCode = -1;
responses.reset();
// Proceed
}
/*
* Allowable input/output sequences:
* [interpreted as request entity]
* - get output, [write output,] get input, [read input]
* - get output, [write output]
* [interpreted as GET]
* - get input, [read input]
* Disallowed:
* - get input, [read input,] get output, [write output]
*/
@Override
public synchronized OutputStream getOutputStream() throws IOException {
connecting = true;
SocketPermission p = URLtoSocketPermission(this.url);
if (p != null) {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction<OutputStream>() {
public OutputStream run() throws IOException {
return getOutputStream0();
}
}, null, p
);
} catch (PrivilegedActionException e) {
throw (IOException) e.getException();
}
} else {
return getOutputStream0();
}
}
private synchronized OutputStream getOutputStream0() throws IOException {
try {
if (!doOutput) {
throw new ProtocolException("cannot write to a URLConnection"
+ " if doOutput=false - call setDoOutput(true)");
}
if (method.equals("GET")) {
method = "POST"; // Backward compatibility
}
if ("TRACE".equals(method) && "http".equals(url.getProtocol())) {
throw new ProtocolException("HTTP method TRACE" +
" doesn't support output");
}
// if there's already an input stream open, throw an exception
if (inputStream != null) {
throw new ProtocolException("Cannot write output after reading input.");
}
if (!checkReuseConnection())
connect();
boolean expectContinue = false;
String expects = requests.findValue("Expect");
if ("100-Continue".equalsIgnoreCase(expects) && streaming()) {
http.setIgnoreContinue(false);
expectContinue = true;
}
if (streaming() && strOutputStream == null) {
writeRequests();
}
if (expectContinue) {
expect100Continue();
}
ps = (PrintStream)http.getOutputStream();
if (streaming()) {
if (strOutputStream == null) {
if (chunkLength != -1) { /* chunked */
strOutputStream = new StreamingOutputStream(
new ChunkedOutputStream(ps, chunkLength), -1L);
} else { /* must be fixed content length */
long length = 0L;
if (fixedContentLengthLong != -1) {
length = fixedContentLengthLong;
} else if (fixedContentLength != -1) {
length = fixedContentLength;
}
strOutputStream = new StreamingOutputStream(ps, length);
}
}
return strOutputStream;
} else {
if (poster == null) {
poster = new PosterOutputStream();
}
return poster;
}
} catch (RuntimeException e) {
disconnectInternal();
throw e;
} catch (ProtocolException e) {
// Save the response code which may have been set while enforcing
// the 100-continue. disconnectInternal() forces it to -1
int i = responseCode;
disconnectInternal();
responseCode = i;
throw e;
} catch (IOException e) {
disconnectInternal();
throw e;
}
}
public boolean streaming () {
return (fixedContentLength != -1) || (fixedContentLengthLong != -1) ||
(chunkLength != -1);
}
/*
* get applicable cookies based on the uri and request headers
* add them to the existing request headers
*/
private void setCookieHeader() throws IOException {
if (cookieHandler != null) {
// we only want to capture the user defined Cookies once, as
// they cannot be changed by user code after we are connected,
// only internally.
synchronized (this) {
if (setUserCookies) {
int k = requests.getKey("Cookie");
if (k != -1)
userCookies = requests.getValue(k);
k = requests.getKey("Cookie2");
if (k != -1)
userCookies2 = requests.getValue(k);
setUserCookies = false;
}
}
// remove old Cookie header before setting new one.
requests.remove("Cookie");
requests.remove("Cookie2");
URI uri = ParseUtil.toURI(url);
if (uri != null) {
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
logger.finest("CookieHandler request for " + uri);
}
Map<String, List
Other Java examples (source code examples)Here is a short list of links related to this Java HttpURLConnection.java source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.