Put the classes in the com.fastcgi package
[catagits/fcgi2.git] / java / FCGIInputStream.java
CommitLineData
61962ef7 1/*
2 * @(#)FCGIInputStream.java
3 *
4 * FastCGi compatibility package Interface
5 *
6 *
7 * Copyright (c) 1996 Open Market, Inc.
8 *
9 * See the file "LICENSE.TERMS" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 *
07c41236 12 * $Id: FCGIInputStream.java,v 1.3 2000/03/21 12:02:29 robs Exp $
61962ef7 13 */
07c41236 14package com.fastcgi;
61962ef7 15
16import java.io.*;
61962ef7 17
18/**
19 * This stream manages buffered reads of FCGI messages.
20 */
21public class FCGIInputStream extends InputStream {
22
23 /* Stream vars */
24
25 public int rdNext;
26 public int stop;
27 public boolean isClosed;
28
29 /* require methods to set, get and clear */
30 private int errno;
31 private Exception errex;
32
33 /* data vars */
34
35 public byte buff[];
36 public int buffLen;
37 public int buffStop;
38 public int type;
39 public int contentLen;
40 public int paddingLen;
41 public boolean skip;
42 public boolean eorStop;
43 public FCGIRequest request;
44
45 public InputStream in;
46
47
48 /**
49 * Creates a new input stream to manage fcgi prototcol stuff
50 * @param in the input stream bufLen length of buffer streamType
51 */
52 public FCGIInputStream(FileInputStream inStream, int bufLen,
53 int streamType,
54 FCGIRequest inReq) {
55
56 in = inStream;
57 buffLen = Math.min(bufLen,FCGIGlobalDefs.def_FCGIMaxLen);
58 buff = new byte[buffLen];
59 type = streamType;
60 stop = rdNext = buffStop = 0;
61 isClosed = false;
62 contentLen = 0;
63 paddingLen = 0;
64 skip = false;
65 eorStop = false;
66 request = inReq;
67
68 }
69 /**
70 * Reads a byte of data. This method will block if no input is
71 * available.
72 * @return the byte read, or -1 if the end of the
73 * stream is reached.
74 * @exception IOException If an I/O error has occurred.
75 */
76 public int read() throws IOException {
77 if (rdNext != stop) {
9c38d1d4 78 return buff[rdNext++] & 0xff;
61962ef7 79 }
80 if (isClosed){
81 return -1;
82 }
83 fill();
84 if (rdNext != stop){
9c38d1d4 85 return buff[rdNext++] & 0xff;
61962ef7 86 }
87 return -1;
88 }
89 /**
90 * Reads into an array of bytes. This method will
91 * block until some input is available.
92 * @param b the buffer into which the data is read
93 * @return the actual number of bytes read, -1 is
94 * returned when the end of the stream is reached.
95 * @exception IOException If an I/O error has occurred.
96 */
97 public int read(byte b[]) throws IOException {
98 return read(b, 0, b.length);
99 }
100
101 /**
102 * Reads into an array of bytes.
103 * Blocks until some input is available.
104 * @param b the buffer into which the data is read
105 * @param off the start offset of the data
106 * @param len the maximum number of bytes read
107 * @return the actual number of bytes read, -1 is
108 * returned when the end of the stream is reached.
109 * @exception IOException If an I/O error has occurred.
110 */
111 public int read(byte b[], int off, int len) throws IOException {
112 int m, bytesMoved;
113
114 if (len <= 0){
115 return 0;
116 }
117 /*
118 *Fast path: len bytes already available.
119 */
120
121 if (len <= stop - rdNext){
122 System.arraycopy(buff, rdNext, b, off, len);
123 rdNext += len;
124 return len;
125 }
126 /*
127 *General case: stream is closed or fill needs to be called
128 */
129 bytesMoved = 0;
130 for(;;){
131 if (rdNext != stop){
132 m = Math.min(len - bytesMoved, stop - rdNext);
133 System.arraycopy(buff, rdNext, b, off, m);
134 bytesMoved += m;
135 rdNext += m;
136 if (bytesMoved == len)
137 return bytesMoved;
138 off += m;
139 }
140 if (isClosed){
141 return bytesMoved;
142 }
143 fill();
144
145 }
146 }
147 /**
148 * Reads into an array of bytes. This method will
149 * block until some input is available.
150 * @param b the buffer into which the data is read
151 * @param off the start offset of the data
152 * @param len the maximum number of bytes read
153 * @return the actual number of bytes read, -1 is
154 * returned when the end of the stream is reached.
155 * @exception IOException If an I/O error has occurred.
156 */
157 public void fill() throws IOException {
158 byte[] headerBuf = new byte[FCGIGlobalDefs.def_FCGIHeaderLen];
159 int headerLen = 0;
160 int status = 0;
161 int count = 0;
162 for(;;) {
163 /*
164 * If buffer is empty, do a read
165 */
166 if (rdNext == buffStop) {
167 try {
168 count = in.read(buff, 0, buffLen);
169 } catch (IOException e) {
170 setException(e);
171 return;
172 }
173 if (count == 0) {
174 setFCGIError(FCGIGlobalDefs.def_FCGIProtocolError);
175 return;
176 }
177 rdNext = 0;
178 buffStop = count; // 1 more than we read
179 }
180 /* Now buf is not empty: If the current record contains more content
181 * bytes, deliver all that are present in buff to callers buffer
182 * unless he asked for less than we have, in which case give him less
183 */
184 if (contentLen > 0) {
185 count = Math.min(contentLen, buffStop - rdNext);
186 contentLen -= count;
187 if (!skip) {
188 stop = rdNext + count;
189 return;
190 }
191 else {
192 rdNext += count;
193 if (contentLen > 0) {
194 continue;
195 }
196 else {
197 skip = false;
198 }
199 }
200 }
201 /* Content has been consumed by client.
202 * If record was padded, skip over padding
203 */
204 if (paddingLen > 0) {
205 count = Math.min(paddingLen, buffStop - rdNext);
206 paddingLen -= count;
207 rdNext += count;
208 if (paddingLen > 0) {
209 continue; // more padding to read
210 }
211 }
212 /* All done with current record, including the padding.
213 * If we are in a recursive call from Process Header, deliver EOF
214 */
215 if (eorStop){
216 stop = rdNext;
217 isClosed = true;
218 return;
219 }
220 /*
221 * Fill header with bytes from input buffer - get the whole header.
222 */
223 count = Math.min(headerBuf.length - headerLen, buffStop - rdNext);
224 System.arraycopy(buff,rdNext, headerBuf, headerLen, count);
225 headerLen += count;
226 rdNext += count;
227 if (headerLen < headerBuf.length) {
228 continue;
229 }
230 headerLen = 0;
231 /*
232 * Interperet the header. eorStop prevents ProcessHeader from
233 * reading past the end of record when using stream to read content
234 */
235 eorStop = true;
236 stop = rdNext;
237 status = 0;
238 status = new FCGIMessage(this).processHeader(headerBuf);
239 eorStop = false;
240 isClosed = false;
241 switch (status){
242 case FCGIGlobalDefs.def_FCGIStreamRecord:
243 if (contentLen == 0) {
244 stop = rdNext;
245 isClosed = true;
246 return;
247 }
248 break;
249 case FCGIGlobalDefs.def_FCGISkip:
250 skip = true;
251 break;
252 case FCGIGlobalDefs.def_FCGIBeginRecord:
253 /*
254 * If this header marked the beginning of a new
255 * request, return role info to caller
256 */
257 return;
258 case FCGIGlobalDefs.def_FCGIMgmtRecord:
259 break;
260 default:
261 /*
262 * ASSERT
263 */
264 setFCGIError(status);
265 return;
266
267 }
268 }
269 }
270
271 /**
272 * Skips n bytes of input.
273 * @param n the number of bytes to be skipped
274 * @return the actual number of bytes skipped.
275 * @exception IOException If an I/O error has occurred.
276 */
277 public long skip(long n) throws IOException {
278 byte data[] = new byte[(int)n];
279 return in.read(data);
280 }
281
282 /*
283 * An FCGI error has occurred. Save the error code in the stream
284 * for diagnostic purposes and set the stream state so that
285 * reads return EOF
286 */
287 public void setFCGIError(int errnum) {
288 /*
289 * Preserve only the first error.
290 */
291 if(errno == 0) {
292 errno = errnum;
293 }
294 isClosed = true;
295 }
296 /*
297 * An Exception has occurred. Save the Exception in the stream
298 * for diagnostic purposes and set the stream state so that
299 * reads return EOF
300 */
301 public void setException(Exception errexpt) {
302 /*
303 * Preserve only the first error.
304 */
305 if(errex == null) {
306 errex = errexpt;
307 }
308 isClosed = true;
309 }
310
311 /*
312 * Clear the stream error code and end-of-file indication.
313 */
314 public void clearFCGIError() {
315 errno = 0;
316 /*
317 * isClosed = false;
318 * XXX: should clear isClosed but work is needed to make it safe
319 * to do so.
320 */
321 }
322 /*
323 * Clear the stream error code and end-of-file indication.
324 */
325 public void clearException() {
326 errex = null;
327 /*
328 * isClosed = false;
329 * XXX: should clear isClosed but work is needed to make it safe
330 * to do so.
331 */
332 }
333
334 /*
335 * accessor method since var is private
336 */
337 public int getFCGIError() {
338 return errno;
339 }
340 /*
341 * accessor method since var is private
342 */
343 public Exception getException() {
344 return errex;
345 }
346 /*
347 * Re-initializes the stream to read data of the specified type.
348 */
349 public void setReaderType(int streamType) {
350
351 type = streamType;
352 eorStop = false;
353 skip = false;
354 contentLen = 0;
355 paddingLen = 0;
356 stop = rdNext;
357 isClosed = false;
358 }
359
360 /*
361 * Close the stream. This method does not really exist for BufferedInputStream in java,
362 * but is implemented here for compatibility with the FCGI structures being used. It
363 * doent really throw any IOExceptions either, but that's there for compatiblity with
364 * the InputStreamInterface.
365 */
366 public void close() throws IOException{
367 isClosed = true;
368 stop = rdNext;
369 }
370
371 /*
372 * Returns the number of bytes that can be read without blocking.
373 */
374
375 public int available() throws IOException {
376 return stop - rdNext + in.available();
377 }
378
379}