KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > server > http > HttpResponse


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.server.http;
31
32 import com.caucho.server.cluster.Server;
33 import com.caucho.server.connection.AbstractHttpRequest;
34 import com.caucho.server.connection.AbstractHttpResponse;
35 import com.caucho.util.Alarm;
36 import com.caucho.util.CharBuffer;
37 import com.caucho.vfs.WriteStream;
38
39 import javax.servlet.http.Cookie JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.util.logging.Level JavaDoc;
42
43 public class HttpResponse extends AbstractHttpResponse {
44   static final byte []_http10ok = "HTTP/1.0 200 OK".getBytes();
45   static final byte []_http11ok = "HTTP/1.1 200 OK".getBytes();
46   static final byte []_contentLengthBytes = "\r\nContent-Length: ".getBytes();
47   static final byte []_contentTypeBytes = "\r\nContent-Type: ".getBytes();
48   static final byte []_textHtmlBytes = "\r\nContent-Type: text/html".getBytes();
49   static final byte []_charsetBytes = "; charset=".getBytes();
50   static final byte []_textHtmlLatin1Bytes = "\r\nContent-Type: text/html; charset=iso-8859-1".getBytes();
51   
52   static final byte []_connectionCloseBytes = "\r\nConnection: close".getBytes();
53
54   final byte []_resinServerBytes;
55
56   static final char []_connectionCb = "Connection".toCharArray();
57   static final CharBuffer _closeCb = new CharBuffer("Close");
58
59   private final HttpRequest _request;
60
61   private final byte []_dateBuffer = new byte[256];
62   private int _dateBufferLength;
63   private final CharBuffer _dateCharBuffer = new CharBuffer();
64   private long _lastDate;
65
66   /**
67    * Creates a new HTTP-protocol response.
68    *
69    * @param request the matching request object.
70    */

71   HttpResponse(HttpRequest request)
72   {
73     super(request);
74
75     _request = request;
76
77     Server server = (Server) request.getDispatchServer();
78
79     _resinServerBytes = ("\r\nServer: " + server.getServerHeader()).getBytes();
80   }
81
82   /**
83    * Switch to raw socket mode.
84    */

85   public void switchToRaw()
86     throws IOException JavaDoc
87   {
88     clearBuffer();
89
90     setStatus(101);
91
92     finish(); // don't need to flush since it'll close anyway
93
}
94
95   /**
96    * Switch to raw socket mode.
97    */

98   public WriteStream getRawOutput()
99     throws IOException JavaDoc
100   {
101     return _rawWrite;
102   }
103
104   /**
105    * Return true for the top request.
106    */

107   public boolean isTop()
108   {
109     if (! (_request instanceof AbstractHttpRequest))
110       return false;
111     else {
112       return ((AbstractHttpRequest) _request).isTop();
113     }
114   }
115
116   /**
117    * Writes the 100 continue response.
118    */

119   protected void writeContinueInt(WriteStream os)
120     throws IOException JavaDoc
121   {
122     os.print("HTTP/1.1 100 Continue");
123
124     if (! containsHeader("Server"))
125       os.write(_resinServerBytes, 0, _resinServerBytes.length);
126
127     os.print("\r\nContent-Length: 0");
128
129     long now = Alarm.getCurrentTime();
130     if (_lastDate + 1000 < now) {
131       fillDate(now);
132     }
133
134     os.write(_dateBuffer, 0, _dateBufferLength);
135     os.flush();
136   }
137
138   /**
139    * Implementation to write the HTTP headers. If the length is positive,
140    * it's a small request where the buffer contains the entire request,
141    * so the length is already known.
142    *
143    * @param os the output stream to write the headers to.
144    * @param length if non-negative, the length of the entire request.
145    *
146    * @return true if the data in the request should use chunked encoding.
147    */

148   protected boolean writeHeadersInt(WriteStream os, int length)
149     throws IOException JavaDoc
150   {
151     boolean isChunked = false;
152
153     int version = _request.getVersion();
154     boolean debug = log.isLoggable(Level.FINE);
155
156     if (version < HttpRequest.HTTP_1_0) {
157       _request.killKeepalive();
158       return false;
159     }
160
161     int statusCode = _statusCode;
162     if (statusCode == 200) {
163       if (version < HttpRequest.HTTP_1_1)
164     os.write(_http10ok, 0, _http10ok.length);
165       else
166     os.write(_http11ok, 0, _http11ok.length);
167     } else {
168       if (version < HttpRequest.HTTP_1_1)
169     os.print("HTTP/1.0 ");
170       else
171     os.print("HTTP/1.1 ");
172
173       os.write((statusCode / 100) % 10 + '0');
174       os.write((statusCode / 10) % 10 + '0');
175       os.write(statusCode % 10 + '0');
176       os.write(' ');
177       os.print(_statusMessage);
178     }
179
180     if (debug) {
181       log.fine(_request.dbgId() + "HTTP/1.1 " +
182            _statusCode + " " + _statusMessage);
183     }
184
185     if (! containsHeader("Server"))
186       os.write(_resinServerBytes, 0, _resinServerBytes.length);
187
188     if (statusCode >= 400) {
189       removeHeader("ETag");
190       removeHeader("Last-Modified");
191     }
192     // server/1b15
193
else if (_isNoCache) {
194       removeHeader("ETag");
195       removeHeader("Last-Modified");
196
197       // even in case of 302, this may be needed for filters which
198
// automatically set cache headers
199
setHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT");
200       os.print("\r\nCache-Control: no-cache");
201
202       if (debug) {
203         log.fine(_request.dbgId() + "" +
204                  "Expires: Thu, 01 Dec 1994 16:00:00 GMT");
205       }
206     }
207     else if (! isPrivateCache()) {
208     }
209     else if (HttpRequest.HTTP_1_1 <= version) {
210       // technically, this could be private="Set-Cookie,Set-Cookie2"
211
// but caches don't recognize it, so there's no real extra value
212
os.print("\r\nCache-Control: private");
213
214       if (debug)
215         log.fine(_request.dbgId() + "Cache-Control: private");
216     }
217     else if (! containsHeader("Cache-Control")) {
218       setHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT");
219       os.print("\r\nCache-Control: no-cache");
220
221       if (debug) {
222         log.fine(_request.dbgId() + "" +
223                  "Expires: Thu, 01 Dec 1994 16:00:00 GMT");
224       }
225     }
226
227     int size = _headerKeys.size();
228     for (int i = 0; i < size; i++) {
229       String JavaDoc key = (String JavaDoc) _headerKeys.get(i);
230       os.write('\r');
231       os.write('\n');
232       os.print(key);
233       os.write(':');
234       os.write(' ');
235       os.print((String JavaDoc) _headerValues.get(i));
236
237       if (debug) {
238         log.fine(_request.dbgId() + "" +
239                  key + ": " + _headerValues.get(i));
240       }
241     }
242
243     long now = Alarm.getCurrentTime();
244     for (int i = 0; i < _cookiesOut.size(); i++) {
245       Cookie JavaDoc cookie = _cookiesOut.get(i);
246       int cookieVersion = cookie.getVersion();
247
248       CharBuffer cb = _cb;
249       // XXX:
250
fillCookie(cb, cookie, now, cookieVersion, false);
251       os.print("\r\nSet-Cookie: ");
252       os.print(cb.getBuffer(), 0, cb.getLength());
253       if (cookieVersion > 0) {
254         fillCookie(cb, cookie, now, cookieVersion, true);
255         os.print("\r\nSet-Cookie2: ");
256         os.print(cb.getBuffer(), 0, cb.getLength());
257       }
258
259       if (debug)
260         log.fine(_request.dbgId() + "Set-Cookie: " + cb);
261     }
262
263     String JavaDoc contentType = _contentType;
264     
265     if (contentType == null) {
266     }
267     else if (contentType != "text/html") {
268       os.write(_contentTypeBytes, 0, _contentTypeBytes.length);
269       os.print(contentType);
270
271       if (_charEncoding != null) {
272     os.write(_charsetBytes, 0, _charsetBytes.length);
273     os.print(_charEncoding);
274       }
275       else if (_hasWriter) {
276     os.write(_charsetBytes, 0, _charsetBytes.length);
277     os.print("iso-8859-1");
278       }
279     }
280     else if (_charEncoding != null) {
281       os.write(_textHtmlBytes, 0, _textHtmlBytes.length);
282       os.write(_charsetBytes, 0, _charsetBytes.length);
283       os.print(_charEncoding);
284     }
285     else {
286       os.write(_textHtmlLatin1Bytes, 0, _textHtmlLatin1Bytes.length);
287     }
288
289     boolean hasContentLength = false;
290     if (_contentLength >= 0) {
291       os.write(_contentLengthBytes, 0, _contentLengthBytes.length);
292       os.print(_contentLength);
293       hasContentLength = true;
294
295       if (debug)
296         log.fine(_request.dbgId() + "Content-Length: " + _contentLength);
297     }
298     else if (statusCode == SC_NOT_MODIFIED || statusCode == SC_NO_CONTENT) {
299       hasContentLength = true;
300       os.write(_contentLengthBytes, 0, _contentLengthBytes.length);
301       os.print(0);
302
303       if (debug)
304         log.fine(_request.dbgId() + "Content-Length: 0");
305     }
306     else if (length >= 0) {
307       os.write(_contentLengthBytes, 0, _contentLengthBytes.length);
308       os.print(length);
309       hasContentLength = true;
310
311       if (debug)
312         log.fine(_request.dbgId() + "Content-Length: " + length);
313     }
314
315     if (version < HttpRequest.HTTP_1_1) {
316       _request.killKeepalive();
317     }
318     else {
319       /* XXX: the request processing already processed this header
320       CharSegment conn = _request.getHeaderBuffer(_connectionCb,
321                                                   _connectionCb.length);
322       if (conn != null && conn.equalsIgnoreCase(_closeCb)) {
323         _request.killKeepalive();
324       }
325       else
326       */

327
328       if (! _request.allowKeepalive()) {
329 /* XXX: || ! req.conn.allocateKeepalive() &&
330                req.rawStream.getOffset() >=
331                req.rawStream.getLength()) {
332 */

333         os.write(_connectionCloseBytes, 0, _connectionCloseBytes.length);
334         _request.killKeepalive();
335
336         if (debug)
337           log.fine(_request.dbgId() + "Connection: close");
338       }
339     }
340
341     if (HttpRequest.HTTP_1_1 <= version &&
342     ! hasContentLength &&
343     ! isHead()) {
344       os.print("\r\nTransfer-Encoding: chunked");
345       isChunked = true;
346
347       if (debug)
348         log.fine(_request.dbgId() + "Transfer-Encoding: chunked");
349     }
350
351     if (_lastDate / 1000 != now / 1000) {
352       fillDate(now);
353     }
354
355     if (isChunked)
356       os.write(_dateBuffer, 0, _dateBufferLength - 2);
357     else
358       os.write(_dateBuffer, 0, _dateBufferLength);
359
360     return isChunked;
361   }
362
363   private void fillDate(long now)
364   {
365     if (_lastDate / 60000 == now / 60000) {
366       _lastDate = now;
367
368       int sec = (int) (now / 1000 % 60);
369
370       int s2 = '0' + (sec / 10);
371       int s1 = '0' + (sec % 10);
372
373       _dateBuffer[31] = (byte) s2;
374       _dateBuffer[32] = (byte) s1;
375       return;
376     }
377
378     _lastDate = now;
379     _calendar.setGMTTime(now);
380     _dateCharBuffer.clear();
381     _dateCharBuffer.append("\r\nDate: ");
382     _calendar.printDate(_dateCharBuffer);
383
384     char []cb = _dateCharBuffer.getBuffer();
385     int len = _dateCharBuffer.getLength();
386
387     for (int i = len - 1; i >= 0; i--)
388       _dateBuffer[i] = (byte) cb[i];
389
390     _dateBuffer[len] = (byte) '\r';
391     _dateBuffer[len + 1] = (byte) '\n';
392     _dateBuffer[len + 2] = (byte) '\r';
393     _dateBuffer[len + 3] = (byte) '\n';
394
395     _dateBufferLength = len + 4;
396   }
397
398   public String JavaDoc toString()
399   {
400     return "HttpResponse" + _request.dbgId();
401   }
402 }
403
Popular Tags