103928aee4356845252ac6b662d5c72c29903813eJake Slack//
203928aee4356845252ac6b662d5c72c29903813eJake Slack//  ========================================================================
303928aee4356845252ac6b662d5c72c29903813eJake Slack//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
403928aee4356845252ac6b662d5c72c29903813eJake Slack//  ------------------------------------------------------------------------
503928aee4356845252ac6b662d5c72c29903813eJake Slack//  All rights reserved. This program and the accompanying materials
603928aee4356845252ac6b662d5c72c29903813eJake Slack//  are made available under the terms of the Eclipse Public License v1.0
703928aee4356845252ac6b662d5c72c29903813eJake Slack//  and Apache License v2.0 which accompanies this distribution.
803928aee4356845252ac6b662d5c72c29903813eJake Slack//
903928aee4356845252ac6b662d5c72c29903813eJake Slack//      The Eclipse Public License is available at
1003928aee4356845252ac6b662d5c72c29903813eJake Slack//      http://www.eclipse.org/legal/epl-v10.html
1103928aee4356845252ac6b662d5c72c29903813eJake Slack//
1203928aee4356845252ac6b662d5c72c29903813eJake Slack//      The Apache License v2.0 is available at
1303928aee4356845252ac6b662d5c72c29903813eJake Slack//      http://www.opensource.org/licenses/apache2.0.php
1403928aee4356845252ac6b662d5c72c29903813eJake Slack//
1503928aee4356845252ac6b662d5c72c29903813eJake Slack//  You may elect to redistribute this code under either of these licenses.
1603928aee4356845252ac6b662d5c72c29903813eJake Slack//  ========================================================================
1703928aee4356845252ac6b662d5c72c29903813eJake Slack//
1803928aee4356845252ac6b662d5c72c29903813eJake Slack
1903928aee4356845252ac6b662d5c72c29903813eJake Slackpackage org.eclipse.jetty.servlet;
2003928aee4356845252ac6b662d5c72c29903813eJake Slack
2103928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.ArrayList;
2203928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.HashMap;
2303928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.List;
2403928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.Map;
2503928aee4356845252ac6b662d5c72c29903813eJake Slack
2603928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.RequestDispatcher;
2703928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.ServletContext;
2803928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.ServletException;
2903928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.http.HttpServletRequest;
3003928aee4356845252ac6b662d5c72c29903813eJake Slack
3103928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.server.handler.ContextHandler;
3203928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.server.handler.ErrorHandler;
3303928aee4356845252ac6b662d5c72c29903813eJake Slack
3403928aee4356845252ac6b662d5c72c29903813eJake Slack/* ------------------------------------------------------------ */
3503928aee4356845252ac6b662d5c72c29903813eJake Slack/** Error Page Error Handler
3603928aee4356845252ac6b662d5c72c29903813eJake Slack *
3703928aee4356845252ac6b662d5c72c29903813eJake Slack * An ErrorHandler that maps exceptions and status codes to URIs for dispatch using
3803928aee4356845252ac6b662d5c72c29903813eJake Slack * the internal ERROR style of dispatch.
3903928aee4356845252ac6b662d5c72c29903813eJake Slack *
4003928aee4356845252ac6b662d5c72c29903813eJake Slack */
4103928aee4356845252ac6b662d5c72c29903813eJake Slackpublic class ErrorPageErrorHandler extends ErrorHandler implements ErrorHandler.ErrorPageMapper
4203928aee4356845252ac6b662d5c72c29903813eJake Slack{
4303928aee4356845252ac6b662d5c72c29903813eJake Slack    public final static String GLOBAL_ERROR_PAGE = "org.eclipse.jetty.server.error_page.global";
4403928aee4356845252ac6b662d5c72c29903813eJake Slack
4503928aee4356845252ac6b662d5c72c29903813eJake Slack    protected ServletContext _servletContext;
4603928aee4356845252ac6b662d5c72c29903813eJake Slack    private final Map<String,String> _errorPages= new HashMap<String,String>(); // code or exception to URL
4703928aee4356845252ac6b662d5c72c29903813eJake Slack    private final List<ErrorCodeRange> _errorPageList=new ArrayList<ErrorCodeRange>(); // list of ErrorCode by range
4803928aee4356845252ac6b662d5c72c29903813eJake Slack
4903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
5003928aee4356845252ac6b662d5c72c29903813eJake Slack    public ErrorPageErrorHandler()
5103928aee4356845252ac6b662d5c72c29903813eJake Slack    {}
5203928aee4356845252ac6b662d5c72c29903813eJake Slack
5303928aee4356845252ac6b662d5c72c29903813eJake Slack    @Override
5403928aee4356845252ac6b662d5c72c29903813eJake Slack    public String getErrorPage(HttpServletRequest request)
5503928aee4356845252ac6b662d5c72c29903813eJake Slack    {
5603928aee4356845252ac6b662d5c72c29903813eJake Slack        String error_page= null;
5703928aee4356845252ac6b662d5c72c29903813eJake Slack        Class<?> exClass= (Class<?>)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
5803928aee4356845252ac6b662d5c72c29903813eJake Slack
5903928aee4356845252ac6b662d5c72c29903813eJake Slack        if (ServletException.class.equals(exClass))
6003928aee4356845252ac6b662d5c72c29903813eJake Slack        {
6103928aee4356845252ac6b662d5c72c29903813eJake Slack            error_page= (String)_errorPages.get(exClass.getName());
6203928aee4356845252ac6b662d5c72c29903813eJake Slack            if (error_page == null)
6303928aee4356845252ac6b662d5c72c29903813eJake Slack            {
6403928aee4356845252ac6b662d5c72c29903813eJake Slack                Throwable th= (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
6503928aee4356845252ac6b662d5c72c29903813eJake Slack                while (th instanceof ServletException)
6603928aee4356845252ac6b662d5c72c29903813eJake Slack                    th= ((ServletException)th).getRootCause();
6703928aee4356845252ac6b662d5c72c29903813eJake Slack                if (th != null)
6803928aee4356845252ac6b662d5c72c29903813eJake Slack                    exClass= th.getClass();
6903928aee4356845252ac6b662d5c72c29903813eJake Slack            }
7003928aee4356845252ac6b662d5c72c29903813eJake Slack        }
7103928aee4356845252ac6b662d5c72c29903813eJake Slack
7203928aee4356845252ac6b662d5c72c29903813eJake Slack        while (error_page == null && exClass != null )
7303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
7403928aee4356845252ac6b662d5c72c29903813eJake Slack            error_page= (String)_errorPages.get(exClass.getName());
7503928aee4356845252ac6b662d5c72c29903813eJake Slack            exClass= exClass.getSuperclass();
7603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
7703928aee4356845252ac6b662d5c72c29903813eJake Slack
7803928aee4356845252ac6b662d5c72c29903813eJake Slack        if (error_page == null)
7903928aee4356845252ac6b662d5c72c29903813eJake Slack        {
8003928aee4356845252ac6b662d5c72c29903813eJake Slack            // look for an exact code match
8103928aee4356845252ac6b662d5c72c29903813eJake Slack            Integer code=(Integer)request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
8203928aee4356845252ac6b662d5c72c29903813eJake Slack            if (code!=null)
8303928aee4356845252ac6b662d5c72c29903813eJake Slack            {
8403928aee4356845252ac6b662d5c72c29903813eJake Slack                error_page= (String)_errorPages.get(Integer.toString(code));
8503928aee4356845252ac6b662d5c72c29903813eJake Slack
8603928aee4356845252ac6b662d5c72c29903813eJake Slack                // if still not found
8703928aee4356845252ac6b662d5c72c29903813eJake Slack                if ((error_page == null) && (_errorPageList != null))
8803928aee4356845252ac6b662d5c72c29903813eJake Slack                {
8903928aee4356845252ac6b662d5c72c29903813eJake Slack                    // look for an error code range match.
9003928aee4356845252ac6b662d5c72c29903813eJake Slack                    for (int i = 0; i < _errorPageList.size(); i++)
9103928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
9203928aee4356845252ac6b662d5c72c29903813eJake Slack                        ErrorCodeRange errCode = (ErrorCodeRange) _errorPageList.get(i);
9303928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (errCode.isInRange(code))
9403928aee4356845252ac6b662d5c72c29903813eJake Slack                        {
9503928aee4356845252ac6b662d5c72c29903813eJake Slack                            error_page = errCode.getUri();
9603928aee4356845252ac6b662d5c72c29903813eJake Slack                            break;
9703928aee4356845252ac6b662d5c72c29903813eJake Slack                        }
9803928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
9903928aee4356845252ac6b662d5c72c29903813eJake Slack                }
10003928aee4356845252ac6b662d5c72c29903813eJake Slack            }
10103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
10203928aee4356845252ac6b662d5c72c29903813eJake Slack
10303928aee4356845252ac6b662d5c72c29903813eJake Slack        //try new servlet 3.0 global error page
10403928aee4356845252ac6b662d5c72c29903813eJake Slack        if (error_page == null)
10503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
10603928aee4356845252ac6b662d5c72c29903813eJake Slack            error_page = _errorPages.get(GLOBAL_ERROR_PAGE);
10703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
10803928aee4356845252ac6b662d5c72c29903813eJake Slack
10903928aee4356845252ac6b662d5c72c29903813eJake Slack        return error_page;
11003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
11103928aee4356845252ac6b662d5c72c29903813eJake Slack
11203928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
11303928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
11403928aee4356845252ac6b662d5c72c29903813eJake Slack     * @return Returns the errorPages.
11503928aee4356845252ac6b662d5c72c29903813eJake Slack     */
11603928aee4356845252ac6b662d5c72c29903813eJake Slack    public Map<String,String> getErrorPages()
11703928aee4356845252ac6b662d5c72c29903813eJake Slack    {
11803928aee4356845252ac6b662d5c72c29903813eJake Slack        return _errorPages;
11903928aee4356845252ac6b662d5c72c29903813eJake Slack    }
12003928aee4356845252ac6b662d5c72c29903813eJake Slack
12103928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
12203928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
12303928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param errorPages The errorPages to set. A map of Exception class name  or error code as a string to URI string
12403928aee4356845252ac6b662d5c72c29903813eJake Slack     */
12503928aee4356845252ac6b662d5c72c29903813eJake Slack    public void setErrorPages(Map<String,String> errorPages)
12603928aee4356845252ac6b662d5c72c29903813eJake Slack    {
12703928aee4356845252ac6b662d5c72c29903813eJake Slack        _errorPages.clear();
12803928aee4356845252ac6b662d5c72c29903813eJake Slack        if (errorPages!=null)
12903928aee4356845252ac6b662d5c72c29903813eJake Slack            _errorPages.putAll(errorPages);
13003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
13103928aee4356845252ac6b662d5c72c29903813eJake Slack
13203928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
13303928aee4356845252ac6b662d5c72c29903813eJake Slack    /** Add Error Page mapping for an exception class
13403928aee4356845252ac6b662d5c72c29903813eJake Slack     * This method is called as a result of an exception-type element in a web.xml file
13503928aee4356845252ac6b662d5c72c29903813eJake Slack     * or may be called directly
13603928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param exception The exception
13703928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param uri The URI of the error page.
13803928aee4356845252ac6b662d5c72c29903813eJake Slack     */
13903928aee4356845252ac6b662d5c72c29903813eJake Slack    public void addErrorPage(Class<? extends Throwable> exception,String uri)
14003928aee4356845252ac6b662d5c72c29903813eJake Slack    {
14103928aee4356845252ac6b662d5c72c29903813eJake Slack        _errorPages.put(exception.getName(),uri);
14203928aee4356845252ac6b662d5c72c29903813eJake Slack    }
14303928aee4356845252ac6b662d5c72c29903813eJake Slack
14403928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
14503928aee4356845252ac6b662d5c72c29903813eJake Slack    /** Add Error Page mapping for an exception class
14603928aee4356845252ac6b662d5c72c29903813eJake Slack     * This method is called as a result of an exception-type element in a web.xml file
14703928aee4356845252ac6b662d5c72c29903813eJake Slack     * or may be called directly
14803928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param exceptionClassName The exception
14903928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param uri The URI of the error page.
15003928aee4356845252ac6b662d5c72c29903813eJake Slack     */
15103928aee4356845252ac6b662d5c72c29903813eJake Slack    public void addErrorPage(String exceptionClassName,String uri)
15203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
15303928aee4356845252ac6b662d5c72c29903813eJake Slack        _errorPages.put(exceptionClassName,uri);
15403928aee4356845252ac6b662d5c72c29903813eJake Slack    }
15503928aee4356845252ac6b662d5c72c29903813eJake Slack
15603928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
15703928aee4356845252ac6b662d5c72c29903813eJake Slack    /** Add Error Page mapping for a status code.
15803928aee4356845252ac6b662d5c72c29903813eJake Slack     * This method is called as a result of an error-code element in a web.xml file
15903928aee4356845252ac6b662d5c72c29903813eJake Slack     * or may be called directly
16003928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param code The HTTP status code to match
16103928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param uri The URI of the error page.
16203928aee4356845252ac6b662d5c72c29903813eJake Slack     */
16303928aee4356845252ac6b662d5c72c29903813eJake Slack    public void addErrorPage(int code,String uri)
16403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
16503928aee4356845252ac6b662d5c72c29903813eJake Slack        _errorPages.put(Integer.toString(code),uri);
16603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
16703928aee4356845252ac6b662d5c72c29903813eJake Slack
16803928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
16903928aee4356845252ac6b662d5c72c29903813eJake Slack    /** Add Error Page mapping for a status code range.
17003928aee4356845252ac6b662d5c72c29903813eJake Slack     * This method is not available from web.xml and must be called
17103928aee4356845252ac6b662d5c72c29903813eJake Slack     * directly.
17203928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param from The lowest matching status code
17303928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param to The highest matching status code
17403928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param uri The URI of the error page.
17503928aee4356845252ac6b662d5c72c29903813eJake Slack     */
17603928aee4356845252ac6b662d5c72c29903813eJake Slack    public void addErrorPage(int from, int to, String uri)
17703928aee4356845252ac6b662d5c72c29903813eJake Slack    {
17803928aee4356845252ac6b662d5c72c29903813eJake Slack        _errorPageList.add(new ErrorCodeRange(from, to, uri));
17903928aee4356845252ac6b662d5c72c29903813eJake Slack    }
18003928aee4356845252ac6b662d5c72c29903813eJake Slack
18103928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
18203928aee4356845252ac6b662d5c72c29903813eJake Slack    @Override
18303928aee4356845252ac6b662d5c72c29903813eJake Slack    protected void doStart() throws Exception
18403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
18503928aee4356845252ac6b662d5c72c29903813eJake Slack        super.doStart();
18603928aee4356845252ac6b662d5c72c29903813eJake Slack        _servletContext=ContextHandler.getCurrentContext();
18703928aee4356845252ac6b662d5c72c29903813eJake Slack    }
18803928aee4356845252ac6b662d5c72c29903813eJake Slack
18903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
19003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
19103928aee4356845252ac6b662d5c72c29903813eJake Slack    private class ErrorCodeRange
19203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
19303928aee4356845252ac6b662d5c72c29903813eJake Slack        private int _from;
19403928aee4356845252ac6b662d5c72c29903813eJake Slack        private int _to;
19503928aee4356845252ac6b662d5c72c29903813eJake Slack        private String _uri;
19603928aee4356845252ac6b662d5c72c29903813eJake Slack
19703928aee4356845252ac6b662d5c72c29903813eJake Slack        ErrorCodeRange(int from, int to, String uri)
19803928aee4356845252ac6b662d5c72c29903813eJake Slack            throws IllegalArgumentException
19903928aee4356845252ac6b662d5c72c29903813eJake Slack        {
20003928aee4356845252ac6b662d5c72c29903813eJake Slack            if (from > to)
20103928aee4356845252ac6b662d5c72c29903813eJake Slack                throw new IllegalArgumentException("from>to");
20203928aee4356845252ac6b662d5c72c29903813eJake Slack
20303928aee4356845252ac6b662d5c72c29903813eJake Slack            _from = from;
20403928aee4356845252ac6b662d5c72c29903813eJake Slack            _to = to;
20503928aee4356845252ac6b662d5c72c29903813eJake Slack            _uri = uri;
20603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
20703928aee4356845252ac6b662d5c72c29903813eJake Slack
20803928aee4356845252ac6b662d5c72c29903813eJake Slack        boolean isInRange(int value)
20903928aee4356845252ac6b662d5c72c29903813eJake Slack        {
21003928aee4356845252ac6b662d5c72c29903813eJake Slack            if ((value >= _from) && (value <= _to))
21103928aee4356845252ac6b662d5c72c29903813eJake Slack            {
21203928aee4356845252ac6b662d5c72c29903813eJake Slack                return true;
21303928aee4356845252ac6b662d5c72c29903813eJake Slack            }
21403928aee4356845252ac6b662d5c72c29903813eJake Slack
21503928aee4356845252ac6b662d5c72c29903813eJake Slack            return false;
21603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
21703928aee4356845252ac6b662d5c72c29903813eJake Slack
21803928aee4356845252ac6b662d5c72c29903813eJake Slack        String getUri()
21903928aee4356845252ac6b662d5c72c29903813eJake Slack        {
22003928aee4356845252ac6b662d5c72c29903813eJake Slack            return _uri;
22103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
22203928aee4356845252ac6b662d5c72c29903813eJake Slack
22303928aee4356845252ac6b662d5c72c29903813eJake Slack        @Override
22403928aee4356845252ac6b662d5c72c29903813eJake Slack        public String toString()
22503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
22603928aee4356845252ac6b662d5c72c29903813eJake Slack            return "from: " + _from + ",to: " + _to + ",uri: " + _uri;
22703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
22803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
22903928aee4356845252ac6b662d5c72c29903813eJake Slack}
230