net.lightbody.bmp.proxy.jetty.jetty.servlet.Dispatcher.java Source code

Java tutorial

Introduction

Here is the source code for net.lightbody.bmp.proxy.jetty.jetty.servlet.Dispatcher.java

Source

// ========================================================================
// $Id: Dispatcher.java,v 1.92 2005/12/12 18:03:31 gregwilkins Exp $
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at 
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================

package net.lightbody.bmp.proxy.jetty.jetty.servlet;

import net.lightbody.bmp.proxy.jetty.http.HttpConnection;
import net.lightbody.bmp.proxy.jetty.http.PathMap;
import net.lightbody.bmp.proxy.jetty.log.LogFactory;
import net.lightbody.bmp.proxy.jetty.util.*;
import org.apache.commons.logging.Log;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

/* ------------------------------------------------------------ */
/** Servlet RequestDispatcher.
 * 
 * @version $Id: Dispatcher.java,v 1.92 2005/12/12 18:03:31 gregwilkins Exp $
 * @author Greg Wilkins (gregw)
 */
public class Dispatcher implements RequestDispatcher {
    static Log log = LogFactory.getLog(Dispatcher.class);

    /* ------------------------------------------------------------ */
    /** Dispatch types */
    public static final int __DEFAULT = 0;
    public static final int __REQUEST = 1;
    public static final int __FORWARD = 2;
    public static final int __INCLUDE = 4;
    public static final int __ERROR = 8;
    public static final int __ALL = 15;

    /** Dispatch include attribute names */
    public final static String __INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
    public final static String __INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
    public final static String __INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
    public final static String __INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
    public final static String __INCLUDE_QUERY_STRING = "javax.servlet.include.query_string";

    /** Dispatch include attribute names */
    public final static String __FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";
    public final static String __FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
    public final static String __FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
    public final static String __FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
    public final static String __FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";

    public final static StringMap __managedAttributes = new StringMap();
    static {
        __managedAttributes.put(__INCLUDE_REQUEST_URI, __INCLUDE_REQUEST_URI);
        __managedAttributes.put(__INCLUDE_CONTEXT_PATH, __INCLUDE_CONTEXT_PATH);
        __managedAttributes.put(__INCLUDE_SERVLET_PATH, __INCLUDE_SERVLET_PATH);
        __managedAttributes.put(__INCLUDE_PATH_INFO, __INCLUDE_PATH_INFO);
        __managedAttributes.put(__INCLUDE_QUERY_STRING, __INCLUDE_QUERY_STRING);

        __managedAttributes.put(__FORWARD_REQUEST_URI, __FORWARD_REQUEST_URI);
        __managedAttributes.put(__FORWARD_CONTEXT_PATH, __FORWARD_CONTEXT_PATH);
        __managedAttributes.put(__FORWARD_SERVLET_PATH, __FORWARD_SERVLET_PATH);
        __managedAttributes.put(__FORWARD_PATH_INFO, __FORWARD_PATH_INFO);
        __managedAttributes.put(__FORWARD_QUERY_STRING, __FORWARD_QUERY_STRING);
    }

    ServletHandler _servletHandler;
    ServletHolder _holder = null;
    String _pathSpec;
    String _uriInContext;
    String _pathInContext;
    String _query;

    /* ------------------------------------------------------------ */
    /** Constructor. 
    /** Constructor. 
     * @param servletHandler 
     * @param uriInContext Encoded uriInContext
     * @param pathInContext Encoded pathInContext
     * @param query
     * @exception IllegalStateException 
     */
    Dispatcher(ServletHandler servletHandler, String uriInContext, String pathInContext, String query,
            Map.Entry entry) throws IllegalStateException {
        if (log.isDebugEnabled())
            log.debug("Dispatcher for " + servletHandler + "," + uriInContext + "," + query);

        _servletHandler = servletHandler;
        _uriInContext = uriInContext;
        _pathInContext = pathInContext;
        _query = query;
        _pathSpec = (String) entry.getKey();
        _holder = (ServletHolder) entry.getValue();
    }

    /* ------------------------------------------------------------ */
    /** Constructor. 
     * @param servletHandler
     * @param name
     */
    Dispatcher(ServletHandler servletHandler, String name) throws IllegalStateException {
        _servletHandler = servletHandler;
        _holder = _servletHandler.getServletHolder(name);
        if (_holder == null)
            throw new IllegalStateException("No named servlet handler in context");
    }

