Bug: 447781 Allow additional methods to be x-www-form-encoded

Added configuration to the HttpConfiguration class to allow additional methods to be set as
acceptable for x-www-form-encoding.
This commit is contained in:
Greg Wilkins 2015-06-24 11:45:44 +10:00
parent 99ce82e4cd
commit 814000531f
7 changed files with 168 additions and 5 deletions

View File

@ -20,10 +20,14 @@ package org.eclipse.jetty.server;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.TreeTrie;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
@ -44,7 +48,8 @@ public class HttpConfiguration
{
public static final String SERVER_VERSION = "Jetty(" + Jetty.VERSION + ")";
private List<Customizer> _customizers=new CopyOnWriteArrayList<>();
private final List<Customizer> _customizers=new CopyOnWriteArrayList<>();
private final Trie<Boolean> _formEncodedMethods = new TreeTrie<>();
private int _outputBufferSize=32*1024;
private int _outputAggregationSize=_outputBufferSize/4;
private int _requestHeaderSize=8*1024;
@ -86,6 +91,8 @@ public class HttpConfiguration
public HttpConfiguration()
{
_formEncodedMethods.put(HttpMethod.POST.asString(),Boolean.TRUE);
_formEncodedMethods.put(HttpMethod.PUT.asString(),Boolean.TRUE);
}
/* ------------------------------------------------------------ */
@ -356,6 +363,7 @@ public class HttpConfiguration
_secureScheme = secureScheme;
}
/* ------------------------------------------------------------ */
@Override
public String toString()
{
@ -367,4 +375,51 @@ public class HttpConfiguration
_secureScheme,_securePort,
_customizers);
}
/* ------------------------------------------------------------ */
/** Set the form encoded methods.
* @param methods HTTP Methods of requests that can be decoded as
* x-www-form-urlencoded content to be made available via the
* {@link Request#getParameter(String)} and associated APIs
*/
public void setFormEncodedMethods(String... methods)
{
_formEncodedMethods.clear();
for (String method:methods)
addFormEncodedMethod(method);
}
/* ------------------------------------------------------------ */
/**
* @return Set of HTTP Methods of requests that can be decoded as
* x-www-form-urlencoded content to be made available via the
* {@link Request#getParameter(String)} and associated APIs
*/
public Set<String> getFormEncodedMethods()
{
return _formEncodedMethods.keySet();
}
/* ------------------------------------------------------------ */
/** Add a form encoded HTTP Method
* @param method HTTP Method of requests that can be decoded as
* x-www-form-urlencoded content to be made available via the
* {@link Request#getParameter(String)} and associated APIs
*/
public void addFormEncodedMethod(String method)
{
_formEncodedMethods.put(method,Boolean.TRUE);
}
/* ------------------------------------------------------------ */
/**
* @param method
* @return True of the requests of this method type can be
* decoded as x-www-form-urlencoded content to be made available via the
* {@link Request#getParameter(String)} and associated APIs
*/
public boolean isFormEncodedMethod(String method)
{
return Boolean.TRUE.equals(_formEncodedMethods.get(method));
}
}

View File

@ -406,7 +406,7 @@ public class Request implements HttpServletRequest
if (contentLength != 0)
{
if (MimeTypes.Type.FORM_ENCODED.is(contentType) && _inputState == __NONE &&
(HttpMethod.POST.is(getMethod()) || HttpMethod.PUT.is(getMethod())))
_channel.getHttpConfiguration().isFormEncodedMethod(getMethod()))
{
extractFormParameters(_contentParameters);
}

View File

