blob: 4de122f2db2f6d589cb28181a0e8cd2b56345f9c [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1994-2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.net.www;
27
28import java.net.URL;
29import java.util.*;
30import java.io.*;
31import sun.net.ProgressSource;
32import sun.net.www.http.ChunkedInputStream;
33
34
35public 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
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
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 */
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
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
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
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
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
169 public synchronized int available() throws IOException {
170 return closed ? 0: in.available();
171 }
172
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
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
199 public boolean markSupported() {
200 if (closed) {
201 return false;
202 }
203 return super.markSupported();
204 }
205
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}