    /* ------------------------------------------------------------ */
    public boolean isNamed() {
        return _pathInContext == null;
    }

    /* ------------------------------------------------------------ */
    public void include(ServletRequest servletRequest, ServletResponse servletResponse)
            throws ServletException, IOException {
        dispatch(servletRequest, servletResponse, Dispatcher.__INCLUDE);
    }

    /* ------------------------------------------------------------ */
    public void forward(ServletRequest servletRequest, ServletResponse servletResponse)
            throws ServletException, IOException {
        dispatch(servletRequest, servletResponse, Dispatcher.__FORWARD);
    }

    /* ------------------------------------------------------------ */
    void error(ServletRequest servletRequest, ServletResponse servletResponse)
            throws ServletException, IOException {
        dispatch(servletRequest, servletResponse, Dispatcher.__ERROR);
    }

    /* ------------------------------------------------------------ */
    void dispatch(ServletRequest servletRequest, ServletResponse servletResponse, int type)
            throws ServletException, IOException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;

        HttpConnection httpConnection = _servletHandler.getHttpContext().getHttpConnection();
        ServletHttpRequest servletHttpRequest = (ServletHttpRequest) httpConnection.getRequest().getWrapper();

        // wrap the request and response
        DispatcherRequest request = new DispatcherRequest(httpServletRequest, servletHttpRequest, type);
        DispatcherResponse response = new DispatcherResponse(request, httpServletResponse);

        if (type == Dispatcher.__FORWARD)
            servletResponse.resetBuffer();

        // Merge parameters
        String query = _query;
        MultiMap parameters = null;
        if (query != null) {
            Map old_params = httpServletRequest.getParameterMap();

            // Add the parameters
            parameters = new MultiMap();
            UrlEncoded.decodeTo(query, parameters, request.getCharacterEncoding());

            if (old_params != null && old_params.size() > 0) {
                // Merge old parameters.
                Iterator iter = old_params.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String name = (String) entry.getKey();
                    String[] values = (String[]) entry.getValue();
                    for (int i = 0; i < values.length; i++)
                        parameters.add(name, values[i]);
                }
            }

            request.setParameters(parameters);

