|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.net.www.http; |
|
|
|
import java.io.*; |
|
import sun.net.ProgressSource; |
|
import sun.net.www.MeteredStream; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public |
|
class KeepAliveStream extends MeteredStream implements Hurryable { |
|
|
|
|
|
HttpClient hc; |
|
|
|
boolean hurried; |
|
|
|
|
|
protected boolean queuedForCleanup = false; |
|
|
|
private static final KeepAliveStreamCleaner queue = new KeepAliveStreamCleaner(); |
|
private static Thread cleanerThread; |
|
|
|
|
|
|
|
*/ |
|
public KeepAliveStream(InputStream is, ProgressSource pi, long expected, HttpClient hc) { |
|
super(is, pi, expected); |
|
this.hc = hc; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void close() throws IOException { |
|
|
|
if (closed) { |
|
return; |
|
} |
|
|
|
|
|
if (queuedForCleanup) { |
|
return; |
|
} |
|
|
|
// Skip past the data that's left in the Inputstream because |
|
// some sort of error may have occurred. |
|
// Do this ONLY if the skip won't block. The stream may have |
|
// been closed at the beginning of a big file and we don't want |
|
// to hang around for nothing. So if we can't skip without blocking |
|
// we just close the socket and, therefore, terminate the keepAlive |
|
|
|
try { |
|
if (expected > count) { |
|
long nskip = expected - count; |
|
if (nskip <= available()) { |
|
do {} while ((nskip = (expected - count)) > 0L |
|
&& skip(Math.min(nskip, available())) > 0L); |
|
} else if (expected <= KeepAliveStreamCleaner.MAX_DATA_REMAINING && !hurried) { |
|
//put this KeepAliveStream on the queue so that the data remaining |
|
|
|
queueForCleanup(new KeepAliveCleanerEntry(this, hc)); |
|
} else { |
|
hc.closeServer(); |
|
} |
|
} |
|
if (!closed && !hurried && !queuedForCleanup) { |
|
hc.finished(); |
|
} |
|
} finally { |
|
if (pi != null) |
|
pi.finishTracking(); |
|
|
|
if (!queuedForCleanup) { |
|
// nulling out the underlying inputstream as well as |
|
|
|
in = null; |
|
hc = null; |
|
closed = true; |
|
} |
|
} |
|
} |
|
|
|
/* we explicitly do not support mark/reset */ |
|
|
|
public boolean markSupported() { |
|
return false; |
|
} |
|
|
|
public void mark(int limit) {} |
|
|
|
public void reset() throws IOException { |
|
throw new IOException("mark/reset not supported"); |
|
} |
|
|
|
public synchronized boolean hurry() { |
|
try { |
|
|
|
if (closed || count >= expected) { |
|
return false; |
|
} else if (in.available() < (expected - count)) { |
|
|
|
return false; |
|
} else { |
|
|
|
|
|
*/ |
|
int size = (int) (expected - count); |
|
byte[] buf = new byte[size]; |
|
DataInputStream dis = new DataInputStream(in); |
|
dis.readFully(buf); |
|
in = new ByteArrayInputStream(buf); |
|
hurried = true; |
|
return true; |
|
} |
|
} catch (IOException e) { |
|
|
|
return false; |
|
} |
|
} |
|
|
|
private static void queueForCleanup(KeepAliveCleanerEntry kace) { |
|
synchronized(queue) { |
|
if(!kace.getQueuedForCleanup()) { |
|
if (!queue.offer(kace)) { |
|
kace.getHttpClient().closeServer(); |
|
return; |
|
} |
|
|
|
kace.setQueuedForCleanup(); |
|
queue.notifyAll(); |
|
} |
|
|
|
boolean startCleanupThread = (cleanerThread == null); |
|
if (!startCleanupThread) { |
|
if (!cleanerThread.isAlive()) { |
|
startCleanupThread = true; |
|
} |
|
} |
|
|
|
if (startCleanupThread) { |
|
java.security.AccessController.doPrivileged( |
|
new java.security.PrivilegedAction<Void>() { |
|
public Void run() { |
|
// We want to create the Keep-Alive-SocketCleaner in the |
|
|
|
ThreadGroup grp = Thread.currentThread().getThreadGroup(); |
|
ThreadGroup parent = null; |
|
while ((parent = grp.getParent()) != null) { |
|
grp = parent; |
|
} |
|
|
|
cleanerThread = new Thread(grp, queue, "Keep-Alive-SocketCleaner"); |
|
cleanerThread.setDaemon(true); |
|
cleanerThread.setPriority(Thread.MAX_PRIORITY - 2); |
|
// Set the context class loader to null in order to avoid |
|
|
|
cleanerThread.setContextClassLoader(null); |
|
cleanerThread.start(); |
|
return null; |
|
} |
|
}); |
|
} |
|
} // queue |
|
} |
|
|
|
protected long remainingToRead() { |
|
return expected - count; |
|
} |
|
|
|
protected void setClosed() { |
|
in = null; |
|
hc = null; |
|
closed = true; |
|
} |
|
} |