419972 - Support sending forms (application/x-www-form-urlencoded).
Implemented introducing HttpClient.FORM() method and FormContentProvider, based on Fields.
This commit is contained in:
parent
bf7ab5d326
commit
c322ed4b90
|
@ -49,12 +49,14 @@ import org.eclipse.jetty.client.api.Destination;
|
||||||
import org.eclipse.jetty.client.api.Request;
|
import org.eclipse.jetty.client.api.Request;
|
||||||
import org.eclipse.jetty.client.api.Response;
|
import org.eclipse.jetty.client.api.Response;
|
||||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||||
|
import org.eclipse.jetty.client.util.FormContentProvider;
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.http.HttpScheme;
|
import org.eclipse.jetty.http.HttpScheme;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||||
|
import org.eclipse.jetty.util.Fields;
|
||||||
import org.eclipse.jetty.util.Jetty;
|
import org.eclipse.jetty.util.Jetty;
|
||||||
import org.eclipse.jetty.util.Promise;
|
import org.eclipse.jetty.util.Promise;
|
||||||
import org.eclipse.jetty.util.SocketAddressResolver;
|
import org.eclipse.jetty.util.SocketAddressResolver;
|
||||||
|
@ -325,6 +327,30 @@ public class HttpClient extends ContainerLifeCycle
|
||||||
return newRequest(uri).send();
|
return newRequest(uri).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a POST request to the specified URI with the given form parameters.
|
||||||
|
*
|
||||||
|
* @param uri the URI to POST
|
||||||
|
* @param fields the fields composing the form name/value pairs
|
||||||
|
* @return the {@link ContentResponse} for the request
|
||||||
|
*/
|
||||||
|
public ContentResponse FORM(String uri, Fields fields) throws InterruptedException, ExecutionException, TimeoutException
|
||||||
|
{
|
||||||
|
return FORM(URI.create(uri), fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a POST request to the specified URI with the given form parameters.
|
||||||
|
*
|
||||||
|
* @param uri the URI to POST
|
||||||
|
* @param fields the fields composing the form name/value pairs
|
||||||
|
* @return the {@link ContentResponse} for the request
|
||||||
|
*/
|
||||||
|
public ContentResponse FORM(URI uri, Fields fields) throws InterruptedException, ExecutionException, TimeoutException
|
||||||
|
{
|
||||||
|
return POST(uri).content(new FormContentProvider(fields)).send();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a POST request to the specified URI.
|
* Creates a POST request to the specified URI.
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2014 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.client.util;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.charset.UnsupportedCharsetException;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.api.ContentProvider;
|
||||||
|
import org.eclipse.jetty.util.Fields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ContentProvider} for form uploads with the
|
||||||
|
* "application/x-www-form-urlencoded" content type.
|
||||||
|
*/
|
||||||
|
public class FormContentProvider extends StringContentProvider
|
||||||
|
{
|
||||||
|
public FormContentProvider(Fields fields)
|
||||||
|
{
|
||||||
|
this(fields, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FormContentProvider(Fields fields, Charset charset)
|
||||||
|
{
|
||||||
|
super("application/x-www-form-urlencoded", convert(fields, charset), charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convert(Fields fields)
|
||||||
|
{
|
||||||
|
return convert(fields, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convert(Fields fields, Charset charset)
|
||||||
|
{
|
||||||
|
// Assume 32 chars between name and value.
|
||||||
|
StringBuilder builder = new StringBuilder(fields.getSize() * 32);
|
||||||
|
for (Fields.Field field : fields)
|
||||||
|
{
|
||||||
|
for (String value : field.getValues())
|
||||||
|
{
|
||||||
|
if (builder.length() > 0)
|
||||||
|
builder.append("&");
|
||||||
|
builder.append(field.getName()).append("=").append(encode(value, charset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String encode(String value, Charset charset)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return URLEncoder.encode(value, charset.name());
|
||||||
|
}
|
||||||
|
catch (UnsupportedEncodingException x)
|
||||||
|
{
|
||||||
|
throw new UnsupportedCharsetException(charset.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2014 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.client.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.AbstractHttpClientServerTest;
|
||||||
|
import org.eclipse.jetty.client.api.ContentResponse;
|
||||||
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
|
import org.eclipse.jetty.http.MimeTypes;
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
import org.eclipse.jetty.util.Fields;
|
||||||
|
import org.eclipse.jetty.util.IO;
|
||||||
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class TypedContentProviderTest extends AbstractHttpClientServerTest
|
||||||
|
{
|
||||||
|
public TypedContentProviderTest(SslContextFactory sslContextFactory)
|
||||||
|
{
|
||||||
|
super(sslContextFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormContentProvider() throws Exception
|
||||||
|
{
|
||||||
|
final String name1 = "a";
|
||||||
|
final String value1 = "1";
|
||||||
|
final String name2 = "b";
|
||||||
|
final String value2 = "2";
|
||||||
|
final String value3 = "\u20AC";
|
||||||
|
|
||||||
|
start(new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
Assert.assertEquals("POST", request.getMethod());
|
||||||
|
Assert.assertEquals(MimeTypes.Type.FORM_ENCODED.asString(), request.getContentType());
|
||||||
|
Assert.assertEquals(value1, request.getParameter(name1));
|
||||||
|
String[] values = request.getParameterValues(name2);
|
||||||
|
Assert.assertNotNull(values);
|
||||||
|
Assert.assertEquals(2, values.length);
|
||||||
|
Assert.assertThat(values, Matchers.arrayContainingInAnyOrder(value2, value3));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Fields fields = new Fields();
|
||||||
|
fields.put(name1, value1);
|
||||||
|
fields.add(name2, value2);
|
||||||
|
fields.add(name2, value3);
|
||||||
|
ContentResponse response = client.FORM(scheme + "://localhost:" + connector.getLocalPort(), fields);
|
||||||
|
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormContentProviderWithDifferentContentType() throws Exception
|
||||||
|
{
|
||||||
|
final String name1 = "a";
|
||||||
|
final String value1 = "1";
|
||||||
|
final String name2 = "b";
|
||||||
|
final String value2 = "2";
|
||||||
|
Fields fields = new Fields();
|
||||||
|
fields.put(name1, value1);
|
||||||
|
fields.add(name2, value2);
|
||||||
|
final String content = FormContentProvider.convert(fields);
|
||||||
|
final String contentType = "text/plain;charset=UTF-8";
|
||||||
|
|
||||||
|
start(new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
Assert.assertEquals("POST", request.getMethod());
|
||||||
|
Assert.assertEquals(contentType, request.getContentType());
|
||||||
|
Assert.assertEquals(content, IO.toString(request.getInputStream()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||||
|
.scheme(scheme)
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.content(new FormContentProvider(fields))
|
||||||
|
.header(HttpHeader.CONTENT_TYPE, contentType)
|
||||||
|
.send();
|
||||||
|
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTypedContentProviderWithNoContentType() throws Exception
|
||||||
|
{
|
||||||
|
final String content = "data";
|
||||||
|
|
||||||
|
start(new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
Assert.assertEquals("GET", request.getMethod());
|
||||||
|
Assert.assertNull(request.getContentType());
|
||||||
|
Assert.assertEquals(content, IO.toString(request.getInputStream()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||||
|
.scheme(scheme)
|
||||||
|
.content(new StringContentProvider(null, content, StandardCharsets.UTF_8))
|
||||||
|
.send();
|
||||||
|
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue