73 |
73 |
74 public class HttpURLConnection extends java.net.HttpURLConnection { |
74 public class HttpURLConnection extends java.net.HttpURLConnection { |
75 |
75 |
76 private static Logger logger = Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection"); |
76 private static Logger logger = Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection"); |
77 |
77 |
|
78 static String HTTP_CONNECT = "CONNECT"; |
|
79 |
78 static final String version; |
80 static final String version; |
79 public static final String userAgent; |
81 public static final String userAgent; |
80 |
82 |
81 /* max # of allowed re-directs */ |
83 /* max # of allowed re-directs */ |
82 static final int defaultmaxRedirects = 20; |
84 static final int defaultmaxRedirects = 20; |
264 private Exception rememberedException = null; |
266 private Exception rememberedException = null; |
265 |
267 |
266 /* If we decide we want to reuse a client, we put it here */ |
268 /* If we decide we want to reuse a client, we put it here */ |
267 private HttpClient reuseClient = null; |
269 private HttpClient reuseClient = null; |
268 |
270 |
|
271 /* Tunnel states */ |
|
272 enum TunnelState { |
|
273 /* No tunnel */ |
|
274 NONE, |
|
275 |
|
276 /* Setting up a tunnel */ |
|
277 SETUP, |
|
278 |
|
279 /* Tunnel has been successfully setup */ |
|
280 TUNNELING |
|
281 } |
|
282 |
|
283 private TunnelState tunnelState = TunnelState.NONE; |
|
284 |
269 /* Redefine timeouts from java.net.URLConnection as we nee -1 to mean |
285 /* Redefine timeouts from java.net.URLConnection as we nee -1 to mean |
270 * not set. This is to ensure backward compatibility. |
286 * not set. This is to ensure backward compatibility. |
271 */ |
287 */ |
272 private int connectTimeout = -1; |
288 private int connectTimeout = -1; |
273 private int readTimeout = -1; |
289 private int readTimeout = -1; |
336 /* print all message headers in the MessageHeader |
352 /* print all message headers in the MessageHeader |
337 * onto the wire - all the ones we've set and any |
353 * onto the wire - all the ones we've set and any |
338 * others that have been set |
354 * others that have been set |
339 */ |
355 */ |
340 // send any pre-emptive authentication |
356 // send any pre-emptive authentication |
341 if (http.usingProxy) { |
357 if (http.usingProxy && tunnelState() != TunnelState.TUNNELING) { |
342 setPreemptiveProxyAuthentication(requests); |
358 setPreemptiveProxyAuthentication(requests); |
343 } |
359 } |
344 if (!setRequests) { |
360 if (!setRequests) { |
345 |
361 |
346 /* We're very particular about the order in which we |
362 /* We're very particular about the order in which we |
1402 if ((proxyAuthentication != null )&& ! (proxyAuthentication instanceof |
1418 if ((proxyAuthentication != null )&& ! (proxyAuthentication instanceof |
1403 NTLMAuthentication)) { |
1419 NTLMAuthentication)) { |
1404 String raw = auth.raw(); |
1420 String raw = auth.raw(); |
1405 if (proxyAuthentication.isAuthorizationStale (raw)) { |
1421 if (proxyAuthentication.isAuthorizationStale (raw)) { |
1406 /* we can retry with the current credentials */ |
1422 /* we can retry with the current credentials */ |
1407 requests.set (proxyAuthentication.getHeaderName(), |
1423 String value; |
1408 proxyAuthentication.getHeaderValue( |
1424 if (tunnelState() == TunnelState.SETUP && |
1409 url, method)); |
1425 proxyAuthentication instanceof DigestAuthentication) { |
|
1426 value = ((DigestAuthentication)proxyAuthentication) |
|
1427 .getHeaderValue(connectRequestURI(url), HTTP_CONNECT); |
|
1428 } else { |
|
1429 value = proxyAuthentication.getHeaderValue(url, method); |
|
1430 } |
|
1431 requests.set(proxyAuthentication.getHeaderName(), value); |
1410 currentProxyCredentials = proxyAuthentication; |
1432 currentProxyCredentials = proxyAuthentication; |
1411 return proxyAuthentication; |
1433 return proxyAuthentication; |
1412 } else { |
1434 } else { |
1413 proxyAuthentication.removeFromCache(); |
1435 proxyAuthentication.removeFromCache(); |
1414 } |
1436 } |
1415 } |
1437 } |
1416 proxyAuthentication = getHttpProxyAuthentication(auth); |
1438 proxyAuthentication = getHttpProxyAuthentication(auth); |
1417 currentProxyCredentials = proxyAuthentication; |
1439 currentProxyCredentials = proxyAuthentication; |
1418 return proxyAuthentication; |
1440 return proxyAuthentication; |
|
1441 } |
|
1442 |
|
1443 /** |
|
1444 * Returns the tunnel state. |
|
1445 * |
|
1446 * @return the state |
|
1447 */ |
|
1448 TunnelState tunnelState() { |
|
1449 return tunnelState; |
|
1450 } |
|
1451 |
|
1452 /** |
|
1453 * Set the tunneling status. |
|
1454 * |
|
1455 * @param the state |
|
1456 */ |
|
1457 void setTunnelState(TunnelState tunnelState) { |
|
1458 this.tunnelState = tunnelState; |
1419 } |
1459 } |
1420 |
1460 |
1421 /** |
1461 /** |
1422 * establish a tunnel through proxy server |
1462 * establish a tunnel through proxy server |
1423 */ |
1463 */ |
1435 |
1475 |
1436 // Read comments labeled "Failed Negotiate" for details. |
1476 // Read comments labeled "Failed Negotiate" for details. |
1437 boolean inNegotiateProxy = false; |
1477 boolean inNegotiateProxy = false; |
1438 |
1478 |
1439 try { |
1479 try { |
|
1480 /* Actively setting up a tunnel */ |
|
1481 setTunnelState(TunnelState.SETUP); |
|
1482 |
1440 do { |
1483 do { |
1441 if (!checkReuseConnection()) { |
1484 if (!checkReuseConnection()) { |
1442 proxiedConnect(url, proxyHost, proxyPort, false); |
1485 proxiedConnect(url, proxyHost, proxyPort, false); |
1443 } |
1486 } |
1444 // send the "CONNECT" request to establish a tunnel |
1487 // send the "CONNECT" request to establish a tunnel |
1510 // cache auth info on success, domain header not relevant. |
1553 // cache auth info on success, domain header not relevant. |
1511 proxyAuthentication.addToCache(); |
1554 proxyAuthentication.addToCache(); |
1512 } |
1555 } |
1513 |
1556 |
1514 if (respCode == HTTP_OK) { |
1557 if (respCode == HTTP_OK) { |
|
1558 setTunnelState(TunnelState.TUNNELING); |
1515 break; |
1559 break; |
1516 } |
1560 } |
1517 // we don't know how to deal with other response code |
1561 // we don't know how to deal with other response code |
1518 // so disconnect and report error |
1562 // so disconnect and report error |
1519 disconnectInternal(); |
1563 disconnectInternal(); |
|
1564 setTunnelState(TunnelState.NONE); |
1520 break; |
1565 break; |
1521 } while (retryTunnel < maxRedirects); |
1566 } while (retryTunnel < maxRedirects); |
1522 |
1567 |
1523 if (retryTunnel >= maxRedirects || (respCode != HTTP_OK)) { |
1568 if (retryTunnel >= maxRedirects || (respCode != HTTP_OK)) { |
1524 throw new IOException("Unable to tunnel through proxy."+ |
1569 throw new IOException("Unable to tunnel through proxy."+ |
1534 // restore original request headers |
1579 // restore original request headers |
1535 requests = savedRequests; |
1580 requests = savedRequests; |
1536 |
1581 |
1537 // reset responses |
1582 // reset responses |
1538 responses.reset(); |
1583 responses.reset(); |
|
1584 } |
|
1585 |
|
1586 static String connectRequestURI(URL url) { |
|
1587 String host = url.getHost(); |
|
1588 int port = url.getPort(); |
|
1589 port = port != -1 ? port : url.getDefaultPort(); |
|
1590 |
|
1591 return host + ":" + port; |
1539 } |
1592 } |
1540 |
1593 |
1541 /** |
1594 /** |
1542 * send a CONNECT request for establishing a tunnel to proxy server |
1595 * send a CONNECT request for establishing a tunnel to proxy server |
1543 */ |
1596 */ |
1549 // so the first one must be the http method (GET, etc.). |
1602 // so the first one must be the http method (GET, etc.). |
1550 // we need to set it to CONNECT soon, remove this one first. |
1603 // we need to set it to CONNECT soon, remove this one first. |
1551 // otherwise, there may have 2 http methods in headers |
1604 // otherwise, there may have 2 http methods in headers |
1552 if (setRequests) requests.set(0, null, null); |
1605 if (setRequests) requests.set(0, null, null); |
1553 |
1606 |
1554 requests.prepend("CONNECT " + url.getHost() + ":" |
1607 requests.prepend(HTTP_CONNECT + " " + connectRequestURI(url) |
1555 + (port != -1 ? port : url.getDefaultPort()) |
|
1556 + " " + httpVersion, null); |
1608 + " " + httpVersion, null); |
1557 requests.setIfNotSet("User-Agent", userAgent); |
1609 requests.setIfNotSet("User-Agent", userAgent); |
1558 |
1610 |
1559 String host = url.getHost(); |
1611 String host = url.getHost(); |
1560 if (port != -1 && port != url.getDefaultPort()) { |
1612 if (port != -1 && port != url.getDefaultPort()) { |
1581 private void setPreemptiveProxyAuthentication(MessageHeader requests) { |
1633 private void setPreemptiveProxyAuthentication(MessageHeader requests) { |
1582 AuthenticationInfo pauth |
1634 AuthenticationInfo pauth |
1583 = AuthenticationInfo.getProxyAuth(http.getProxyHostUsed(), |
1635 = AuthenticationInfo.getProxyAuth(http.getProxyHostUsed(), |
1584 http.getProxyPortUsed()); |
1636 http.getProxyPortUsed()); |
1585 if (pauth != null && pauth.supportsPreemptiveAuthorization()) { |
1637 if (pauth != null && pauth.supportsPreemptiveAuthorization()) { |
|
1638 String value; |
|
1639 if (tunnelState() == TunnelState.SETUP && |
|
1640 pauth instanceof DigestAuthentication) { |
|
1641 value = ((DigestAuthentication)pauth) |
|
1642 .getHeaderValue(connectRequestURI(url), HTTP_CONNECT); |
|
1643 } else { |
|
1644 value = pauth.getHeaderValue(url, method); |
|
1645 } |
|
1646 |
1586 // Sets "Proxy-authorization" |
1647 // Sets "Proxy-authorization" |
1587 requests.set(pauth.getHeaderName(), |
1648 requests.set(pauth.getHeaderName(), value); |
1588 pauth.getHeaderValue(url,method)); |
|
1589 currentProxyCredentials = pauth; |
1649 currentProxyCredentials = pauth; |
1590 } |
1650 } |
1591 } |
1651 } |
1592 |
1652 |
1593 /** |
1653 /** |