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
|