diff src/org/eclipse/jetty/server/Response.java @ 802:3428c60d7cfc

replace jetty jars with source
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 21:15:48 -0600
parents
children 09d518d313b7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/eclipse/jetty/server/Response.java	Wed Sep 07 21:15:48 2016 -0600
@@ -0,0 +1,1307 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Enumeration;
+import java.util.Locale;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.http.HttpCookie;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpGenerator;
+import org.eclipse.jetty.http.HttpHeaderValues;
+import org.eclipse.jetty.http.HttpHeaders;
+import org.eclipse.jetty.http.HttpSchemes;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.HttpVersions;
+import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.io.BufferCache.CachedBuffer;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ErrorHandler;
+import org.eclipse.jetty.util.ByteArrayISO8859Writer;
+import org.eclipse.jetty.util.QuotedStringTokenizer;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/** Response.
+ * <p>
+ * Implements {@link javax.servlet.http.HttpServletResponse} from the <code>javax.servlet.http</code> package.
+ * </p>
+ */
+public class Response implements HttpServletResponse
+{
+    private static final Logger LOG = Log.getLogger(Response.class);
+
+    
+    public static final int
+        NONE=0,
+        STREAM=1,
+        WRITER=2;
+
+    /**
+     * If a header name starts with this string,  the header (stripped of the prefix)
+     * can be set during include using only {@link #setHeader(String, String)} or
+     * {@link #addHeader(String, String)}.
+     */
+    public final static String SET_INCLUDE_HEADER_PREFIX = "org.eclipse.jetty.server.include.";
+
+    /**
+     * If this string is found within the comment of a cookie added with {@link #addCookie(Cookie)}, then the cookie 
+     * will be set as HTTP ONLY.
+     */
+    public final static String HTTP_ONLY_COMMENT="__HTTP_ONLY__";
+    
+    
+    /* ------------------------------------------------------------ */
+    public static Response getResponse(HttpServletResponse response)
+    {
+        if (response instanceof Response)
+            return (Response)response;
+
+        return AbstractHttpConnection.getCurrentConnection().getResponse();
+    }
+    
+    private final AbstractHttpConnection _connection;
+    private int _status=SC_OK;
+    private String _reason;
+    private Locale _locale;
+    private String _mimeType;
+    private CachedBuffer _cachedMimeType;
+    private String _characterEncoding;
+    private boolean _explicitEncoding;
+    private String _contentType;
+    private volatile int _outputState;
+    private PrintWriter _writer;
+
+    /* ------------------------------------------------------------ */
+    /**
+     *
+     */
+    public Response(AbstractHttpConnection connection)
+    {
+        _connection=connection;
+    }
+
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#reset()
+     */
+    protected void recycle()
+    {
+        _status=SC_OK;
+        _reason=null;
+        _locale=null;
+        _mimeType=null;
+        _cachedMimeType=null;
+        _characterEncoding=null;
+        _explicitEncoding=false;
+        _contentType=null;
+        _writer=null;
+        _outputState=NONE;
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#addCookie(javax.servlet.http.Cookie)
+     */
+    public void addCookie(HttpCookie cookie)
+    {
+        _connection.getResponseFields().addSetCookie(cookie);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#addCookie(javax.servlet.http.Cookie)
+     */
+    public void addCookie(Cookie cookie)
+    {
+        String comment=cookie.getComment();
+        boolean http_only=false;
+        
+        if (comment!=null)
+        {
+            int i=comment.indexOf(HTTP_ONLY_COMMENT);
+            if (i>=0)
+            {
+                http_only=true;
+                comment=comment.replace(HTTP_ONLY_COMMENT,"").trim();
+                if (comment.length()==0)
+                    comment=null;
+            }
+        }
+        _connection.getResponseFields().addSetCookie(cookie.getName(),
+                cookie.getValue(),
+                cookie.getDomain(),
+                cookie.getPath(),
+                cookie.getMaxAge(),
+                comment,
+                cookie.getSecure(),
+                http_only || cookie.isHttpOnly(),
+                cookie.getVersion());
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#containsHeader(java.lang.String)
+     */
+    public boolean containsHeader(String name)
+    {
+        return _connection.getResponseFields().containsKey(name);
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#encodeURL(java.lang.String)
+     */
+    public String encodeURL(String url)
+    {
+        final Request request=_connection.getRequest();
+        SessionManager sessionManager = request.getSessionManager();
+        if (sessionManager==null)
+            return url;
+        
+        HttpURI uri = null;
+        if (sessionManager.isCheckingRemoteSessionIdEncoding() && URIUtil.hasScheme(url))
+        {
+            uri = new HttpURI(url);
+            String path = uri.getPath();
+            path = (path == null?"":path);
+            int port=uri.getPort();
+            if (port<0) 
+                port = HttpSchemes.HTTPS.equalsIgnoreCase(uri.getScheme())?443:80;
+            if (!request.getServerName().equalsIgnoreCase(uri.getHost()) ||
+                request.getServerPort()!=port ||
+                !path.startsWith(request.getContextPath())) //TODO the root context path is "", with which every non null string starts
+                return url;
+        }
+        
+        String sessionURLPrefix = sessionManager.getSessionIdPathParameterNamePrefix();
+        if (sessionURLPrefix==null)
+            return url;
+
+        if (url==null)
+            return null;
+        
+        // should not encode if cookies in evidence
+        if ((sessionManager.isUsingCookies() && request.isRequestedSessionIdFromCookie()) || !sessionManager.isUsingURLs()) 
+        {
+            int prefix=url.indexOf(sessionURLPrefix);
+            if (prefix!=-1)
+            {
+                int suffix=url.indexOf("?",prefix);
+                if (suffix<0)
+                    suffix=url.indexOf("#",prefix);
+
+                if (suffix<=prefix)
+                    return url.substring(0,prefix);
+                return url.substring(0,prefix)+url.substring(suffix);
+            }
+            return url;
+        }
+
+        // get session;
+        HttpSession session=request.getSession(false);
+
+        // no session
+        if (session == null)
+            return url;
+
+        // invalid session
+        if (!sessionManager.isValid(session))
+            return url;
+
+        String id=sessionManager.getNodeId(session);
+
+        if (uri == null)
+                uri = new HttpURI(url);
+     
+        
+        // Already encoded
+        int prefix=url.indexOf(sessionURLPrefix);
+        if (prefix!=-1)
+        {
+            int suffix=url.indexOf("?",prefix);
+            if (suffix<0)
+                suffix=url.indexOf("#",prefix);
+
+            if (suffix<=prefix)
+                return url.substring(0,prefix+sessionURLPrefix.length())+id;
+            return url.substring(0,prefix+sessionURLPrefix.length())+id+
+                url.substring(suffix);
+        }
+
+        // edit the session
+        int suffix=url.indexOf('?');
+        if (suffix<0)
+            suffix=url.indexOf('#');
+        if (suffix<0) 
+        {          
+            return url+ 
+                   ((HttpSchemes.HTTPS.equalsIgnoreCase(uri.getScheme()) || HttpSchemes.HTTP.equalsIgnoreCase(uri.getScheme())) && uri.getPath()==null?"/":"") + //if no path, insert the root path
+                   sessionURLPrefix+id;
+        }
+     
+        
+        return url.substring(0,suffix)+
+            ((HttpSchemes.HTTPS.equalsIgnoreCase(uri.getScheme()) || HttpSchemes.HTTP.equalsIgnoreCase(uri.getScheme())) && uri.getPath()==null?"/":"")+ //if no path so insert the root path
+            sessionURLPrefix+id+url.substring(suffix);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see javax.servlet.http.HttpServletResponse#encodeRedirectURL(java.lang.String)
+     */
+    public String encodeRedirectURL(String url)
+    {
+        return encodeURL(url);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Deprecated
+    public String encodeUrl(String url)
+    {
+        return encodeURL(url);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Deprecated
+    public String encodeRedirectUrl(String url)
+    {
+        return encodeRedirectURL(url);
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#sendError(int, java.lang.String)
+     */
+    public void sendError(int code, String message) throws IOException
+    {
+    	if (_connection.isIncluding())
+    		return;
+
+        if (isCommitted())
+            LOG.warn("Committed before "+code+" "+message);
+
+        resetBuffer();
+        _characterEncoding=null;
+        setHeader(HttpHeaders.EXPIRES,null);
+        setHeader(HttpHeaders.LAST_MODIFIED,null);
+        setHeader(HttpHeaders.CACHE_CONTROL,null);
+        setHeader(HttpHeaders.CONTENT_TYPE,null);
+        setHeader(HttpHeaders.CONTENT_LENGTH,null);
+
+        _outputState=NONE;
+        setStatus(code,message);
+
+        if (message==null)
+            message=HttpStatus.getMessage(code);
+
+        // If we are allowed to have a body
+        if (code!=SC_NO_CONTENT &&
+            code!=SC_NOT_MODIFIED &&
+            code!=SC_PARTIAL_CONTENT &&
+            code>=SC_OK)
+        {
+            Request request = _connection.getRequest();
+
+            ErrorHandler error_handler = null;
+            ContextHandler.Context context = request.getContext();
+            if (context!=null)
+                error_handler=context.getContextHandler().getErrorHandler();
+            if (error_handler==null)
+                error_handler = _connection.getConnector().getServer().getBean(ErrorHandler.class);
+            if (error_handler!=null)
+            {
+                request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(code));
+                request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
+                request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
+                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,request.getServletName());
+                error_handler.handle(null,_connection.getRequest(),_connection.getRequest(),this );
+            }
+            else
+            {
+                setHeader(HttpHeaders.CACHE_CONTROL, "must-revalidate,no-cache,no-store");
+                setContentType(MimeTypes.TEXT_HTML_8859_1);
+                ByteArrayISO8859Writer writer= new ByteArrayISO8859Writer(2048);
+                if (message != null)
+                {
+                    message= StringUtil.replace(message, "&", "&amp;");
+                    message= StringUtil.replace(message, "<", "&lt;");
+                    message= StringUtil.replace(message, ">", "&gt;");
+                }
+                String uri= request.getRequestURI();
+                if (uri!=null)
+                {
+                    uri= StringUtil.replace(uri, "&", "&amp;");
+                    uri= StringUtil.replace(uri, "<", "&lt;");
+                    uri= StringUtil.replace(uri, ">", "&gt;");
+                }
+
+                writer.write("<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\"/>\n");
+                writer.write("<title>Error ");
+                writer.write(Integer.toString(code));
+                writer.write(' ');
+                if (message==null)
+                    message=HttpStatus.getMessage(code);
+                writer.write(message);
+                writer.write("</title>\n</head>\n<body>\n<h2>HTTP ERROR: ");
+                writer.write(Integer.toString(code));
+                writer.write("</h2>\n<p>Problem accessing ");
+                writer.write(uri);
+                writer.write(". Reason:\n<pre>    ");
+                writer.write(message);
+                writer.write("</pre>");
+                writer.write("</p>\n<hr /><i><small>Powered by Jetty://</small></i>");
+
+                for (int i= 0; i < 20; i++)
+                    writer.write("\n                                                ");
+                writer.write("\n</body>\n</html>\n");
+
+                writer.flush();
+                setContentLength(writer.size());
+                writer.writeTo(getOutputStream());
+                writer.destroy();
+            }
+        }
+        else if (code!=SC_PARTIAL_CONTENT)
+        {
+            _connection.getRequestFields().remove(HttpHeaders.CONTENT_TYPE_BUFFER);
+            _connection.getRequestFields().remove(HttpHeaders.CONTENT_LENGTH_BUFFER);
+            _characterEncoding=null;
+            _mimeType=null;
+            _cachedMimeType=null;
+        }
+
+        complete();
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#sendError(int)
+     */
+    public void sendError(int sc) throws IOException
+    {
+        if (sc==102)
+            sendProcessing();
+        else
+            sendError(sc,null);
+    }
+
+    /* ------------------------------------------------------------ */
+    /* Send a 102-Processing response.
+     * If the connection is a HTTP connection, the version is 1.1 and the
+     * request has a Expect header starting with 102, then a 102 response is
+     * sent. This indicates that the request still be processed and real response
+     * can still be sent.   This method is called by sendError if it is passed 102.
+     * @see javax.servlet.http.HttpServletResponse#sendError(int)
+     */
+    public void sendProcessing() throws IOException
+    {
+        if (_connection.isExpecting102Processing() && !isCommitted())
+            ((HttpGenerator)_connection.getGenerator()).send1xx(HttpStatus.PROCESSING_102);
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#sendRedirect(java.lang.String)
+     */
+    public void sendRedirect(String location) throws IOException
+    {
+    	if (_connection.isIncluding())
+    		return;
+
+        if (location==null)
+            throw new IllegalArgumentException();
+
+        if (!URIUtil.hasScheme(location))
+        {
+            StringBuilder buf = _connection.getRequest().getRootURL();
+            if (location.startsWith("/"))
+                buf.append(location);
+            else
+            {
+                String path=_connection.getRequest().getRequestURI();
+                String parent=(path.endsWith("/"))?path:URIUtil.parentPath(path);
+                location=URIUtil.addPaths(parent,location);
+                if(location==null)
+                    throw new IllegalStateException("path cannot be above root");
+                if (!location.startsWith("/"))
+                    buf.append('/');
+                buf.append(location);
+            }
+
+            location=buf.toString();
+            HttpURI uri = new HttpURI(location);
+            String path=uri.getDecodedPath();
+            String canonical=URIUtil.canonicalPath(path);
+            if (canonical==null)
+                throw new IllegalArgumentException();
+            if (!canonical.equals(path))
+            {
+                buf = _connection.getRequest().getRootURL();
+                buf.append(URIUtil.encodePath(canonical));
+                String param=uri.getParam();
+                if (param!=null)
+                {
+                    buf.append(';');
+                    buf.append(param);
+                }
+                String query=uri.getQuery();
+                if (query!=null)
+                {
+                    buf.append('?');
+                    buf.append(query);
+                }
+                String fragment=uri.getFragment();
+                if (fragment!=null)
+                {
+                    buf.append('#');
+                    buf.append(fragment);
+                }
+                location=buf.toString();
+            }
+        }
+        
+        resetBuffer();
+        setHeader(HttpHeaders.LOCATION,location);
+        setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+        complete();
+
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#setDateHeader(java.lang.String, long)
+     */
+    public void setDateHeader(String name, long date)
+    {
+        if (!_connection.isIncluding())
+            _connection.getResponseFields().putDateField(name, date);
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#addDateHeader(java.lang.String, long)
+     */
+    public void addDateHeader(String name, long date)
+    {
+        if (!_connection.isIncluding())
+            _connection.getResponseFields().addDateField(name, date);
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#setHeader(java.lang.String, java.lang.String)
+     */
+    public void setHeader(String name, String value)
+    {
+        if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name))
+            setContentType(value);
+        else
+        {
+            if (_connection.isIncluding())
+            {
+                if (name.startsWith(SET_INCLUDE_HEADER_PREFIX))
+                    name=name.substring(SET_INCLUDE_HEADER_PREFIX.length());
+                else
+                    return;
+            }
+            _connection.getResponseFields().put(name, value);
+            if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name))
+            {
+                if (value==null)
+                    _connection._generator.setContentLength(-1);
+                else
+                    _connection._generator.setContentLength(Long.parseLong(value));
+            }
+        }
+    }
+
+
+    /* ------------------------------------------------------------ */
+    public Collection<String> getHeaderNames()
+    {
+        final HttpFields fields=_connection.getResponseFields();
+        return fields.getFieldNamesCollection();
+    }
+    
+    /* ------------------------------------------------------------ */
+    /*
+     */
+    public String getHeader(String name)
+    {
+        return _connection.getResponseFields().getStringField(name);
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     */
+    public Collection<String> getHeaders(String name)
+    {
+        final HttpFields fields=_connection.getResponseFields();
+        Collection<String> i = fields.getValuesCollection(name);
+        if (i==null)
+            return Collections.EMPTY_LIST;
+        return i;
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#addHeader(java.lang.String, java.lang.String)
+     */
+    public void addHeader(String name, String value)
+    {
+
+        if (_connection.isIncluding())
+        {
+            if (name.startsWith(SET_INCLUDE_HEADER_PREFIX))
+                name=name.substring(SET_INCLUDE_HEADER_PREFIX.length());
+            else
+                return;
+        }
+
+        if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name))
+        {
+            setContentType(value);
+            return;
+        }
+        
+        _connection.getResponseFields().add(name, value);
+        if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name))
+            _connection._generator.setContentLength(Long.parseLong(value));
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#setIntHeader(java.lang.String, int)
+     */
+    public void setIntHeader(String name, int value)
+    {
+        if (!_connection.isIncluding())
+        {
+            _connection.getResponseFields().putLongField(name, value);
+            if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name))
+                _connection._generator.setContentLength(value);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#addIntHeader(java.lang.String, int)
+     */
+    public void addIntHeader(String name, int value)
+    {
+        if (!_connection.isIncluding())
+        {
+            _connection.getResponseFields().addLongField(name, value);
+            if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name))
+                _connection._generator.setContentLength(value);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#setStatus(int)
+     */
+    public void setStatus(int sc)
+    {
+        setStatus(sc,null);
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.http.HttpServletResponse#setStatus(int, java.lang.String)
+     */
+    public void setStatus(int sc, String sm)
+    {
+        if (sc<=0)
+            throw new IllegalArgumentException();
+        if (!_connection.isIncluding())
+        {
+            _status=sc;
+            _reason=sm;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#getCharacterEncoding()
+     */
+    public String getCharacterEncoding()
+    {
+        if (_characterEncoding==null)
+            _characterEncoding=StringUtil.__ISO_8859_1;
+        return _characterEncoding;
+    }
+    
+    /* ------------------------------------------------------------ */
+    String getSetCharacterEncoding()
+    {
+        return _characterEncoding;
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#getContentType()
+     */
+    public String getContentType()
+    {
+        return _contentType;
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#getOutputStream()
+     */
+    public ServletOutputStream getOutputStream() throws IOException
+    {
+        if (_outputState!=NONE && _outputState!=STREAM)
+            throw new IllegalStateException("WRITER");
+
+        ServletOutputStream out = _connection.getOutputStream();
+        _outputState=STREAM;
+        return out;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isWriting()
+    {
+        return _outputState==WRITER;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isOutputing()
+    {
+        return _outputState!=NONE;
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#getWriter()
+     */
+    public PrintWriter getWriter() throws IOException
+    {
+        if (_outputState!=NONE && _outputState!=WRITER)
+            throw new IllegalStateException("STREAM");
+
+        /* if there is no writer yet */
+        if (_writer==null)
+        {
+            /* get encoding from Content-Type header */
+            String encoding = _characterEncoding;
+
+            if (encoding==null)
+            {
+                /* implementation of educated defaults */
+                if(_cachedMimeType != null)
+                    encoding = MimeTypes.getCharsetFromContentType(_cachedMimeType);
+
+                if (encoding==null)
+                    encoding = StringUtil.__ISO_8859_1;
+
+                setCharacterEncoding(encoding);
+            }
+
+            /* construct Writer using correct encoding */
+            _writer = _connection.getPrintWriter(encoding);
+        }
+        _outputState=WRITER;
+        return _writer;
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#setCharacterEncoding(java.lang.String)
+     */
+    public void setCharacterEncoding(String encoding)
+    {
+    	if (_connection.isIncluding())
+    		return;
+
+        if (this._outputState==0 && !isCommitted())
+        {
+            _explicitEncoding=true;
+
+            if (encoding==null)
+            {
+                // Clear any encoding.
+                if (_characterEncoding!=null)
+                {
+                    _characterEncoding=null;
+                    if (_cachedMimeType!=null)
+                        _contentType=_cachedMimeType.toString();
+                    else if (_mimeType!=null)
+                        _contentType=_mimeType;
+                    else
+                        _contentType=null;
+
+                    if (_contentType==null)
+                        _connection.getResponseFields().remove(HttpHeaders.CONTENT_TYPE_BUFFER);
+                    else
+                        _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                }
+            }
+            else
+            {
+                // No, so just add this one to the mimetype
+                _characterEncoding=encoding;
+                if (_contentType!=null)
+                {
+                    int i0=_contentType.indexOf(';');
+                    if (i0<0)
+                    {
+                        _contentType=null;
+                        if(_cachedMimeType!=null)
+                        {
+                            CachedBuffer content_type = _cachedMimeType.getAssociate(_characterEncoding);
+                            if (content_type!=null)
+                            {
+                                _contentType=content_type.toString();
+                                _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,content_type);
+                            }
+                        }
+
+                        if (_contentType==null)
+                        {
+                            _contentType = _mimeType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
+                            _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                        }
+                    }
+                    else
+                    {
+                        int i1=_contentType.indexOf("charset=",i0);
+                        if (i1<0)
+                        {
+                            _contentType = _contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
+                        }
+                        else
+                        {
+                            int i8=i1+8;
+                            int i2=_contentType.indexOf(" ",i8);
+                            if (i2<0)
+                                _contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
+                            else
+                                _contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ")+_contentType.substring(i2);
+                        }
+                        _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                    }
+                }
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#setContentLength(int)
+     */
+    public void setContentLength(int len)
+    {
+        // Protect from setting after committed as default handling
+        // of a servlet HEAD request ALWAYS sets _content length, even
+        // if the getHandling committed the response!
+        if (isCommitted() || _connection.isIncluding())
+            return;
+        _connection._generator.setContentLength(len);
+        if (len>0)
+        {
+            _connection.getResponseFields().putLongField(HttpHeaders.CONTENT_LENGTH, len);
+            if (_connection._generator.isAllContentWritten())
+            {
+                if (_outputState==WRITER)
+                    _writer.close();
+                else if (_outputState==STREAM)
+                {
+                    try
+                    {
+                        getOutputStream().close();
+                    }
+                    catch(IOException e)
+                    {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#setContentLength(int)
+     */
+    public void setLongContentLength(long len)
+    {
+        // Protect from setting after committed as default handling
+        // of a servlet HEAD request ALWAYS sets _content length, even
+        // if the getHandling committed the response!
+        if (isCommitted() || _connection.isIncluding())
+        	return;
+        _connection._generator.setContentLength(len);
+        _connection.getResponseFields().putLongField(HttpHeaders.CONTENT_LENGTH, len);
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#setContentType(java.lang.String)
+     */
+    public void setContentType(String contentType)
+    {
+        if (isCommitted() || _connection.isIncluding())
+            return;
+
+        // Yes this method is horribly complex.... but there are lots of special cases and
+        // as this method is called on every request, it is worth trying to save string creation.
+        //
+
+        if (contentType==null)
+        {
+            if (_locale==null)
+                _characterEncoding=null;
+            _mimeType=null;
+            _cachedMimeType=null;
+            _contentType=null;
+            _connection.getResponseFields().remove(HttpHeaders.CONTENT_TYPE_BUFFER);
+        }
+        else
+        {
+            // Look for encoding in contentType
+            int i0=contentType.indexOf(';');
+
+            if (i0>0)
+            {
+                // we have content type parameters
+
+                // Extract params off mimetype
+                _mimeType=contentType.substring(0,i0).trim();
+                _cachedMimeType=MimeTypes.CACHE.get(_mimeType);
+
+                // Look for charset
+                int i1=contentType.indexOf("charset=",i0+1);
+                if (i1>=0)
+                {
+                    _explicitEncoding=true;
+                    int i8=i1+8;
+                    int i2 = contentType.indexOf(' ',i8);
+
+                    if (_outputState==WRITER)
+                    {
+                        // strip the charset and ignore;
+                        if ((i1==i0+1 && i2<0) || (i1==i0+2 && i2<0 && contentType.charAt(i0+1)==' '))
+                        {
+                            if (_cachedMimeType!=null)
+                            {
+                                CachedBuffer content_type = _cachedMimeType.getAssociate(_characterEncoding);
+                                if (content_type!=null)
+                                {
+                                    _contentType=content_type.toString();
+                                    _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,content_type);
+                                }
+                                else
+                                {
+                                    _contentType=_mimeType+";charset="+_characterEncoding;
+                                    _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                                }
+                            }
+                            else
+                            {
+                                _contentType=_mimeType+";charset="+_characterEncoding;
+                                _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                            }
+                        }
+                        else if (i2<0)
+                        {
+                            _contentType=contentType.substring(0,i1)+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
+                            _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                        }
+                        else
+                        {
+                            _contentType=contentType.substring(0,i1)+contentType.substring(i2)+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
+                            _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                        }
+                    }
+                    else if ((i1==i0+1 && i2<0) || (i1==i0+2 && i2<0 && contentType.charAt(i0+1)==' '))
+                    {
+                        // The params are just the char encoding
+                        _cachedMimeType=MimeTypes.CACHE.get(_mimeType);
+                        _characterEncoding = QuotedStringTokenizer.unquote(contentType.substring(i8));
+
+                        if (_cachedMimeType!=null)
+                        {
+                            CachedBuffer content_type = _cachedMimeType.getAssociate(_characterEncoding);
+                            if (content_type!=null)
+                            {
+                                _contentType=content_type.toString();
+                                _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,content_type);
+                            }
+                            else
+                            {
+                                _contentType=contentType;
+                                _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                            }
+                        }
+                        else
+                        {
+                            _contentType=contentType;
+                            _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                        }
+                    }
+                    else if (i2>0)
+                    {
+                        _characterEncoding = QuotedStringTokenizer.unquote(contentType.substring(i8,i2));
+                        _contentType=contentType;
+                        _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                    }
+                    else
+                    {
+                        _characterEncoding = QuotedStringTokenizer.unquote(contentType.substring(i8));
+                        _contentType=contentType;
+                        _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                    }
+                }
+                else // No encoding in the params.
+                {
+                    _cachedMimeType=null;
+                    _contentType=_characterEncoding==null?contentType:contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
+                    _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                }
+            }
+            else // No params at all
+            {
+                _mimeType=contentType;
+                _cachedMimeType=MimeTypes.CACHE.get(_mimeType);
+
+                if (_characterEncoding!=null)
+                {
+                    if (_cachedMimeType!=null)
+                    {
+                        CachedBuffer content_type = _cachedMimeType.getAssociate(_characterEncoding);
+                        if (content_type!=null)
+                        {
+                            _contentType=content_type.toString();
+                            _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,content_type);
+                        }
+                        else
+                        {
+                            _contentType=_mimeType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
+                            _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                        }
+                    }
+                    else
+                    {
+                        _contentType=contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
+                        _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                    }
+                }
+                else if (_cachedMimeType!=null)
+                {
+                    _contentType=_cachedMimeType.toString();
+                    _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_cachedMimeType);
+                }
+                else
+                {
+                    _contentType=contentType;
+                    _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+                }
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#setBufferSize(int)
+     */
+    public void setBufferSize(int size)
+    {
+        if (isCommitted() || getContentCount()>0)
+            throw new IllegalStateException("Committed or content written");
+        _connection.getGenerator().increaseContentBufferSize(size);
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#getBufferSize()
+     */
+    public int getBufferSize()
+    {
+        return _connection.getGenerator().getContentBufferSize();
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#flushBuffer()
+     */
+    public void flushBuffer() throws IOException
+    {
+        _connection.flushResponse();
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#reset()
+     */
+    public void reset()
+    {
+        resetBuffer();
+        fwdReset();
+        _status=200;
+        _reason=null;
+        
+        HttpFields response_fields=_connection.getResponseFields();
+        
+        response_fields.clear();
+        String connection=_connection.getRequestFields().getStringField(HttpHeaders.CONNECTION_BUFFER);
+        if (connection!=null)
+        {
+            String[] values = connection.split(",");
+            for  (int i=0;values!=null && i<values.length;i++)
+            {
+                CachedBuffer cb = HttpHeaderValues.CACHE.get(values[0].trim());
+
+                if (cb!=null)
+                {
+                    switch(cb.getOrdinal())
+                    {
+                        case HttpHeaderValues.CLOSE_ORDINAL:
+                            response_fields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
+                            break;
+
+                        case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
+                            if (HttpVersions.HTTP_1_0.equalsIgnoreCase(_connection.getRequest().getProtocol()))
+                                response_fields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE);
+                            break;
+                        case HttpHeaderValues.TE_ORDINAL:
+                            response_fields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.TE);
+                            break;
+                    }
+                }
+            }
+        }
+    }
+    
+
+    public void reset(boolean preserveCookies)
+    { 
+        if (!preserveCookies)
+            reset();
+        else
+        {
+            HttpFields response_fields=_connection.getResponseFields();
+
+            ArrayList<String> cookieValues = new ArrayList<String>(5);
+            Enumeration<String> vals = response_fields.getValues(HttpHeaders.SET_COOKIE);
+            while (vals.hasMoreElements())
+                cookieValues.add((String)vals.nextElement());
+
+            reset();
+
+            for (String v:cookieValues)
+                response_fields.add(HttpHeaders.SET_COOKIE, v);
+        }
+    }
+    
+    
+    
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#reset()
+     */
+    public void fwdReset()
+    {
+        resetBuffer();
+
+        _writer=null;
+        _outputState=NONE;
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#resetBuffer()
+     */
+    public void resetBuffer()
+    {
+        if (isCommitted())
+            throw new IllegalStateException("Committed");
+        _connection.getGenerator().resetBuffer();
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#isCommitted()
+     */
+    public boolean isCommitted()
+    {
+        return _connection.isResponseCommitted();
+    }
+
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#setLocale(java.util.Locale)
+     */
+    public void setLocale(Locale locale)
+    {
+        if (locale == null || isCommitted() ||_connection.isIncluding())
+            return;
+
+        _locale = locale;
+        _connection.getResponseFields().put(HttpHeaders.CONTENT_LANGUAGE_BUFFER,locale.toString().replace('_','-'));
+
+        if (_explicitEncoding || _outputState!=0 )
+            return;
+
+        if (_connection.getRequest().getContext()==null)
+            return;
+
+        String charset = _connection.getRequest().getContext().getContextHandler().getLocaleEncoding(locale);
+
+        if (charset!=null && charset.length()>0)
+        {
+            _characterEncoding=charset;
+
+            /* get current MIME type from Content-Type header */
+            String type=getContentType();
+            if (type!=null)
+            {
+                _characterEncoding=charset;
+                int semi=type.indexOf(';');
+                if (semi<0)
+                {
+                    _mimeType=type;
+                    _contentType= type += ";charset="+charset;
+                }
+                else
+                {
+                    _mimeType=type.substring(0,semi);
+                    _contentType= _mimeType += ";charset="+charset;
+                }
+
+                _cachedMimeType=MimeTypes.CACHE.get(_mimeType);
+                _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType);
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /*
+     * @see javax.servlet.ServletResponse#getLocale()
+     */
+    public Locale getLocale()
+    {
+        if (_locale==null)
+            return Locale.getDefault();
+        return _locale;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return The HTTP status code that has been set for this request. This will be <code>200<code>
+     *    ({@link HttpServletResponse#SC_OK}), unless explicitly set through one of the <code>setStatus</code> methods.
+     */
+    public int getStatus()
+    {
+        return _status;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return The reason associated with the current {@link #getStatus() status}. This will be <code>null</code>,
+     *    unless one of the <code>setStatus</code> methods have been called.
+     */
+    public String getReason()
+    {
+        return _reason;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     */
+    public void complete()
+        throws IOException
+    {
+        _connection.completeResponse();
+    }
+
+    /* ------------------------------------------------------------- */
+    /**
+     * @return the number of bytes actually written in response body
+     */
+    public long getContentCount()
+    {
+        if (_connection==null || _connection.getGenerator()==null)
+            return -1;
+        return _connection.getGenerator().getContentWritten();
+    }
+
+    /* ------------------------------------------------------------ */
+    public HttpFields getHttpFields()
+    {
+        return _connection.getResponseFields();
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String toString()
+    {
+        return "HTTP/1.1 "+_status+" "+ (_reason==null?"":_reason) +System.getProperty("line.separator")+
+        _connection.getResponseFields().toString();
+    }
+    
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    private static class NullOutput extends ServletOutputStream
+    {
+        @Override
+        public void write(int b) throws IOException
+        {
+        }
+
+        @Override
+        public void print(String s) throws IOException
+        {
+        }
+
+        @Override
+        public void println(String s) throws IOException
+        {
+        }
+
+        @Override
+        public void write(byte[] b, int off, int len) throws IOException
+        {
+        }
+
+    }
+
+}