View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.client5.http.impl.auth;
28  
29  import java.io.ByteArrayInputStream;
30  import java.io.ByteArrayOutputStream;
31  import java.io.IOException;
32  import java.io.ObjectInputStream;
33  import java.io.ObjectOutputStream;
34  import java.io.Serializable;
35  import java.util.Map;
36  import java.util.concurrent.ConcurrentHashMap;
37  
38  import org.apache.hc.client5.http.SchemePortResolver;
39  import org.apache.hc.client5.http.auth.AuthCache;
40  import org.apache.hc.client5.http.auth.AuthScheme;
41  import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
42  import org.apache.hc.client5.http.routing.RoutingSupport;
43  import org.apache.hc.core5.annotation.Contract;
44  import org.apache.hc.core5.annotation.ThreadingBehavior;
45  import org.apache.hc.core5.http.HttpHost;
46  import org.apache.hc.core5.util.Args;
47  import org.slf4j.Logger;
48  import org.slf4j.LoggerFactory;
49  
50  /**
51   * Default implementation of {@link AuthCache}. This implements
52   * expects {@link org.apache.hc.client5.http.auth.AuthScheme} to be {@link java.io.Serializable}
53   * in order to be cacheable.
54   * <p>
55   * Instances of this class are thread safe as of version 4.4.
56   * </p>
57   *
58   * @since 4.1
59   */
60  @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
61  public class BasicAuthCache implements AuthCache {
62  
63      private static final Logger LOG = LoggerFactory.getLogger(BasicAuthCache.class);
64  
65      private final Map<HttpHost, byte[]> map;
66      private final SchemePortResolver schemePortResolver;
67  
68      /**
69       * Default constructor.
70       *
71       * @since 4.3
72       */
73      public BasicAuthCache(final SchemePortResolver schemePortResolver) {
74          super();
75          this.map = new ConcurrentHashMap<>();
76          this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
77      }
78  
79      public BasicAuthCache() {
80          this(null);
81      }
82  
83      @Override
84      public void put(final HttpHost host, final AuthScheme authScheme) {
85          Args.notNull(host, "HTTP host");
86          if (authScheme == null) {
87              return;
88          }
89          if (authScheme instanceof Serializable) {
90              try {
91                  final ByteArrayOutputStream buf = new ByteArrayOutputStream();
92                  try (final ObjectOutputStream out = new ObjectOutputStream(buf)) {
93                      out.writeObject(authScheme);
94                  }
95                  final HttpHost key = RoutingSupport.normalize(host, schemePortResolver);
96                  this.map.put(key, buf.toByteArray());
97              } catch (final IOException ex) {
98                  if (LOG.isWarnEnabled()) {
99                      LOG.warn("Unexpected I/O error while serializing auth scheme", ex);
100                 }
101             }
102         } else {
103             if (LOG.isDebugEnabled()) {
104                 LOG.debug("Auth scheme {} is not serializable", authScheme.getClass());
105             }
106         }
107     }
108 
109     @Override
110     public AuthScheme get(final HttpHost host) {
111         Args.notNull(host, "HTTP host");
112         final HttpHost key = RoutingSupport.normalize(host, schemePortResolver);
113         final byte[] bytes = this.map.get(key);
114         if (bytes != null) {
115             try {
116                 final ByteArrayInputStream buf = new ByteArrayInputStream(bytes);
117                 try (final ObjectInputStream in = new ObjectInputStream(buf)) {
118                     return (AuthScheme) in.readObject();
119                 }
120             } catch (final IOException ex) {
121                 if (LOG.isWarnEnabled()) {
122                     LOG.warn("Unexpected I/O error while de-serializing auth scheme", ex);
123                 }
124             } catch (final ClassNotFoundException ex) {
125                 if (LOG.isWarnEnabled()) {
126                     LOG.warn("Unexpected error while de-serializing auth scheme", ex);
127                 }
128             }
129         }
130         return null;
131     }
132 
133     @Override
134     public void remove(final HttpHost host) {
135         Args.notNull(host, "HTTP host");
136         final HttpHost key = RoutingSupport.normalize(host, schemePortResolver);
137         this.map.remove(key);
138     }
139 
140     @Override
141     public void clear() {
142         this.map.clear();
143     }
144 
145     @Override
146     public String toString() {
147         return this.map.toString();
148     }
149 
150 }