001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027package org.apache.http.impl.client; 028 029import java.io.ByteArrayInputStream; 030import java.io.ByteArrayOutputStream; 031import java.io.IOException; 032import java.io.ObjectInputStream; 033import java.io.ObjectOutputStream; 034import java.io.Serializable; 035import java.util.Map; 036import java.util.concurrent.ConcurrentHashMap; 037 038import org.apache.commons.logging.Log; 039import org.apache.commons.logging.LogFactory; 040import org.apache.http.HttpHost; 041import org.apache.http.annotation.Contract; 042import org.apache.http.annotation.ThreadingBehavior; 043import org.apache.http.auth.AuthScheme; 044import org.apache.http.client.AuthCache; 045import org.apache.http.conn.SchemePortResolver; 046import org.apache.http.conn.UnsupportedSchemeException; 047import org.apache.http.impl.conn.DefaultSchemePortResolver; 048import org.apache.http.util.Args; 049 050/** 051 * Default implementation of {@link org.apache.http.client.AuthCache}. This implements 052 * expects {@link org.apache.http.auth.AuthScheme} to be {@link java.io.Serializable} 053 * in order to be cacheable. 054 * <p> 055 * Instances of this class are thread safe as of version 4.4. 056 * </p> 057 * 058 * @since 4.1 059 */ 060@Contract(threading = ThreadingBehavior.SAFE) 061public class BasicAuthCache implements AuthCache { 062 063 private final Log log = LogFactory.getLog(getClass()); 064 065 private final Map<HttpHost, byte[]> map; 066 private final SchemePortResolver schemePortResolver; 067 068 /** 069 * Default constructor. 070 * 071 * @since 4.3 072 */ 073 public BasicAuthCache(final SchemePortResolver schemePortResolver) { 074 super(); 075 this.map = new ConcurrentHashMap<HttpHost, byte[]>(); 076 this.schemePortResolver = schemePortResolver != null ? schemePortResolver : 077 DefaultSchemePortResolver.INSTANCE; 078 } 079 080 public BasicAuthCache() { 081 this(null); 082 } 083 084 protected HttpHost getKey(final HttpHost host) { 085 if (host.getPort() <= 0) { 086 final int port; 087 try { 088 port = schemePortResolver.resolve(host); 089 } catch (final UnsupportedSchemeException ignore) { 090 return host; 091 } 092 return new HttpHost(host.getHostName(), port, host.getSchemeName()); 093 } else { 094 return host; 095 } 096 } 097 098 @Override 099 public void put(final HttpHost host, final AuthScheme authScheme) { 100 Args.notNull(host, "HTTP host"); 101 if (authScheme == null) { 102 return; 103 } 104 if (authScheme instanceof Serializable) { 105 try { 106 final ByteArrayOutputStream buf = new ByteArrayOutputStream(); 107 final ObjectOutputStream out = new ObjectOutputStream(buf); 108 out.writeObject(authScheme); 109 out.close(); 110 this.map.put(getKey(host), buf.toByteArray()); 111 } catch (final IOException ex) { 112 if (log.isWarnEnabled()) { 113 log.warn("Unexpected I/O error while serializing auth scheme", ex); 114 } 115 } 116 } else { 117 if (log.isDebugEnabled()) { 118 log.debug("Auth scheme " + authScheme.getClass() + " is not serializable"); 119 } 120 } 121 } 122 123 @Override 124 public AuthScheme get(final HttpHost host) { 125 Args.notNull(host, "HTTP host"); 126 final byte[] bytes = this.map.get(getKey(host)); 127 if (bytes != null) { 128 try { 129 final ByteArrayInputStream buf = new ByteArrayInputStream(bytes); 130 final ObjectInputStream in = new ObjectInputStream(buf); 131 final AuthScheme authScheme = (AuthScheme) in.readObject(); 132 in.close(); 133 return authScheme; 134 } catch (final IOException ex) { 135 if (log.isWarnEnabled()) { 136 log.warn("Unexpected I/O error while de-serializing auth scheme", ex); 137 } 138 return null; 139 } catch (final ClassNotFoundException ex) { 140 if (log.isWarnEnabled()) { 141 log.warn("Unexpected error while de-serializing auth scheme", ex); 142 } 143 return null; 144 } 145 } else { 146 return null; 147 } 148 } 149 150 @Override 151 public void remove(final HttpHost host) { 152 Args.notNull(host, "HTTP host"); 153 this.map.remove(getKey(host)); 154 } 155 156 @Override 157 public void clear() { 158 this.map.clear(); 159 } 160 161 @Override 162 public String toString() { 163 return this.map.toString(); 164 } 165 166}