Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/net/www/http/KeepAliveStream.java
38923 views
/*1* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.net.www.http;2627import java.io.*;28import sun.net.ProgressSource;29import sun.net.www.MeteredStream;3031/**32* A stream that has the property of being able to be kept alive for33* multiple downloads from the same server.34*35* @author Stephen R. Pietrowicz (NCSA)36* @author Dave Brown37*/38public39class KeepAliveStream extends MeteredStream implements Hurryable {4041// instance variables42HttpClient hc;4344boolean hurried;4546// has this KeepAliveStream been put on the queue for asynchronous cleanup.47protected boolean queuedForCleanup = false;4849private static final KeepAliveStreamCleaner queue = new KeepAliveStreamCleaner();50private static Thread cleanerThread; // null5152/**53* Constructor54*/55public KeepAliveStream(InputStream is, ProgressSource pi, long expected, HttpClient hc) {56super(is, pi, expected);57this.hc = hc;58}5960/**61* Attempt to cache this connection62*/63public void close() throws IOException {64// If the inputstream is closed already, just return.65if (closed) {66return;67}6869// If this stream has already been queued for cleanup.70if (queuedForCleanup) {71return;72}7374// Skip past the data that's left in the Inputstream because75// some sort of error may have occurred.76// Do this ONLY if the skip won't block. The stream may have77// been closed at the beginning of a big file and we don't want78// to hang around for nothing. So if we can't skip without blocking79// we just close the socket and, therefore, terminate the keepAlive80// NOTE: Don't close super class81try {82if (expected > count) {83long nskip = expected - count;84if (nskip <= available()) {85do {} while ((nskip = (expected - count)) > 0L86&& skip(Math.min(nskip, available())) > 0L);87} else if (expected <= KeepAliveStreamCleaner.MAX_DATA_REMAINING && !hurried) {88//put this KeepAliveStream on the queue so that the data remaining89//on the socket can be cleanup asyncronously.90queueForCleanup(new KeepAliveCleanerEntry(this, hc));91} else {92hc.closeServer();93}94}95if (!closed && !hurried && !queuedForCleanup) {96hc.finished();97}98} finally {99if (pi != null)100pi.finishTracking();101102if (!queuedForCleanup) {103// nulling out the underlying inputstream as well as104// httpClient to let gc collect the memories faster105in = null;106hc = null;107closed = true;108}109}110}111112/* we explicitly do not support mark/reset */113114public boolean markSupported() {115return false;116}117118public void mark(int limit) {}119120public void reset() throws IOException {121throw new IOException("mark/reset not supported");122}123124public synchronized boolean hurry() {125try {126/* CASE 0: we're actually already done */127if (closed || count >= expected) {128return false;129} else if (in.available() < (expected - count)) {130/* CASE I: can't meet the demand */131return false;132} else {133/* CASE II: fill our internal buffer134* Remind: possibly check memory here135*/136int size = (int) (expected - count);137byte[] buf = new byte[size];138DataInputStream dis = new DataInputStream(in);139dis.readFully(buf);140in = new ByteArrayInputStream(buf);141hurried = true;142return true;143}144} catch (IOException e) {145// e.printStackTrace();146return false;147}148}149150private static void queueForCleanup(KeepAliveCleanerEntry kace) {151synchronized(queue) {152if(!kace.getQueuedForCleanup()) {153if (!queue.offer(kace)) {154kace.getHttpClient().closeServer();155return;156}157158kace.setQueuedForCleanup();159queue.notifyAll();160}161162boolean startCleanupThread = (cleanerThread == null);163if (!startCleanupThread) {164if (!cleanerThread.isAlive()) {165startCleanupThread = true;166}167}168169if (startCleanupThread) {170java.security.AccessController.doPrivileged(171new java.security.PrivilegedAction<Void>() {172public Void run() {173// We want to create the Keep-Alive-SocketCleaner in the174// system threadgroup175ThreadGroup grp = Thread.currentThread().getThreadGroup();176ThreadGroup parent = null;177while ((parent = grp.getParent()) != null) {178grp = parent;179}180181cleanerThread = new Thread(grp, queue, "Keep-Alive-SocketCleaner");182cleanerThread.setDaemon(true);183cleanerThread.setPriority(Thread.MAX_PRIORITY - 2);184// Set the context class loader to null in order to avoid185// keeping a strong reference to an application classloader.186cleanerThread.setContextClassLoader(null);187cleanerThread.start();188return null;189}190});191}192} // queue193}194195protected long remainingToRead() {196return expected - count;197}198199protected void setClosed() {200in = null;201hc = null;202closed = true;203}204}205206207