001: package com.quadcap.net.server;
002:
003: /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.FileOutputStream;
042: import java.io.IOException;
043: import java.io.InputStream;
044:
045: import com.quadcap.util.Debug;
046: import com.quadcap.util.Util;
047:
048: /**
049: * An efficient worker input stream, which supports recycling.
050: * Additionally, this class performs all necessary buffering and
051: * some other higher level functions on the socket input stream, so
052: * no extra 'buffered' are needed.
053: *
054: * <p>In a violoation of layering, but to achieve maximum performance,
055: * this class knows how to "parse" HTTP headers.</p>
056: *
057: * @author Stan Bailes
058: */
059: public final class WorkerInputStream extends InputStream {
060: final static int MAX = 4096;
061: byte[] buf = new byte[MAX + 1];
062: int pos = 0;
063: int lim = 0;
064: boolean eof = false;
065: InputStream in;
066:
067: //#ifdef DEBUG
068: static boolean doTrace = false;
069: FileOutputStream log;
070:
071: //#endif
072:
073: public WorkerInputStream(FileOutputStream f) {
074: //#ifdef DEBUG
075: doTrace = (f != null);
076: log = f;
077: //#endif
078: }
079:
080: public final void reset(InputStream in) throws IOException {
081: this .in = in;
082: this .eof = false;
083: this .pos = 0;
084: this .lim = 0;
085: //#ifdef DEBUG
086: if (doTrace) {
087: log
088: .write(("RESET " + Thread.currentThread().getName() + "\r\n")
089: .getBytes());
090: }
091: //#endif
092: }
093:
094: public final int read() throws IOException {
095: if (pos >= lim && !eof)
096: fill();
097: int c = eof ? -1 : buf[pos++];
098: return c;
099: }
100:
101: public void unread(int c) {
102: buf[--pos] = (byte) c;
103: }
104:
105: /**
106: * Fill the buffer. Return true unless we're at end of file and have
107: * returned zero bytes in this fill
108: */
109: final boolean fill() throws IOException {
110: boolean ret = true;
111: pos = 0;
112: lim = in.read(buf, 0, MAX);
113: if (lim < 0) {
114: eof = true;
115: lim = 0;
116: ret = false;
117: }
118: //#ifdef DEBUG
119: if (doTrace)
120: log.write(buf, 0, lim);
121: //#endif
122: return ret;
123: }
124:
125: public final int read(byte[] b, int off, int len)
126: throws IOException {
127: int rlim = off + len;
128: while (off < rlim && !eof) {
129: if (pos >= lim)
130: fill();
131: int cnt = lim - pos;
132: if (len < cnt)
133: cnt = len;
134: if (cnt > 0) {
135: System.arraycopy(buf, pos, b, off, cnt);
136: pos += cnt;
137: off += cnt;
138: }
139: }
140: int cnt = off - (rlim - len);
141: return cnt == 0 ? (eof ? -1 : 0) : cnt;
142: }
143:
144: public final int read(byte[] b) throws IOException {
145: return read(b, 0, b.length);
146: }
147:
148: static byte[] CRLF = { 0x0d, 0x0a, 0x0d, 0x0a };
149:
150: /**
151: * Read HTTP readers from the input stream.
152: * @param hbuf We place the entire header octet sequence into hbuf,
153: * terminated with CRLF
154: * @param offsets We place the byte offset of the start of each
155: * header into the offsets array
156: * @return the number of headers found
157: */
158: public final int readHeaders(byte[] hbuf, int[] offsets)
159: throws IOException {
160: int off = 0; // offset into hbuf
161: int p = pos;
162: int l = lim;
163: int hcnt = 1;
164: buf[lim] = (byte) '\r';
165: int s = 1;
166: while (true) {
167: while (buf[p++] != '\r')
168: continue;
169: while (l - p < 4 - s) {
170: if (p > l) {
171: p--;
172: s--;
173: }
174: while (p < l && buf[p++] == CRLF[s]) {
175: if (++s == 2 && off + p - pos > 2) {
176: offsets[hcnt++] = p - pos + off;
177: }
178: }
179: int len = p - pos;
180: System.arraycopy(buf, pos, hbuf, off, len);
181: fill();
182: if (eof) {
183: offsets[0] = hcnt - 1;
184: return off + len;
185: }
186: p = 0;
187: l = lim;
188: buf[lim] = (byte) '\r';
189: off += len;
190: }
191: while (buf[p++] == CRLF[s]) {
192: ++s;
193: final int len = p - pos;
194: if (s == 2 && len + off > 2) {
195: offsets[hcnt++] = len + off;
196: } else if (s == 4) {
197: System.arraycopy(buf, pos, hbuf, off, len);
198: pos = p;
199: offsets[0] = hcnt - 1;
200: return off + len;
201: }
202: }
203: s = 1;
204: }
205: }
206:
207: final void show(String s, int p) {
208: System.out.println("------ " + s);
209: for (int i = 0; i < lim; i++) {
210: if (buf[i] == '\r')
211: System.out.print('D');
212: else if (buf[i] == '\n')
213: System.out.print('A');
214: else
215: System.out.print((char) buf[i]);
216: }
217: System.out.println("");
218: for (int i = 0; i < p; i++) {
219: System.out.print(" ");
220: }
221: System.out.println("^");
222: System.out.println("");
223: }
224:
225: public final void close() throws IOException {
226: in.close();
227: in = null;
228: //#ifdef DEBUG
229: if (doTrace)
230: log.write("CLOSE\r\n".getBytes());
231: //#endif
232: }
233:
234: public String toString() {
235: return Util.strBytes(buf, 0, lim);
236: }
237:
238: }
|