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.server.handler;
2003928aee4356845252ac6b662d5c72c29903813eJake Slack
2103928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.IOException;
2203928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.OutputStream;
2303928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.net.URL;
2403928aee4356845252ac6b662d5c72c29903813eJake Slack
2503928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.ServletException;
2603928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.http.HttpServletRequest;
2703928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.http.HttpServletResponse;
2803928aee4356845252ac6b662d5c72c29903813eJake Slack
2903928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.http.HttpHeaders;
3003928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.http.HttpMethods;
3103928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.http.MimeTypes;
3203928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.server.Handler;
3303928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.server.Request;
3403928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.server.Server;
3503928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.ByteArrayISO8859Writer;
3603928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.IO;
3703928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Log;
3803928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Logger;
3903928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.resource.Resource;
4003928aee4356845252ac6b662d5c72c29903813eJake Slack
4103928aee4356845252ac6b662d5c72c29903813eJake Slack
4203928aee4356845252ac6b662d5c72c29903813eJake Slack/* ------------------------------------------------------------ */
4303928aee4356845252ac6b662d5c72c29903813eJake Slack/** Default Handler.
4403928aee4356845252ac6b662d5c72c29903813eJake Slack *
4503928aee4356845252ac6b662d5c72c29903813eJake Slack * This handle will deal with unhandled requests in the server.
4603928aee4356845252ac6b662d5c72c29903813eJake Slack * For requests for favicon.ico, the Jetty icon is served.
4703928aee4356845252ac6b662d5c72c29903813eJake Slack * For reqests to '/' a 404 with a list of known contexts is served.
4803928aee4356845252ac6b662d5c72c29903813eJake Slack * For all other requests a normal 404 is served.
4903928aee4356845252ac6b662d5c72c29903813eJake Slack * TODO Implement OPTIONS and TRACE methods for the server.
5003928aee4356845252ac6b662d5c72c29903813eJake Slack *
5103928aee4356845252ac6b662d5c72c29903813eJake Slack *
5203928aee4356845252ac6b662d5c72c29903813eJake Slack * @org.apache.xbean.XBean
5303928aee4356845252ac6b662d5c72c29903813eJake Slack */
5403928aee4356845252ac6b662d5c72c29903813eJake Slackpublic class DefaultHandler extends AbstractHandler
5503928aee4356845252ac6b662d5c72c29903813eJake Slack{
5603928aee4356845252ac6b662d5c72c29903813eJake Slack    private static final Logger LOG = Log.getLogger(DefaultHandler.class);
5703928aee4356845252ac6b662d5c72c29903813eJake Slack
5803928aee4356845252ac6b662d5c72c29903813eJake Slack    final long _faviconModified=(System.currentTimeMillis()/1000)*1000L;
5903928aee4356845252ac6b662d5c72c29903813eJake Slack    byte[] _favicon;
6003928aee4356845252ac6b662d5c72c29903813eJake Slack    boolean _serveIcon=true;
6103928aee4356845252ac6b662d5c72c29903813eJake Slack    boolean _showContexts=true;
6203928aee4356845252ac6b662d5c72c29903813eJake Slack
6303928aee4356845252ac6b662d5c72c29903813eJake Slack    public DefaultHandler()
6403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
6503928aee4356845252ac6b662d5c72c29903813eJake Slack        try
6603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
6703928aee4356845252ac6b662d5c72c29903813eJake Slack            URL fav = this.getClass().getClassLoader().getResource("org/eclipse/jetty/favicon.ico");
6803928aee4356845252ac6b662d5c72c29903813eJake Slack            if (fav!=null)
6903928aee4356845252ac6b662d5c72c29903813eJake Slack            {
7003928aee4356845252ac6b662d5c72c29903813eJake Slack                Resource r = Resource.newResource(fav);
7103928aee4356845252ac6b662d5c72c29903813eJake Slack                _favicon=IO.readBytes(r.getInputStream());
7203928aee4356845252ac6b662d5c72c29903813eJake Slack            }
7303928aee4356845252ac6b662d5c72c29903813eJake Slack        }
7403928aee4356845252ac6b662d5c72c29903813eJake Slack        catch(Exception e)
7503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
7603928aee4356845252ac6b662d5c72c29903813eJake Slack            LOG.warn(e);
7703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
7803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
7903928aee4356845252ac6b662d5c72c29903813eJake Slack
8003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
8103928aee4356845252ac6b662d5c72c29903813eJake Slack    /*
8203928aee4356845252ac6b662d5c72c29903813eJake Slack     * @see org.eclipse.jetty.server.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
8303928aee4356845252ac6b662d5c72c29903813eJake Slack     */
8403928aee4356845252ac6b662d5c72c29903813eJake Slack    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
8503928aee4356845252ac6b662d5c72c29903813eJake Slack    {
8603928aee4356845252ac6b662d5c72c29903813eJake Slack        if (response.isCommitted() || baseRequest.isHandled())
8703928aee4356845252ac6b662d5c72c29903813eJake Slack            return;
8803928aee4356845252ac6b662d5c72c29903813eJake Slack
8903928aee4356845252ac6b662d5c72c29903813eJake Slack        baseRequest.setHandled(true);
9003928aee4356845252ac6b662d5c72c29903813eJake Slack
9103928aee4356845252ac6b662d5c72c29903813eJake Slack        String method=request.getMethod();
9203928aee4356845252ac6b662d5c72c29903813eJake Slack
9303928aee4356845252ac6b662d5c72c29903813eJake Slack        // little cheat for common request
9403928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_serveIcon && _favicon!=null && method.equals(HttpMethods.GET) && request.getRequestURI().equals("/favicon.ico"))
9503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
9603928aee4356845252ac6b662d5c72c29903813eJake Slack            if (request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE)==_faviconModified)
9703928aee4356845252ac6b662d5c72c29903813eJake Slack                response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
9803928aee4356845252ac6b662d5c72c29903813eJake Slack            else
9903928aee4356845252ac6b662d5c72c29903813eJake Slack            {
10003928aee4356845252ac6b662d5c72c29903813eJake Slack                response.setStatus(HttpServletResponse.SC_OK);
10103928aee4356845252ac6b662d5c72c29903813eJake Slack                response.setContentType("image/x-icon");
10203928aee4356845252ac6b662d5c72c29903813eJake Slack                response.setContentLength(_favicon.length);
10303928aee4356845252ac6b662d5c72c29903813eJake Slack                response.setDateHeader(HttpHeaders.LAST_MODIFIED, _faviconModified);
10403928aee4356845252ac6b662d5c72c29903813eJake Slack                response.setHeader(HttpHeaders.CACHE_CONTROL,"max-age=360000,public");
10503928aee4356845252ac6b662d5c72c29903813eJake Slack                response.getOutputStream().write(_favicon);
10603928aee4356845252ac6b662d5c72c29903813eJake Slack            }
10703928aee4356845252ac6b662d5c72c29903813eJake Slack            return;
10803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
10903928aee4356845252ac6b662d5c72c29903813eJake Slack
11003928aee4356845252ac6b662d5c72c29903813eJake Slack
11103928aee4356845252ac6b662d5c72c29903813eJake Slack        if (!method.equals(HttpMethods.GET) || !request.getRequestURI().equals("/"))
11203928aee4356845252ac6b662d5c72c29903813eJake Slack        {
11303928aee4356845252ac6b662d5c72c29903813eJake Slack            response.sendError(HttpServletResponse.SC_NOT_FOUND);
11403928aee4356845252ac6b662d5c72c29903813eJake Slack            return;
11503928aee4356845252ac6b662d5c72c29903813eJake Slack        }
11603928aee4356845252ac6b662d5c72c29903813eJake Slack
11703928aee4356845252ac6b662d5c72c29903813eJake Slack        response.setStatus(HttpServletResponse.SC_NOT_FOUND);
11803928aee4356845252ac6b662d5c72c29903813eJake Slack        response.setContentType(MimeTypes.TEXT_HTML);
11903928aee4356845252ac6b662d5c72c29903813eJake Slack
12003928aee4356845252ac6b662d5c72c29903813eJake Slack        ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(1500);
12103928aee4356845252ac6b662d5c72c29903813eJake Slack
12203928aee4356845252ac6b662d5c72c29903813eJake Slack        writer.write("<HTML>\n<HEAD>\n<TITLE>Error 404 - Not Found");
12303928aee4356845252ac6b662d5c72c29903813eJake Slack        writer.write("</TITLE>\n<BODY>\n<H2>Error 404 - Not Found.</H2>\n");
12403928aee4356845252ac6b662d5c72c29903813eJake Slack        writer.write("No context on this server matched or handled this request.<BR>");
12503928aee4356845252ac6b662d5c72c29903813eJake Slack
12603928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_showContexts)
12703928aee4356845252ac6b662d5c72c29903813eJake Slack        {
12803928aee4356845252ac6b662d5c72c29903813eJake Slack            writer.write("Contexts known to this server are: <ul>");
12903928aee4356845252ac6b662d5c72c29903813eJake Slack
13003928aee4356845252ac6b662d5c72c29903813eJake Slack            Server server = getServer();
13103928aee4356845252ac6b662d5c72c29903813eJake Slack            Handler[] handlers = server==null?null:server.getChildHandlersByClass(ContextHandler.class);
13203928aee4356845252ac6b662d5c72c29903813eJake Slack
13303928aee4356845252ac6b662d5c72c29903813eJake Slack            for (int i=0;handlers!=null && i<handlers.length;i++)
13403928aee4356845252ac6b662d5c72c29903813eJake Slack            {
13503928aee4356845252ac6b662d5c72c29903813eJake Slack                ContextHandler context = (ContextHandler)handlers[i];
13603928aee4356845252ac6b662d5c72c29903813eJake Slack                if (context.isRunning())
13703928aee4356845252ac6b662d5c72c29903813eJake Slack                {
13803928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write("<li><a href=\"");
13903928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
14003928aee4356845252ac6b662d5c72c29903813eJake Slack                        writer.write("http://"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
14103928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write(context.getContextPath());
14203928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (context.getContextPath().length()>1 && context.getContextPath().endsWith("/"))
14303928aee4356845252ac6b662d5c72c29903813eJake Slack                        writer.write("/");
14403928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write("\">");
14503928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write(context.getContextPath());
14603928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
14703928aee4356845252ac6b662d5c72c29903813eJake Slack                        writer.write("&nbsp;@&nbsp;"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
14803928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write("&nbsp;--->&nbsp;");
14903928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write(context.toString());
15003928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write("</a></li>\n");
15103928aee4356845252ac6b662d5c72c29903813eJake Slack                }
15203928aee4356845252ac6b662d5c72c29903813eJake Slack                else
15303928aee4356845252ac6b662d5c72c29903813eJake Slack                {
15403928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write("<li>");
15503928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write(context.getContextPath());
15603928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
15703928aee4356845252ac6b662d5c72c29903813eJake Slack                        writer.write("&nbsp;@&nbsp;"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
15803928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write("&nbsp;--->&nbsp;");
15903928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write(context.toString());
16003928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (context.isFailed())
16103928aee4356845252ac6b662d5c72c29903813eJake Slack                        writer.write(" [failed]");
16203928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (context.isStopped())
16303928aee4356845252ac6b662d5c72c29903813eJake Slack                        writer.write(" [stopped]");
16403928aee4356845252ac6b662d5c72c29903813eJake Slack                    writer.write("</li>\n");
16503928aee4356845252ac6b662d5c72c29903813eJake Slack                }
16603928aee4356845252ac6b662d5c72c29903813eJake Slack            }
16703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
16803928aee4356845252ac6b662d5c72c29903813eJake Slack
16903928aee4356845252ac6b662d5c72c29903813eJake Slack        for (int i=0;i<10;i++)
17003928aee4356845252ac6b662d5c72c29903813eJake Slack            writer.write("\n<!-- Padding for IE                  -->");
17103928aee4356845252ac6b662d5c72c29903813eJake Slack
17203928aee4356845252ac6b662d5c72c29903813eJake Slack        writer.write("\n</BODY>\n</HTML>\n");
17303928aee4356845252ac6b662d5c72c29903813eJake Slack        writer.flush();
17403928aee4356845252ac6b662d5c72c29903813eJake Slack        response.setContentLength(writer.size());
17503928aee4356845252ac6b662d5c72c29903813eJake Slack        OutputStream out=response.getOutputStream();
17603928aee4356845252ac6b662d5c72c29903813eJake Slack        writer.writeTo(out);
17703928aee4356845252ac6b662d5c72c29903813eJake Slack        out.close();
17803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
17903928aee4356845252ac6b662d5c72c29903813eJake Slack
18003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
18103928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
18203928aee4356845252ac6b662d5c72c29903813eJake Slack     * @return Returns true if the handle can server the jetty favicon.ico
18303928aee4356845252ac6b662d5c72c29903813eJake Slack     */
18403928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean getServeIcon()
18503928aee4356845252ac6b662d5c72c29903813eJake Slack    {
18603928aee4356845252ac6b662d5c72c29903813eJake Slack        return _serveIcon;
18703928aee4356845252ac6b662d5c72c29903813eJake Slack    }
18803928aee4356845252ac6b662d5c72c29903813eJake Slack
18903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
19003928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
19103928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param serveIcon true if the handle can server the jetty favicon.ico
19203928aee4356845252ac6b662d5c72c29903813eJake Slack     */
19303928aee4356845252ac6b662d5c72c29903813eJake Slack    public void setServeIcon(boolean serveIcon)
19403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
19503928aee4356845252ac6b662d5c72c29903813eJake Slack        _serveIcon = serveIcon;
19603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
19703928aee4356845252ac6b662d5c72c29903813eJake Slack
19803928aee4356845252ac6b662d5c72c29903813eJake Slack    public boolean getShowContexts()
19903928aee4356845252ac6b662d5c72c29903813eJake Slack    {
20003928aee4356845252ac6b662d5c72c29903813eJake Slack        return _showContexts;
20103928aee4356845252ac6b662d5c72c29903813eJake Slack    }
20203928aee4356845252ac6b662d5c72c29903813eJake Slack
20303928aee4356845252ac6b662d5c72c29903813eJake Slack    public void setShowContexts(boolean show)
20403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
20503928aee4356845252ac6b662d5c72c29903813eJake Slack        _showContexts = show;
20603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
20703928aee4356845252ac6b662d5c72c29903813eJake Slack
20803928aee4356845252ac6b662d5c72c29903813eJake Slack}
209