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.servlets;
2003928aee4356845252ac6b662d5c72c29903813eJake Slack
2103928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.File;
2203928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.FileOutputStream;
2303928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.IOException;
2403928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.InputStream;
2503928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.OutputStream;
2603928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.net.URI;
2703928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.net.URISyntaxException;
2803928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.Arrays;
2903928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.HashSet;
3003928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.Set;
3103928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.concurrent.ConcurrentHashMap;
3203928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.concurrent.ConcurrentMap;
3303928aee4356845252ac6b662d5c72c29903813eJake Slack
3403928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.Filter;
3503928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.FilterChain;
3603928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.FilterConfig;
3703928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.ServletContext;
3803928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.ServletException;
3903928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.ServletRequest;
4003928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.ServletResponse;
4103928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.UnavailableException;
4203928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.http.HttpServletRequest;
4303928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.http.HttpServletResponse;
4403928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.http.HttpServletResponseWrapper;
4503928aee4356845252ac6b662d5c72c29903813eJake Slack
4603928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.IO;
4703928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.URIUtil;
4803928aee4356845252ac6b662d5c72c29903813eJake Slack
4903928aee4356845252ac6b662d5c72c29903813eJake Slack/**
5003928aee4356845252ac6b662d5c72c29903813eJake Slack * PutFilter
5103928aee4356845252ac6b662d5c72c29903813eJake Slack *
5203928aee4356845252ac6b662d5c72c29903813eJake Slack * A Filter that handles PUT, DELETE and MOVE methods.
5303928aee4356845252ac6b662d5c72c29903813eJake Slack * Files are hidden during PUT operations, so that 404's result.
5403928aee4356845252ac6b662d5c72c29903813eJake Slack *
5503928aee4356845252ac6b662d5c72c29903813eJake Slack * The following init parameters pay be used:<ul>
5603928aee4356845252ac6b662d5c72c29903813eJake Slack * <li><b>baseURI</b> - The file URI of the document root for put content.
5703928aee4356845252ac6b662d5c72c29903813eJake Slack * <li><b>delAllowed</b> - boolean, if true DELETE and MOVE methods are supported.
5803928aee4356845252ac6b662d5c72c29903813eJake Slack * <li><b>putAtomic</b> - boolean, if true PUT files are written to a temp location and moved into place.
5903928aee4356845252ac6b662d5c72c29903813eJake Slack * </ul>
6003928aee4356845252ac6b662d5c72c29903813eJake Slack *
6103928aee4356845252ac6b662d5c72c29903813eJake Slack */
6203928aee4356845252ac6b662d5c72c29903813eJake Slackpublic class PutFilter implements Filter
6303928aee4356845252ac6b662d5c72c29903813eJake Slack{
6403928aee4356845252ac6b662d5c72c29903813eJake Slack    public final static String __PUT="PUT";
6503928aee4356845252ac6b662d5c72c29903813eJake Slack    public final static String __DELETE="DELETE";
6603928aee4356845252ac6b662d5c72c29903813eJake Slack    public final static String __MOVE="MOVE";
6703928aee4356845252ac6b662d5c72c29903813eJake Slack    public final static String __OPTIONS="OPTIONS";
6803928aee4356845252ac6b662d5c72c29903813eJake Slack
6903928aee4356845252ac6b662d5c72c29903813eJake Slack    Set<String> _operations = new HashSet<String>();
7003928aee4356845252ac6b662d5c72c29903813eJake Slack    private ConcurrentMap<String,String> _hidden = new ConcurrentHashMap<String, String>();
7103928aee4356845252ac6b662d5c72c29903813eJake Slack
7203928aee4356845252ac6b662d5c72c29903813eJake Slack    private ServletContext _context;
7303928aee4356845252ac6b662d5c72c29903813eJake Slack    private String _baseURI;
7403928aee4356845252ac6b662d5c72c29903813eJake Slack    private boolean _delAllowed;
7503928aee4356845252ac6b662d5c72c29903813eJake Slack    private boolean _putAtomic;
7603928aee4356845252ac6b662d5c72c29903813eJake Slack    private File _tmpdir;
7703928aee4356845252ac6b662d5c72c29903813eJake Slack
7803928aee4356845252ac6b662d5c72c29903813eJake Slack
7903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
8003928aee4356845252ac6b662d5c72c29903813eJake Slack    public void init(FilterConfig config) throws ServletException
8103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
8203928aee4356845252ac6b662d5c72c29903813eJake Slack        _context=config.getServletContext();
8303928aee4356845252ac6b662d5c72c29903813eJake Slack
8403928aee4356845252ac6b662d5c72c29903813eJake Slack        _tmpdir=(File)_context.getAttribute("javax.servlet.context.tempdir");
8503928aee4356845252ac6b662d5c72c29903813eJake Slack
8603928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_context.getRealPath("/")==null)
8703928aee4356845252ac6b662d5c72c29903813eJake Slack           throw new UnavailableException("Packed war");
8803928aee4356845252ac6b662d5c72c29903813eJake Slack
8903928aee4356845252ac6b662d5c72c29903813eJake Slack        String b = config.getInitParameter("baseURI");
9003928aee4356845252ac6b662d5c72c29903813eJake Slack        if (b != null)
9103928aee4356845252ac6b662d5c72c29903813eJake Slack        {
9203928aee4356845252ac6b662d5c72c29903813eJake Slack            _baseURI=b;
9303928aee4356845252ac6b662d5c72c29903813eJake Slack        }
9403928aee4356845252ac6b662d5c72c29903813eJake Slack        else
9503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
9603928aee4356845252ac6b662d5c72c29903813eJake Slack            File base=new File(_context.getRealPath("/"));
9703928aee4356845252ac6b662d5c72c29903813eJake Slack            _baseURI=base.toURI().toString();
9803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
9903928aee4356845252ac6b662d5c72c29903813eJake Slack
10003928aee4356845252ac6b662d5c72c29903813eJake Slack        _delAllowed = getInitBoolean(config,"delAllowed");
10103928aee4356845252ac6b662d5c72c29903813eJake Slack        _putAtomic = getInitBoolean(config,"putAtomic");
10203928aee4356845252ac6b662d5c72c29903813eJake Slack
10303928aee4356845252ac6b662d5c72c29903813eJake Slack        _operations.add(__OPTIONS);
10403928aee4356845252ac6b662d5c72c29903813eJake Slack        _operations.add(__PUT);
10503928aee4356845252ac6b662d5c72c29903813eJake Slack        if (_delAllowed)
10603928aee4356845252ac6b662d5c72c29903813eJake Slack        {
10703928aee4356845252ac6b662d5c72c29903813eJake Slack            _operations.add(__DELETE);
10803928aee4356845252ac6b662d5c72c29903813eJake Slack            _operations.add(__MOVE);
10903928aee4356845252ac6b662d5c72c29903813eJake Slack        }
11003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
11103928aee4356845252ac6b662d5c72c29903813eJake Slack
11203928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
11303928aee4356845252ac6b662d5c72c29903813eJake Slack    private boolean getInitBoolean(FilterConfig config,String name)
11403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
11503928aee4356845252ac6b662d5c72c29903813eJake Slack        String value = config.getInitParameter(name);
11603928aee4356845252ac6b662d5c72c29903813eJake Slack        return value != null && value.length() > 0 && (value.startsWith("t") || value.startsWith("T") || value.startsWith("y") || value.startsWith("Y") || value.startsWith("1"));
11703928aee4356845252ac6b662d5c72c29903813eJake Slack    }
11803928aee4356845252ac6b662d5c72c29903813eJake Slack
11903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
12003928aee4356845252ac6b662d5c72c29903813eJake Slack    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
12103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
12203928aee4356845252ac6b662d5c72c29903813eJake Slack        HttpServletRequest request=(HttpServletRequest)req;
12303928aee4356845252ac6b662d5c72c29903813eJake Slack        HttpServletResponse response=(HttpServletResponse)res;
12403928aee4356845252ac6b662d5c72c29903813eJake Slack
12503928aee4356845252ac6b662d5c72c29903813eJake Slack        String servletPath =request.getServletPath();
12603928aee4356845252ac6b662d5c72c29903813eJake Slack        String pathInfo = request.getPathInfo();
12703928aee4356845252ac6b662d5c72c29903813eJake Slack        String pathInContext = URIUtil.addPaths(servletPath, pathInfo);
12803928aee4356845252ac6b662d5c72c29903813eJake Slack
12903928aee4356845252ac6b662d5c72c29903813eJake Slack        String resource = URIUtil.addPaths(_baseURI,pathInContext);
13003928aee4356845252ac6b662d5c72c29903813eJake Slack
13103928aee4356845252ac6b662d5c72c29903813eJake Slack        String method = request.getMethod();
13203928aee4356845252ac6b662d5c72c29903813eJake Slack        boolean op = _operations.contains(method);
13303928aee4356845252ac6b662d5c72c29903813eJake Slack
13403928aee4356845252ac6b662d5c72c29903813eJake Slack        if (op)
13503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
13603928aee4356845252ac6b662d5c72c29903813eJake Slack            File file = null;
13703928aee4356845252ac6b662d5c72c29903813eJake Slack            try
13803928aee4356845252ac6b662d5c72c29903813eJake Slack            {
13903928aee4356845252ac6b662d5c72c29903813eJake Slack                if (method.equals(__OPTIONS))
14003928aee4356845252ac6b662d5c72c29903813eJake Slack                    handleOptions(chain,request, response);
14103928aee4356845252ac6b662d5c72c29903813eJake Slack                else
14203928aee4356845252ac6b662d5c72c29903813eJake Slack                {
14303928aee4356845252ac6b662d5c72c29903813eJake Slack                    file=new File(new URI(resource));
14403928aee4356845252ac6b662d5c72c29903813eJake Slack                    boolean exists = file.exists();
14503928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (exists && !passConditionalHeaders(request, response, file))
14603928aee4356845252ac6b662d5c72c29903813eJake Slack                        return;
14703928aee4356845252ac6b662d5c72c29903813eJake Slack
14803928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (method.equals(__PUT))
14903928aee4356845252ac6b662d5c72c29903813eJake Slack                        handlePut(request, response,pathInContext, file);
15003928aee4356845252ac6b662d5c72c29903813eJake Slack                    else if (method.equals(__DELETE))
15103928aee4356845252ac6b662d5c72c29903813eJake Slack                        handleDelete(request, response, pathInContext, file);
15203928aee4356845252ac6b662d5c72c29903813eJake Slack                    else if (method.equals(__MOVE))
15303928aee4356845252ac6b662d5c72c29903813eJake Slack                        handleMove(request, response, pathInContext, file);
15403928aee4356845252ac6b662d5c72c29903813eJake Slack                    else
15503928aee4356845252ac6b662d5c72c29903813eJake Slack                        throw new IllegalStateException();
15603928aee4356845252ac6b662d5c72c29903813eJake Slack                }
15703928aee4356845252ac6b662d5c72c29903813eJake Slack            }
15803928aee4356845252ac6b662d5c72c29903813eJake Slack            catch(Exception e)
15903928aee4356845252ac6b662d5c72c29903813eJake Slack            {
16003928aee4356845252ac6b662d5c72c29903813eJake Slack                _context.log(e.toString(),e);
16103928aee4356845252ac6b662d5c72c29903813eJake Slack                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
16203928aee4356845252ac6b662d5c72c29903813eJake Slack            }
16303928aee4356845252ac6b662d5c72c29903813eJake Slack        }
16403928aee4356845252ac6b662d5c72c29903813eJake Slack        else
16503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
16603928aee4356845252ac6b662d5c72c29903813eJake Slack            if (isHidden(pathInContext))
16703928aee4356845252ac6b662d5c72c29903813eJake Slack                response.sendError(HttpServletResponse.SC_NOT_FOUND);
16803928aee4356845252ac6b662d5c72c29903813eJake Slack            else
16903928aee4356845252ac6b662d5c72c29903813eJake Slack                chain.doFilter(request,response);
17003928aee4356845252ac6b662d5c72c29903813eJake Slack            return;
17103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
17203928aee4356845252ac6b662d5c72c29903813eJake Slack    }
17303928aee4356845252ac6b662d5c72c29903813eJake Slack
17403928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
17503928aee4356845252ac6b662d5c72c29903813eJake Slack    private boolean isHidden(String pathInContext)
17603928aee4356845252ac6b662d5c72c29903813eJake Slack    {
17703928aee4356845252ac6b662d5c72c29903813eJake Slack        return _hidden.containsKey(pathInContext);
17803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
17903928aee4356845252ac6b662d5c72c29903813eJake Slack
18003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
18103928aee4356845252ac6b662d5c72c29903813eJake Slack    public void destroy()
18203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
18303928aee4356845252ac6b662d5c72c29903813eJake Slack    }
18403928aee4356845252ac6b662d5c72c29903813eJake Slack
18503928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------- */
18603928aee4356845252ac6b662d5c72c29903813eJake Slack    public void handlePut(HttpServletRequest request, HttpServletResponse response, String pathInContext, File file) throws ServletException, IOException
18703928aee4356845252ac6b662d5c72c29903813eJake Slack    {
18803928aee4356845252ac6b662d5c72c29903813eJake Slack        boolean exists = file.exists();
18903928aee4356845252ac6b662d5c72c29903813eJake Slack        if (pathInContext.endsWith("/"))
19003928aee4356845252ac6b662d5c72c29903813eJake Slack        {
19103928aee4356845252ac6b662d5c72c29903813eJake Slack            if (!exists)
19203928aee4356845252ac6b662d5c72c29903813eJake Slack            {
19303928aee4356845252ac6b662d5c72c29903813eJake Slack                if (!file.mkdirs())
19403928aee4356845252ac6b662d5c72c29903813eJake Slack                    response.sendError(HttpServletResponse.SC_FORBIDDEN);
19503928aee4356845252ac6b662d5c72c29903813eJake Slack                else
19603928aee4356845252ac6b662d5c72c29903813eJake Slack                {
19703928aee4356845252ac6b662d5c72c29903813eJake Slack                    response.setStatus(HttpServletResponse.SC_CREATED);
19803928aee4356845252ac6b662d5c72c29903813eJake Slack                    response.flushBuffer();
19903928aee4356845252ac6b662d5c72c29903813eJake Slack                }
20003928aee4356845252ac6b662d5c72c29903813eJake Slack            }
20103928aee4356845252ac6b662d5c72c29903813eJake Slack            else
20203928aee4356845252ac6b662d5c72c29903813eJake Slack            {
20303928aee4356845252ac6b662d5c72c29903813eJake Slack                response.setStatus(HttpServletResponse.SC_OK);
20403928aee4356845252ac6b662d5c72c29903813eJake Slack                response.flushBuffer();
20503928aee4356845252ac6b662d5c72c29903813eJake Slack            }
20603928aee4356845252ac6b662d5c72c29903813eJake Slack        }
20703928aee4356845252ac6b662d5c72c29903813eJake Slack        else
20803928aee4356845252ac6b662d5c72c29903813eJake Slack        {
20903928aee4356845252ac6b662d5c72c29903813eJake Slack            boolean ok=false;
21003928aee4356845252ac6b662d5c72c29903813eJake Slack            try
21103928aee4356845252ac6b662d5c72c29903813eJake Slack            {
21203928aee4356845252ac6b662d5c72c29903813eJake Slack                _hidden.put(pathInContext,pathInContext);
21303928aee4356845252ac6b662d5c72c29903813eJake Slack                File parent = file.getParentFile();
21403928aee4356845252ac6b662d5c72c29903813eJake Slack                parent.mkdirs();
21503928aee4356845252ac6b662d5c72c29903813eJake Slack                int toRead = request.getContentLength();
21603928aee4356845252ac6b662d5c72c29903813eJake Slack                InputStream in = request.getInputStream();
21703928aee4356845252ac6b662d5c72c29903813eJake Slack
21803928aee4356845252ac6b662d5c72c29903813eJake Slack
21903928aee4356845252ac6b662d5c72c29903813eJake Slack                if (_putAtomic)
22003928aee4356845252ac6b662d5c72c29903813eJake Slack                {
22103928aee4356845252ac6b662d5c72c29903813eJake Slack                    File tmp=File.createTempFile(file.getName(),null,_tmpdir);
22203928aee4356845252ac6b662d5c72c29903813eJake Slack                    OutputStream out = new FileOutputStream(tmp,false);
22303928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (toRead >= 0)
22403928aee4356845252ac6b662d5c72c29903813eJake Slack                        IO.copy(in, out, toRead);
22503928aee4356845252ac6b662d5c72c29903813eJake Slack                    else
22603928aee4356845252ac6b662d5c72c29903813eJake Slack                        IO.copy(in, out);
22703928aee4356845252ac6b662d5c72c29903813eJake Slack                    out.close();
22803928aee4356845252ac6b662d5c72c29903813eJake Slack
22903928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (!tmp.renameTo(file))
23003928aee4356845252ac6b662d5c72c29903813eJake Slack                        throw new IOException("rename from "+tmp+" to "+file+" failed");
23103928aee4356845252ac6b662d5c72c29903813eJake Slack                }
23203928aee4356845252ac6b662d5c72c29903813eJake Slack                else
23303928aee4356845252ac6b662d5c72c29903813eJake Slack                {
23403928aee4356845252ac6b662d5c72c29903813eJake Slack                    OutputStream out = new FileOutputStream(file,false);
23503928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (toRead >= 0)
23603928aee4356845252ac6b662d5c72c29903813eJake Slack                        IO.copy(in, out, toRead);
23703928aee4356845252ac6b662d5c72c29903813eJake Slack                    else
23803928aee4356845252ac6b662d5c72c29903813eJake Slack                        IO.copy(in, out);
23903928aee4356845252ac6b662d5c72c29903813eJake Slack                    out.close();
24003928aee4356845252ac6b662d5c72c29903813eJake Slack                }
24103928aee4356845252ac6b662d5c72c29903813eJake Slack
24203928aee4356845252ac6b662d5c72c29903813eJake Slack                response.setStatus(exists ? HttpServletResponse.SC_OK : HttpServletResponse.SC_CREATED);
24303928aee4356845252ac6b662d5c72c29903813eJake Slack                response.flushBuffer();
24403928aee4356845252ac6b662d5c72c29903813eJake Slack                ok=true;
24503928aee4356845252ac6b662d5c72c29903813eJake Slack            }
24603928aee4356845252ac6b662d5c72c29903813eJake Slack            catch (Exception ex)
24703928aee4356845252ac6b662d5c72c29903813eJake Slack            {
24803928aee4356845252ac6b662d5c72c29903813eJake Slack                _context.log(ex.toString(),ex);
24903928aee4356845252ac6b662d5c72c29903813eJake Slack                response.sendError(HttpServletResponse.SC_FORBIDDEN);
25003928aee4356845252ac6b662d5c72c29903813eJake Slack            }
25103928aee4356845252ac6b662d5c72c29903813eJake Slack            finally
25203928aee4356845252ac6b662d5c72c29903813eJake Slack            {
25303928aee4356845252ac6b662d5c72c29903813eJake Slack                if (!ok)
25403928aee4356845252ac6b662d5c72c29903813eJake Slack                {
25503928aee4356845252ac6b662d5c72c29903813eJake Slack                    try
25603928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
25703928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (file.exists())
25803928aee4356845252ac6b662d5c72c29903813eJake Slack                            file.delete();
25903928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
26003928aee4356845252ac6b662d5c72c29903813eJake Slack                    catch(Exception e)
26103928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
26203928aee4356845252ac6b662d5c72c29903813eJake Slack                        _context.log(e.toString(),e);
26303928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
26403928aee4356845252ac6b662d5c72c29903813eJake Slack                }
26503928aee4356845252ac6b662d5c72c29903813eJake Slack                _hidden.remove(pathInContext);
26603928aee4356845252ac6b662d5c72c29903813eJake Slack            }
26703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
26803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
26903928aee4356845252ac6b662d5c72c29903813eJake Slack
27003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------- */
27103928aee4356845252ac6b662d5c72c29903813eJake Slack    public void handleDelete(HttpServletRequest request, HttpServletResponse response, String pathInContext, File file) throws ServletException, IOException
27203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
27303928aee4356845252ac6b662d5c72c29903813eJake Slack        try
27403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
27503928aee4356845252ac6b662d5c72c29903813eJake Slack            // delete the file
27603928aee4356845252ac6b662d5c72c29903813eJake Slack            if (file.delete())
27703928aee4356845252ac6b662d5c72c29903813eJake Slack            {
27803928aee4356845252ac6b662d5c72c29903813eJake Slack                response.setStatus(HttpServletResponse.SC_NO_CONTENT);
27903928aee4356845252ac6b662d5c72c29903813eJake Slack                response.flushBuffer();
28003928aee4356845252ac6b662d5c72c29903813eJake Slack            }
28103928aee4356845252ac6b662d5c72c29903813eJake Slack            else
28203928aee4356845252ac6b662d5c72c29903813eJake Slack                response.sendError(HttpServletResponse.SC_FORBIDDEN);
28303928aee4356845252ac6b662d5c72c29903813eJake Slack        }
28403928aee4356845252ac6b662d5c72c29903813eJake Slack        catch (SecurityException sex)
28503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
28603928aee4356845252ac6b662d5c72c29903813eJake Slack            _context.log(sex.toString(),sex);
28703928aee4356845252ac6b662d5c72c29903813eJake Slack            response.sendError(HttpServletResponse.SC_FORBIDDEN);
28803928aee4356845252ac6b662d5c72c29903813eJake Slack        }
28903928aee4356845252ac6b662d5c72c29903813eJake Slack    }
29003928aee4356845252ac6b662d5c72c29903813eJake Slack
29103928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------------- */
29203928aee4356845252ac6b662d5c72c29903813eJake Slack    public void handleMove(HttpServletRequest request, HttpServletResponse response, String pathInContext, File file)
29303928aee4356845252ac6b662d5c72c29903813eJake Slack        throws ServletException, IOException, URISyntaxException
29403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
29503928aee4356845252ac6b662d5c72c29903813eJake Slack        String newPath = URIUtil.canonicalPath(request.getHeader("new-uri"));
29603928aee4356845252ac6b662d5c72c29903813eJake Slack        if (newPath == null)
29703928aee4356845252ac6b662d5c72c29903813eJake Slack        {
29803928aee4356845252ac6b662d5c72c29903813eJake Slack            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
29903928aee4356845252ac6b662d5c72c29903813eJake Slack            return;
30003928aee4356845252ac6b662d5c72c29903813eJake Slack        }
30103928aee4356845252ac6b662d5c72c29903813eJake Slack
30203928aee4356845252ac6b662d5c72c29903813eJake Slack        String contextPath = request.getContextPath();
30303928aee4356845252ac6b662d5c72c29903813eJake Slack        if (contextPath != null && !newPath.startsWith(contextPath))
30403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
30503928aee4356845252ac6b662d5c72c29903813eJake Slack            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
30603928aee4356845252ac6b662d5c72c29903813eJake Slack            return;
30703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
30803928aee4356845252ac6b662d5c72c29903813eJake Slack        String newInfo = newPath;
30903928aee4356845252ac6b662d5c72c29903813eJake Slack        if (contextPath != null)
31003928aee4356845252ac6b662d5c72c29903813eJake Slack            newInfo = newInfo.substring(contextPath.length());
31103928aee4356845252ac6b662d5c72c29903813eJake Slack
31203928aee4356845252ac6b662d5c72c29903813eJake Slack        String new_resource = URIUtil.addPaths(_baseURI,newInfo);
31303928aee4356845252ac6b662d5c72c29903813eJake Slack        File new_file=new File(new URI(new_resource));
31403928aee4356845252ac6b662d5c72c29903813eJake Slack
31503928aee4356845252ac6b662d5c72c29903813eJake Slack        file.renameTo(new_file);
31603928aee4356845252ac6b662d5c72c29903813eJake Slack
31703928aee4356845252ac6b662d5c72c29903813eJake Slack        response.setStatus(HttpServletResponse.SC_NO_CONTENT);
31803928aee4356845252ac6b662d5c72c29903813eJake Slack        response.flushBuffer();
31903928aee4356845252ac6b662d5c72c29903813eJake Slack    }
32003928aee4356845252ac6b662d5c72c29903813eJake Slack
32103928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
32203928aee4356845252ac6b662d5c72c29903813eJake Slack    public void handleOptions(FilterChain chain, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
32303928aee4356845252ac6b662d5c72c29903813eJake Slack    {
32403928aee4356845252ac6b662d5c72c29903813eJake Slack        chain.doFilter(request,new HttpServletResponseWrapper(response)
32503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
32603928aee4356845252ac6b662d5c72c29903813eJake Slack            @Override
32703928aee4356845252ac6b662d5c72c29903813eJake Slack            public void setHeader(String name, String value)
32803928aee4356845252ac6b662d5c72c29903813eJake Slack            {
32903928aee4356845252ac6b662d5c72c29903813eJake Slack                if ("Allow".equalsIgnoreCase(name))
33003928aee4356845252ac6b662d5c72c29903813eJake Slack                {
33103928aee4356845252ac6b662d5c72c29903813eJake Slack                    Set<String> options = new HashSet<String>();
33203928aee4356845252ac6b662d5c72c29903813eJake Slack                    options.addAll(Arrays.asList(value.split(" *, *")));
33303928aee4356845252ac6b662d5c72c29903813eJake Slack                    options.addAll(_operations);
33403928aee4356845252ac6b662d5c72c29903813eJake Slack                    value=null;
33503928aee4356845252ac6b662d5c72c29903813eJake Slack                    for (String o : options)
33603928aee4356845252ac6b662d5c72c29903813eJake Slack                        value=value==null?o:(value+", "+o);
33703928aee4356845252ac6b662d5c72c29903813eJake Slack                }
33803928aee4356845252ac6b662d5c72c29903813eJake Slack
33903928aee4356845252ac6b662d5c72c29903813eJake Slack                super.setHeader(name,value);
34003928aee4356845252ac6b662d5c72c29903813eJake Slack            }
34103928aee4356845252ac6b662d5c72c29903813eJake Slack        });
34203928aee4356845252ac6b662d5c72c29903813eJake Slack
34303928aee4356845252ac6b662d5c72c29903813eJake Slack    }
34403928aee4356845252ac6b662d5c72c29903813eJake Slack
34503928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
34603928aee4356845252ac6b662d5c72c29903813eJake Slack    /*
34703928aee4356845252ac6b662d5c72c29903813eJake Slack     * Check modification date headers.
34803928aee4356845252ac6b662d5c72c29903813eJake Slack     */
34903928aee4356845252ac6b662d5c72c29903813eJake Slack    protected boolean passConditionalHeaders(HttpServletRequest request, HttpServletResponse response, File file) throws IOException
35003928aee4356845252ac6b662d5c72c29903813eJake Slack    {
35103928aee4356845252ac6b662d5c72c29903813eJake Slack        long date = 0;
35203928aee4356845252ac6b662d5c72c29903813eJake Slack
35303928aee4356845252ac6b662d5c72c29903813eJake Slack        if ((date = request.getDateHeader("if-unmodified-since")) > 0)
35403928aee4356845252ac6b662d5c72c29903813eJake Slack        {
35503928aee4356845252ac6b662d5c72c29903813eJake Slack            if (file.lastModified() / 1000 > date / 1000)
35603928aee4356845252ac6b662d5c72c29903813eJake Slack            {
35703928aee4356845252ac6b662d5c72c29903813eJake Slack                response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
35803928aee4356845252ac6b662d5c72c29903813eJake Slack                return false;
35903928aee4356845252ac6b662d5c72c29903813eJake Slack            }
36003928aee4356845252ac6b662d5c72c29903813eJake Slack        }
36103928aee4356845252ac6b662d5c72c29903813eJake Slack
36203928aee4356845252ac6b662d5c72c29903813eJake Slack        if ((date = request.getDateHeader("if-modified-since")) > 0)
36303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
36403928aee4356845252ac6b662d5c72c29903813eJake Slack            if (file.lastModified() / 1000 <= date / 1000)
36503928aee4356845252ac6b662d5c72c29903813eJake Slack            {
36603928aee4356845252ac6b662d5c72c29903813eJake Slack                response.reset();
36703928aee4356845252ac6b662d5c72c29903813eJake Slack                response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
36803928aee4356845252ac6b662d5c72c29903813eJake Slack                response.flushBuffer();
36903928aee4356845252ac6b662d5c72c29903813eJake Slack                return false;
37003928aee4356845252ac6b662d5c72c29903813eJake Slack            }
37103928aee4356845252ac6b662d5c72c29903813eJake Slack        }
37203928aee4356845252ac6b662d5c72c29903813eJake Slack        return true;
37303928aee4356845252ac6b662d5c72c29903813eJake Slack    }
37403928aee4356845252ac6b662d5c72c29903813eJake Slack}
375