Path: blob/master/src/java.base/share/classes/sun/net/www/MeteredStream.java
41159 views
/*1* Copyright (c) 1994, 2020, 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;2627import java.io.*;28import java.util.concurrent.locks.ReentrantLock;29import sun.net.ProgressSource;30import sun.net.www.http.ChunkedInputStream;313233public class MeteredStream extends FilterInputStream {3435// Instance variables.36/* if expected != -1, after we've read >= expected, we're "closed" and return -137* from subsequest read() 's38*/39protected boolean closed = false;40protected long expected;41protected long count = 0;42protected long markedCount = 0;43protected int markLimit = -1;44protected ProgressSource pi;45private final ReentrantLock readLock = new ReentrantLock();4647public MeteredStream(InputStream is, ProgressSource pi, long expected)48{49super(is);5051this.pi = pi;52this.expected = expected;5354if (pi != null) {55pi.updateProgress(0, expected);56}57}5859private final void justRead(long n) throws IOException {60assert isLockHeldByCurrentThread();6162if (n == -1) {6364/*65* don't close automatically when mark is set and is valid;66* cannot reset() after close()67*/68if (!isMarked()) {69close();70}71return;72}7374count += n;7576/**77* If read beyond the markLimit, invalidate the mark78*/79if (count - markedCount > markLimit) {80markLimit = -1;81}8283if (pi != null)84pi.updateProgress(count, expected);8586if (isMarked()) {87return;88}8990// if expected length is known, we could determine if91// read overrun.92if (expected > 0) {93if (count >= expected) {94close();95}96}97}9899/**100* Returns true if the mark is valid, false otherwise101*/102private boolean isMarked() {103assert isLockHeldByCurrentThread();104105if (markLimit < 0) {106return false;107}108109// mark is set, but is not valid anymore110if (count - markedCount > markLimit) {111return false;112}113114// mark still holds115return true;116}117118public int read() throws java.io.IOException {119lock();120try {121if (closed) return -1;122int c = in.read();123if (c != -1) {124justRead(1);125} else {126justRead(c);127}128return c;129} finally {130unlock();131}132}133134public int read(byte b[], int off, int len)135throws java.io.IOException {136lock();137try {138if (closed) return -1;139140int n = in.read(b, off, len);141justRead(n);142return n;143} finally {144unlock();145}146}147148public long skip(long n) throws IOException {149lock();150try {151// REMIND: what does skip do on EOF????152if (closed) return 0;153154if (in instanceof ChunkedInputStream) {155n = in.skip(n);156} else {157// just skip min(n, num_bytes_left)158long min = (n > expected - count) ? expected - count : n;159n = in.skip(min);160}161justRead(n);162return n;163} finally {164unlock();165}166}167168public void close() throws IOException {169lock();170try {171if (closed) return;172if (pi != null)173pi.finishTracking();174175closed = true;176in.close();177} finally {178unlock();179}180}181182public int available() throws IOException {183lock();184try {185return closed ? 0 : in.available();186} finally {187unlock();188}189}190191public void mark(int readLimit) {192lock();193try {194if (closed) return;195super.mark(readLimit);196197/*198* mark the count to restore upon reset199*/200markedCount = count;201markLimit = readLimit;202} finally {203unlock();204}205}206207public void reset() throws IOException {208lock();209try {210if (closed) return;211if (!isMarked()) {212throw new IOException("Resetting to an invalid mark");213}214215count = markedCount;216super.reset();217} finally {218unlock();219}220}221222public boolean markSupported() {223lock();224try {225if (closed) return false;226return super.markSupported();227} finally {228unlock();229}230}231232public final void lock() {233readLock.lock();234}235236public final void unlock() {237readLock.unlock();238}239240public final boolean isLockHeldByCurrentThread() {241return readLock.isHeldByCurrentThread();242}243244@SuppressWarnings("deprecation")245protected void finalize() throws Throwable {246try {247close();248if (pi != null)249pi.close();250}251finally {252// Call super class253super.finalize();254}255}256}257258259