330417 Atomic PUT in PutFilter
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@2526 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
parent
a9a56e8716
commit
d955fa0c3a
|
@ -3,6 +3,7 @@ jetty-7.2.2-SNAPSHOT
|
|||
+ 330208 Support new wording on servlet-mapping and filter-mapping merging from servlet3.0a
|
||||
+ 330188 Reject web-fragment.xml with same <name> as another already loaded one
|
||||
+ 330229 Jetty tries to parse META-INF/*.tld when jsp-api is not on classpath, causing DTD entity resoluton to fail
|
||||
+ 330417 Atomic PUT in PutFilter
|
||||
|
||||
jetty-7.2.1.v20101111 11 November 2010
|
||||
+ 324679 Fixed dedection of write before static content
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -32,9 +33,11 @@ import javax.servlet.ServletContext;
|
|||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.ServletResponseWrapper;
|
||||
import javax.servlet.UnavailableException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
@ -45,9 +48,10 @@ import org.eclipse.jetty.util.URIUtil;
|
|||
* A Filter that handles PUT, DELETE and MOVE methods.
|
||||
* Files are hidden during PUT operations, so that 404's result.
|
||||
*
|
||||
* The following init paramters pay be used:<ul>
|
||||
* The following init parameters pay be used:<ul>
|
||||
* <li><b>baseURI</b> - The file URI of the document root for put content.
|
||||
* <li><b>delAllowed</b> - boolean, if true DELETE and MOVE methods are supported.
|
||||
* <li><b>putAtomic</b> - boolean, if true PUT files are written to a temp location and moved into place.
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
|
@ -59,17 +63,23 @@ public class PutFilter implements Filter
|
|||
public final static String __OPTIONS="OPTIONS";
|
||||
|
||||
Set<String> _operations = new HashSet<String>();
|
||||
protected ConcurrentMap<String,String> _hidden = new ConcurrentHashMap<String, String>();
|
||||
protected String _options;
|
||||
private ConcurrentMap<String,String> _hidden = new ConcurrentHashMap<String, String>();
|
||||
private String _options=null;
|
||||
|
||||
protected ServletContext _context;
|
||||
protected String _baseURI;
|
||||
protected boolean _delAllowed;
|
||||
private ServletContext _context;
|
||||
private String _baseURI;
|
||||
private boolean _delAllowed;
|
||||
private boolean _putAtomic;
|
||||
private File _tmpdir;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void init(FilterConfig config) throws ServletException
|
||||
{
|
||||
_context=config.getServletContext();
|
||||
|
||||
_tmpdir=(File)_context.getAttribute("javax.servlet.context.tempdir");
|
||||
|
||||
if (_context.getRealPath("/")==null)
|
||||
throw new UnavailableException("Packed war");
|
||||
|
||||
|
@ -83,17 +93,16 @@ public class PutFilter implements Filter
|
|||
File base=new File(_context.getRealPath("/"));
|
||||
_baseURI=base.toURI().toString();
|
||||
}
|
||||
|
||||
|
||||
_delAllowed = getInitBoolean(config,"delAllowed");
|
||||
_putAtomic = getInitBoolean(config,"putAtomic");
|
||||
|
||||
_operations.add(__OPTIONS);
|
||||
_operations.add(__PUT);
|
||||
_options="GET,HEAD,POST,OPTIONS,PUT";
|
||||
if (_delAllowed)
|
||||
{
|
||||
_operations.add(__DELETE);
|
||||
_operations.add(__MOVE);
|
||||
_options+=",DELETE";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +116,6 @@ public class PutFilter implements Filter
|
|||
/* ------------------------------------------------------------ */
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
|
||||
{
|
||||
|
||||
HttpServletRequest request=(HttpServletRequest)req;
|
||||
HttpServletResponse response=(HttpServletResponse)res;
|
||||
|
||||
|
@ -126,7 +134,7 @@ public class PutFilter implements Filter
|
|||
try
|
||||
{
|
||||
if (method.equals(__OPTIONS))
|
||||
handleOptions(request, response);
|
||||
handleOptions(chain,request, response);
|
||||
else
|
||||
{
|
||||
file=new File(new URI(resource));
|
||||
|
@ -203,12 +211,30 @@ public class PutFilter implements Filter
|
|||
parent.mkdirs();
|
||||
int toRead = request.getContentLength();
|
||||
InputStream in = request.getInputStream();
|
||||
OutputStream out = new FileOutputStream(file,false);
|
||||
if (toRead >= 0)
|
||||
IO.copy(in, out, toRead);
|
||||
|
||||
|
||||
if (_putAtomic)
|
||||
{
|
||||
File tmp=File.createTempFile(file.getName(),null,_tmpdir);
|
||||
OutputStream out = new FileOutputStream(tmp,false);
|
||||
if (toRead >= 0)
|
||||
IO.copy(in, out, toRead);
|
||||
else
|
||||
IO.copy(in, out);
|
||||
out.close();
|
||||
|
||||
if (!tmp.renameTo(file))
|
||||
throw new IOException("rename from "+tmp+" to "+file+" failed");
|
||||
}
|
||||
else
|
||||
IO.copy(in, out);
|
||||
out.close();
|
||||
{
|
||||
OutputStream out = new FileOutputStream(file,false);
|
||||
if (toRead >= 0)
|
||||
IO.copy(in, out, toRead);
|
||||
else
|
||||
IO.copy(in, out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
response.setStatus(exists ? HttpServletResponse.SC_OK : HttpServletResponse.SC_CREATED);
|
||||
response.flushBuffer();
|
||||
|
@ -290,10 +316,27 @@ public class PutFilter implements Filter
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handleOptions(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
public void handleOptions(FilterChain chain, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
// TODO filter real options and add PUT & DELETE
|
||||
response.setHeader("Allow", _options);
|
||||
chain.doFilter(request,new HttpServletResponseWrapper(response)
|
||||
{
|
||||
@Override
|
||||
public void setHeader(String name, String value)
|
||||
{
|
||||
if ("Allow".equalsIgnoreCase(name))
|
||||
{
|
||||
Set<String> options = new HashSet<String>();
|
||||
options.addAll(Arrays.asList(value.split(" *, *")));
|
||||
options.addAll(_operations);
|
||||
value=null;
|
||||
for (String o : options)
|
||||
value=value==null?o:(value+", "+o);
|
||||
}
|
||||
|
||||
super.setHeader(name,value);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -18,6 +18,10 @@ import java.io.FileInputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
|
@ -51,6 +55,7 @@ public class PutFilterTest
|
|||
tester.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/");
|
||||
FilterHolder holder = tester.addFilter(PutFilter.class,"/*",0);
|
||||
holder.setInitParameter("delAllowed","true");
|
||||
holder.setInitParameter("putAtomic","true");
|
||||
tester.start();
|
||||
}
|
||||
|
||||
|
@ -58,6 +63,7 @@ public class PutFilterTest
|
|||
public void tearDown() throws Exception
|
||||
{
|
||||
tester.stop();
|
||||
IO.delete(_dir);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -233,9 +239,29 @@ public class PutFilterTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testHandleOptions()
|
||||
public void testHandleOptions() throws Exception
|
||||
{
|
||||
// TODO implement
|
||||
// generated and parsed test
|
||||
HttpTester request = new HttpTester();
|
||||
HttpTester response = new HttpTester();
|
||||
|
||||
// test PUT1
|
||||
request.setMethod("OPTIONS");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setURI("/context/file.txt");
|
||||
response.parse(tester.getResponses(request.generate()));
|
||||
assertTrue(response.getMethod()==null);
|
||||
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
|
||||
|
||||
Set<String> options = new HashSet<String>();
|
||||
options.addAll(Arrays.asList(response.getHeader("Allow").split(" *, *")));
|
||||
|
||||
assertTrue(options.contains("GET"));
|
||||
assertTrue(options.contains("POST"));
|
||||
assertTrue(options.contains("PUT"));
|
||||
assertTrue(options.contains("MOVE"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue