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