1 /* |
1 /* |
2 * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
28 import java.io.*; |
28 import java.io.*; |
29 import java.net.*; |
29 import java.net.*; |
30 import java.util.Locale; |
30 import java.util.Locale; |
31 import java.util.Objects; |
31 import java.util.Objects; |
32 import java.util.Properties; |
32 import java.util.Properties; |
|
33 import java.util.concurrent.locks.Lock; |
|
34 import java.util.concurrent.locks.ReentrantLock; |
|
35 |
33 import sun.net.NetworkClient; |
36 import sun.net.NetworkClient; |
34 import sun.net.ProgressSource; |
37 import sun.net.ProgressSource; |
35 import sun.net.www.MessageHeader; |
38 import sun.net.www.MessageHeader; |
36 import sun.net.www.HeaderParser; |
39 import sun.net.www.HeaderParser; |
37 import sun.net.www.MeteredStream; |
40 import sun.net.www.MeteredStream; |
45 /** |
48 /** |
46 * @author Herb Jellinek |
49 * @author Herb Jellinek |
47 * @author Dave Brown |
50 * @author Dave Brown |
48 */ |
51 */ |
49 public class HttpClient extends NetworkClient { |
52 public class HttpClient extends NetworkClient { |
|
53 protected final ReentrantLock clientLock = new ReentrantLock(); |
|
54 |
50 // whether this httpclient comes from the cache |
55 // whether this httpclient comes from the cache |
51 protected boolean cachedHttpClient = false; |
56 protected boolean cachedHttpClient = false; |
52 |
57 |
53 protected boolean inCache; |
58 protected boolean inCache; |
54 |
59 |
313 if (ret != null) { |
318 if (ret != null) { |
314 String ak = httpuc == null ? AuthenticatorKeys.DEFAULT |
319 String ak = httpuc == null ? AuthenticatorKeys.DEFAULT |
315 : httpuc.getAuthenticatorKey(); |
320 : httpuc.getAuthenticatorKey(); |
316 boolean compatible = Objects.equals(ret.proxy, p) |
321 boolean compatible = Objects.equals(ret.proxy, p) |
317 && Objects.equals(ret.getAuthenticatorKey(), ak); |
322 && Objects.equals(ret.getAuthenticatorKey(), ak); |
|
323 final Lock lock = ret.clientLock; |
318 if (compatible) { |
324 if (compatible) { |
319 synchronized (ret) { |
325 lock.lock(); |
|
326 try { |
320 ret.cachedHttpClient = true; |
327 ret.cachedHttpClient = true; |
321 assert ret.inCache; |
328 assert ret.inCache; |
322 ret.inCache = false; |
329 ret.inCache = false; |
323 if (httpuc != null && ret.needsTunneling()) |
330 if (httpuc != null && ret.needsTunneling()) |
324 httpuc.setTunnelState(TUNNELING); |
331 httpuc.setTunnelState(TUNNELING); |
325 logFinest("KeepAlive stream retrieved from the cache, " + ret); |
332 logFinest("KeepAlive stream retrieved from the cache, " + ret); |
|
333 } finally { |
|
334 lock.unlock(); |
326 } |
335 } |
327 } else { |
336 } else { |
328 // We cannot return this connection to the cache as it's |
337 // We cannot return this connection to the cache as it's |
329 // KeepAliveTimeout will get reset. We simply close the connection. |
338 // KeepAliveTimeout will get reset. We simply close the connection. |
330 // This should be fine as it is very rare that a connection |
339 // This should be fine as it is very rare that a connection |
331 // to the same host will not use the same proxy. |
340 // to the same host will not use the same proxy. |
332 synchronized(ret) { |
341 lock.lock(); |
|
342 try { |
333 ret.inCache = false; |
343 ret.inCache = false; |
334 ret.closeServer(); |
344 ret.closeServer(); |
|
345 } finally { |
|
346 lock.unlock(); |
335 } |
347 } |
336 ret = null; |
348 ret = null; |
337 } |
349 } |
338 } |
350 } |
339 } |
351 } |
434 } |
447 } |
435 } catch (IOException e) { |
448 } catch (IOException e) { |
436 logFinest("HttpClient.available(): " + |
449 logFinest("HttpClient.available(): " + |
437 "SocketException: not available"); |
450 "SocketException: not available"); |
438 available = false; |
451 available = false; |
|
452 } finally { |
|
453 clientLock.unlock(); |
439 } |
454 } |
440 return available; |
455 return available; |
441 } |
456 } |
442 |
457 |
443 protected synchronized void putInKeepAliveCache() { |
458 protected void putInKeepAliveCache() { |
444 if (inCache) { |
459 clientLock.lock(); |
445 assert false : "Duplicate put to keep alive cache"; |
460 try { |
446 return; |
461 if (inCache) { |
447 } |
462 assert false : "Duplicate put to keep alive cache"; |
448 inCache = true; |
463 return; |
449 kac.put(url, null, this); |
464 } |
450 } |
465 inCache = true; |
451 |
466 kac.put(url, null, this); |
452 protected synchronized boolean isInKeepAliveCache() { |
467 } finally { |
453 return inCache; |
468 clientLock.unlock(); |
|
469 } |
|
470 } |
|
471 |
|
472 protected boolean isInKeepAliveCache() { |
|
473 clientLock.lock(); |
|
474 try { |
|
475 return inCache; |
|
476 } finally { |
|
477 clientLock.unlock(); |
|
478 } |
454 } |
479 } |
455 |
480 |
456 /* |
481 /* |
457 * Close an idle connection to this URL (if it exists in the |
482 * Close an idle connection to this URL (if it exists in the |
458 * cache). |
483 * cache). |
495 } |
520 } |
496 |
521 |
497 /* |
522 /* |
498 * Returns true if this httpclient is from cache |
523 * Returns true if this httpclient is from cache |
499 */ |
524 */ |
500 public synchronized boolean isCachedConnection() { |
525 public boolean isCachedConnection() { |
501 return cachedHttpClient; |
526 clientLock.lock(); |
|
527 try { |
|
528 return cachedHttpClient; |
|
529 } finally { |
|
530 clientLock.unlock(); |
|
531 } |
502 } |
532 } |
503 |
533 |
504 /* |
534 /* |
505 * Finish any work left after the socket connection is |
535 * Finish any work left after the socket connection is |
506 * established. In the normal http case, it's a NO-OP. Subclass |
536 * established. In the normal http case, it's a NO-OP. Subclass |
514 } |
544 } |
515 |
545 |
516 /* |
546 /* |
517 * call openServer in a privileged block |
547 * call openServer in a privileged block |
518 */ |
548 */ |
519 private synchronized void privilegedOpenServer(final InetSocketAddress server) |
549 private void privilegedOpenServer(final InetSocketAddress server) |
520 throws IOException |
550 throws IOException |
521 { |
551 { |
|
552 assert clientLock.isHeldByCurrentThread(); |
522 try { |
553 try { |
523 java.security.AccessController.doPrivileged( |
554 java.security.AccessController.doPrivileged( |
524 new java.security.PrivilegedExceptionAction<>() { |
555 new java.security.PrivilegedExceptionAction<>() { |
525 public Void run() throws IOException { |
556 public Void run() throws IOException { |
526 openServer(server.getHostString(), server.getPort()); |
557 openServer(server.getHostString(), server.getPort()); |
542 super.openServer(proxyHost, proxyPort); |
573 super.openServer(proxyHost, proxyPort); |
543 } |
574 } |
544 |
575 |
545 /* |
576 /* |
546 */ |
577 */ |
547 protected synchronized void openServer() throws IOException { |
578 protected void openServer() throws IOException { |
548 |
579 |
549 SecurityManager security = System.getSecurityManager(); |
580 SecurityManager security = System.getSecurityManager(); |
550 |
581 |
551 if (security != null) { |
582 clientLock.lock(); |
552 security.checkConnect(host, port); |
583 try { |
553 } |
584 if (security != null) { |
554 |
585 security.checkConnect(host, port); |
555 if (keepingAlive) { // already opened |
586 } |
556 return; |
587 |
557 } |
588 if (keepingAlive) { // already opened |
558 |
|
559 if (url.getProtocol().equals("http") || |
|
560 url.getProtocol().equals("https") ) { |
|
561 |
|
562 if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) { |
|
563 sun.net.www.URLConnection.setProxiedHost(host); |
|
564 privilegedOpenServer((InetSocketAddress) proxy.address()); |
|
565 usingProxy = true; |
|
566 return; |
589 return; |
|
590 } |
|
591 |
|
592 if (url.getProtocol().equals("http") || |
|
593 url.getProtocol().equals("https")) { |
|
594 |
|
595 if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) { |
|
596 sun.net.www.URLConnection.setProxiedHost(host); |
|
597 privilegedOpenServer((InetSocketAddress) proxy.address()); |
|
598 usingProxy = true; |
|
599 return; |
|
600 } else { |
|
601 // make direct connection |
|
602 openServer(host, port); |
|
603 usingProxy = false; |
|
604 return; |
|
605 } |
|
606 |
567 } else { |
607 } else { |
568 // make direct connection |
608 /* we're opening some other kind of url, most likely an |
569 openServer(host, port); |
609 * ftp url. |
570 usingProxy = false; |
610 */ |
571 return; |
611 if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) { |
572 } |
612 sun.net.www.URLConnection.setProxiedHost(host); |
573 |
613 privilegedOpenServer((InetSocketAddress) proxy.address()); |
574 } else { |
614 usingProxy = true; |
575 /* we're opening some other kind of url, most likely an |
615 return; |
576 * ftp url. |
616 } else { |
577 */ |
617 // make direct connection |
578 if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) { |
618 super.openServer(host, port); |
579 sun.net.www.URLConnection.setProxiedHost(host); |
619 usingProxy = false; |
580 privilegedOpenServer((InetSocketAddress) proxy.address()); |
620 return; |
581 usingProxy = true; |
621 } |
582 return; |
622 } |
583 } else { |
623 } finally { |
584 // make direct connection |
624 clientLock.unlock(); |
585 super.openServer(host, port); |
|
586 usingProxy = false; |
|
587 return; |
|
588 } |
|
589 } |
625 } |
590 } |
626 } |
591 |
627 |
592 public String getURLFile() throws IOException { |
628 public String getURLFile() throws IOException { |
593 |
629 |