1 /* 2 * Copyright (c) 1994, 2004, 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; 27 28 import java.net.URL; 29 import java.util.*; 30 import java.io.*; 31 import sun.net.ProgressSource; 32 import sun.net.www.http.ChunkedInputStream; 33 34 35 public class MeteredStream extends FilterInputStream { 36 37 // Instance variables. 38 /* if expected != -1, after we've read >= expected, we're "closed" and return -1 39 * from subsequest read() 's 40 */ 41 protected boolean closed = false; 42 protected long expected; 43 protected long count = 0; 44 protected long markedCount = 0; 45 protected int markLimit = -1; 46 protected ProgressSource pi; 47 MeteredStream(InputStream is, ProgressSource pi, long expected)48 public MeteredStream(InputStream is, ProgressSource pi, long expected) 49 { 50 super(is); 51 52 this.pi = pi; 53 this.expected = expected; 54 55 if (pi != null) { 56 pi.updateProgress(0, expected); 57 } 58 } 59 justRead(long n)60 private final void justRead(long n) throws IOException { 61 if (n == -1) { 62 63 /* 64 * don't close automatically when mark is set and is valid; 65 * cannot reset() after close() 66 */ 67 if (!isMarked()) { 68 close(); 69 } 70 return; 71 } 72 73 count += n; 74 75 /** 76 * If read beyond the markLimit, invalidate the mark 77 */ 78 if (count - markedCount > markLimit) { 79 markLimit = -1; 80 } 81 82 if (pi != null) 83 pi.updateProgress(count, expected); 84 85 if (isMarked()) { 86 return; 87 } 88 89 // if expected length is known, we could determine if 90 // read overrun. 91 if (expected > 0) { 92 if (count >= expected) { 93 close(); 94 } 95 } 96 } 97 98 /** 99 * Returns true if the mark is valid, false otherwise 100 */ isMarked()101 private boolean isMarked() { 102 103 if (markLimit < 0) { 104 return false; 105 } 106 107 // mark is set, but is not valid anymore 108 if (count - markedCount > markLimit) { 109 return false; 110 } 111 112 // mark still holds 113 return true; 114 } 115 read()116 public synchronized int read() throws java.io.IOException { 117 if (closed) { 118 return -1; 119 } 120 int c = in.read(); 121 if (c != -1) { 122 justRead(1); 123 } else { 124 justRead(c); 125 } 126 return c; 127 } 128 read(byte b[], int off, int len)129 public synchronized int read(byte b[], int off, int len) 130 throws java.io.IOException { 131 if (closed) { 132 return -1; 133 } 134 int n = in.read(b, off, len); 135 justRead(n); 136 return n; 137 } 138 skip(long n)139 public synchronized long skip(long n) throws IOException { 140 141 // REMIND: what does skip do on EOF???? 142 if (closed) { 143 return 0; 144 } 145 146 if (in instanceof ChunkedInputStream) { 147 n = in.skip(n); 148 } 149 else { 150 // just skip min(n, num_bytes_left) 151 long min = (n > expected - count) ? expected - count: n; 152 n = in.skip(min); 153 } 154 justRead(n); 155 return n; 156 } 157 close()158 public void close() throws IOException { 159 if (closed) { 160 return; 161 } 162 if (pi != null) 163 pi.finishTracking(); 164 165 closed = true; 166 in.close(); 167 } 168 available()169 public synchronized int available() throws IOException { 170 return closed ? 0: in.available(); 171 } 172 mark(int readLimit)173 public synchronized void mark(int readLimit) { 174 if (closed) { 175 return; 176 } 177 super.mark(readLimit); 178 179 /* 180 * mark the count to restore upon reset 181 */ 182 markedCount = count; 183 markLimit = readLimit; 184 } 185 reset()186 public synchronized void reset() throws IOException { 187 if (closed) { 188 return; 189 } 190 191 if (!isMarked()) { 192 throw new IOException ("Resetting to an invalid mark"); 193 } 194 195 count = markedCount; 196 super.reset(); 197 } 198 markSupported()199 public boolean markSupported() { 200 if (closed) { 201 return false; 202 } 203 return super.markSupported(); 204 } 205 finalize()206 protected void finalize() throws Throwable { 207 try { 208 close(); 209 if (pi != null) 210 pi.close(); 211 } 212 finally { 213 // Call super class 214 super.finalize(); 215 } 216 } 217 } 218