< prev index next >

src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java

Print this page
rev 1564 : 7090158: Networking Libraries don't build with javac -Werror
7125055: ContentHandler.getContent API changed in error
Summary: Minor changes to networking java files to remove warnings
Reviewed-by: chegar, weijun, hawtin, alanb
Contributed-by: kurchi.subhra.hazra@oracle.com, sasha_bu@hotmail.com
rev 1571 : 8010297: Missing isLoggable() checks in logging code
Summary: Add isLoggable() checks
Reviewed-by: anthony, mchung, serb
Contributed-by: Laurent Bourges <bourges.laurent@gmail.com>
rev 1572 : 8160838: Better HTTP service
Reviewed-by: ahgross, alanb, michaelm


   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.net.www.protocol.http;
  27 
  28 import java.lang.reflect.Constructor;
  29 import java.net.URL;
  30 import java.net.URLConnection;
  31 import java.net.ProtocolException;







  32 import java.net.HttpRetryException;
  33 import java.net.PasswordAuthentication;
  34 import java.net.Authenticator;
  35 import java.net.InetAddress;
  36 import java.net.UnknownHostException;
  37 import java.net.SocketTimeoutException;

  38 import java.net.Proxy;
  39 import java.net.ProxySelector;
  40 import java.net.URI;
  41 import java.net.InetSocketAddress;
  42 import java.net.CookieHandler;
  43 import java.net.ResponseCache;
  44 import java.net.CacheResponse;
  45 import java.net.SecureCacheResponse;
  46 import java.net.CacheRequest;




  47 import java.net.Authenticator.RequestorType;
  48 import java.io.*;





  49 import java.util.Date;
  50 import java.util.Map;
  51 import java.util.List;
  52 import java.util.Locale;
  53 import java.util.StringTokenizer;
  54 import java.util.Iterator;
  55 import java.util.HashSet;
  56 import java.util.HashMap;
  57 import java.util.Set;

  58 import sun.net.*;
  59 import sun.net.www.*;
  60 import sun.net.www.http.HttpClient;
  61 import sun.net.www.http.PosterOutputStream;
  62 import sun.net.www.http.ChunkedInputStream;
  63 import sun.net.www.http.ChunkedOutputStream;
  64 import sun.net.www.http.HttpCapture;
  65 import java.text.SimpleDateFormat;
  66 import java.util.TimeZone;
  67 import java.net.MalformedURLException;
  68 import java.nio.ByteBuffer;
  69 import static sun.net.www.protocol.http.AuthScheme.BASIC;
  70 import static sun.net.www.protocol.http.AuthScheme.DIGEST;
  71 import static sun.net.www.protocol.http.AuthScheme.NTLM;
  72 import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
  73 import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
  74 import static sun.net.www.protocol.http.AuthScheme.UNKNOWN;
  75 
  76 /**
  77  * A class to represent an HTTP connection to a remote object.
  78  */
  79 
  80 
  81 public class HttpURLConnection extends java.net.HttpURLConnection {
  82 
  83     static final String version;
  84     public static final String userAgent;
  85 
  86     /* max # of allowed re-directs */
  87     static final int defaultmaxRedirects = 20;
  88     static final int maxRedirects;
  89 
  90     /* Not all servers support the (Proxy)-Authentication-Info headers.
  91      * By default, we don't require them to be sent
  92      */
  93     static final boolean validateProxy;
  94     static final boolean validateServer;
  95 








  96     private StreamingOutputStream strOutputStream;
  97     private final static String RETRY_MSG1 =
  98         "cannot retry due to proxy authentication, in streaming mode";
  99     private final static String RETRY_MSG2 =
 100         "cannot retry due to server authentication, in streaming mode";
 101     private final static String RETRY_MSG3 =
 102         "cannot retry due to redirection, in streaming mode";
 103 
 104     /*
 105      * System properties related to error stream handling:
 106      *
 107      * sun.net.http.errorstream.enableBuffering = <boolean>
 108      *
 109      * With the above system property set to true (default is false),
 110      * when the response code is >=400, the HTTP handler will try to
 111      * buffer the response body (up to a certain amount and within a
 112      * time limit). Thus freeing up the underlying socket connection
 113      * for reuse. The rationale behind this is that usually when the
 114      * server responds with a >=400 error (client error or server
 115      * error, such as 404 file not found), the server will send a


 175         "Access-Control-Request-Method",
 176         "Connection", /* close is allowed */
 177         "Content-Length",
 178         //"Cookie",
 179         //"Cookie2",
 180         "Content-Transfer-Encoding",
 181         //"Date",
 182         "Expect",
 183         "Host",
 184         "Keep-Alive",
 185         "Origin",
 186         // "Referer", 
 187         // "TE",
 188         "Trailer",
 189         "Transfer-Encoding",
 190         "Upgrade",
 191         //"User-Agent",
 192         "Via"
 193     };
 194 




















 195     static {
 196         maxRedirects = java.security.AccessController.doPrivileged(
 197             new sun.security.action.GetIntegerAction(
 198                 "http.maxRedirects", defaultmaxRedirects)).intValue();
 199         version = java.security.AccessController.doPrivileged(
 200                     new sun.security.action.GetPropertyAction("java.version"));
 201         String agent = java.security.AccessController.doPrivileged(
 202                     new sun.security.action.GetPropertyAction("http.agent"));
 203         if (agent == null) {
 204             agent = "Java/"+version;
 205         } else {
 206             agent = agent + " Java/"+version;
 207         }
 208         userAgent = agent;








 209         validateProxy = java.security.AccessController.doPrivileged(
 210                 new sun.security.action.GetBooleanAction(
 211                     "http.auth.digest.validateProxy")).booleanValue();
 212         validateServer = java.security.AccessController.doPrivileged(
 213                 new sun.security.action.GetBooleanAction(
 214                     "http.auth.digest.validateServer")).booleanValue();
 215 
 216         enableESBuffer = java.security.AccessController.doPrivileged(
 217                 new sun.security.action.GetBooleanAction(
 218                     "sun.net.http.errorstream.enableBuffering")).booleanValue();
 219         timeout4ESBuffer = java.security.AccessController.doPrivileged(
 220                 new sun.security.action.GetIntegerAction(
 221                     "sun.net.http.errorstream.timeout", 300)).intValue();
 222         if (timeout4ESBuffer <= 0) {
 223             timeout4ESBuffer = 300; // use the default
 224         }
 225 
 226         bufSize4ES = java.security.AccessController.doPrivileged(
 227                 new sun.security.action.GetIntegerAction(
 228                     "sun.net.http.errorstream.bufferSize", 4096)).intValue();
 229         if (bufSize4ES <= 0) {
 230             bufSize4ES = 4096; // use the default
 231         }
 232 
 233         allowRestrictedHeaders = ((Boolean)java.security.AccessController.doPrivileged( 
 234                 new sun.security.action.GetBooleanAction( 
 235                     "sun.net.http.allowRestrictedHeaders"))).booleanValue(); 
 236         if (!allowRestrictedHeaders) { 
 237             restrictedHeaderSet = new HashSet<String>(restrictedHeaders.length); 
 238             for (int i=0; i < restrictedHeaders.length; i++) { 
 239                 restrictedHeaderSet.add(restrictedHeaders[i].toLowerCase()); 
 240             }
 241         } else {
 242             restrictedHeaderSet = null;
 243         }
 244     }
 245 
 246     static final String httpVersion = "HTTP/1.1";
 247     static final String acceptString =
 248         "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2";
 249 
 250     // the following http request headers should NOT have their values
 251     // returned for security reasons.
 252     private static final String[] EXCLUDE_HEADERS = {
 253             "Proxy-Authorization",
 254             "Authorization"
 255     };


 273     protected CacheResponse cachedResponse;
 274     private MessageHeader cachedHeaders;
 275     private InputStream cachedInputStream;
 276 
 277     /* output stream to server */
 278     protected PrintStream ps = null;
 279 
 280 
 281     /* buffered error stream */
 282     private InputStream errorStream = null;
 283 
 284     /* User set Cookies */
 285     private boolean setUserCookies = true;
 286     private String userCookies = null;
 287     private String userCookies2 = null;
 288 
 289     /* We only have a single static authenticator for now.
 290      * REMIND:  backwards compatibility with JDK 1.1.  Should be
 291      * eliminated for JDK 2.0.
 292      */

 293     private static HttpAuthenticator defaultAuth;
 294 
 295     /* all the headers we send
 296      * NOTE: do *NOT* dump out the content of 'requests' in the
 297      * output or stacktrace since it may contain security-sensitive
 298      * headers such as those defined in EXCLUDE_HEADERS.
 299      */
 300     private MessageHeader requests;
 301 
 302     /* The following two fields are only used with Digest Authentication */
 303     String domain;      /* The list of authentication domains */
 304     DigestAuthentication.Parameters digestparams;
 305 
 306     /* Current credentials in use */
 307     AuthenticationInfo  currentProxyCredentials = null;
 308     AuthenticationInfo  currentServerCredentials = null;
 309     boolean             needToCheck = true;
 310     private boolean doingNTLM2ndStage = false; /* doing the 2nd stage of an NTLM server authentication */
 311     private boolean doingNTLMp2ndStage = false; /* doing the 2nd stage of an NTLM proxy authentication */
 312 


 696             } catch (SecurityException se) { /* swallow exception */ }
 697         } else {
 698             cookieHandler = java.security.AccessController.doPrivileged(
 699                 new java.security.PrivilegedAction<CookieHandler>() {
 700                 public CookieHandler run() {
 701                     return CookieHandler.getDefault();
 702                 }
 703             });
 704         }
 705         cacheHandler = java.security.AccessController.doPrivileged(
 706             new java.security.PrivilegedAction<ResponseCache>() {
 707             public ResponseCache run() {
 708                 return ResponseCache.getDefault();
 709             }
 710         });
 711     }
 712 
 713     /**
 714      * @deprecated.  Use java.net.Authenticator.setDefault() instead.
 715      */

 716     public static void setDefaultAuthenticator(HttpAuthenticator a) {
 717         defaultAuth = a;
 718     }
 719 
 720     /**
 721      * opens a stream allowing redirects only to the same host.
 722      */
 723     public static InputStream openConnectionCheckRedirects(URLConnection c)
 724         throws IOException
 725     {
 726         boolean redir;
 727         int redirects = 0;
 728         InputStream in;
 729 
 730         do {
 731             if (c instanceof HttpURLConnection) {
 732                 ((HttpURLConnection) c).setInstanceFollowRedirects(false);
 733             }
 734 
 735             // We want to open the input stream before


1253                 if (HttpCapture.isLoggable("FINE")) {
1254                     HttpCapture.fine(responses.toString());
1255                 }
1256                 inputStream = http.getInputStream();
1257 
1258                 respCode = getResponseCode();
1259                 if (respCode == HTTP_PROXY_AUTH) {
1260                     if (streaming()) {
1261                         disconnectInternal();
1262                         throw new HttpRetryException (
1263                             RETRY_MSG1, HTTP_PROXY_AUTH);
1264                     }
1265 
1266                     // changes: add a 3rd parameter to the constructor of
1267                     // AuthenticationHeader, so that NegotiateAuthentication.
1268                     // isSupported can be tested.
1269                     // The other 2 appearances of "new AuthenticationHeader" is
1270                     // altered in similar ways.
1271 
1272                     AuthenticationHeader authhdr = new AuthenticationHeader (
1273                         "Proxy-Authenticate", responses,
1274                             new HttpCallerInfo(url, http.getProxyHostUsed(),
1275                                 http.getProxyPortUsed())



1276                     );
1277 
1278                     if (!doingNTLMp2ndStage) {
1279                         proxyAuthentication =
1280                             resetProxyAuthentication(proxyAuthentication, authhdr);
1281                         if (proxyAuthentication != null) {
1282                             redirects++;
1283                             disconnectInternal();
1284                             continue;
1285                         }
1286                     } else {
1287                         /* in this case, only one header field will be present */
1288                         String raw = responses.findValue ("Proxy-Authenticate");
1289                         reset ();
1290                         if (!proxyAuthentication.setHeaders(this,
1291                                                         authhdr.headerParser(), raw)) {
1292                             disconnectInternal();
1293                             throw new IOException ("Authentication failure");
1294                         }
1295                         if (serverAuthentication != null && srvHdr != null &&


1452                     }
1453                     http.finished();
1454                     http = null;
1455                     inputStream = new EmptyInputStream();
1456                     connected = false;
1457                 }
1458 
1459                 if (respCode == 200 || respCode == 203 || respCode == 206 ||
1460                     respCode == 300 || respCode == 301 || respCode == 410) {
1461                     if (cacheHandler != null && getUseCaches()) {
1462                         // give cache a chance to save response in cache
1463                         URI uri = ParseUtil.toURI(url);
1464                         if (uri != null) {
1465                             URLConnection uconn = this;
1466                             if ("https".equalsIgnoreCase(uri.getScheme())) {
1467                                 try {
1468                                 // use reflection to get to the public
1469                                 // HttpsURLConnection instance saved in
1470                                 // DelegateHttpsURLConnection
1471                                 uconn = (URLConnection)this.getClass().getField("httpsURLConnection").get(this);
1472                                 } catch (IllegalAccessException iae) {
1473                                     // ignored; use 'this'
1474                                 } catch (NoSuchFieldException nsfe) {
1475                                     // ignored; use 'this'
1476                                 }
1477                             }
1478                             CacheRequest cacheRequest =
1479                                 cacheHandler.put(uri, uconn);
1480                             if (cacheRequest != null && http != null) {
1481                                 http.setCacheRequest(cacheRequest);
1482                                 inputStream = new HttpInputStream(inputStream, cacheRequest);
1483                             }
1484                         }
1485                     }
1486                 }
1487 
1488                 if (!(inputStream instanceof HttpInputStream)) {
1489                     inputStream = new HttpInputStream(inputStream);
1490                 }
1491 
1492                 if (respCode >= 400) {
1493                     if (respCode == 404 || respCode == 410) {
1494                         throw new FileNotFoundException(url.toString());


1618                 // send the "CONNECT" request to establish a tunnel
1619                 // through proxy server
1620                 sendCONNECTRequest();
1621                 responses.reset();
1622 
1623                 // There is no need to track progress in HTTP Tunneling,
1624                 // so ProgressSource is null.
1625                 http.parseHTTP(responses, null, this);
1626 
1627                 /* Log the response to the CONNECT */
1628                 if (HttpCapture.isLoggable("FINE")) {
1629                     HttpCapture.fine(responses.toString());
1630                 }
1631 
1632                 statusLine = responses.getValue(0);
1633                 StringTokenizer st = new StringTokenizer(statusLine);
1634                 st.nextToken();
1635                 respCode = Integer.parseInt(st.nextToken().trim());
1636                 if (respCode == HTTP_PROXY_AUTH) {
1637                     AuthenticationHeader authhdr = new AuthenticationHeader (
1638                         "Proxy-Authenticate", responses,
1639                             new HttpCallerInfo(url, http.getProxyHostUsed(),
1640                                 http.getProxyPortUsed())



1641                     );
1642                     if (!doingNTLMp2ndStage) {
1643                         proxyAuthentication =
1644                             resetProxyAuthentication(proxyAuthentication, authhdr);
1645                         if (proxyAuthentication != null) {
1646                             proxyHost = http.getProxyHostUsed();
1647                             proxyPort = http.getProxyPortUsed();
1648                             disconnectInternal();
1649                             retryTunnel++;
1650                             continue;
1651                         }
1652                     } else {
1653                         String raw = responses.findValue ("Proxy-Authenticate");
1654                         reset ();
1655                         if (!proxyAuthentication.setHeaders(this,
1656                                                 authhdr.headerParser(), raw)) {
1657                             disconnectInternal();
1658                             throw new IOException ("Authentication failure");
1659                         }
1660                         authObj = null;


1736 
1737     /**
1738      * Sets pre-emptive proxy authentication in header
1739      */
1740     private void setPreemptiveProxyAuthentication(MessageHeader requests) {
1741         AuthenticationInfo pauth
1742             = AuthenticationInfo.getProxyAuth(http.getProxyHostUsed(),
1743                                               http.getProxyPortUsed());
1744         if (pauth != null && pauth.supportsPreemptiveAuthorization()) {
1745             // Sets "Proxy-authorization"
1746             requests.set(pauth.getHeaderName(),
1747                                  pauth.getHeaderValue(url,method));
1748             currentProxyCredentials = pauth;
1749         }
1750     }
1751 
1752     /**
1753      * Gets the authentication for an HTTP proxy, and applies it to
1754      * the connection.
1755      */

1756     private AuthenticationInfo getHttpProxyAuthentication (AuthenticationHeader authhdr) {
1757         /* get authorization from authenticator */
1758         AuthenticationInfo ret = null;
1759         String raw = authhdr.raw();
1760         String host = http.getProxyHostUsed();
1761         int port = http.getProxyPortUsed();
1762         if (host != null && authhdr.isPresent()) {
1763             HeaderParser p = authhdr.headerParser();
1764             String realm = p.findValue("realm");
1765             String scheme = authhdr.scheme();
1766             AuthScheme authScheme = UNKNOWN;
1767             if ("basic".equalsIgnoreCase(scheme)) {
1768                 authScheme = BASIC;
1769             } else if ("digest".equalsIgnoreCase(scheme)) {
1770                 authScheme = DIGEST;
1771             } else if ("ntlm".equalsIgnoreCase(scheme)) {
1772                 authScheme = NTLM;
1773                 doingNTLMp2ndStage = true;
1774             } else if ("Kerberos".equalsIgnoreCase(scheme)) {
1775                 authScheme = KERBEROS;


1805                     PasswordAuthentication a =
1806                         privilegedRequestPasswordAuthentication(
1807                                     host, addr, port, "http",
1808                                     realm, scheme, url, RequestorType.PROXY);
1809                     if (a != null) {
1810                         ret = new BasicAuthentication(true, host, port, realm, a);
1811                     }
1812                     break;
1813                 case DIGEST:
1814                     a = privilegedRequestPasswordAuthentication(
1815                                     host, null, port, url.getProtocol(),
1816                                     realm, scheme, url, RequestorType.PROXY);
1817                     if (a != null) {
1818                         DigestAuthentication.Parameters params =
1819                             new DigestAuthentication.Parameters();
1820                         ret = new DigestAuthentication(true, host, port, realm,
1821                                                             scheme, a, params);
1822                     }
1823                     break;
1824                 case NTLM:
1825                     if (NTLMAuthenticationProxy.proxy.supported) {
1826                         /* tryTransparentNTLMProxy will always be true the first
1827                          * time around, but verify that the platform supports it
1828                          * otherwise don't try. */
1829                         if (tryTransparentNTLMProxy) {
1830                             tryTransparentNTLMProxy =
1831                                     NTLMAuthenticationProxy.proxy.supportsTransparentAuth;
1832                             /* If the platform supports transparent authentication
1833                              * then normally it's ok to do transparent auth to a proxy
1834                                          * because we generally trust proxies (chosen by the user)
1835                                          * But not in the case of 305 response where the server
1836                              * chose it. */
1837                             if (tryTransparentNTLMProxy && useProxyResponseCode) {
1838                                 tryTransparentNTLMProxy = false;
1839                             }
1840                         }
1841                         a = null;
1842                         if (tryTransparentNTLMProxy) {
1843                             HttpCapture.finest("Trying Transparent NTLM authentication");
1844                         } else {
1845                             a = privilegedRequestPasswordAuthentication(
1846                                                 host, null, port, url.getProtocol(),
1847                                                 "", scheme, url, RequestorType.PROXY);
1848                         }
1849                         /* If we are not trying transparent authentication then
1850                          * we need to have a PasswordAuthentication instance. For
1851                          * transparent authentication (Windows only) the username
1852                          * and password will be picked up from the current logged
1853                          * on users credentials.
1854                         */
1855                         if (tryTransparentNTLMProxy ||
1856                               (!tryTransparentNTLMProxy && a != null)) {
1857                             ret = NTLMAuthenticationProxy.proxy.create(true, host, port, a);
1858                         }
1859 
1860                         /* set to false so that we do not try again */
1861                         tryTransparentNTLMProxy = false;
1862                     }
1863                     break;
1864                 case NEGOTIATE:
1865                     ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Negotiate"));
1866                     break;
1867                 case KERBEROS:
1868                     ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Kerberos"));
1869                     break;
1870                 case UNKNOWN:

1871                     HttpCapture.finest("Unknown/Unsupported authentication scheme: " + scheme);


1872                 default:
1873                     throw new AssertionError("should not reach here");
1874                 }
1875             }
1876             // For backwards compatibility, we also try defaultAuth
1877             // REMIND:  Get rid of this for JDK2.0.
1878 
1879             if (ret == null && defaultAuth != null
1880                 && defaultAuth.schemeSupported(scheme)) {
1881                 try {
1882                     URL u = new URL("http", host, port, "/");
1883                     String a = defaultAuth.authString(u, scheme, realm);
1884                     if (a != null) {
1885                         ret = new BasicAuthentication (true, host, port, realm, a);
1886                         // not in cache by default - cache on success
1887                     }
1888                 } catch (java.net.MalformedURLException ignored) {
1889                 }
1890             }
1891             if (ret != null) {
1892                 if (!ret.setHeaders(this, p, raw)) {
1893                     ret = null;
1894                 }
1895             }
1896         }
1897         if (HttpCapture.isLoggable("FINER")) {
1898             HttpCapture.finer("Proxy Authentication for " + authhdr.toString() +" returned " + (ret != null ? ret.toString() : "null"));
1899         }
1900         return ret;
1901     }
1902 
1903     /**
1904      * Gets the authentication for an HTTP server, and applies it to
1905      * the connection.
1906      * @param authHdr the AuthenticationHeader which tells what auth scheme is
1907      * prefered.
1908      */

1909     private AuthenticationInfo getServerAuthentication (AuthenticationHeader authhdr) {
1910         /* get authorization from authenticator */
1911         AuthenticationInfo ret = null;
1912         String raw = authhdr.raw();
1913         /* When we get an NTLM auth from cache, don't set any special headers */
1914         if (authhdr.isPresent()) {
1915             HeaderParser p = authhdr.headerParser();
1916             String realm = p.findValue("realm");
1917             String scheme = authhdr.scheme();
1918             AuthScheme authScheme = UNKNOWN;
1919             if ("basic".equalsIgnoreCase(scheme)) {
1920                 authScheme = BASIC;
1921             } else if ("digest".equalsIgnoreCase(scheme)) {
1922                 authScheme = DIGEST;
1923             } else if ("ntlm".equalsIgnoreCase(scheme)) {
1924                 authScheme = NTLM;
1925                 doingNTLM2ndStage = true;
1926             } else if ("Kerberos".equalsIgnoreCase(scheme)) {
1927                 authScheme = KERBEROS;
1928                 doingNTLM2ndStage = true;


1958                     break;
1959                 case BASIC:
1960                     PasswordAuthentication a =
1961                         privilegedRequestPasswordAuthentication(
1962                             url.getHost(), addr, port, url.getProtocol(),
1963                             realm, scheme, url, RequestorType.SERVER);
1964                     if (a != null) {
1965                         ret = new BasicAuthentication(false, url, realm, a);
1966                     }
1967                     break;
1968                 case DIGEST:
1969                     a = privilegedRequestPasswordAuthentication(
1970                             url.getHost(), addr, port, url.getProtocol(),
1971                             realm, scheme, url, RequestorType.SERVER);
1972                     if (a != null) {
1973                         digestparams = new DigestAuthentication.Parameters();
1974                         ret = new DigestAuthentication(false, url, realm, scheme, a, digestparams);
1975                     }
1976                     break;
1977                 case NTLM:
1978                     if (NTLMAuthenticationProxy.proxy.supported) {
1979                         URL url1;
1980                         try {
1981                             url1 = new URL (url, "/"); /* truncate the path */
1982                         } catch (Exception e) {
1983                             url1 = url;
1984                         }
1985 
1986                         /* tryTransparentNTLMServer will always be true the first
1987                          * time around, but verify that the platform supports it
1988                          * otherwise don't try. */
1989                         if (tryTransparentNTLMServer) {
1990                             tryTransparentNTLMServer =
1991                                     NTLMAuthenticationProxy.proxy.supportsTransparentAuth;
1992                         }
1993                         a = null;
1994                         if (tryTransparentNTLMServer) {
1995                             HttpCapture.finest("Trying Transparent NTLM authentication");
1996                         } else {
1997                             a = privilegedRequestPasswordAuthentication(
1998                                 url.getHost(), addr, port, url.getProtocol(),
1999                                 "", scheme, url, RequestorType.SERVER);
2000                         }
2001 
2002                         /* If we are not trying transparent authentication then
2003                          * we need to have a PasswordAuthentication instance. For
2004                          * transparent authentication (Windows only) the username
2005                          * and password will be picked up from the current logged
2006                          * on users credentials.
2007                          */
2008                         if (tryTransparentNTLMServer ||
2009                               (!tryTransparentNTLMServer && a != null)) {
2010                             ret = NTLMAuthenticationProxy.proxy.create(false, url1, a);
2011                         }
2012 
2013                         /* set to false so that we do not try again */
2014                         tryTransparentNTLMServer = false;
2015                     }
2016                     break;
2017                 case UNKNOWN:

2018                     HttpCapture.finest("Unknown/Unsupported authentication scheme: " + scheme);


2019                 default:
2020                     throw new AssertionError("should not reach here");
2021                 }
2022             }
2023 
2024             // For backwards compatibility, we also try defaultAuth
2025             // REMIND:  Get rid of this for JDK2.0.
2026 
2027             if (ret == null && defaultAuth != null
2028                 && defaultAuth.schemeSupported(scheme)) {
2029                 String a = defaultAuth.authString(url, scheme, realm);
2030                 if (a != null) {
2031                     ret = new BasicAuthentication (false, url, realm, a);
2032                     // not in cache by default - cache on success
2033                 }
2034             }
2035 
2036             if (ret != null ) {
2037                 if (!ret.setHeaders(this, p, raw)) {
2038                     ret = null;


2513      * of Strings that represents the corresponding
2514      * field values.
2515      *
2516      * @return  a Map of the general request properties for this connection.
2517      * @throws IllegalStateException if already connected
2518      * @since 1.4
2519      */
2520     @Override
2521     public synchronized Map<String, List<String>> getRequestProperties() {
2522         if (connected)
2523             throw new IllegalStateException("Already connected");
2524 
2525         // exclude headers containing security-sensitive info
2526         if (setUserCookies) {
2527             return requests.getHeaders(EXCLUDE_HEADERS);
2528         }
2529         /*
2530          * The cookies in the requests message headers may have
2531          * been modified. Use the saved user cookies instead.
2532          */
2533         Map userCookiesMap = null;
2534         if (userCookies != null || userCookies2 != null) {
2535             userCookiesMap = new HashMap();
2536             if (userCookies != null) {
2537                 userCookiesMap.put("Cookie", userCookies);
2538             }
2539             if (userCookies2 != null) {
2540                 userCookiesMap.put("Cookie2", userCookies2);
2541             }
2542         }
2543         return requests.filterAndAddHeaders(EXCLUDE_HEADERS2, userCookiesMap);
2544     }
2545 
2546     @Override
2547     public void setConnectTimeout(int timeout) {
2548         if (timeout < 0)
2549             throw new IllegalArgumentException("timeouts can't be negative");
2550         connectTimeout = timeout;
2551     }
2552 
2553 
2554     /**
2555      * Returns setting for connect timeout.
2556      * <p>
2557      * 0 return implies that the option is disabled
2558      * (i.e., timeout of infinity).
2559      *
2560      * @return an <code>int</code> that indicates the connect timeout




   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.net.www.protocol.http;
  27 
  28 import java.lang.reflect.Constructor;
  29 import java.io.FileNotFoundException;
  30 import java.io.FilterInputStream;
  31 import java.io.FilterOutputStream;
  32 import java.io.InputStream;
  33 import java.io.IOException;
  34 import java.io.OutputStream;
  35 import java.io.PrintStream;
  36 import java.net.CacheResponse;
  37 import java.net.CacheRequest;
  38 import java.net.CookieHandler;
  39 import java.net.HttpRetryException;
  40 import java.net.PasswordAuthentication;
  41 import java.net.Authenticator;
  42 import java.net.InetAddress;
  43 import java.net.InetSocketAddress;
  44 import java.net.MalformedURLException;
  45 import java.net.ProtocolException;
  46 import java.net.Proxy;
  47 import java.net.ProxySelector;



  48 import java.net.ResponseCache;

  49 import java.net.SecureCacheResponse;
  50 import java.net.SocketTimeoutException;
  51 import java.net.UnknownHostException;
  52 import java.net.URI;
  53 import java.net.URL;
  54 import java.net.URLConnection;
  55 import java.net.Authenticator.RequestorType;
  56 import java.nio.ByteBuffer;
  57 import java.security.AccessController;
  58 import java.security.PrivilegedAction;
  59 import java.text.SimpleDateFormat;
  60 import java.util.Arrays;
  61 import java.util.Collections;
  62 import java.util.Date;
  63 import java.util.Map;
  64 import java.util.List;
  65 import java.util.Locale;
  66 import java.util.StringTokenizer;
  67 import java.util.Iterator;
  68 import java.util.HashSet;
  69 import java.util.HashMap;
  70 import java.util.Set;
  71 import java.util.TimeZone;
  72 import sun.net.*;
  73 import sun.net.www.*;
  74 import sun.net.www.http.HttpClient;
  75 import sun.net.www.http.PosterOutputStream;
  76 import sun.net.www.http.ChunkedInputStream;
  77 import sun.net.www.http.ChunkedOutputStream;
  78 import sun.net.www.http.HttpCapture;




  79 import static sun.net.www.protocol.http.AuthScheme.BASIC;
  80 import static sun.net.www.protocol.http.AuthScheme.DIGEST;
  81 import static sun.net.www.protocol.http.AuthScheme.NTLM;
  82 import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
  83 import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
  84 import static sun.net.www.protocol.http.AuthScheme.UNKNOWN;
  85 
  86 /**
  87  * A class to represent an HTTP connection to a remote object.
  88  */
  89 
  90 
  91 public class HttpURLConnection extends java.net.HttpURLConnection {
  92 
  93     static final String version;
  94     public static final String userAgent;
  95 
  96     /* max # of allowed re-directs */
  97     static final int defaultmaxRedirects = 20;
  98     static final int maxRedirects;
  99 
 100     /* Not all servers support the (Proxy)-Authentication-Info headers.
 101      * By default, we don't require them to be sent
 102      */
 103     static final boolean validateProxy;
 104     static final boolean validateServer;
 105 
 106     /** A, possibly empty, set of authentication schemes that are disabled
 107      *  when proxying plain HTTP ( not HTTPS ). */
 108     static final Set<String> disabledProxyingSchemes;
 109 
 110     /** A, possibly empty, set of authentication schemes that are disabled
 111      *  when setting up a tunnel for HTTPS ( HTTP CONNECT ). */
 112     static final Set<String> disabledTunnelingSchemes;
 113 
 114     private StreamingOutputStream strOutputStream;
 115     private final static String RETRY_MSG1 =
 116         "cannot retry due to proxy authentication, in streaming mode";
 117     private final static String RETRY_MSG2 =
 118         "cannot retry due to server authentication, in streaming mode";
 119     private final static String RETRY_MSG3 =
 120         "cannot retry due to redirection, in streaming mode";
 121 
 122     /*
 123      * System properties related to error stream handling:
 124      *
 125      * sun.net.http.errorstream.enableBuffering = <boolean>
 126      *
 127      * With the above system property set to true (default is false),
 128      * when the response code is >=400, the HTTP handler will try to
 129      * buffer the response body (up to a certain amount and within a
 130      * time limit). Thus freeing up the underlying socket connection
 131      * for reuse. The rationale behind this is that usually when the
 132      * server responds with a >=400 error (client error or server
 133      * error, such as 404 file not found), the server will send a


 193         "Access-Control-Request-Method",
 194         "Connection", /* close is allowed */
 195         "Content-Length",
 196         //"Cookie",
 197         //"Cookie2",
 198         "Content-Transfer-Encoding",
 199         //"Date",
 200         "Expect",
 201         "Host",
 202         "Keep-Alive",
 203         "Origin",
 204         // "Referer", 
 205         // "TE",
 206         "Trailer",
 207         "Transfer-Encoding",
 208         "Upgrade",
 209         //"User-Agent",
 210         "Via"
 211     };
 212 
 213     private static String getNetProperty(final String name) {
 214         return AccessController.doPrivileged(new PrivilegedAction<String>() {
 215                 @Override
 216                 public String run() {
 217                     return NetProperties.get(name);
 218                 }
 219             });
 220     }
 221 
 222     private static Set<String> schemesListToSet(String list) {
 223         if (list == null || list.isEmpty())
 224             return Collections.<String>emptySet();
 225 
 226         Set<String> s = new HashSet<String>();
 227         String[] parts = list.split("\\s*,\\s*");
 228         for (String part : parts)
 229             s.add(part.toLowerCase(Locale.ROOT));
 230         return s;
 231     }
 232 
 233     static {
 234         maxRedirects = java.security.AccessController.doPrivileged(
 235             new sun.security.action.GetIntegerAction(
 236                 "http.maxRedirects", defaultmaxRedirects)).intValue();
 237         version = java.security.AccessController.doPrivileged(
 238                     new sun.security.action.GetPropertyAction("java.version"));
 239         String agent = java.security.AccessController.doPrivileged(
 240                     new sun.security.action.GetPropertyAction("http.agent"));
 241         if (agent == null) {
 242             agent = "Java/"+version;
 243         } else {
 244             agent = agent + " Java/"+version;
 245         }
 246         userAgent = agent;
 247 
 248         // A set of net properties to control the use of authentication schemes
 249         // when proxing/tunneling.
 250         String p = getNetProperty("jdk.http.auth.tunneling.disabledSchemes");
 251         disabledTunnelingSchemes = schemesListToSet(p);
 252         p = getNetProperty("jdk.http.auth.proxying.disabledSchemes");
 253         disabledProxyingSchemes = schemesListToSet(p);
 254 
 255         validateProxy = java.security.AccessController.doPrivileged(
 256                 new sun.security.action.GetBooleanAction(
 257                     "http.auth.digest.validateProxy")).booleanValue();
 258         validateServer = java.security.AccessController.doPrivileged(
 259                 new sun.security.action.GetBooleanAction(
 260                     "http.auth.digest.validateServer")).booleanValue();
 261 
 262         enableESBuffer = java.security.AccessController.doPrivileged(
 263                 new sun.security.action.GetBooleanAction(
 264                     "sun.net.http.errorstream.enableBuffering")).booleanValue();
 265         timeout4ESBuffer = java.security.AccessController.doPrivileged(
 266                 new sun.security.action.GetIntegerAction(
 267                     "sun.net.http.errorstream.timeout", 300)).intValue();
 268         if (timeout4ESBuffer <= 0) {
 269             timeout4ESBuffer = 300; // use the default
 270         }
 271 
 272         bufSize4ES = java.security.AccessController.doPrivileged(
 273                 new sun.security.action.GetIntegerAction(
 274                     "sun.net.http.errorstream.bufferSize", 4096)).intValue();
 275         if (bufSize4ES <= 0) {
 276             bufSize4ES = 4096; // use the default
 277         }
 278 
 279         allowRestrictedHeaders = java.security.AccessController.doPrivileged(
 280                 new sun.security.action.GetBooleanAction( 
 281                     "sun.net.http.allowRestrictedHeaders")).booleanValue();
 282         if (!allowRestrictedHeaders) { 
 283             restrictedHeaderSet = new HashSet<String>(restrictedHeaders.length); 
 284             for (int i=0; i < restrictedHeaders.length; i++) { 
 285                 restrictedHeaderSet.add(restrictedHeaders[i].toLowerCase()); 
 286             }
 287         } else {
 288             restrictedHeaderSet = null;
 289         }
 290     }
 291 
 292     static final String httpVersion = "HTTP/1.1";
 293     static final String acceptString =
 294         "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2";
 295 
 296     // the following http request headers should NOT have their values
 297     // returned for security reasons.
 298     private static final String[] EXCLUDE_HEADERS = {
 299             "Proxy-Authorization",
 300             "Authorization"
 301     };


 319     protected CacheResponse cachedResponse;
 320     private MessageHeader cachedHeaders;
 321     private InputStream cachedInputStream;
 322 
 323     /* output stream to server */
 324     protected PrintStream ps = null;
 325 
 326 
 327     /* buffered error stream */
 328     private InputStream errorStream = null;
 329 
 330     /* User set Cookies */
 331     private boolean setUserCookies = true;
 332     private String userCookies = null;
 333     private String userCookies2 = null;
 334 
 335     /* We only have a single static authenticator for now.
 336      * REMIND:  backwards compatibility with JDK 1.1.  Should be
 337      * eliminated for JDK 2.0.
 338      */
 339     @Deprecated
 340     private static HttpAuthenticator defaultAuth;
 341 
 342     /* all the headers we send
 343      * NOTE: do *NOT* dump out the content of 'requests' in the
 344      * output or stacktrace since it may contain security-sensitive
 345      * headers such as those defined in EXCLUDE_HEADERS.
 346      */
 347     private MessageHeader requests;
 348 
 349     /* The following two fields are only used with Digest Authentication */
 350     String domain;      /* The list of authentication domains */
 351     DigestAuthentication.Parameters digestparams;
 352 
 353     /* Current credentials in use */
 354     AuthenticationInfo  currentProxyCredentials = null;
 355     AuthenticationInfo  currentServerCredentials = null;
 356     boolean             needToCheck = true;
 357     private boolean doingNTLM2ndStage = false; /* doing the 2nd stage of an NTLM server authentication */
 358     private boolean doingNTLMp2ndStage = false; /* doing the 2nd stage of an NTLM proxy authentication */
 359 


 743             } catch (SecurityException se) { /* swallow exception */ }
 744         } else {
 745             cookieHandler = java.security.AccessController.doPrivileged(
 746                 new java.security.PrivilegedAction<CookieHandler>() {
 747                 public CookieHandler run() {
 748                     return CookieHandler.getDefault();
 749                 }
 750             });
 751         }
 752         cacheHandler = java.security.AccessController.doPrivileged(
 753             new java.security.PrivilegedAction<ResponseCache>() {
 754             public ResponseCache run() {
 755                 return ResponseCache.getDefault();
 756             }
 757         });
 758     }
 759 
 760     /**
 761      * @deprecated.  Use java.net.Authenticator.setDefault() instead.
 762      */
 763     @Deprecated
 764     public static void setDefaultAuthenticator(HttpAuthenticator a) {
 765         defaultAuth = a;
 766     }
 767 
 768     /**
 769      * opens a stream allowing redirects only to the same host.
 770      */
 771     public static InputStream openConnectionCheckRedirects(URLConnection c)
 772         throws IOException
 773     {
 774         boolean redir;
 775         int redirects = 0;
 776         InputStream in;
 777 
 778         do {
 779             if (c instanceof HttpURLConnection) {
 780                 ((HttpURLConnection) c).setInstanceFollowRedirects(false);
 781             }
 782 
 783             // We want to open the input stream before


1301                 if (HttpCapture.isLoggable("FINE")) {
1302                     HttpCapture.fine(responses.toString());
1303                 }
1304                 inputStream = http.getInputStream();
1305 
1306                 respCode = getResponseCode();
1307                 if (respCode == HTTP_PROXY_AUTH) {
1308                     if (streaming()) {
1309                         disconnectInternal();
1310                         throw new HttpRetryException (
1311                             RETRY_MSG1, HTTP_PROXY_AUTH);
1312                     }
1313 
1314                     // changes: add a 3rd parameter to the constructor of
1315                     // AuthenticationHeader, so that NegotiateAuthentication.
1316                     // isSupported can be tested.
1317                     // The other 2 appearances of "new AuthenticationHeader" is
1318                     // altered in similar ways.
1319 
1320                     AuthenticationHeader authhdr = new AuthenticationHeader (
1321                             "Proxy-Authenticate",
1322                             responses,
1323                             new HttpCallerInfo(url,
1324                                                http.getProxyHostUsed(),
1325                                                http.getProxyPortUsed()),
1326                             disabledProxyingSchemes
1327                     );
1328 
1329                     if (!doingNTLMp2ndStage) {
1330                         proxyAuthentication =
1331                             resetProxyAuthentication(proxyAuthentication, authhdr);
1332                         if (proxyAuthentication != null) {
1333                             redirects++;
1334                             disconnectInternal();
1335                             continue;
1336                         }
1337                     } else {
1338                         /* in this case, only one header field will be present */
1339                         String raw = responses.findValue ("Proxy-Authenticate");
1340                         reset ();
1341                         if (!proxyAuthentication.setHeaders(this,
1342                                                         authhdr.headerParser(), raw)) {
1343                             disconnectInternal();
1344                             throw new IOException ("Authentication failure");
1345                         }
1346                         if (serverAuthentication != null && srvHdr != null &&


1503                     }
1504                     http.finished();
1505                     http = null;
1506                     inputStream = new EmptyInputStream();
1507                     connected = false;
1508                 }
1509 
1510                 if (respCode == 200 || respCode == 203 || respCode == 206 ||
1511                     respCode == 300 || respCode == 301 || respCode == 410) {
1512                     if (cacheHandler != null && getUseCaches()) {
1513                         // give cache a chance to save response in cache
1514                         URI uri = ParseUtil.toURI(url);
1515                         if (uri != null) {
1516                             URLConnection uconn = this;
1517                             if ("https".equalsIgnoreCase(uri.getScheme())) {
1518                                 try {
1519                                 // use reflection to get to the public
1520                                 // HttpsURLConnection instance saved in
1521                                 // DelegateHttpsURLConnection
1522                                 uconn = (URLConnection)this.getClass().getField("httpsURLConnection").get(this);
1523                                 } catch (IllegalAccessException e) {
1524                                     // ignored; use 'this'
1525                                 } catch (NoSuchFieldException e) {
1526                                     // ignored; use 'this'
1527                                 }
1528                             }
1529                             CacheRequest cacheRequest =
1530                                 cacheHandler.put(uri, uconn);
1531                             if (cacheRequest != null && http != null) {
1532                                 http.setCacheRequest(cacheRequest);
1533                                 inputStream = new HttpInputStream(inputStream, cacheRequest);
1534                             }
1535                         }
1536                     }
1537                 }
1538 
1539                 if (!(inputStream instanceof HttpInputStream)) {
1540                     inputStream = new HttpInputStream(inputStream);
1541                 }
1542 
1543                 if (respCode >= 400) {
1544                     if (respCode == 404 || respCode == 410) {
1545                         throw new FileNotFoundException(url.toString());


1669                 // send the "CONNECT" request to establish a tunnel
1670                 // through proxy server
1671                 sendCONNECTRequest();
1672                 responses.reset();
1673 
1674                 // There is no need to track progress in HTTP Tunneling,
1675                 // so ProgressSource is null.
1676                 http.parseHTTP(responses, null, this);
1677 
1678                 /* Log the response to the CONNECT */
1679                 if (HttpCapture.isLoggable("FINE")) {
1680                     HttpCapture.fine(responses.toString());
1681                 }
1682 
1683                 statusLine = responses.getValue(0);
1684                 StringTokenizer st = new StringTokenizer(statusLine);
1685                 st.nextToken();
1686                 respCode = Integer.parseInt(st.nextToken().trim());
1687                 if (respCode == HTTP_PROXY_AUTH) {
1688                     AuthenticationHeader authhdr = new AuthenticationHeader (
1689                             "Proxy-Authenticate",
1690                             responses,
1691                             new HttpCallerInfo(url,
1692                                                http.getProxyHostUsed(),
1693                                                http.getProxyPortUsed()),
1694                             disabledTunnelingSchemes
1695                     );
1696                     if (!doingNTLMp2ndStage) {
1697                         proxyAuthentication =
1698                             resetProxyAuthentication(proxyAuthentication, authhdr);
1699                         if (proxyAuthentication != null) {
1700                             proxyHost = http.getProxyHostUsed();
1701                             proxyPort = http.getProxyPortUsed();
1702                             disconnectInternal();
1703                             retryTunnel++;
1704                             continue;
1705                         }
1706                     } else {
1707                         String raw = responses.findValue ("Proxy-Authenticate");
1708                         reset ();
1709                         if (!proxyAuthentication.setHeaders(this,
1710                                                 authhdr.headerParser(), raw)) {
1711                             disconnectInternal();
1712                             throw new IOException ("Authentication failure");
1713                         }
1714                         authObj = null;


1790 
1791     /**
1792      * Sets pre-emptive proxy authentication in header
1793      */
1794     private void setPreemptiveProxyAuthentication(MessageHeader requests) {
1795         AuthenticationInfo pauth
1796             = AuthenticationInfo.getProxyAuth(http.getProxyHostUsed(),
1797                                               http.getProxyPortUsed());
1798         if (pauth != null && pauth.supportsPreemptiveAuthorization()) {
1799             // Sets "Proxy-authorization"
1800             requests.set(pauth.getHeaderName(),
1801                                  pauth.getHeaderValue(url,method));
1802             currentProxyCredentials = pauth;
1803         }
1804     }
1805 
1806     /**
1807      * Gets the authentication for an HTTP proxy, and applies it to
1808      * the connection.
1809      */
1810     @SuppressWarnings("fallthrough")
1811     private AuthenticationInfo getHttpProxyAuthentication (AuthenticationHeader authhdr) {
1812         /* get authorization from authenticator */
1813         AuthenticationInfo ret = null;
1814         String raw = authhdr.raw();
1815         String host = http.getProxyHostUsed();
1816         int port = http.getProxyPortUsed();
1817         if (host != null && authhdr.isPresent()) {
1818             HeaderParser p = authhdr.headerParser();
1819             String realm = p.findValue("realm");
1820             String scheme = authhdr.scheme();
1821             AuthScheme authScheme = UNKNOWN;
1822             if ("basic".equalsIgnoreCase(scheme)) {
1823                 authScheme = BASIC;
1824             } else if ("digest".equalsIgnoreCase(scheme)) {
1825                 authScheme = DIGEST;
1826             } else if ("ntlm".equalsIgnoreCase(scheme)) {
1827                 authScheme = NTLM;
1828                 doingNTLMp2ndStage = true;
1829             } else if ("Kerberos".equalsIgnoreCase(scheme)) {
1830                 authScheme = KERBEROS;


1860                     PasswordAuthentication a =
1861                         privilegedRequestPasswordAuthentication(
1862                                     host, addr, port, "http",
1863                                     realm, scheme, url, RequestorType.PROXY);
1864                     if (a != null) {
1865                         ret = new BasicAuthentication(true, host, port, realm, a);
1866                     }
1867                     break;
1868                 case DIGEST:
1869                     a = privilegedRequestPasswordAuthentication(
1870                                     host, null, port, url.getProtocol(),
1871                                     realm, scheme, url, RequestorType.PROXY);
1872                     if (a != null) {
1873                         DigestAuthentication.Parameters params =
1874                             new DigestAuthentication.Parameters();
1875                         ret = new DigestAuthentication(true, host, port, realm,
1876                                                             scheme, a, params);
1877                     }
1878                     break;
1879                 case NTLM:
1880                     if (NTLMAuthenticationProxy.supported) {
1881                         /* tryTransparentNTLMProxy will always be true the first
1882                          * time around, but verify that the platform supports it
1883                          * otherwise don't try. */
1884                         if (tryTransparentNTLMProxy) {
1885                             tryTransparentNTLMProxy =
1886                                     NTLMAuthenticationProxy.supportsTransparentAuth;
1887                             /* If the platform supports transparent authentication
1888                              * then normally it's ok to do transparent auth to a proxy
1889                                          * because we generally trust proxies (chosen by the user)
1890                                          * But not in the case of 305 response where the server
1891                              * chose it. */
1892                             if (tryTransparentNTLMProxy && useProxyResponseCode) {
1893                                 tryTransparentNTLMProxy = false;
1894                             }
1895                         }
1896                         a = null;
1897                         if (tryTransparentNTLMProxy) {
1898                             HttpCapture.finest("Trying Transparent NTLM authentication");
1899                         } else {
1900                             a = privilegedRequestPasswordAuthentication(
1901                                                 host, null, port, url.getProtocol(),
1902                                                 "", scheme, url, RequestorType.PROXY);
1903                         }
1904                         /* If we are not trying transparent authentication then
1905                          * we need to have a PasswordAuthentication instance. For
1906                          * transparent authentication (Windows only) the username
1907                          * and password will be picked up from the current logged
1908                          * on users credentials.
1909                         */
1910                         if (tryTransparentNTLMProxy ||
1911                               (!tryTransparentNTLMProxy && a != null)) {
1912                             ret = NTLMAuthenticationProxy.proxy.create(true, host, port, a);
1913                         }
1914 
1915                         /* set to false so that we do not try again */
1916                         tryTransparentNTLMProxy = false;
1917                     }
1918                     break;
1919                 case NEGOTIATE:
1920                     ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Negotiate"));
1921                     break;
1922                 case KERBEROS:
1923                     ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Kerberos"));
1924                     break;
1925                 case UNKNOWN:
1926                     if (HttpCapture.isLoggable("FINEST")) {
1927                         HttpCapture.finest("Unknown/Unsupported authentication scheme: " + scheme);
1928                     }
1929                 /*fall through*/
1930                 default:
1931                     throw new AssertionError("should not reach here");
1932                 }
1933             }
1934             // For backwards compatibility, we also try defaultAuth
1935             // REMIND:  Get rid of this for JDK2.0.
1936 
1937             if (ret == null && defaultAuth != null
1938                 && defaultAuth.schemeSupported(scheme)) {
1939                 try {
1940                     URL u = new URL("http", host, port, "/");
1941                     String a = defaultAuth.authString(u, scheme, realm);
1942                     if (a != null) {
1943                         ret = new BasicAuthentication (true, host, port, realm, a);
1944                         // not in cache by default - cache on success
1945                     }
1946                 } catch (java.net.MalformedURLException ignored) {
1947                 }
1948             }
1949             if (ret != null) {
1950                 if (!ret.setHeaders(this, p, raw)) {
1951                     ret = null;
1952                 }
1953             }
1954         }
1955         if (HttpCapture.isLoggable("FINER")) {
1956             HttpCapture.finer("Proxy Authentication for " + authhdr.toString() +" returned " + (ret != null ? ret.toString() : "null"));
1957         }
1958         return ret;
1959     }
1960 
1961     /**
1962      * Gets the authentication for an HTTP server, and applies it to
1963      * the connection.
1964      * @param authHdr the AuthenticationHeader which tells what auth scheme is
1965      * prefered.
1966      */
1967     @SuppressWarnings("fallthrough")
1968     private AuthenticationInfo getServerAuthentication (AuthenticationHeader authhdr) {
1969         /* get authorization from authenticator */
1970         AuthenticationInfo ret = null;
1971         String raw = authhdr.raw();
1972         /* When we get an NTLM auth from cache, don't set any special headers */
1973         if (authhdr.isPresent()) {
1974             HeaderParser p = authhdr.headerParser();
1975             String realm = p.findValue("realm");
1976             String scheme = authhdr.scheme();
1977             AuthScheme authScheme = UNKNOWN;
1978             if ("basic".equalsIgnoreCase(scheme)) {
1979                 authScheme = BASIC;
1980             } else if ("digest".equalsIgnoreCase(scheme)) {
1981                 authScheme = DIGEST;
1982             } else if ("ntlm".equalsIgnoreCase(scheme)) {
1983                 authScheme = NTLM;
1984                 doingNTLM2ndStage = true;
1985             } else if ("Kerberos".equalsIgnoreCase(scheme)) {
1986                 authScheme = KERBEROS;
1987                 doingNTLM2ndStage = true;


2017                     break;
2018                 case BASIC:
2019                     PasswordAuthentication a =
2020                         privilegedRequestPasswordAuthentication(
2021                             url.getHost(), addr, port, url.getProtocol(),
2022                             realm, scheme, url, RequestorType.SERVER);
2023                     if (a != null) {
2024                         ret = new BasicAuthentication(false, url, realm, a);
2025                     }
2026                     break;
2027                 case DIGEST:
2028                     a = privilegedRequestPasswordAuthentication(
2029                             url.getHost(), addr, port, url.getProtocol(),
2030                             realm, scheme, url, RequestorType.SERVER);
2031                     if (a != null) {
2032                         digestparams = new DigestAuthentication.Parameters();
2033                         ret = new DigestAuthentication(false, url, realm, scheme, a, digestparams);
2034                     }
2035                     break;
2036                 case NTLM:
2037                     if (NTLMAuthenticationProxy.supported) {
2038                         URL url1;
2039                         try {
2040                             url1 = new URL (url, "/"); /* truncate the path */
2041                         } catch (Exception e) {
2042                             url1 = url;
2043                         }
2044 
2045                         /* tryTransparentNTLMServer will always be true the first
2046                          * time around, but verify that the platform supports it
2047                          * otherwise don't try. */
2048                         if (tryTransparentNTLMServer) {
2049                             tryTransparentNTLMServer =
2050                                     NTLMAuthenticationProxy.supportsTransparentAuth;
2051                         }
2052                         a = null;
2053                         if (tryTransparentNTLMServer) {
2054                             HttpCapture.finest("Trying Transparent NTLM authentication");
2055                         } else {
2056                             a = privilegedRequestPasswordAuthentication(
2057                                 url.getHost(), addr, port, url.getProtocol(),
2058                                 "", scheme, url, RequestorType.SERVER);
2059                         }
2060 
2061                         /* If we are not trying transparent authentication then
2062                          * we need to have a PasswordAuthentication instance. For
2063                          * transparent authentication (Windows only) the username
2064                          * and password will be picked up from the current logged
2065                          * on users credentials.
2066                          */
2067                         if (tryTransparentNTLMServer ||
2068                               (!tryTransparentNTLMServer && a != null)) {
2069                             ret = NTLMAuthenticationProxy.proxy.create(false, url1, a);
2070                         }
2071 
2072                         /* set to false so that we do not try again */
2073                         tryTransparentNTLMServer = false;
2074                     }
2075                     break;
2076                 case UNKNOWN:
2077                     if (HttpCapture.isLoggable("FINEST")) {
2078                         HttpCapture.finest("Unknown/Unsupported authentication scheme: " + scheme);
2079                     }
2080                 /*fall through*/
2081                 default:
2082                     throw new AssertionError("should not reach here");
2083                 }
2084             }
2085 
2086             // For backwards compatibility, we also try defaultAuth
2087             // REMIND:  Get rid of this for JDK2.0.
2088 
2089             if (ret == null && defaultAuth != null
2090                 && defaultAuth.schemeSupported(scheme)) {
2091                 String a = defaultAuth.authString(url, scheme, realm);
2092                 if (a != null) {
2093                     ret = new BasicAuthentication (false, url, realm, a);
2094                     // not in cache by default - cache on success
2095                 }
2096             }
2097 
2098             if (ret != null ) {
2099                 if (!ret.setHeaders(this, p, raw)) {
2100                     ret = null;


2575      * of Strings that represents the corresponding
2576      * field values.
2577      *
2578      * @return  a Map of the general request properties for this connection.
2579      * @throws IllegalStateException if already connected
2580      * @since 1.4
2581      */
2582     @Override
2583     public synchronized Map<String, List<String>> getRequestProperties() {
2584         if (connected)
2585             throw new IllegalStateException("Already connected");
2586 
2587         // exclude headers containing security-sensitive info
2588         if (setUserCookies) {
2589             return requests.getHeaders(EXCLUDE_HEADERS);
2590         }
2591         /*
2592          * The cookies in the requests message headers may have
2593          * been modified. Use the saved user cookies instead.
2594          */
2595         Map<String, List<String>> userCookiesMap = null;
2596         if (userCookies != null || userCookies2 != null) {
2597             userCookiesMap = new HashMap<String, List<String>>();
2598             if (userCookies != null) {
2599                 userCookiesMap.put("Cookie", Arrays.asList(userCookies));
2600             }
2601             if (userCookies2 != null) {
2602                 userCookiesMap.put("Cookie2", Arrays.asList(userCookies2));
2603             }
2604         }
2605         return requests.filterAndAddHeaders(EXCLUDE_HEADERS2, userCookiesMap);
2606     }
2607 
2608     @Override
2609     public void setConnectTimeout(int timeout) {
2610         if (timeout < 0)
2611             throw new IllegalArgumentException("timeouts can't be negative");
2612         connectTimeout = timeout;
2613     }
2614 
2615 
2616     /**
2617      * Returns setting for connect timeout.
2618      * <p>
2619      * 0 return implies that the option is disabled
2620      * (i.e., timeout of infinity).
2621      *
2622      * @return an <code>int</code> that indicates the connect timeout


< prev index next >