1 /* 2 * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 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 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.net.www.http; 27 28 import java.io.IOException; 29 import java.util.LinkedList; 30 import sun.net.NetProperties; 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 34 /** 35 * This class is used to cleanup any remaining data that may be on a KeepAliveStream 36 * so that the connection can be cached in the KeepAliveCache. 37 * Instances of this class can be used as a FIFO queue for KeepAliveCleanerEntry objects. 38 * Executing this Runnable removes each KeepAliveCleanerEntry from the Queue, reads 39 * the reamining bytes on its KeepAliveStream, and if successful puts the connection in 40 * the KeepAliveCache. 41 * 42 * @author Chris Hegarty 43 */ 44 45 @SuppressWarnings("serial") // never serialized 46 class KeepAliveStreamCleaner 47 extends LinkedList<KeepAliveCleanerEntry> 48 implements Runnable 49 { 50 // maximum amount of remaining data that we will try to cleanup 51 protected static int MAX_DATA_REMAINING = 512; 52 53 // maximum amount of KeepAliveStreams to be queued 54 protected static int MAX_CAPACITY = 10; 55 56 // timeout for both socket and poll on the queue 57 protected static final int TIMEOUT = 5000; 58 59 // max retries for skipping data 60 private static final int MAX_RETRIES = 5; 61 62 static { 63 final String maxDataKey = "http.KeepAlive.remainingData"; 64 int maxData = AccessController.doPrivileged( 65 new PrivilegedAction<Integer>() { 66 public Integer run() { 67 return NetProperties.getInteger(maxDataKey, MAX_DATA_REMAINING); 68 }}).intValue() * 1024; 69 MAX_DATA_REMAINING = maxData; 70 71 final String maxCapacityKey = "http.KeepAlive.queuedConnections"; 72 int maxCapacity = AccessController.doPrivileged( 73 new PrivilegedAction<Integer>() { 74 public Integer run() { 75 return NetProperties.getInteger(maxCapacityKey, MAX_CAPACITY); 76 }}).intValue(); 77 MAX_CAPACITY = maxCapacity; 78 79 } 80 81 82 @Override offer(KeepAliveCleanerEntry e)83 public boolean offer(KeepAliveCleanerEntry e) { 84 if (size() >= MAX_CAPACITY) 85 return false; 86 87 return super.offer(e); 88 } 89 90 @Override run()91 public void run() 92 { 93 KeepAliveCleanerEntry kace = null; 94 95 do { 96 try { 97 synchronized(this) { 98 long before = System.currentTimeMillis(); 99 long timeout = TIMEOUT; 100 while ((kace = poll()) == null) { 101 this.wait(timeout); 102 103 long after = System.currentTimeMillis(); 104 long elapsed = after - before; 105 if (elapsed > timeout) { 106 /* one last try */ 107 kace = poll(); 108 break; 109 } 110 before = after; 111 timeout -= elapsed; 112 } 113 } 114 115 if(kace == null) 116 break; 117 118 KeepAliveStream kas = kace.getKeepAliveStream(); 119 120 if (kas != null) { 121 synchronized(kas) { 122 HttpClient hc = kace.getHttpClient(); 123 try { 124 if (hc != null && !hc.isInKeepAliveCache()) { 125 int oldTimeout = hc.getReadTimeout(); 126 hc.setReadTimeout(TIMEOUT); 127 long remainingToRead = kas.remainingToRead(); 128 if (remainingToRead > 0) { 129 long n = 0; 130 int retries = 0; 131 while (n < remainingToRead && retries < MAX_RETRIES) { 132 remainingToRead = remainingToRead - n; 133 n = kas.skip(remainingToRead); 134 if (n == 0) 135 retries++; 136 } 137 remainingToRead = remainingToRead - n; 138 } 139 if (remainingToRead == 0) { 140 hc.setReadTimeout(oldTimeout); 141 hc.finished(); 142 } else 143 hc.closeServer(); 144 } 145 } catch (IOException ioe) { 146 hc.closeServer(); 147 } finally { 148 kas.setClosed(); 149 } 150 } 151 } 152 } catch (InterruptedException ie) { } 153 } while (kace != null); 154 } 155 } 156