001: /*
002: License $Id: ResponseLine.java,v 1.7 2003/09/13 04:59:55 hendriks73 Exp $
003:
004: Copyright (c) 2001-2005 tagtraum industries.
005:
006: LGPL
007: ====
008:
009: jo! is free software; you can redistribute it and/or
010: modify it under the terms of the GNU Lesser General Public
011: License as published by the Free Software Foundation; either
012: version 2.1 of the License, or (at your option) any later version.
013:
014: jo! is distributed in the hope that it will be useful,
015: but WITHOUT ANY WARRANTY; without even the implied warranty of
016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: Lesser General Public License for more details.
018:
019: You should have received a copy of the GNU Lesser General Public
020: License along with this library; if not, write to the Free Software
021: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022:
023: For LGPL see <http://www.fsf.org/copyleft/lesser.txt>
024:
025:
026: Sun license
027: ===========
028:
029: This release contains software by Sun Microsystems. Therefore
030: the following conditions have to be met, too. They apply to the
031: files
032:
033: - lib/mail.jar
034: - lib/activation.jar
035: - lib/jsse.jar
036: - lib/jcert.jar
037: - lib/jaxp.jar
038: - lib/crimson.jar
039: - lib/servlet.jar
040: - lib/jnet.jar
041: - lib/jaas.jar
042: - lib/jaasmod.jar
043:
044: contained in this release.
045:
046: a. Licensee may not modify the Java Platform
047: Interface (JPI, identified as classes contained within the javax
048: package or any subpackages of the javax package), by creating additional
049: classes within the JPI or otherwise causing the addition to or modification
050: of the classes in the JPI. In the event that Licensee creates any
051: Java-related API and distribute such API to others for applet or
052: application development, you must promptly publish broadly, an accurate
053: specification for such API for free use by all developers of Java-based
054: software.
055:
056: b. Software is confidential copyrighted information of Sun and
057: title to all copies is retained by Sun and/or its licensors. Licensee
058: shall not modify, decompile, disassemble, decrypt, extract, or otherwise
059: reverse engineer Software. Software may not be leased, assigned, or
060: sublicensed, in whole or in part. Software is not designed or intended
061: for use in on-line control of aircraft, air traffic, aircraft navigation
062: or aircraft communications; or in the design, construction, operation or
063: maintenance of any nuclear facility. Licensee warrants that it will not
064: use or redistribute the Software for such purposes.
065:
066: c. Software is provided "AS IS," without a warranty
067: of any kind. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES,
068: INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
069: PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
070:
071: d. This License is effective until terminated. Licensee may
072: terminate this License at any time by destroying all copies of Software.
073: This License will terminate immediately without notice from Sun if Licensee
074: fails to comply with any provision of this License. Upon such termination,
075: Licensee must destroy all copies of Software.
076:
077: e. Software, including technical data, is subject to U.S.
078: export control laws, including the U.S. Export Administration Act and its
079: associated regulations, and may be subject to export or import regulations
080: in other countries. Licensee agrees to comply strictly with all such
081: regulations and acknowledges that it has the responsibility to obtain
082: licenses to export, re-export, or import Software. Software may not be
083: downloaded, or otherwise exported or re-exported (i) into, or to a national
084: or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, Syria or any
085: country to which the U.S. has embargoed goods; or (ii) to anyone on the
086: U.S. Treasury Department's list of Specially Designated Nations or the U.S.
087: Commerce Department's Table of Denial Orders.
088:
089:
090: Feedback
091: ========
092:
093: We encourage your feedback and suggestions and want to use your feedback to
094: improve the Software. Send all such feedback to:
095: <feedback@tagtraum.com>
096:
097: For more information on tagtraum industries and jo!
098: please see <http://www.tagtraum.com/>.
099:
100:
101: */
102: package com.tagtraum.framework.http;
103:
104: import com.tagtraum.perf.util.SingleDelimiterStringTokenizer;
105:
106: import javax.servlet.ServletInputStream;
107: import javax.servlet.ServletOutputStream;
108: import javax.servlet.http.HttpServletResponse;
109: import java.io.IOException;
110: import java.io.InputStream;
111: import java.io.OutputStream;
112: import java.io.Serializable;
113: import java.util.NoSuchElementException;
114:
115: /**
116: * Encapsulates a ResponseLine. This class is not synchronized.
117: *
118: * @version 1.1beta1 $Id: ResponseLine.java,v 1.7 2003/09/13 04:59:55 hendriks73 Exp $
119: * @author Hendrik Schreiber
120: */
121: public class ResponseLine implements C_Http, Serializable {
122:
123: /**
124: * Source-Version
125: */
126: public static String vcid = "$Id: ResponseLine.java,v 1.7 2003/09/13 04:59:55 hendriks73 Exp $";
127:
128: /**
129: *
130: */
131: protected String myResponseLine;
132:
133: /**
134: *
135: */
136: protected int myStatusCode;
137:
138: /**
139: *
140: */
141: protected String myProtocol;
142:
143: /**
144: *
145: */
146: protected String myReasonPhrase;
147:
148: protected byte[] readbuf = new byte[1024];
149: private SingleDelimiterStringTokenizer tokenizer;
150:
151: /**
152: * Constructor.
153: */
154: public ResponseLine() {
155: myStatusCode = StatusCodes.SC_OK;
156: myReasonPhrase = StatusCodes.get(StatusCodes.SC_OK);
157: myProtocol = C_HTTP_1_0;
158: tokenizer = new SingleDelimiterStringTokenizer();
159: }
160:
161: /**
162: * Constructor.
163: */
164: public ResponseLine(String aResponseLine) throws HttpException {
165: this ();
166:
167: read(aResponseLine);
168: }
169:
170: /**
171: * Constructor.
172: */
173: public ResponseLine(InputStream in) throws HttpException,
174: IOException {
175: this ();
176:
177: read(in);
178: }
179:
180: /**
181: * Reads a ResponseLine from a string.
182: *
183: * @param aResponseLine the line
184: */
185: public void read(String aResponseLine) throws HttpException {
186: parseResponseLine(aResponseLine);
187: }
188:
189: /**
190: * Reads a ResponseLine from an <code>InputStream</code>.
191: *
192: * @param in the stream
193: */
194: public void read(InputStream in) throws IOException, HttpException {
195: parseResponseLine(readLine(in));
196: }
197:
198: /**
199: * Reads a ResponseLine from an <code>ServletInputStream</code>.
200: *
201: * @param in the stream
202: */
203: public void read(ServletInputStream in) throws IOException,
204: HttpException {
205: byte[] b = new byte[1024];
206: int len = in.readLine(b, 0, 1024);
207:
208: // complain about too long URIs
209: if (len == 1024) {
210: throw new HttpException("ResponseLine is too long.");
211: }
212:
213: parseResponseLine((new String(b, 0)).trim());
214: }
215:
216: /**
217: * Writes the ResponseLine to an <code>OuputStream</code>.
218: *
219: * @param out the OutputStream
220: */
221: public void write(OutputStream out) throws IOException {
222: String line = toString();
223: int len = line.length();
224: byte[] buf = new byte[len];
225: line.getBytes(0, len, buf, 0); // use deprecated method for speed
226: out.write(buf);
227: // actually the right way - slower? (rik)
228: // out.write(toString().getBytes("ASCII"));
229: }
230:
231: /**
232: * Writes the ResponseLine to an <code>ServletOuputStream</code>.
233: *
234: * @param out the ServletOutputStream
235: */
236: public void write(ServletOutputStream out) throws IOException {
237: out.print(toString());
238: }
239:
240: /**
241: * Returns the StatusCode.
242: */
243: public int getStatusCode() {
244: return myStatusCode;
245: }
246:
247: /**
248: * Sets a StatusCode. The ReasonPhrase is set accordingly.
249: */
250: public void setStatusCode(int aStatusCode) {
251: myStatusCode = aStatusCode;
252: myReasonPhrase = StatusCodes.get(aStatusCode);
253: }
254:
255: /**
256: * Sets a StatusCode and a ReasonPhrase.
257: */
258: public void setStatusCode(int aStatusCode, String aReasonPhrase) {
259: myStatusCode = aStatusCode;
260: myReasonPhrase = aReasonPhrase;
261: }
262:
263: /**
264: * Returns the protocol.
265: */
266: public String getProtocol() {
267: return myProtocol;
268: }
269:
270: /**
271: * Sets a protocol.
272: */
273: public void setProtocol(String aProtocol) {
274: myProtocol = aProtocol;
275: }
276:
277: /**
278: * Returns the ReasonPhrase.
279: */
280: public String getReasonPhrase() {
281: return myReasonPhrase;
282: }
283:
284: /**
285: * Sets a ReasonPhrase.
286: */
287: public void setReasonPhrase(String aReasonPhrase) {
288: myReasonPhrase = aReasonPhrase;
289: }
290:
291: /**
292: * String.
293: */
294: public String toString() {
295: int protocolLength = myProtocol.length();
296: int reasonPhraseLength = 0;
297: if (myReasonPhrase != null) {
298: reasonPhraseLength = myReasonPhrase.length();
299: }
300: char[] buf = new char[protocolLength + reasonPhraseLength + 5];
301: myProtocol.getChars(0, protocolLength, buf, 0);
302: buf[protocolLength] = ' ';
303: buf[protocolLength + 1] = (char) (myStatusCode / 100 + 48);
304: buf[protocolLength + 2] = (char) ((myStatusCode - (myStatusCode / 100) * 100) / 10 + 48);
305: buf[protocolLength + 3] = (char) ((myStatusCode - (myStatusCode / 10) * 10) + 48);
306: buf[protocolLength + 4] = ' ';
307: if (myReasonPhrase != null) {
308: myReasonPhrase.getChars(0, reasonPhraseLength, buf,
309: protocolLength + 5);
310: }
311: return new String(buf);
312: }
313:
314: /**
315: * Parses a ResponseLine.
316: */
317: protected void parseResponseLine(String aResponseLine)
318: throws HttpException {
319: if (aResponseLine == null) {
320: throw new HttpException("Malformed ResponseLine: null");
321: }
322:
323: tokenizer.init(aResponseLine, ' ');
324: String theStatusCode = null;
325:
326: try {
327: myProtocol = tokenizer.nextToken();
328: theStatusCode = tokenizer.nextToken();
329: myStatusCode = Integer.parseInt(theStatusCode);
330:
331: int i = myProtocol.length() + theStatusCode.length() + 1;
332:
333: if (aResponseLine.length() > i) {
334: myReasonPhrase = aResponseLine.substring(i);
335: } else {
336: myReasonPhrase = StatusCodes.get(myStatusCode);
337: }
338: } catch (NoSuchElementException nsee) {
339: throw new HttpException("Malformed ResponseLine: "
340: + aResponseLine);
341: } catch (NumberFormatException nfe) {
342: throw new HttpException("Bad statuscode in ResponseLine: "
343: + aResponseLine);
344: }
345: }
346:
347: /**
348: * Reads a line from the <code>InputStream</code>.
349: *
350: * @param aInputStream the InputStream
351: * @exception IllegalArgumentException if the line is longer than 1024 chars
352: */
353: protected String readLine(InputStream aInputStream)
354: throws IOException, HttpException {
355: int c;
356: int pos = 0;
357:
358: LineLoop: while ((c = aInputStream.read()) != -1) {
359: if (pos == 1024) {
360: throw new HttpException(
361: HttpServletResponse.SC_REQUEST_URI_TOO_LONG);
362: }
363:
364: switch (c) {
365:
366: case 10: // \n
367: readbuf[pos] = (byte) c;
368: pos++;
369:
370: break LineLoop;
371:
372: default:
373: readbuf[pos] = (byte) c;
374: pos++;
375:
376: break;
377: }
378: }
379:
380: if (c == -1 && pos == 0) {
381: throw new HttpException(
382: "Failed to read ResponseLine: Unexpected end of stream.");
383: }
384:
385: return new String(readbuf, 0, 0, pos);
386: }
387:
388: }
|