396253 FilterRegistration wrong order

This commit is contained in:
Jan Bartel 2013-01-14 12:55:53 +11:00
parent 863944873d
commit 1689aa8143
2 changed files with 555 additions and 10 deletions

View File

@ -65,6 +65,7 @@ import org.eclipse.jetty.server.ServletResponseHttpWrapper;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ScopedHandler;
import org.eclipse.jetty.servlet.Holder.Source;
import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.MultiMap;
@ -97,6 +98,8 @@ public class ServletHandler extends ScopedHandler
private ContextHandler.Context _servletContext;
private FilterHolder[] _filters=new FilterHolder[0];
private FilterMapping[] _filterMappings;
private int _matchBeforeIndex = -1; //index of last programmatic FilterMapping with isMatchAfter=false
private int _matchAfterIndex = -1; //index of 1st programmatic FilterMapping with isMatchAfter=true
private boolean _filterChainsCached=true;
private int _maxFilterChainsCacheSize=512;
private boolean _startWithUnavailable=true;
@ -924,7 +927,9 @@ public class ServletHandler extends ScopedHandler
mapping.setFilterName(holder.getName());
mapping.setPathSpec(pathSpec);
mapping.setDispatcherTypes(dispatches);
setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
//setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
addFilterMapping(mapping);
}
catch (RuntimeException e)
{
@ -992,7 +997,8 @@ public class ServletHandler extends ScopedHandler
mapping.setFilterName(holder.getName());
mapping.setPathSpec(pathSpec);
mapping.setDispatches(dispatches);
setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
//setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
addFilterMapping(mapping);
}
catch (RuntimeException e)
{
@ -1031,7 +1037,8 @@ public class ServletHandler extends ScopedHandler
if (filter != null)
setFilters((FilterHolder[])LazyList.addToArray(getFilters(), filter, FilterHolder.class));
if (filterMapping != null)
setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), filterMapping, FilterMapping.class));
//setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), filterMapping, FilterMapping.class));
addFilterMapping(filterMapping);
}
/* ------------------------------------------------------------ */
@ -1051,9 +1058,43 @@ public class ServletHandler extends ScopedHandler
public void addFilterMapping (FilterMapping mapping)
{
if (mapping != null)
setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
{
Source source = (mapping.getFilterHolder()==null?null:mapping.getFilterHolder().getSource());
FilterMapping[] mappings =getFilterMappings();
if (mappings==null || mappings.length==0)
{
setFilterMappings(insertFilterMapping(mapping,0,false));
if (source != null && source == Source.JAVAX_API)
_matchAfterIndex = 0;
}
else
{
//there are existing entries. If this is a programmatic filtermapping, it is added at the end of the list.
//If this is a normal filtermapping, it is inserted after all the other filtermappings (matchBefores and normals),
//but before the first matchAfter filtermapping.
if (source != null && Source.JAVAX_API == source)
{
setFilterMappings(insertFilterMapping(mapping,mappings.length-1, false));
if (_matchAfterIndex < 0)
_matchAfterIndex = getFilterMappings().length-1;
}
else
{
//insert non-programmatic filter mappings before any matchAfters, if any
if (_matchAfterIndex < 0)
setFilterMappings(insertFilterMapping(mapping,mappings.length-1, false));
else
{
FilterMapping[] new_mappings = insertFilterMapping(mapping, _matchAfterIndex, true);
++_matchAfterIndex;
setFilterMappings(new_mappings);
}
}
}
}
}
/* ------------------------------------------------------------ */
/** Convenience method to add a preconstructed FilterMapping
* @param mapping
@ -1062,20 +1103,99 @@ public class ServletHandler extends ScopedHandler
{
if (mapping != null)
{
FilterMapping[] mappings =getFilterMappings();
Source source = mapping.getFilterHolder().getSource();
FilterMapping[] mappings = getFilterMappings();
if (mappings==null || mappings.length==0)
setFilterMappings(new FilterMapping[] {mapping});
{
setFilterMappings(insertFilterMapping(mapping, 0, false));
if (source != null && Source.JAVAX_API == source)
_matchBeforeIndex = 0;
}
else
{
if (source != null && Source.JAVAX_API == source)
{
//programmatically defined filter mappings are prepended to mapping list in the order
//in which they were defined. In other words, insert this mapping at the tail of the
//programmatically added filter mappings, BEFORE the first web.xml defined filter mapping.
FilterMapping[] new_mappings=new FilterMapping[mappings.length+1];
System.arraycopy(mappings,0,new_mappings,1,mappings.length);
new_mappings[0]=mapping;
setFilterMappings(new_mappings);
if (_matchBeforeIndex < 0)
{
//no programmatically defined prepended filter mappings yet, prepend this one
_matchBeforeIndex = 0;
FilterMapping[] new_mappings = insertFilterMapping(mapping, 0, true);
setFilterMappings(new_mappings);
}
else
{
FilterMapping[] new_mappings = insertFilterMapping(mapping,_matchBeforeIndex, false);
++_matchBeforeIndex;
setFilterMappings(new_mappings);
}
}
else
{
//non programmatically defined, just prepend to list
FilterMapping[] new_mappings = insertFilterMapping(mapping, 0, true);
setFilterMappings(new_mappings);
}
//adjust matchAfterIndex ptr to take account of the mapping we just prepended
if (_matchAfterIndex >= 0)
++_matchAfterIndex;
}
}
}
/**
* Insert a filtermapping in the list
* @param mapping the FilterMapping to add
* @param pos the position in the existing arry at which to add it
* @param before if true, insert before pos, if false insert after it
* @return
*/
protected FilterMapping[] insertFilterMapping (FilterMapping mapping, int pos, boolean before)
{
if (pos < 0)
throw new IllegalArgumentException("FilterMapping insertion pos < 0");
FilterMapping[] mappings = getFilterMappings();
if (mappings==null || mappings.length==0)
{
return new FilterMapping[] {mapping};
}
FilterMapping[] new_mappings = new FilterMapping[mappings.length+1];
if (before)
{
//copy existing filter mappings up to but not including the pos
System.arraycopy(mappings,0,new_mappings,0,pos);
//add in the new mapping
new_mappings[pos] = mapping;
//copy the old pos mapping and any remaining existing mappings
System.arraycopy(mappings,pos,new_mappings,pos+1, mappings.length-pos);
}
else
{
//copy existing filter mappings up to and including the pos
System.arraycopy(mappings,0,new_mappings,0,pos+1);
//add in the new mapping after the pos
new_mappings[pos+1] = mapping;
//copy the remaining existing mappings
if (mappings.length > pos+1)
System.arraycopy(mappings,pos+1,new_mappings,pos+2, mappings.length-(pos+1));
}
return new_mappings;
}
/* ------------------------------------------------------------ */
protected synchronized void updateNameMappings()
{

View File

@ -0,0 +1,425 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.servlet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import org.eclipse.jetty.servlet.Holder.Source;
import org.junit.Before;
import org.junit.Test;
public class ServletHandlerTest
{
FilterHolder fh1 = new FilterHolder(Holder.Source.DESCRIPTOR);
FilterMapping fm1 = new FilterMapping();
FilterHolder fh2 = new FilterHolder(Holder.Source.DESCRIPTOR);
FilterMapping fm2 = new FilterMapping();
FilterHolder fh3 = new FilterHolder(Holder.Source.JAVAX_API);
FilterMapping fm3 = new FilterMapping();
FilterHolder fh4 = new FilterHolder(Holder.Source.JAVAX_API);
FilterMapping fm4 = new FilterMapping();
FilterHolder fh5 = new FilterHolder(Holder.Source.JAVAX_API);
FilterMapping fm5 = new FilterMapping();
@Before
public void initMappings()
{
fh1.setName("fh1");
fm1.setPathSpec("/*");
fm1.setFilterHolder(fh1);
fh2.setName("fh2");
fm2.setPathSpec("/*");
fm2.setFilterHolder(fh2);
fh3.setName("fh3");
fm3.setPathSpec("/*");
fm3.setFilterHolder(fh3);
fh4.setName("fh4");
fm4.setPathSpec("/*");
fm4.setFilterHolder(fh4);
fh5.setName("fh5");
fm5.setPathSpec("/*");
fm5.setFilterHolder(fh5);
}
@Test
public void testAllNonProgrammaticFilterMappings() throws Exception
{
ServletHandler handler = new ServletHandler();
handler.addFilter(fh1);
handler.addFilter(fh2);
//add some ordinary filter mappings
handler.addFilterMapping(fm1);
handler.addFilterMapping(fm2);
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertTrue(fm1 == mappings[0]);
assertTrue(fm2 == mappings[1]);
//add another ordinary mapping
FilterHolder of1 = new FilterHolder(Source.DESCRIPTOR);
FilterMapping ofm1 = new FilterMapping();
ofm1.setFilterHolder(of1);
ofm1.setPathSpec("/*");
handler.addFilter(of1);
handler.addFilterMapping(ofm1);
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertTrue(fm1 == mappings[0]);
assertTrue(fm2 == mappings[1]);
assertTrue(ofm1 == mappings[2]);
}
@Test
public void testAllBeforeFilterMappings() throws Exception
{
ServletHandler handler = new ServletHandler();
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=false)
handler.addFilter(fh4);
handler.prependFilterMapping(fm4);
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(1, mappings.length);
//add another with isMatchAfter=false
handler.addFilter(fh5);
handler.prependFilterMapping(fm5);
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]);
assertTrue(fm5 == mappings[1]);
}
@Test
public void testAllAfterFilterMappings() throws Exception
{
ServletHandler handler = new ServletHandler();
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
handler.addFilter(fh4);
handler.addFilterMapping(fm4);
FilterMapping[] mappings = handler.getFilterMappings();
assertEquals(1, mappings.length);
assertTrue(fm4 == mappings[0]);
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
handler.addFilter(fh5);
handler.addFilterMapping(fm5);
mappings = handler.getFilterMappings();
assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]);
assertTrue(fm5 == mappings[1]);
}
@Test
public void testMatchAfterAndBefore() throws Exception
{
ServletHandler handler = new ServletHandler();
//add a programmatic one, isMatchAfter=true
handler.addFilter(fh3);
handler.addFilterMapping(fm3);
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(1, mappings.length);
assertTrue(fm3 == mappings[0]);
//add a programmatic one, isMatchAfter=false
handler.addFilter(fh4);
handler.prependFilterMapping(fm4);
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]);
assertTrue(fm3 == mappings[1]);
}
@Test
public void testMatchBeforeAndAfter() throws Exception
{
ServletHandler handler = new ServletHandler();
//add a programmatic one, isMatchAfter=false
handler.addFilter(fh3);
handler.prependFilterMapping(fm3);
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(1, mappings.length);
assertTrue(fm3 == mappings[0]);
//add a programmatic one, isMatchAfter=true
handler.addFilter(fh4);
handler.addFilterMapping(fm4);
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(2, mappings.length);
assertTrue(fm3 == mappings[0]);
assertTrue(fm4 == mappings[1]);
}
@Test
public void testExistingFilterMappings() throws Exception
{
ServletHandler handler = new ServletHandler();
handler.addFilter(fh1);
handler.addFilter(fh2);
//add some ordinary filter mappings first
handler.addFilterMapping(fm1);
handler.addFilterMapping(fm2);
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertTrue(fm1 == mappings[0]);
assertTrue(fm2 == mappings[1]);
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=false)
handler.addFilter(fh4);
handler.prependFilterMapping(fm4);
mappings = handler.getFilterMappings();
assertEquals(3, mappings.length);
assertTrue(fm4 == mappings[0]);
//do equivalent of FilterRegistration.addMappingForUrlPatterns(isMatchAfter=true)
handler.addFilter(fh5);
handler.addFilterMapping(fm5);
mappings = handler.getFilterMappings();
assertEquals(4, mappings.length);
assertTrue(fm5 == mappings[mappings.length-1]);
}
@Test
public void testFilterMappingsMix() throws Exception
{
ServletHandler handler = new ServletHandler();
//add a non-programmatic one to begin with
handler.addFilter(fh1);
handler.addFilterMapping(fm1);
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertTrue(fm1 == mappings[0]);
//add a programmatic one, isMatchAfter=false
handler.addFilter(fh4);
handler.prependFilterMapping(fm4);
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(2, mappings.length);
assertTrue(fm4 == mappings[0]);
assertTrue(fm1 == mappings[1]);
//add a programmatic one, isMatchAfter=true
handler.addFilter(fh3);
handler.addFilterMapping(fm3);
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(3, mappings.length);
assertTrue(fm4 == mappings[0]);
assertTrue(fm1 == mappings[1]);
assertTrue(fm3 == mappings[2]);
//add a programmatic one, isMatchAfter=false
handler.addFilter(fh5);
handler.prependFilterMapping(fm5);
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(4, mappings.length);
assertTrue(fm4 == mappings[0]);//isMatchAfter = false;
assertTrue(fm5 == mappings[1]);//isMatchAfter = false;
assertTrue(fm1 == mappings[2]);//ordinary
assertTrue(fm3 == mappings[3]);//isMatchAfter = true;
//add a non-programmatic one
FilterHolder f = new FilterHolder(Source.EMBEDDED);
f.setName("non-programmatic");
FilterMapping fm = new FilterMapping();
fm.setFilterHolder(f);
fm.setPathSpec("/*");
handler.addFilter(f);
handler.addFilterMapping(fm);
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(5, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false;
assertTrue(fm1 == mappings[2]); //ordinary
assertTrue(fm == mappings[3]); //ordinary
assertTrue(fm3 == mappings[4]); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=true
FilterHolder pf = new FilterHolder(Source.JAVAX_API);
pf.setName("programmaticA");
FilterMapping pfm = new FilterMapping();
pfm.setFilterHolder(pf);
pfm.setPathSpec("/*");
handler.addFilter(pf);
handler.addFilterMapping(pfm);
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(6, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false;
assertTrue(fm1 == mappings[2]); //ordinary
assertTrue(fm == mappings[3]); //ordinary
assertTrue(fm3 == mappings[4]); //isMatchAfter = true;
assertTrue(pfm == mappings[5]); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=false
FilterHolder pf2 = new FilterHolder(Source.JAVAX_API);
pf2.setName("programmaticB");
FilterMapping pfm2 = new FilterMapping();
pfm2.setFilterHolder(pf2);
pfm2.setPathSpec("/*");
handler.addFilter(pf2);
handler.prependFilterMapping(pfm2);
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(7, mappings.length);
assertTrue(fm4 == mappings[0]); //isMatchAfter = false;
assertTrue(fm5 == mappings[1]); //isMatchAfter = false;
assertTrue(pfm2 == mappings[2]);//isMatchAfter = false;
assertTrue(fm1 == mappings[3]); //ordinary
assertTrue(fm == mappings[4]); //ordinary
assertTrue(fm3 == mappings[5]); //isMatchAfter = true;
assertTrue(pfm == mappings[6]); //isMatchAfter = true;
}
@Test
public void testAddFilterWithMappingAPI() throws Exception
{
ServletHandler handler = new ServletHandler();
//add a non-programmatic one to begin with
handler.addFilterWithMapping(fh1, "/*", EnumSet.allOf(DispatcherType.class));
FilterMapping[] mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertTrue(fh1 == mappings[0].getFilterHolder());
//add a programmatic one, isMatchAfter=false
fh4.setServletHandler(handler);
handler.addFilter(fh4);
fh4.getRegistration().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(2, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder());
assertTrue(fh1 == mappings[1].getFilterHolder());
//add a programmatic one, isMatchAfter=true
fh3.setServletHandler(handler);
handler.addFilter(fh3);
fh3.getRegistration().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(3, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder());
assertTrue(fh1 == mappings[1].getFilterHolder());
assertTrue(fh3 == mappings[2].getFilterHolder());
//add a programmatic one, isMatchAfter=false
fh5.setServletHandler(handler);
handler.addFilter(fh5);
fh5.getRegistration().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(4, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder());//isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder());//isMatchAfter = false;
assertTrue(fh1 == mappings[2].getFilterHolder());//ordinary
assertTrue(fh3 == mappings[3].getFilterHolder());//isMatchAfter = true;
//add a non-programmatic one
FilterHolder f = new FilterHolder(Source.EMBEDDED);
f.setName("non-programmatic");
handler.addFilterWithMapping(f, "/*", EnumSet.allOf(DispatcherType.class));
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(5, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh1 == mappings[2].getFilterHolder()); //ordinary
assertTrue(f == mappings[3].getFilterHolder()); //ordinary
assertTrue(fh3 == mappings[4].getFilterHolder()); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=true
FilterHolder pf = new FilterHolder(Source.JAVAX_API);
pf.setServletHandler(handler);
pf.setName("programmaticA");
handler.addFilter(pf);
pf.getRegistration().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(6, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh1 == mappings[2].getFilterHolder()); //ordinary
assertTrue(f == mappings[3].getFilterHolder()); //ordinary
assertTrue(fh3 == mappings[4].getFilterHolder()); //isMatchAfter = true;
assertTrue(pf == mappings[5].getFilterHolder()); //isMatchAfter = true;
//add a programmatic one, isMatchAfter=false
FilterHolder pf2 = new FilterHolder(Source.JAVAX_API);
pf2.setServletHandler(handler);
pf2.setName("programmaticB");
handler.addFilter(pf2);
pf2.getRegistration().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
mappings = handler.getFilterMappings();
assertNotNull(mappings);
assertEquals(7, mappings.length);
assertTrue(fh4 == mappings[0].getFilterHolder()); //isMatchAfter = false;
assertTrue(fh5 == mappings[1].getFilterHolder()); //isMatchAfter = false;
assertTrue(pf2 == mappings[2].getFilterHolder());//isMatchAfter = false;
assertTrue(fh1 == mappings[3].getFilterHolder()); //ordinary
assertTrue(f == mappings[4].getFilterHolder()); //ordinary
assertTrue(fh3 == mappings[5].getFilterHolder()); //isMatchAfter = true;
assertTrue(pf == mappings[6].getFilterHolder()); //isMatchAfter = true;
}
}