0001: //========================================================================
0002: //$Id: Response.java,v 1.8 2005/11/25 21:01:45 gregwilkins Exp $
0003: //Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
0004: //------------------------------------------------------------------------
0005: //Licensed under the Apache License, Version 2.0 (the "License");
0006: //you may not use this file except in compliance with the License.
0007: //You may obtain a copy of the License at
0008: //http://www.apache.org/licenses/LICENSE-2.0
0009: //Unless required by applicable law or agreed to in writing, software
0010: //distributed under the License is distributed on an "AS IS" BASIS,
0011: //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012: //See the License for the specific language governing permissions and
0013: //limitations under the License.
0014: //========================================================================
0015:
0016: package org.mortbay.jetty;
0017:
0018: import java.io.IOException;
0019: import java.io.PrintWriter;
0020: import java.util.Collections;
0021: import java.util.Enumeration;
0022: import java.util.Locale;
0023:
0024: import javax.servlet.ServletOutputStream;
0025: import javax.servlet.http.Cookie;
0026: import javax.servlet.http.HttpServletResponse;
0027: import javax.servlet.http.HttpSession;
0028:
0029: import org.mortbay.io.BufferCache.CachedBuffer;
0030: import org.mortbay.jetty.handler.ContextHandler;
0031: import org.mortbay.jetty.handler.ErrorHandler;
0032: import org.mortbay.jetty.servlet.ServletHandler;
0033: import org.mortbay.log.Log;
0034: import org.mortbay.util.ByteArrayISO8859Writer;
0035: import org.mortbay.util.IO;
0036: import org.mortbay.util.QuotedStringTokenizer;
0037: import org.mortbay.util.StringUtil;
0038: import org.mortbay.util.URIUtil;
0039:
0040: /* ------------------------------------------------------------ */
0041: /** Response.
0042: * <p>
0043: * Implements {@link javax.servlet.HttpServletResponse} from the {@link javax.servlet} package.
0044: * </p>
0045: *
0046: * @author gregw
0047: *
0048: */
0049: public class Response implements HttpServletResponse {
0050: public static final int DISABLED = -1, NONE = 0, STREAM = 1,
0051: WRITER = 2;
0052:
0053: private static PrintWriter __nullPrintWriter;
0054: private static ServletOutputStream __nullServletOut;
0055:
0056: static {
0057: try {
0058: __nullPrintWriter = new PrintWriter(IO.getNullWriter());
0059: __nullServletOut = new NullOutput();
0060: } catch (Exception e) {
0061: Log.warn(e);
0062: }
0063: }
0064:
0065: private HttpConnection _connection;
0066: private int _status = SC_OK;
0067: private String _reason;
0068: private Locale _locale;
0069: private String _mimeType;
0070: private CachedBuffer _cachedMimeType;
0071: private String _characterEncoding;
0072: private boolean _explicitEncoding;
0073: private String _contentType;
0074: private int _outputState;
0075: private PrintWriter _writer;
0076:
0077: /* ------------------------------------------------------------ */
0078: /**
0079: *
0080: */
0081: public Response(HttpConnection connection) {
0082: _connection = connection;
0083: }
0084:
0085: /* ------------------------------------------------------------ */
0086: /*
0087: * @see javax.servlet.ServletResponse#reset()
0088: */
0089: protected void recycle() {
0090: _status = SC_OK;
0091: _reason = null;
0092: _locale = null;
0093: _mimeType = null;
0094: _cachedMimeType = null;
0095: _characterEncoding = null;
0096: _explicitEncoding = false;
0097: _contentType = null;
0098: _outputState = NONE;
0099: _writer = null;
0100: }
0101:
0102: /* ------------------------------------------------------------ */
0103: /*
0104: * @see javax.servlet.http.HttpServletResponse#addCookie(javax.servlet.http.Cookie)
0105: */
0106: public void addCookie(Cookie cookie) {
0107: _connection.getResponseFields().addSetCookie(cookie);
0108: }
0109:
0110: /* ------------------------------------------------------------ */
0111: /*
0112: * @see javax.servlet.http.HttpServletResponse#containsHeader(java.lang.String)
0113: */
0114: public boolean containsHeader(String name) {
0115: return _connection.getResponseFields().containsKey(name);
0116: }
0117:
0118: /* ------------------------------------------------------------ */
0119: /*
0120: * @see javax.servlet.http.HttpServletResponse#encodeURL(java.lang.String)
0121: */
0122: public String encodeURL(String url) {
0123: Request request = _connection.getRequest();
0124:
0125: // should not encode if cookies in evidence
0126: if (url == null || request == null
0127: || request.isRequestedSessionIdFromCookie())
0128: return url;
0129:
0130: // get session;
0131: HttpSession session = request.getSession(false);
0132:
0133: // no session
0134: if (session == null)
0135: return url;
0136:
0137: SessionManager sessionManager = request.getSessionManager();
0138:
0139: // invalid session
0140: if (!sessionManager.isValid(session))
0141: return url;
0142: String id = session.getId();
0143:
0144: // TODO Check host and port are for this server
0145: String sessionURLPrefix = sessionManager.getSessionURLPrefix();
0146: // Already encoded
0147: int prefix = url.indexOf(sessionURLPrefix);
0148: if (prefix != -1) {
0149: int suffix = url.indexOf("?", prefix);
0150: if (suffix < 0)
0151: suffix = url.indexOf("#", prefix);
0152:
0153: if (suffix <= prefix)
0154: return url.substring(0, prefix
0155: + sessionURLPrefix.length())
0156: + id;
0157: return url.substring(0, prefix + sessionURLPrefix.length())
0158: + id + url.substring(suffix);
0159: }
0160:
0161: // edit the session
0162: int suffix = url.indexOf('?');
0163: if (suffix < 0)
0164: suffix = url.indexOf('#');
0165: if (suffix < 0)
0166: return url + sessionURLPrefix + id;
0167: return url.substring(0, suffix) + sessionURLPrefix + id
0168: + url.substring(suffix);
0169: }
0170:
0171: /* ------------------------------------------------------------ */
0172: /*
0173: * @see javax.servlet.http.HttpServletResponse#encodeRedirectURL(java.lang.String)
0174: */
0175: public String encodeRedirectURL(String url) {
0176: return encodeURL(url);
0177: }
0178:
0179: /* ------------------------------------------------------------ */
0180: /*
0181: * @see javax.servlet.http.HttpServletResponse#encodeUrl(java.lang.String)
0182: */
0183: public String encodeUrl(String url) {
0184: return encodeURL(url);
0185: }
0186:
0187: /* ------------------------------------------------------------ */
0188: /*
0189: * @see javax.servlet.http.HttpServletResponse#encodeRedirectUrl(java.lang.String)
0190: */
0191: public String encodeRedirectUrl(String url) {
0192: return encodeURL(url);
0193: }
0194:
0195: /* ------------------------------------------------------------ */
0196: /*
0197: * @see javax.servlet.http.HttpServletResponse#sendError(int, java.lang.String)
0198: */
0199: public void sendError(int code, String message) throws IOException {
0200: if (_connection.isIncluding())
0201: return;
0202:
0203: if (isCommitted())
0204: Log.warn("Committed before " + code + " " + message);
0205:
0206: reset();
0207: setStatus(code, message);
0208:
0209: if (message == null)
0210: message = HttpGenerator.getReason(code);
0211:
0212: // If we are allowed to have a body
0213: if (code != SC_NO_CONTENT && code != SC_NOT_MODIFIED
0214: && code != SC_PARTIAL_CONTENT && code >= SC_OK) {
0215: Request request = _connection.getRequest();
0216:
0217: ErrorHandler error_handler = null;
0218: ContextHandler.SContext context = request.getContext();
0219: if (context != null)
0220: error_handler = context.getContextHandler()
0221: .getErrorHandler();
0222: if (error_handler != null) {
0223: // TODO - probably should reset these after the request?
0224: request.setAttribute(
0225: ServletHandler.__J_S_ERROR_STATUS_CODE,
0226: new Integer(code));
0227: request.setAttribute(
0228: ServletHandler.__J_S_ERROR_MESSAGE, message);
0229: request.setAttribute(
0230: ServletHandler.__J_S_ERROR_REQUEST_URI, request
0231: .getRequestURI());
0232: request.setAttribute(
0233: ServletHandler.__J_S_ERROR_SERVLET_NAME,
0234: request.getServletName());
0235:
0236: error_handler.handle(null, _connection.getRequest(),
0237: this , Handler.ERROR);
0238: } else {
0239: setContentType(MimeTypes.TEXT_HTML_8859_1);
0240: ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(
0241: 2048);
0242: if (message != null) {
0243: message = StringUtil.replace(message, "&", "&");
0244: message = StringUtil.replace(message, "<", "<");
0245: message = StringUtil.replace(message, ">", ">");
0246: }
0247: String uri = request.getRequestURI();
0248: if (uri != null) {
0249: uri = StringUtil.replace(uri, "&", "&");
0250: uri = StringUtil.replace(uri, "<", "<");
0251: uri = StringUtil.replace(uri, ">", ">");
0252: }
0253:
0254: writer
0255: .write("<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"/>\n");
0256: writer.write("<title>Error ");
0257: writer.write(Integer.toString(code));
0258: writer.write(' ');
0259: if (message == null)
0260: message = HttpGenerator.getReason(code);
0261: writer.write(message);
0262: writer
0263: .write("</title>\n</head>\n<body>\n<h2>HTTP ERROR: ");
0264: writer.write(Integer.toString(code));
0265: writer.write("</h2><pre>");
0266: writer.write(message);
0267: writer.write("</pre>\n<p>RequestURI=");
0268: writer.write(uri);
0269: writer
0270: .write("</p>\n<p><i><small><a href=\"http://jetty.mortbay.org\">Powered by jetty://</a></small></i></p>");
0271:
0272: for (int i = 0; i < 20; i++)
0273: writer
0274: .write("\n ");
0275: writer.write("\n</body>\n</html>\n");
0276:
0277: writer.flush();
0278: setContentLength(writer.size());
0279: writer.writeTo(getOutputStream());
0280: writer.destroy();
0281: }
0282: } else if (code != SC_PARTIAL_CONTENT) {
0283: _connection.getRequestFields().remove(
0284: HttpHeaders.CONTENT_TYPE_BUFFER);
0285: _connection.getRequestFields().remove(
0286: HttpHeaders.CONTENT_LENGTH_BUFFER);
0287: _characterEncoding = null;
0288: _mimeType = null;
0289: _cachedMimeType = null;
0290: }
0291:
0292: complete();
0293: }
0294:
0295: /* ------------------------------------------------------------ */
0296: /*
0297: * @see javax.servlet.http.HttpServletResponse#sendError(int)
0298: */
0299: public void sendError(int sc) throws IOException {
0300: if (sc == 102)
0301: sendProcessing();
0302: else
0303: sendError(sc, null);
0304: }
0305:
0306: /* ------------------------------------------------------------ */
0307: /* Send a 102-Processing response.
0308: * If the connection is a HTTP connection, the version is 1.1 and the
0309: * request has a Expect header starting with 102, then a 102 response is
0310: * sent. This indicates that the request still be processed and real response
0311: * can still be sent. This method is called by sendError if it is passed 102.
0312: * @see javax.servlet.http.HttpServletResponse#sendError(int)
0313: */
0314: public void sendProcessing() throws IOException {
0315: Generator g = _connection.getGenerator();
0316: if (g instanceof HttpGenerator) {
0317: HttpGenerator generator = (HttpGenerator) g;
0318:
0319: String expect = _connection.getRequest().getHeader(
0320: HttpHeaders.EXPECT);
0321:
0322: if (expect != null
0323: && expect.startsWith("102")
0324: && generator.getVersion() >= HttpVersions.HTTP_1_1_ORDINAL) {
0325: boolean was_persistent = generator.isPersistent();
0326: generator.setResponse(
0327: HttpStatus.ORDINAL_102_Processing, null);
0328: generator.completeHeader(null, true);
0329: generator.setPersistent(true);
0330: generator.complete();
0331: generator.flush();
0332: generator.reset(false);
0333: generator.setPersistent(was_persistent);
0334: }
0335: }
0336: }
0337:
0338: /* ------------------------------------------------------------ */
0339: /*
0340: * @see javax.servlet.http.HttpServletResponse#sendRedirect(java.lang.String)
0341: */
0342: public void sendRedirect(String location) throws IOException {
0343: if (_connection.isIncluding())
0344: return;
0345:
0346: if (location == null)
0347: throw new IllegalArgumentException();
0348:
0349: if (!URIUtil.hasScheme(location)) {
0350: StringBuffer buf = _connection.getRequest().getRootURL();
0351: if (location.startsWith("/"))
0352: buf.append(URIUtil.canonicalPath(location));
0353: else {
0354: String path = _connection.getRequest().getRequestURI();
0355: String parent = (path.endsWith("/")) ? path : URIUtil
0356: .parentPath(path);
0357: location = URIUtil.canonicalPath(URIUtil.addPaths(
0358: parent, location));
0359: if (!location.startsWith("/"))
0360: buf.append('/');
0361: buf.append(location);
0362: }
0363:
0364: location = buf.toString();
0365: }
0366: resetBuffer();
0367:
0368: setHeader(HttpHeaders.LOCATION, location);
0369: setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
0370: complete();
0371:
0372: }
0373:
0374: /* ------------------------------------------------------------ */
0375: /*
0376: * @see javax.servlet.http.HttpServletResponse#setDateHeader(java.lang.String, long)
0377: */
0378: public void setDateHeader(String name, long date) {
0379: if (!_connection.isIncluding())
0380: _connection.getResponseFields().putDateField(name, date);
0381: }
0382:
0383: /* ------------------------------------------------------------ */
0384: /*
0385: * @see javax.servlet.http.HttpServletResponse#addDateHeader(java.lang.String, long)
0386: */
0387: public void addDateHeader(String name, long date) {
0388: if (!_connection.isIncluding())
0389: _connection.getResponseFields().addDateField(name, date);
0390: }
0391:
0392: /* ------------------------------------------------------------ */
0393: /*
0394: * @see javax.servlet.http.HttpServletResponse#setHeader(java.lang.String, java.lang.String)
0395: */
0396: public void setHeader(String name, String value) {
0397: if (!_connection.isIncluding()) {
0398: _connection.getResponseFields().put(name, value);
0399: if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name))
0400: _connection._generator.setContentLength(Long
0401: .parseLong(value));
0402: }
0403: }
0404:
0405: /* ------------------------------------------------------------ */
0406: /*
0407: */
0408: public String getHeader(String name) {
0409: return _connection.getResponseFields().getStringField(name);
0410: }
0411:
0412: /* ------------------------------------------------------------ */
0413: /*
0414: */
0415: public Enumeration getHeaders(String name) {
0416: Enumeration e = _connection.getResponseFields().getValues(name);
0417: if (e == null)
0418: return Collections.enumeration(Collections.EMPTY_LIST);
0419: return e;
0420: }
0421:
0422: /* ------------------------------------------------------------ */
0423: /*
0424: * @see javax.servlet.http.HttpServletResponse#addHeader(java.lang.String, java.lang.String)
0425: */
0426: public void addHeader(String name, String value) {
0427: if (!_connection.isIncluding()) {
0428: _connection.getResponseFields().add(name, value);
0429: if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name))
0430: _connection._generator.setContentLength(Long
0431: .parseLong(value));
0432: }
0433: }
0434:
0435: /* ------------------------------------------------------------ */
0436: /*
0437: * @see javax.servlet.http.HttpServletResponse#setIntHeader(java.lang.String, int)
0438: */
0439: public void setIntHeader(String name, int value) {
0440: if (!_connection.isIncluding()) {
0441: _connection.getResponseFields().putLongField(name, value);
0442: if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name))
0443: _connection._generator.setContentLength(value);
0444: }
0445: }
0446:
0447: /* ------------------------------------------------------------ */
0448: /*
0449: * @see javax.servlet.http.HttpServletResponse#addIntHeader(java.lang.String, int)
0450: */
0451: public void addIntHeader(String name, int value) {
0452: if (!_connection.isIncluding()) {
0453: _connection.getResponseFields().addLongField(name, value);
0454: if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name))
0455: _connection._generator.setContentLength(value);
0456: }
0457: }
0458:
0459: /* ------------------------------------------------------------ */
0460: /*
0461: * @see javax.servlet.http.HttpServletResponse#setStatus(int)
0462: */
0463: public void setStatus(int sc) {
0464: setStatus(sc, null);
0465: }
0466:
0467: /* ------------------------------------------------------------ */
0468: /*
0469: * @see javax.servlet.http.HttpServletResponse#setStatus(int, java.lang.String)
0470: */
0471: public void setStatus(int sc, String sm) {
0472: if (!_connection.isIncluding()) {
0473: _status = sc;
0474: _reason = sm;
0475: }
0476: }
0477:
0478: /* ------------------------------------------------------------ */
0479: /*
0480: * @see javax.servlet.ServletResponse#getCharacterEncoding()
0481: */
0482: public String getCharacterEncoding() {
0483: if (_characterEncoding == null)
0484: _characterEncoding = StringUtil.__ISO_8859_1;
0485: return _characterEncoding;
0486: }
0487:
0488: /* ------------------------------------------------------------ */
0489: /*
0490: * @see javax.servlet.ServletResponse#getContentType()
0491: */
0492: public String getContentType() {
0493: return _contentType;
0494: }
0495:
0496: /* ------------------------------------------------------------ */
0497: /*
0498: * @see javax.servlet.ServletResponse#getOutputStream()
0499: */
0500: public ServletOutputStream getOutputStream() throws IOException {
0501: if (_outputState == DISABLED)
0502: return __nullServletOut;
0503:
0504: if (_outputState != NONE && _outputState != STREAM)
0505: throw new IllegalStateException("WRITER");
0506:
0507: _outputState = STREAM;
0508: return _connection.getOutputStream();
0509: }
0510:
0511: /* ------------------------------------------------------------ */
0512: public boolean isWriting() {
0513: return _outputState == WRITER;
0514: }
0515:
0516: /* ------------------------------------------------------------ */
0517: /*
0518: * @see javax.servlet.ServletResponse#getWriter()
0519: */
0520: public PrintWriter getWriter() throws IOException {
0521: if (_outputState == DISABLED)
0522: return __nullPrintWriter;
0523:
0524: if (_outputState != NONE && _outputState != WRITER)
0525: throw new IllegalStateException("STREAM");
0526:
0527: /* if there is no writer yet */
0528: if (_writer == null) {
0529: /* get encoding from Content-Type header */
0530: String encoding = _characterEncoding;
0531:
0532: if (encoding == null) {
0533: /* implementation of educated defaults */
0534: if (_mimeType != null)
0535: encoding = null; // TODO getHttpContext().getEncodingByMimeType(_mimeType);
0536:
0537: if (encoding == null)
0538: encoding = StringUtil.__ISO_8859_1;
0539:
0540: setCharacterEncoding(encoding);
0541: }
0542:
0543: /* construct Writer using correct encoding */
0544: _writer = _connection.getPrintWriter(encoding);
0545: }
0546: _outputState = WRITER;
0547: return _writer;
0548: }
0549:
0550: /* ------------------------------------------------------------ */
0551: /*
0552: * @see javax.servlet.ServletResponse#setCharacterEncoding(java.lang.String)
0553: */
0554: public void setCharacterEncoding(String encoding) {
0555: if (_connection.isIncluding())
0556: return;
0557:
0558: // TODO throw unsupported encoding exception ???
0559:
0560: if (this ._outputState == 0 && !isCommitted()) {
0561: _explicitEncoding = true;
0562:
0563: if (encoding == null) {
0564: // Clear any encoding.
0565: if (_characterEncoding != null) {
0566: _characterEncoding = null;
0567: if (_cachedMimeType != null)
0568: _connection.getResponseFields().put(
0569: HttpHeaders.CONTENT_TYPE_BUFFER,
0570: _cachedMimeType);
0571: else
0572: _connection.getResponseFields().put(
0573: HttpHeaders.CONTENT_TYPE_BUFFER,
0574: _mimeType);
0575: }
0576: } else {
0577: // No, so just add this one to the mimetype
0578: _characterEncoding = encoding;
0579: if (_contentType != null) {
0580: int i0 = _contentType.indexOf(';');
0581: if (i0 < 0) {
0582: _contentType = null;
0583: if (_cachedMimeType != null) {
0584: CachedBuffer content_type = _cachedMimeType
0585: .getAssociate(_characterEncoding);
0586: if (content_type != null) {
0587: _contentType = content_type.toString();
0588: _connection
0589: .getResponseFields()
0590: .put(
0591: HttpHeaders.CONTENT_TYPE_BUFFER,
0592: content_type);
0593: }
0594: }
0595:
0596: if (_contentType == null) {
0597: _contentType = _mimeType
0598: + "; charset="
0599: + QuotedStringTokenizer.quote(
0600: _characterEncoding, ";= ");
0601: _connection.getResponseFields().put(
0602: HttpHeaders.CONTENT_TYPE_BUFFER,
0603: _contentType);
0604: }
0605: } else {
0606: int i1 = _contentType.indexOf("charset=", i0);
0607: if (i1 < 0) {
0608: _contentType = _contentType
0609: + " charset="
0610: + QuotedStringTokenizer.quote(
0611: _characterEncoding, ";= ");
0612: } else {
0613: int i8 = i1 + 8;
0614: int i2 = _contentType.indexOf(" ", i8);
0615: if (i2 < 0)
0616: _contentType = _contentType.substring(
0617: 0, i8)
0618: + QuotedStringTokenizer.quote(
0619: _characterEncoding,
0620: ";= ");
0621: else
0622: _contentType = _contentType.substring(
0623: 0, i8)
0624: + QuotedStringTokenizer.quote(
0625: _characterEncoding,
0626: ";= ")
0627: + _contentType.substring(i2);
0628: }
0629: _connection.getResponseFields().put(
0630: HttpHeaders.CONTENT_TYPE_BUFFER,
0631: _contentType);
0632: }
0633: }
0634: }
0635: }
0636: }
0637:
0638: /* ------------------------------------------------------------ */
0639: /*
0640: * @see javax.servlet.ServletResponse#setContentLength(int)
0641: */
0642: public void setContentLength(int len) {
0643: // Protect from setting after committed as default handling
0644: // of a servlet HEAD request ALWAYS sets _content length, even
0645: // if the getHandling committed the response!
0646: if (isCommitted() || _connection.isIncluding())
0647: return;
0648: _connection._generator.setContentLength(len);
0649: _connection.getResponseFields().putLongField(
0650: HttpHeaders.CONTENT_LENGTH, len);
0651: }
0652:
0653: /* ------------------------------------------------------------ */
0654: /*
0655: * @see javax.servlet.ServletResponse#setContentLength(int)
0656: */
0657: public void setLongContentLength(long len) {
0658: // Protect from setting after committed as default handling
0659: // of a servlet HEAD request ALWAYS sets _content length, even
0660: // if the getHandling committed the response!
0661: if (isCommitted() || _connection.isIncluding())
0662: return;
0663: _connection._generator.setContentLength(len);
0664: _connection.getResponseFields().putLongField(
0665: HttpHeaders.CONTENT_LENGTH, len);
0666: }
0667:
0668: /* ------------------------------------------------------------ */
0669: /*
0670: * @see javax.servlet.ServletResponse#setContentType(java.lang.String)
0671: */
0672: public void setContentType(String contentType) {
0673: if (isCommitted() || _connection.isIncluding())
0674: return;
0675:
0676: // Yes this method is horribly complex.... but there are lots of special cases and
0677: // as this method is called on every request, it is worth trying to save string creation.
0678: //
0679:
0680: if (contentType == null) {
0681: if (_locale == null)
0682: _characterEncoding = null;
0683: _mimeType = null;
0684: _cachedMimeType = null;
0685: _contentType = null;
0686: _connection.getResponseFields().remove(
0687: HttpHeaders.CONTENT_TYPE_BUFFER);
0688: } else {
0689: // Look for encoding in contentType
0690: int i0 = contentType.indexOf(';');
0691:
0692: if (i0 > 0) {
0693: // we have content type parameters
0694:
0695: // Extract params off mimetype
0696: _mimeType = contentType.substring(0, i0).trim();
0697: _cachedMimeType = MimeTypes.CACHE.get(_mimeType);
0698:
0699: // Look for charset
0700: int i1 = contentType.indexOf("charset=", i0 + 1);
0701: if (i1 >= 0) {
0702: _explicitEncoding = true;
0703: int i8 = i1 + 8;
0704: int i2 = contentType.indexOf(' ', i8);
0705:
0706: if (_outputState == WRITER) {
0707: // strip the charset and ignore;
0708: if ((i1 == i0 + 1 && i2 < 0)
0709: || (i1 == i0 + 2 && i2 < 0 && contentType
0710: .charAt(i0 + 1) == ' ')) {
0711: if (_cachedMimeType != null) {
0712: CachedBuffer content_type = _cachedMimeType
0713: .getAssociate(_characterEncoding);
0714: if (content_type != null) {
0715: _contentType = content_type
0716: .toString();
0717: _connection
0718: .getResponseFields()
0719: .put(
0720: HttpHeaders.CONTENT_TYPE_BUFFER,
0721: content_type);
0722: } else {
0723: _contentType = _mimeType
0724: + "; charset="
0725: + _characterEncoding;
0726: _connection
0727: .getResponseFields()
0728: .put(
0729: HttpHeaders.CONTENT_TYPE_BUFFER,
0730: _contentType);
0731: }
0732: } else {
0733: _contentType = _mimeType + "; charset="
0734: + _characterEncoding;
0735: _connection
0736: .getResponseFields()
0737: .put(
0738: HttpHeaders.CONTENT_TYPE_BUFFER,
0739: _contentType);
0740: }
0741: } else if (i2 < 0) {
0742: _contentType = contentType.substring(0, i1)
0743: + " charset="
0744: + QuotedStringTokenizer.quote(
0745: _characterEncoding, ";= ");
0746: _connection.getResponseFields().put(
0747: HttpHeaders.CONTENT_TYPE_BUFFER,
0748: _contentType);
0749: } else {
0750: _contentType = contentType.substring(0, i1)
0751: + contentType.substring(i2)
0752: + " charset="
0753: + QuotedStringTokenizer.quote(
0754: _characterEncoding, ";= ");
0755: _connection.getResponseFields().put(
0756: HttpHeaders.CONTENT_TYPE_BUFFER,
0757: _contentType);
0758: }
0759: } else if ((i1 == i0 + 1 && i2 < 0)
0760: || (i1 == i0 + 2 && i2 < 0 && contentType
0761: .charAt(i0 + 1) == ' ')) {
0762: // The params are just the char encoding
0763: _cachedMimeType = MimeTypes.CACHE
0764: .get(_mimeType);
0765: _characterEncoding = QuotedStringTokenizer
0766: .unquote(contentType.substring(i8));
0767:
0768: if (_cachedMimeType != null) {
0769: CachedBuffer content_type = _cachedMimeType
0770: .getAssociate(_characterEncoding);
0771: if (content_type != null) {
0772: _contentType = content_type.toString();
0773: _connection
0774: .getResponseFields()
0775: .put(
0776: HttpHeaders.CONTENT_TYPE_BUFFER,
0777: content_type);
0778: } else {
0779: _contentType = contentType;
0780: _connection
0781: .getResponseFields()
0782: .put(
0783: HttpHeaders.CONTENT_TYPE_BUFFER,
0784: _contentType);
0785: }
0786: } else {
0787: _contentType = contentType;
0788: _connection.getResponseFields().put(
0789: HttpHeaders.CONTENT_TYPE_BUFFER,
0790: _contentType);
0791: }
0792: } else if (i2 > 0) {
0793: _characterEncoding = QuotedStringTokenizer
0794: .unquote(contentType.substring(i8, i2));
0795: _contentType = contentType;
0796: _connection.getResponseFields().put(
0797: HttpHeaders.CONTENT_TYPE_BUFFER,
0798: _contentType);
0799: } else {
0800: _characterEncoding = QuotedStringTokenizer
0801: .unquote(contentType.substring(i8));
0802: _contentType = contentType;
0803: _connection.getResponseFields().put(
0804: HttpHeaders.CONTENT_TYPE_BUFFER,
0805: _contentType);
0806: }
0807: } else // No encoding in the params.
0808: {
0809: _cachedMimeType = null;
0810: _contentType = _characterEncoding == null ? contentType
0811: : contentType
0812: + " charset="
0813: + QuotedStringTokenizer.quote(
0814: _characterEncoding, ";= ");
0815: _connection.getResponseFields().put(
0816: HttpHeaders.CONTENT_TYPE_BUFFER,
0817: _contentType);
0818: }
0819: } else // No params at all
0820: {
0821: _mimeType = contentType;
0822: _cachedMimeType = MimeTypes.CACHE.get(_mimeType);
0823:
0824: if (_characterEncoding != null) {
0825: if (_cachedMimeType != null) {
0826: CachedBuffer content_type = _cachedMimeType
0827: .getAssociate(_characterEncoding);
0828: if (content_type != null) {
0829: _contentType = content_type.toString();
0830: _connection.getResponseFields().put(
0831: HttpHeaders.CONTENT_TYPE_BUFFER,
0832: content_type);
0833: } else {
0834: _contentType = _mimeType
0835: + "; charset="
0836: + QuotedStringTokenizer.quote(
0837: _characterEncoding, ";= ");
0838: _connection.getResponseFields().put(
0839: HttpHeaders.CONTENT_TYPE_BUFFER,
0840: _contentType);
0841: }
0842: } else {
0843: _contentType = contentType
0844: + "; charset="
0845: + QuotedStringTokenizer.quote(
0846: _characterEncoding, ";= ");
0847: _connection.getResponseFields().put(
0848: HttpHeaders.CONTENT_TYPE_BUFFER,
0849: _contentType);
0850: }
0851: } else if (_cachedMimeType != null) {
0852: _contentType = _cachedMimeType.toString();
0853: _connection.getResponseFields().put(
0854: HttpHeaders.CONTENT_TYPE_BUFFER,
0855: _cachedMimeType);
0856: } else {
0857: _contentType = contentType;
0858: _connection.getResponseFields().put(
0859: HttpHeaders.CONTENT_TYPE_BUFFER,
0860: _contentType);
0861: }
0862: }
0863: }
0864: }
0865:
0866: /* ------------------------------------------------------------ */
0867: /*
0868: * @see javax.servlet.ServletResponse#setBufferSize(int)
0869: */
0870: public void setBufferSize(int size) {
0871: if (isCommitted() || getContentCount() > 0)
0872: throw new IllegalStateException(
0873: "Committed or content written");
0874: _connection.getGenerator().increaseContentBufferSize(size);
0875: }
0876:
0877: /* ------------------------------------------------------------ */
0878: /*
0879: * @see javax.servlet.ServletResponse#getBufferSize()
0880: */
0881: public int getBufferSize() {
0882: return _connection.getGenerator().getContentBufferSize();
0883: }
0884:
0885: /* ------------------------------------------------------------ */
0886: /*
0887: * @see javax.servlet.ServletResponse#flushBuffer()
0888: */
0889: public void flushBuffer() throws IOException {
0890: _connection.flushResponse();
0891: }
0892:
0893: /* ------------------------------------------------------------ */
0894: /*
0895: * @see javax.servlet.ServletResponse#reset()
0896: */
0897: public void reset() {
0898: resetBuffer();
0899:
0900: _status = 200;
0901: _reason = null;
0902: _mimeType = null;
0903: _cachedMimeType = null;
0904: _contentType = null;
0905: _characterEncoding = null;
0906: _explicitEncoding = false;
0907: _locale = null;
0908: _outputState = NONE;
0909: _writer = null;
0910: }
0911:
0912: /* ------------------------------------------------------------ */
0913: /*
0914: * @see javax.servlet.ServletResponse#resetBuffer()
0915: */
0916: public void resetBuffer() {
0917: if (isCommitted())
0918: throw new IllegalStateException("Committed");
0919: _connection.getGenerator().resetBuffer();
0920: }
0921:
0922: /* ------------------------------------------------------------ */
0923: /*
0924: * @see javax.servlet.ServletResponse#isCommitted()
0925: */
0926: public boolean isCommitted() {
0927: return _connection.isResponseCommitted();
0928: }
0929:
0930: /* ------------------------------------------------------------ */
0931: /*
0932: * @see javax.servlet.ServletResponse#setLocale(java.util.Locale)
0933: */
0934: public void setLocale(Locale locale) {
0935: if (locale == null || isCommitted()
0936: || _connection.isIncluding())
0937: return;
0938:
0939: _locale = locale;
0940: _connection.getResponseFields().put(
0941: HttpHeaders.CONTENT_LANGUAGE_BUFFER,
0942: locale.toString().replace('_', '-'));
0943:
0944: if (_explicitEncoding || _outputState != 0)
0945: return;
0946:
0947: if (_connection.getRequest().getContext() == null)
0948: return;
0949:
0950: String charset = _connection.getRequest().getContext()
0951: .getContextHandler().getLocaleEncoding(locale);
0952:
0953: if (charset != null && charset.length() > 0) {
0954: _characterEncoding = charset;
0955:
0956: /* get current MIME type from Content-Type header */
0957: String type = getContentType();
0958: if (type != null) {
0959: _characterEncoding = charset;
0960: int semi = type.indexOf(';');
0961: if (semi < 0) {
0962: _mimeType = type;
0963: _contentType = type += "; charset=" + charset;
0964: } else {
0965: _mimeType = type.substring(0, semi);
0966: _contentType = _mimeType += "; charset=" + charset;
0967: }
0968:
0969: _cachedMimeType = MimeTypes.CACHE.get(_mimeType);
0970: _connection.getResponseFields().put(
0971: HttpHeaders.CONTENT_TYPE_BUFFER, _contentType);
0972: }
0973: }
0974: }
0975:
0976: /* ------------------------------------------------------------ */
0977: /*
0978: * @see javax.servlet.ServletResponse#getLocale()
0979: */
0980: public Locale getLocale() {
0981: if (_locale == null)
0982: return Locale.getDefault();
0983: return _locale;
0984: }
0985:
0986: /* ------------------------------------------------------------ */
0987: /**
0988: * @return The HTTP status code that has been set for this request. This will be <code>200<code>
0989: * ({@link HttpServletResponse#SC_OK}), unless explicitly set through one of the <code>setStatus</code> methods.
0990: */
0991: public int getStatus() {
0992: return _status;
0993: }
0994:
0995: /* ------------------------------------------------------------ */
0996: /**
0997: * @return The reason associated with the current {@link #getStatus() status}. This will be <code>null</code>,
0998: * unless one of the <code>setStatus</code> methods have been called.
0999: */
1000: public String getReason() {
1001: return _reason;
1002: }
1003:
1004: /* ------------------------------------------------------------ */
1005: /**
1006: *
1007: */
1008: public void complete() throws IOException {
1009: _connection.completeResponse();
1010: }
1011:
1012: /* ------------------------------------------------------------- */
1013: /**
1014: * @return the number of bytes actually written in response body
1015: */
1016: public long getContentCount() {
1017: if (_connection == null || _connection.getGenerator() == null)
1018: return -1;
1019: return _connection.getGenerator().getContentWritten();
1020: }
1021:
1022: /* ------------------------------------------------------------ */
1023: public HttpFields getHttpFields() {
1024: return _connection.getResponseFields();
1025: }
1026:
1027: /* ------------------------------------------------------------ */
1028: public String toString() {
1029: return "HTTP/1.1 " + _status + " "
1030: + (_reason == null ? "" : _reason)
1031: + System.getProperty("line.separator")
1032: + _connection.getResponseFields().toString();
1033: }
1034:
1035: /* ------------------------------------------------------------ */
1036: /* ------------------------------------------------------------ */
1037: /* ------------------------------------------------------------ */
1038: private static class NullOutput extends ServletOutputStream {
1039: public void write(int b) throws IOException {
1040: }
1041: }
1042:
1043: }
|