src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java
branchJDK-8229867-branch
changeset 57968 8595871a5446
parent 57956 e0b8b019d2f5
equal deleted inserted replaced
57966:e89c7aaf2906 57968:8595871a5446
    29 import java.io.ObjectInputStream;
    29 import java.io.ObjectInputStream;
    30 import java.net.PasswordAuthentication;
    30 import java.net.PasswordAuthentication;
    31 import java.net.URL;
    31 import java.net.URL;
    32 import java.util.HashMap;
    32 import java.util.HashMap;
    33 import java.util.Objects;
    33 import java.util.Objects;
       
    34 import java.util.concurrent.locks.Condition;
       
    35 import java.util.concurrent.locks.ReentrantLock;
    34 import java.util.function.Function;
    36 import java.util.function.Function;
    35 
    37 
    36 import sun.net.www.HeaderParser;
    38 import sun.net.www.HeaderParser;
    37 
    39 
    38 
    40 
   124      * i.e. if multiple threads need to get credentials from the user
   126      * i.e. if multiple threads need to get credentials from the user
   125      * at the same time, then all but the first will block until
   127      * at the same time, then all but the first will block until
   126      * the first completes its authentication.
   128      * the first completes its authentication.
   127      */
   129      */
   128     private static HashMap<String,Thread> requests = new HashMap<>();
   130     private static HashMap<String,Thread> requests = new HashMap<>();
   129 
   131     private static final ReentrantLock requestLock = new ReentrantLock();
       
   132     private static final Condition requestFinished = requestLock.newCondition();
   130     /*
   133     /*
   131      * check if AuthenticationInfo is available in the cache.
   134      * check if AuthenticationInfo is available in the cache.
   132      * If not, check if a request for this destination is in progress
   135      * If not, check if a request for this destination is in progress
   133      * and if so block until the other request is finished authenticating
   136      * and if so block until the other request is finished authenticating
   134      * and returns the cached authentication value.
   137      * and returns the cached authentication value.
   140             // either we already have a value in the cache, and we can
   143             // either we already have a value in the cache, and we can
   141             // use that immediately, or the serializeAuth behavior is disabled,
   144             // use that immediately, or the serializeAuth behavior is disabled,
   142             // and we can revert to concurrent requests
   145             // and we can revert to concurrent requests
   143             return cached;
   146             return cached;
   144         }
   147         }
   145         synchronized (requests) {
   148         requestLock.lock();
   146             // check again after synchronizing, and if available
   149         try {
       
   150             // check again after locking, and if available
   147             // just return the cached value.
   151             // just return the cached value.
   148             cached = cache.apply(key);
   152             cached = cache.apply(key);
   149             if (cached != null) return cached;
   153             if (cached != null) return cached;
   150 
   154 
   151             // Otherwise, if no request is in progress, record this
   155             // Otherwise, if no request is in progress, record this
   162                 return cached;
   166                 return cached;
   163             }
   167             }
   164             // Otherwise, an other thread is currently performing authentication:
   168             // Otherwise, an other thread is currently performing authentication:
   165             // wait until it finishes.
   169             // wait until it finishes.
   166             while (requests.containsKey(key)) {
   170             while (requests.containsKey(key)) {
   167                 try {
   171                 requestFinished.awaitUninterruptibly();
   168                     requests.wait ();
       
   169                 } catch (InterruptedException e) {}
       
   170             }
   172             }
       
   173         } finally {
       
   174             requestLock.unlock();
   171         }
   175         }
   172         /* entry may be in cache now. */
   176         /* entry may be in cache now. */
   173         return cache.apply(key);
   177         return cache.apply(key);
   174     }
   178     }
   175 
   179 
   176     /* signal completion of an authentication (whether it succeeded or not)
   180     /* signal completion of an authentication (whether it succeeded or not)
   177      * so that other threads can continue.
   181      * so that other threads can continue.
   178      */
   182      */
   179     private static void requestCompleted (String key) {
   183     private static void requestCompleted (String key) {
   180         synchronized (requests) {
   184         requestLock.lock();
       
   185         try {
   181             Thread thread = requests.get(key);
   186             Thread thread = requests.get(key);
   182             if (thread != null && thread == Thread.currentThread()) {
   187             if (thread != null && thread == Thread.currentThread()) {
   183                 boolean waspresent = requests.remove(key) != null;
   188                 boolean waspresent = requests.remove(key) != null;
   184                 assert waspresent;
   189                 assert waspresent;
   185             }
   190             }
   186             requests.notifyAll();
   191             requestFinished.signalAll();
       
   192         } finally {
       
   193             requestLock.unlock();
   187         }
   194         }
   188     }
   195     }
   189 
   196 
   190     //public String toString () {
   197     //public String toString () {
   191         //return ("{"+type+":"+authScheme+":"+protocol+":"+host+":"+port+":"+realm+":"+path+"}");
   198         //return ("{"+type+":"+authScheme+":"+protocol+":"+host+":"+port+":"+realm+":"+path+"}");
   412 
   419 
   413     static void endAuthRequest (String key) {
   420     static void endAuthRequest (String key) {
   414         if (!serializeAuth) {
   421         if (!serializeAuth) {
   415             return;
   422             return;
   416         }
   423         }
   417         synchronized (requests) {
   424         requestCompleted(key);
   418             requestCompleted(key);
       
   419         }
       
   420     }
   425     }
   421 
   426 
   422     /**
   427     /**
   423      * Remove this authentication from the cache
   428      * Remove this authentication from the cache
   424      */
   429      */
   498     }
   503     }
   499 
   504 
   500     String s1, s2;  /* used for serialization of pw */
   505     String s1, s2;  /* used for serialization of pw */
   501 
   506 
   502     @java.io.Serial
   507     @java.io.Serial
       
   508     // should be safe to keep synchronized here
   503     private synchronized void readObject(ObjectInputStream s)
   509     private synchronized void readObject(ObjectInputStream s)
   504         throws IOException, ClassNotFoundException
   510         throws IOException, ClassNotFoundException
   505     {
   511     {
   506         s.defaultReadObject ();
   512         s.defaultReadObject ();
   507         pw = new PasswordAuthentication (s1, s2.toCharArray());
   513         pw = new PasswordAuthentication (s1, s2.toCharArray());
   510             authenticatorKey = AuthenticatorKeys.DEFAULT;
   516             authenticatorKey = AuthenticatorKeys.DEFAULT;
   511         }
   517         }
   512     }
   518     }
   513 
   519 
   514     @java.io.Serial
   520     @java.io.Serial
       
   521     // should be safe to keep synchronized here
   515     private synchronized void writeObject(java.io.ObjectOutputStream s)
   522     private synchronized void writeObject(java.io.ObjectOutputStream s)
   516         throws IOException
   523         throws IOException
   517     {
   524     {
   518         Objects.requireNonNull(authenticatorKey);
   525         Objects.requireNonNull(authenticatorKey);
   519         s1 = pw.getUserName();
   526         s1 = pw.getUserName();