001: // Reply.java
002: // $Id: Reply.java,v 1.18 2003/01/06 17:11:20 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1996.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.www.protocol.http;
007:
008: import java.io.IOException;
009: import java.io.InputStream;
010: import java.io.StringBufferInputStream;
011:
012: import org.w3c.www.mime.MimeParser;
013: import org.w3c.www.mime.MimeType;
014:
015: import org.w3c.www.http.ChunkedInputStream;
016: import org.w3c.www.http.ContentLengthInputStream;
017: import org.w3c.www.http.HTTP;
018: import org.w3c.www.http.HttpEntityMessage;
019: import org.w3c.www.http.HttpFactory;
020: import org.w3c.www.http.HttpMessage;
021: import org.w3c.www.http.HttpMimeType;
022: import org.w3c.www.http.HttpReplyMessage;
023: import org.w3c.www.http.HttpRequestMessage;
024: import org.w3c.www.http.HttpStreamObserver;
025:
026: public class Reply extends HttpReplyMessage {
027: protected static HttpMimeType DEFAULT_TYPE = null;
028:
029: static {
030: DEFAULT_TYPE = HttpFactory.makeMimeType(MimeType.TEXT_HTML);
031: }
032:
033: MimeParser parser = null;
034: HttpStreamObserver observer = null;
035:
036: public boolean keepsAlive() {
037: if (major >= 1) {
038: // HTTP/1.1 is quite cool, in some sense
039: if (minor >= 1)
040: return ((getContentLength() >= 0) || hasTransferEncoding("chunked"));
041: // HTTP/1.0 tries to be as cool, with no success
042: return (hasConnection("keep-alive") || hasProxyConnection("keep-alive"));
043: }
044: return false;
045: }
046:
047: /**
048: * Set an stream observer on the reply entity stream.
049: * This method should be called <em>before</em> any caller gets
050: * a chance to execute <code>getInputStream</code>. It is needed
051: * for HttpServer instances to be notified when the stream becomes
052: * available for the next request.
053: */
054:
055: protected void setStreamObserver(HttpStreamObserver observer) {
056: this .observer = observer;
057: }
058:
059: /**
060: * Notify this reply that is has been built to answer given request.
061: * Perform has many ugly hack HTTP/1.1 requires.
062: * @param request The request that is answered by this reply.
063: */
064:
065: protected void matchesRequest(Request request) {
066: String mth = request.getMethod();
067: if (mth.equals("HEAD") /* || mth.equals("OPTIONS") */)
068: setStream(null);
069: }
070:
071: protected InputStream input = null;
072: protected boolean definesInput = false;
073:
074: /**
075: * Set this reply's input stream.
076: * @param input The stream to read the reply's entity from.
077: */
078:
079: public void setStream(InputStream input) {
080: this .input = input;
081: this .definesInput = true;
082: }
083:
084: /**
085: * Get this reply entity body.
086: * The reply entity body is returned as an InputStream, that the caller
087: * has to read to actually get the bytes of the content.
088: * @return An InputStream instance. If the reply has no body, the
089: * returned input stream will just return <strong>-1</strong> on
090: * first read.
091: */
092:
093: public InputStream getInputStream() throws IOException {
094: if (definesInput)
095: return input;
096: // Check the status code, there are some special cases floating around
097: switch (getStatus()) {
098: case HTTP.NOT_MODIFIED:
099: case HTTP.NO_CONTENT:
100: return null;
101: }
102: // First, do we have chunked encoding:
103: if (hasTransferEncoding("chunked")) {
104: definesInput = true;
105: input = new ChunkedInputStream(observer, parser
106: .getInputStream());
107: return input;
108: }
109: // Find out if there is a content length
110: int len = getContentLength();
111: if (len >= 0) {
112: input = new ContentLengthInputStream(observer, parser
113: .getInputStream(), len);
114: definesInput = true;
115: return input;
116: }
117: // Everything has failed, we assume the connection will close:
118: if (observer != null)
119: observer.notifyFailure(parser.getInputStream());
120: return parser.getInputStream();
121: }
122:
123: /**
124: * Does this reply has an associated entity stream ?
125: * @return A boolean, <strong>true</strong> if the reply has an entity
126: * stream, <strong>false</strong> otherwise.
127: */
128:
129: public boolean hasInputStream() throws IOException {
130: return getInputStream() != null;
131: }
132:
133: /**
134: * Set this reply content.
135: * This method allows to set the reply content to a simple String instance.
136: * @param msg The reply content.
137: */
138:
139: public void setContent(String msg) {
140: if (!hasHeader(H_CONTENT_TYPE))
141: setHeaderValue(H_CONTENT_TYPE, DEFAULT_TYPE);
142: setContentLength(msg.length());
143: setStream(new StringBufferInputStream(msg));
144: }
145:
146: protected Reply(short major, short minor, int status) {
147: this .major = major;
148: this .minor = minor;
149: this .setStatus(status);
150: }
151:
152: protected Reply(MimeParser parser) {
153: super(parser);
154: this.parser = parser;
155: }
156:
157: }
|