@ -643,6 +643,82 @@ public class RequestTest
}
}
@Test
public void testEncodedForm() throws Exception
{
_handler._checker = new RequestTester()
{
@Override
public boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException
{
String actual = request.getParameter("name2");
return "test2".equals(actual);
}
};
String content="name1=test&name2=test2&name3=&name4=test";
String request="POST / HTTP/1.1\r\n"+
"Host: whatever\r\n"+
"Content-Type: "+MimeTypes.Type.FORM_ENCODED.asString()+"\r\n" +
"Content-Length: "+content.length()+"\r\n"+
"Connection: close\r\n"+
"\r\n"+
content;
String response = _connector.getResponses(request);
assertThat(response,Matchers.containsString(" 200 OK"));
}
@Test
public void testEncodedFormUnknownMethod() throws Exception
{
_handler._checker = new RequestTester()
{
@Override
public boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException
{
return request.getParameter("name1")==null && request.getParameter("name2")==null && request.getParameter("name3")==null;
}
};
String content="name1=test&name2=test2&name3=&name4=test";
String request="UNKNOWN / HTTP/1.1\r\n"+
"Host: whatever\r\n"+
"Content-Type: "+MimeTypes.Type.FORM_ENCODED.asString()+"\r\n" +
"Content-Length: "+content.length()+"\r\n"+
"Connection: close\r\n"+
"\r\n"+
content;
String response = _connector.getResponses(request);
assertThat(response,Matchers.containsString(" 200 OK"));
}
@Test
public void testEncodedFormExtraMethod() throws Exception
{
_handler._checker = new RequestTester()
{
@Override
public boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException
{
String actual = request.getParameter("name2");
return "test2".equals(actual);
}
};
_connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().addFormEncodedMethod("Extra");
String content="name1=test&name2=test2&name3=&name4=test";
String request="EXTRA / HTTP/1.1\r\n"+
"Host: whatever\r\n"+
"Content-Type: "+MimeTypes.Type.FORM_ENCODED.asString()+"\r\n" +
"Content-Length: "+content.length()+"\r\n"+
"Connection: close\r\n"+
"\r\n"+
content;
String response = _connector.getResponses(request);
assertThat(response,Matchers.containsString(" 200 OK"));
}
@Test
public void test8859EncodedForm() throws Exception
{
@ -659,7 +735,6 @@ public class RequestTest
}
};
String content="name1=test&name2=test%E4&name3=&name4=test";
String request="POST / HTTP/1.1\r\n"+
"Host: whatever\r\n"+

View File

@ -155,6 +155,16 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
_tree=Arrays.copyOf(trie._tree, capacity*ROW_SIZE);
_key=Arrays.copyOf(trie._key, capacity);
}
/* ------------------------------------------------------------ */
@Override
public void clear()
{
_rows=0;
Arrays.fill(_value,null);
Arrays.fill(_tree,(char)0);
Arrays.fill(_key,null);
}
/* ------------------------------------------------------------ */
@Override

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.util;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@ -132,7 +133,16 @@ public class ArrayTrie<V> extends AbstractTrie<V>
_rowIndex=new char[capacity*32];
_key=new String[capacity];
}
/* ------------------------------------------------------------ */
@Override
public void clear()
{
_rows=0;
Arrays.fill(_value,null);
Arrays.fill(_rowIndex,(char)0);
Arrays.fill(_key,null);
}
/* ------------------------------------------------------------ */
@Override

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.util;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -33,7 +34,7 @@ import java.util.Set;
* <p>This Trie is stored in a Tree and is unlimited in capacity</p>
*
* <p>This Trie is not Threadsafe and contains no mutual exclusion
* or deliberate memory barriers. It is intended for an ArrayTrie to be
* or deliberate memory barriers. It is intended for an TreeTrie to be
* built by a single thread and then used concurrently by multiple threads
* and not mutated during that access. If concurrent mutations of the
* Trie is required external locks need to be applied.
@ -74,6 +75,15 @@ public class TreeTrie<V> extends AbstractTrie<V>
_nextIndex = new TreeTrie[INDEX];
this._c=c;
}
@Override
public void clear()
{
Arrays.fill(_nextIndex,null);
_nextOther.clear();
_key=null;
_value=null;
}
@Override
public boolean put(String s, V v)

View File

@ -123,4 +123,7 @@ public interface Trie<V>
/* ------------------------------------------------------------ */
public boolean isCaseInsensitive();
/* ------------------------------------------------------------ */
public void clear();
}