            String old_query = httpServletRequest.getQueryString();
            if (old_query != null)
                request.setQuery(query + "&" + old_query);
            else
                request.setQuery(query);
        }

        Object old_scope = null;
        try {
            if (request.crossContext()) {
                // Setup new _context
                old_scope = _servletHandler.getHttpContext().enterContextScope(httpConnection.getRequest(),
                        httpConnection.getResponse());
            }

            if (isNamed()) {
                // No further modifications required.
                if (_servletHandler instanceof WebApplicationHandler) {
                    JSR154Filter filter = ((WebApplicationHandler) _servletHandler).getJsr154Filter();
                    if (filter != null && filter.isUnwrappedDispatchSupported()) {
                        filter.setDispatch(request, response);
                        _servletHandler.dispatch(null, httpServletRequest, httpServletResponse, _holder, type);
                    } else
                        _servletHandler.dispatch(null, request, response, _holder, type);
                } else
                    _servletHandler.dispatch(null, request, response, _holder, type);
            } else {
                // Adjust servlet paths
                request.setPaths(_servletHandler.getHttpContext().getContextPath(),
                        PathMap.pathMatch(_pathSpec, _pathInContext), PathMap.pathInfo(_pathSpec, _pathInContext));

                // are we wrap over or wrap under
                if (_servletHandler instanceof WebApplicationHandler) {
                    JSR154Filter filter = ((WebApplicationHandler) _servletHandler).getJsr154Filter();
                    if (filter != null && filter.isUnwrappedDispatchSupported()) {
                        filter.setDispatch(request, response);
                        _servletHandler.dispatch(_pathInContext, httpServletRequest, httpServletResponse, _holder,
                                type);
                    } else
                        _servletHandler.dispatch(_pathInContext, request, response, _holder, type);
                } else
                    _servletHandler.dispatch(_pathInContext, request, response, _holder, type);

                if (type != Dispatcher.__INCLUDE)
                    response.close();
                else if (response.isFlushNeeded())
                    response.flushBuffer();
            }
        } finally {
            // restore _context
            if (request.crossContext())
                _servletHandler.getHttpContext().leaveContextScope(httpConnection.getRequest(),
                        httpConnection.getResponse(), old_scope);
        }
    }

    /* ------------------------------------------------------------ */
    public String toString() {
        return "Dispatcher[" + _pathSpec + "," + _holder + "]";
    }

    /* ------------------------------------------------------------ */
    /** Dispatch type from name
     */
    public static int type(String type) {
        if ("request".equalsIgnoreCase(type))
            return __REQUEST;
        if ("forward".equalsIgnoreCase(type))
            return __FORWARD;
        if ("include".equalsIgnoreCase(type))
            return __INCLUDE;
        if ("error".equalsIgnoreCase(type))
            return __ERROR;
        throw new IllegalArgumentException(type);
    }

    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    class DispatcherRequest extends HttpServletRequestWrapper {
        DispatcherResponse _response;
        int _filterType;
        String _contextPath;
        String _servletPath;
        String _pathInfo;
        MultiMap _parameters;
        HashMap _attributes;
        boolean _xContext;
        HttpSession _xSession;
        ServletHttpRequest _servletHttpRequest;
        String _query;

        /* ------------------------------------------------------------ */
        DispatcherRequest(HttpServletRequest httpServletRequest, ServletHttpRequest servletHttpRequest,
                int filterType) {
            super(httpServletRequest);
            _servletHttpRequest = servletHttpRequest;
            _filterType = filterType;

            // Is this being dispatched to a different context?
            _xContext = servletHttpRequest.getServletHandler() != _servletHandler;
            if (_xContext) {
                // Look for an existing or requested session ID.
                HttpSession session = httpServletRequest.getSession(false);
                String session_id = (session == null) ? httpServletRequest.getRequestedSessionId()
                        : session.getId();

                // Look for that session in new context to access it.
                if (session_id != null) {
                    _xSession = _servletHandler.getHttpSession(session_id);
                    if (_xSession != null)
                        ((SessionManager.Session) _xSession).access();
                }
            }
        }

        /* ------------------------------------------------------------ */
        boolean crossContext() {
            return _xContext;
        }

        /* ------------------------------------------------------------ */
        void setPaths(String cp, String sp, String pi) {
            _contextPath = (cp.length() == 1 && cp.charAt(0) == '/') ? "" : cp;
            _servletPath = sp;
            _pathInfo = pi;
        }

        /* ------------------------------------------------------------ */
        void setQuery(String q) {
            this._query = q;
        }

        /* ------------------------------------------------------------ */
        int getFilterType() {
            return _filterType;
        }

        /* ------------------------------------------------------------ */
        String getPathInContext() {
            if (_pathInContext != null)
                return _pathInContext;
            else
                return URI.addPaths(getServletPath(), getPathInfo());
        }

        /* ------------------------------------------------------------ */
        public String getRequestURI() {
            if (_filterType == Dispatcher.__INCLUDE || isNamed())
                return super.getRequestURI();
            return URI.addPaths(_contextPath, _uriInContext);
        }

        /* ------------------------------------------------------------ */
        public StringBuffer getRequestURL() {
            if (_filterType == Dispatcher.__INCLUDE || isNamed())
                return super.getRequestURL();
            StringBuffer buf = getRootURL();
            if (_contextPath.length() > 0)
                buf.append(_contextPath);
            buf.append(_uriInContext);
            return buf;
        }

        /* ------------------------------------------------------------ */
        public String getPathTranslated() {
            String info = getPathInfo();
            if (info == null)
                return null;
            return getRealPath(info);
        }

        /* ------------------------------------------------------------ */
        StringBuffer getRootURL() {
            StringBuffer buf = super.getRequestURL();
            int d = 3;
            for (int i = 0; i < buf.length(); i++) {
                if (buf.charAt(i) == '/' && --d == 0) {
                    buf.setLength(i);
                    break;
                }
            }
            return buf;
        }

        /* ------------------------------------------------------------ */
        public String getContextPath() {
            return (_filterType == Dispatcher.__INCLUDE || isNamed()) ? super.getContextPath() : _contextPath;
        }

        /* ------------------------------------------------------------ */
        public String getServletPath() {
            return (_filterType == Dispatcher.__INCLUDE || isNamed()) ? super.getServletPath() : _servletPath;
        }

        /* ------------------------------------------------------------ */
        public String getPathInfo() {
            return (_filterType == Dispatcher.__INCLUDE || isNamed()) ? super.getPathInfo() : _pathInfo;
        }

        /* ------------------------------------------------------------ */
        public String getQueryString() {
            if (this._query == null)
                return super.getQueryString();
            return this._query;
        }

        /* ------------------------------------------------------------ */
        void setParameters(MultiMap parameters) {
            _parameters = parameters;
        }

        /* -------------------------------------------------------------- */
        public Enumeration getParameterNames() {
            if (_parameters == null)
                return super.getParameterNames();

            return Collections.enumeration(_parameters.keySet());
        }

        /* -------------------------------------------------------------- */
        public String getParameter(String name) {
            if (_parameters == null)
                return super.getParameter(name);
            return (String) _parameters.getValue(name, 0);
        }

        /* -------------------------------------------------------------- */
        public String[] getParameterValues(String name) {
            if (_parameters == null)
                return super.getParameterValues(name);
            List l = _parameters.getValues(name);
            if (l == null)
                return null;
            return (String[]) l.toArray(new String[l.size()]);
        }

        /* -------------------------------------------------------------- */
        public Map getParameterMap() {
            if (_parameters == null)
                return super.getParameterMap();

            return _parameters.toStringArrayMap();
        }

        /* ------------------------------------------------------------ */
        public void setAttribute(String name, Object value) {
            if (__managedAttributes.containsKey(name)) {
                if (_attributes == null)
                    _attributes = new HashMap(3);
                _attributes.put(name, value);
            } else
                super.setAttribute(name, value);
        }

        /* ------------------------------------------------------------ */
        public Object getAttribute(String name) {
            if (_attributes != null && _attributes.containsKey(name))
                return _attributes.get(name);

            if (_filterType == Dispatcher.__INCLUDE && !isNamed()) {
                if (name.equals(__INCLUDE_PATH_INFO))
                    return _pathInfo;
                if (name.equals(__INCLUDE_REQUEST_URI))
                    return URI.addPaths(_contextPath, _uriInContext);
                if (name.equals(__INCLUDE_SERVLET_PATH))
                    return _servletPath;
                if (name.equals(__INCLUDE_CONTEXT_PATH))
                    return _contextPath;
                if (name.equals(__INCLUDE_QUERY_STRING))
                    return Dispatcher.this._query;
            } else {
                if (name.equals(__INCLUDE_PATH_INFO))
                    return null;
                if (name.equals(__INCLUDE_REQUEST_URI))
                    return null;
                if (name.equals(__INCLUDE_SERVLET_PATH))
                    return null;
                if (name.equals(__INCLUDE_CONTEXT_PATH))
                    return null;
                if (name.equals(__INCLUDE_QUERY_STRING))
                    return null;
            }

            if (_filterType != Dispatcher.__INCLUDE && !isNamed()) {
                if (name.equals(__FORWARD_PATH_INFO))
                    return _servletHttpRequest.getPathInfo();
                if (name.equals(__FORWARD_REQUEST_URI))
                    return _servletHttpRequest.getRequestURI();
                if (name.equals(__FORWARD_SERVLET_PATH))
                    return _servletHttpRequest.getServletPath();
                if (name.equals(__FORWARD_CONTEXT_PATH))
                    return _servletHttpRequest.getContextPath();
                if (name.equals(__FORWARD_QUERY_STRING))
                    return _servletHttpRequest.getQueryString();
            }

            return super.getAttribute(name);
        }

        /* ------------------------------------------------------------ */
        public Enumeration getAttributeNames() {
            HashSet set = new HashSet();
            Enumeration e = super.getAttributeNames();
            while (e.hasMoreElements())
                set.add(e.nextElement());

            if (_filterType == Dispatcher.__INCLUDE && !isNamed()) {
                if (_pathInfo != null)
                    set.add(__INCLUDE_PATH_INFO);
                else
                    set.remove(__INCLUDE_PATH_INFO);
                set.add(__INCLUDE_REQUEST_URI);
                set.add(__INCLUDE_SERVLET_PATH);
                set.add(__INCLUDE_CONTEXT_PATH);
                if (Dispatcher.this._query != null)
                    set.add(__INCLUDE_QUERY_STRING);
                else
                    set.remove(__INCLUDE_QUERY_STRING);

            } else {
                set.remove(__INCLUDE_PATH_INFO);
                set.remove(__INCLUDE_REQUEST_URI);
                set.remove(__INCLUDE_SERVLET_PATH);
                set.remove(__INCLUDE_CONTEXT_PATH);
                set.remove(__INCLUDE_QUERY_STRING);
            }

            if (_filterType != Dispatcher.__INCLUDE && !isNamed()) {
                if (_servletHttpRequest.getPathInfo() != null)
                    set.add(__FORWARD_PATH_INFO);
                else
                    set.remove(__FORWARD_PATH_INFO);

                set.add(__FORWARD_REQUEST_URI);
                set.add(__FORWARD_SERVLET_PATH);
                set.add(__FORWARD_CONTEXT_PATH);
                if (_servletHttpRequest.getQueryString() != null)
                    set.add(__FORWARD_QUERY_STRING);
                else
                    set.remove(__FORWARD_QUERY_STRING);
            }

            if (_attributes != null)
                set.addAll(_attributes.keySet());

            return Collections.enumeration(set);
        }

        /* ------------------------------------------------------------ */
        /**
         *  If the request attribute "org.mortbay.jetty.servlet.Dispatcher.shared_session" is set, then 
         * sessions are shared in cross context dispatch.  Watch out for class loading issues!
         */
        public HttpSession getSession(boolean create) {
            if (_xContext) {
                if (_xSession == null) {
                    if (getAttribute(
                            "net.lightbody.bmp.proxy.jetty.jetty.servlet.Dispatcher.shared_session") != null)
                        _xSession = super.getSession(create);
                    else {
                        log.debug("Ctx dispatch session");

                        String rsid = getRequestedSessionId();
                        if (rsid == null) {
                            HttpSession session = super.getSession(false);
                            if (session != null)
                                rsid = session.getId();
                        }
                        _xSession = _servletHandler.getHttpSession(rsid);
                        if (create && _xSession == null) {
                            _xSession = _servletHandler.newHttpSession(this);
                            Cookie cookie = _servletHandler.getSessionManager().getSessionCookie(_xSession,
                                    isSecure());
                            if (cookie != null)
                                _servletHttpRequest.getHttpRequest().getHttpResponse().addSetCookie(cookie);
                        }
                    }

                }
                return _xSession;
            } else
                return super.getSession(create);
        }

        /* ------------------------------------------------------------ */
        public boolean isRequestedSessionIdValid() {
            if (_xContext) {
                String requestedSessionid = super.getRequestedSessionId();
                if (requestedSessionid != null) {
                    HttpSession session = getSession(false);
                    if (session != null) {
                        return ((AbstractSessionManager.Session) session).isValid()
                                && requestedSessionid.equals(session.getId());
                    }
                }
                return false;
            } else {
                return super.isRequestedSessionIdValid();
            }
        }

        /* ------------------------------------------------------------ */
        public HttpSession getSession() {
            return getSession(true);
        }

        /* ------------------------------------------------------------ */
        public String getRealPath(String path) {
            return _servletHandler.getServletContext().getRealPath(path);
        }

        /* ------------------------------------------------------------ */
        public RequestDispatcher getRequestDispatcher(String url) {
            if (url == null)
                return null;

            if (!url.startsWith("/")) {
                String relTo = URI.addPaths(getServletPath(), getPathInfo());
                int slash = relTo.lastIndexOf("/");
                if (slash > 1)
                    relTo = relTo.substring(0, slash + 1);
                else
                    relTo = "/";
                url = URI.addPaths(relTo, url);
            }

            return _servletHandler.getServletContext().getRequestDispatcher(url);
        }

        public String getMethod() {
            if (this._filterType == Dispatcher.__ERROR)
                return net.lightbody.bmp.proxy.jetty.http.HttpRequest.__GET;
            return super.getMethod();
        }
    }

    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    class DispatcherResponse extends HttpServletResponseWrapper {
        DispatcherRequest _request;
        private ServletOutputStream _out = null;
        private PrintWriter _writer = null;
        private boolean _flushNeeded = false;
        private boolean _include;

        /* ------------------------------------------------------------ */
        DispatcherResponse(DispatcherRequest request, HttpServletResponse response) {
            super(response);
            _request = request;
            request._response = this;
            _include = _request._filterType == Dispatcher.__INCLUDE;

        }

        /* ------------------------------------------------------------ */
        public ServletOutputStream getOutputStream() throws IOException {
            if (_writer != null)
                throw new IllegalStateException("getWriter called");

            if (_out == null) {
                try {
                    _out = super.getOutputStream();
                } catch (IllegalStateException e) {
                    LogSupport.ignore(log, e);
                    _flushNeeded = true;
                    _out = new ServletOut(new WriterOutputStream(super.getWriter()));
                }
            }

            if (_include)
                _out = new DontCloseServletOut(_out);

            return _out;
        }

        /* ------------------------------------------------------------ */
        public PrintWriter getWriter() throws IOException {
            if (_out != null)
                throw new IllegalStateException("getOutputStream called");

            if (_writer == null) {
                try {
                    _writer = super.getWriter();
                } catch (IllegalStateException e) {
                    LogSupport.ignore(log, e);
                    _flushNeeded = true;
                    _writer = new ServletWriter(super.getOutputStream(), getCharacterEncoding());
                }
            }

            if (_include)
                _writer = new DontCloseWriter(_writer);
            return _writer;
        }

        /* ------------------------------------------------------------ */
        boolean isFlushNeeded() {
            return _flushNeeded;
        }

        /* ------------------------------------------------------------ */
        public void flushBuffer() throws IOException {
            if (_writer != null)
                _writer.flush();
            if (_out != null)
                _out.flush();
            super.flushBuffer();
        }

        /* ------------------------------------------------------------ */
        public void close() throws IOException {
            if (_writer != null)
                _writer.close();
            if (_out != null)
                _out.close();
        }

        /* ------------------------------------------------------------ */
        public void setLocale(Locale locale) {
            if (!_include)
                super.setLocale(locale);
        }

        /* ------------------------------------------------------------ */
        public void sendError(int status, String message) throws IOException {
            if (_request._filterType != Dispatcher.__ERROR && !_include)
                super.sendError(status, message);
        }

        /* ------------------------------------------------------------ */
        public void sendError(int status) throws IOException {
            if (_request._filterType != Dispatcher.__ERROR && !_include)
                super.sendError(status);
        }

        /* ------------------------------------------------------------ */
        public void sendRedirect(String url) throws IOException {
            if (!_include) {
                if (!url.startsWith("http:/") && !url.startsWith("https:/")) {
                    StringBuffer buf = _request.getRootURL();

                    if (url.startsWith("/"))
                        buf.append(URI.canonicalPath(url));
                    else
                        buf.append(URI.canonicalPath(URI.addPaths(URI.parentPath(_request.getRequestURI()), url)));
                    url = buf.toString();
                }

                super.sendRedirect(url);
            }
        }

        /* ------------------------------------------------------------ */
        public void setDateHeader(String name, long value) {
            if (!_include)
                super.setDateHeader(name, value);
        }

        /* ------------------------------------------------------------ */
        public void setHeader(String name, String value) {
            if (!_include)
                super.setHeader(name, value);
        }

        /* ------------------------------------------------------------ */
        public void setIntHeader(String name, int value) {
            if (!_include)
                super.setIntHeader(name, value);
        }

        /* ------------------------------------------------------------ */
        public void addHeader(String name, String value) {
            if (!_include)
                super.addHeader(name, value);
        }

        /* ------------------------------------------------------------ */
        public void addDateHeader(String name, long value) {
            if (!_include)
                super.addDateHeader(name, value);
        }

        /* ------------------------------------------------------------ */
        public void addIntHeader(String name, int value) {
            if (!_include)
                super.addIntHeader(name, value);
        }

        /* ------------------------------------------------------------ */
        public void setStatus(int status) {
            if (_request._filterType != Dispatcher.__ERROR && !_include)
                super.setStatus(status);
        }

        /* ------------------------------------------------------------ */
        /**
        * The default behavior of this method is to call setStatus(int sc, String sm)
        * on the wrapped response object.
        * 
        * @deprecated As of version 2.1 of the Servlet spec.
        * To set a status code 
        * use <code>setStatus(int)</code>, to send an error with a description
        * use <code>sendError(int, String)</code>.
        * 
        * @param status the status code
        * @param message the status message
        */
        public void setStatus(int status, String message) {
            if (_request._filterType != Dispatcher.__ERROR && !_include)
                super.setStatus(status, message);
        }

        /* ------------------------------------------------------------ */
        public void setContentLength(int len) {
            if (!_include)
                super.setContentLength(len);
        }

        /* ------------------------------------------------------------ */
        public void setContentType(String contentType) {
            if (!_include)
                super.setContentType(contentType);
        }

        /* ------------------------------------------------------------ */
        public void addCookie(Cookie cookie) {
            if (!_include)
                super.addCookie(cookie);
        }
    }

    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    private class DontCloseWriter extends PrintWriter {
        DontCloseWriter(PrintWriter writer) {
            super(writer);
        }

        public void close() {
        }
    }

    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    private class DontCloseServletOut extends ServletOut {
        DontCloseServletOut(ServletOutputStream output) {
            super(output);
        }

        public void close() throws IOException {
        }
    }
};