432939 - Jetty Client ContentResponse should have methods such as getContentType() and getMediaType().
Introduced ContentResponse.getMediaType() and ContentResponse .getEncoding(), as well as BufferingResponseListener.getMediaType() to make the media type and the encoding available to applications.
This commit is contained in:
parent
b603964bb6
commit
d75b9177c5
|
@ -82,7 +82,7 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
|
|||
public void onComplete(Result result)
|
||||
{
|
||||
HttpRequest request = (HttpRequest)result.getRequest();
|
||||
ContentResponse response = new HttpContentResponse(result.getResponse(), getContent(), getEncoding());
|
||||
ContentResponse response = new HttpContentResponse(result.getResponse(), getContent(), getMediaType(), getEncoding());
|
||||
if (result.isFailed())
|
||||
{
|
||||
Throwable failure = result.getFailure();
|
||||
|
|
|
@ -88,7 +88,7 @@ public class ContinueProtocolHandler implements ProtocolHandler
|
|||
// or it does and wants to refuse the request content,
|
||||
// or we got some other HTTP status code like a redirect.
|
||||
List<Response.ResponseListener> listeners = exchange.getResponseListeners();
|
||||
HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getEncoding());
|
||||
HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding());
|
||||
notifier.forwardSuccess(listeners, contentResponse);
|
||||
exchange.proceed(new HttpRequestException("Expectation failed", exchange.getRequest()));
|
||||
break;
|
||||
|
@ -108,7 +108,7 @@ public class ContinueProtocolHandler implements ProtocolHandler
|
|||
HttpExchange exchange = conversation.getExchanges().peekLast();
|
||||
assert exchange.getResponse() == response;
|
||||
List<Response.ResponseListener> listeners = exchange.getResponseListeners();
|
||||
HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getEncoding());
|
||||
HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding());
|
||||
notifier.forwardFailureComplete(listeners, exchange.getRequest(), exchange.getRequestFailure(), contentResponse, failure);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,12 +33,14 @@ public class HttpContentResponse implements ContentResponse
|
|||
{
|
||||
private final Response response;
|
||||
private final byte[] content;
|
||||
private final String mediaType;
|
||||
private final String encoding;
|
||||
|
||||
public HttpContentResponse(Response response, byte[] content, String encoding)
|
||||
public HttpContentResponse(Response response, byte[] content, String mediaType, String encoding)
|
||||
{
|
||||
this.response = response;
|
||||
this.content = content;
|
||||
this.mediaType = mediaType;
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
|
@ -84,6 +86,18 @@ public class HttpContentResponse implements ContentResponse
|
|||
return response.abort(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMediaType()
|
||||
{
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEncoding()
|
||||
{
|
||||
return encoding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContent()
|
||||
{
|
||||
|
|
|
@ -118,7 +118,7 @@ public class HttpRedirector
|
|||
{
|
||||
resultRef.set(new Result(result.getRequest(),
|
||||
result.getRequestFailure(),
|
||||
new HttpContentResponse(result.getResponse(), getContent(), getEncoding()),
|
||||
new HttpContentResponse(result.getResponse(), getContent(), getMediaType(), getEncoding()),
|
||||
result.getResponseFailure()));
|
||||
latch.countDown();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,16 @@ package org.eclipse.jetty.client.api;
|
|||
*/
|
||||
public interface ContentResponse extends Response
|
||||
{
|
||||
/**
|
||||
* @return the media type of the content, such as "text/html" or "application/octet-stream"
|
||||
*/
|
||||
String getMediaType();
|
||||
|
||||
/**
|
||||
* @return the encoding of the content, such as "UTF-8"
|
||||
*/
|
||||
String getEncoding();
|
||||
|
||||
/**
|
||||
* @return the response content
|
||||
*/
|
||||
|
|
|
@ -236,7 +236,7 @@ public interface Request
|
|||
Request agent(String agent);
|
||||
|
||||
/**
|
||||
* @param accepts the content types that are acceptable in the response, such as
|
||||
* @param accepts the media types that are acceptable in the response, such as
|
||||
* "text/plain;q=0.5" or "text/html" (corresponds to the {@code Accept} header)
|
||||
* @return this request object
|
||||
*/
|
||||
|
|
|
@ -20,12 +20,9 @@ package org.eclipse.jetty.client.util;
|
|||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
|
@ -45,6 +42,7 @@ public abstract class BufferingResponseListener extends Listener.Adapter
|
|||
{
|
||||
private final int maxLength;
|
||||
private volatile ByteBuffer buffer;
|
||||
private volatile String mediaType;
|
||||
private volatile String encoding;
|
||||
|
||||
/**
|
||||
|
@ -62,14 +60,14 @@ public abstract class BufferingResponseListener extends Listener.Adapter
|
|||
*/
|
||||
public BufferingResponseListener(int maxLength)
|
||||
{
|
||||
this.maxLength=maxLength;
|
||||
this.maxLength = maxLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeaders(Response response)
|
||||
{
|
||||
super.onHeaders(response);
|
||||
|
||||
|
||||
HttpFields headers = response.getHeaders();
|
||||
long length = headers.getLongField(HttpHeader.CONTENT_LENGTH.asString());
|
||||
if (length > maxLength)
|
||||
|
@ -77,47 +75,58 @@ public abstract class BufferingResponseListener extends Listener.Adapter
|
|||
response.abort(new IllegalArgumentException("Buffering capacity exceeded"));
|
||||
return;
|
||||
}
|
||||
|
||||
buffer=BufferUtil.allocate((length > 0)?(int)length:1024);
|
||||
|
||||
|
||||
buffer = BufferUtil.allocate(length > 0 ? (int)length : 1024);
|
||||
|
||||
String contentType = headers.get(HttpHeader.CONTENT_TYPE);
|
||||
if (contentType != null)
|
||||
{
|
||||
String media = contentType;
|
||||
|
||||
String charset = "charset=";
|
||||
int index = contentType.toLowerCase(Locale.ENGLISH).indexOf(charset);
|
||||
if (index > 0)
|
||||
{
|
||||
media = contentType.substring(0, index);
|
||||
String encoding = contentType.substring(index + charset.length());
|
||||
// Sometimes charsets arrive with an ending semicolon
|
||||
index = encoding.indexOf(';');
|
||||
if (index > 0)
|
||||
encoding = encoding.substring(0, index);
|
||||
int semicolon = encoding.indexOf(';');
|
||||
if (semicolon > 0)
|
||||
encoding = encoding.substring(0, semicolon).trim();
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
int semicolon = media.indexOf(';');
|
||||
if (semicolon > 0)
|
||||
media = media.substring(0, semicolon).trim();
|
||||
this.mediaType = media;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContent(Response response, ByteBuffer content)
|
||||
{
|
||||
{
|
||||
int length = content.remaining();
|
||||
if (length>BufferUtil.space(buffer))
|
||||
if (length > BufferUtil.space(buffer))
|
||||
{
|
||||
int requiredCapacity = buffer==null?0:buffer.capacity()+length;
|
||||
if (requiredCapacity>maxLength)
|
||||
int requiredCapacity = buffer == null ? 0 : buffer.capacity() + length;
|
||||
if (requiredCapacity > maxLength)
|
||||
response.abort(new IllegalArgumentException("Buffering capacity exceeded"));
|
||||
|
||||
int newCapacity = Math.min(Integer.highestOneBit(requiredCapacity) << 1, maxLength);
|
||||
buffer = BufferUtil.ensureCapacity(buffer,newCapacity);
|
||||
}
|
||||
|
||||
int newCapacity = Math.min(Integer.highestOneBit(requiredCapacity) << 1, maxLength);
|
||||
buffer = BufferUtil.ensureCapacity(buffer, newCapacity);
|
||||
}
|
||||
BufferUtil.append(buffer, content);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void onComplete(Result result);
|
||||
|
||||
public String getMediaType()
|
||||
{
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
public String getEncoding()
|
||||
{
|
||||
return encoding;
|
||||
|
@ -129,14 +138,14 @@ public abstract class BufferingResponseListener extends Listener.Adapter
|
|||
*/
|
||||
public byte[] getContent()
|
||||
{
|
||||
if (buffer==null)
|
||||
if (buffer == null)
|
||||
return new byte[0];
|
||||
return BufferUtil.toArray(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the content as a string, using the "Content-Type" header to detect the encoding
|
||||
* or defaulting to UTF-8 if the encoding could not be detected.
|
||||
* or defaulting to UTF-8 if the encoding could not be detected.
|
||||
* @see #getContentAsString(String)
|
||||
*/
|
||||
public String getContentAsString()
|
||||
|
@ -154,7 +163,7 @@ public abstract class BufferingResponseListener extends Listener.Adapter
|
|||
*/
|
||||
public String getContentAsString(String encoding)
|
||||
{
|
||||
if (buffer==null)
|
||||
if (buffer == null)
|
||||
return null;
|
||||
return BufferUtil.toString(buffer, Charset.forName(encoding));
|
||||
}
|
||||
|
@ -166,18 +175,17 @@ public abstract class BufferingResponseListener extends Listener.Adapter
|
|||
*/
|
||||
public String getContentAsString(Charset encoding)
|
||||
{
|
||||
if (buffer==null)
|
||||
if (buffer == null)
|
||||
return null;
|
||||
return BufferUtil.toString(buffer, encoding);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return Content as InputStream
|
||||
*/
|
||||
public InputStream getContentAsInputStream()
|
||||
{
|
||||
if (buffer==null)
|
||||
if (buffer == null)
|
||||
return new ByteArrayInputStream(new byte[]{});
|
||||
return new ByteArrayInputStream(buffer.array(), buffer.arrayOffset(), buffer.remaining());
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ public class FutureResponseListener extends BufferingResponseListener implements
|
|||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
response = new HttpContentResponse(result.getResponse(), getContent(), getEncoding());
|
||||
response = new HttpContentResponse(result.getResponse(), getContent(), getMediaType(), getEncoding());
|
||||
failure = result.getFailure();
|
||||
latch.countDown();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ContentResponseTest extends AbstractHttpClientServerTest
|
||||
{
|
||||
public ContentResponseTest(SslContextFactory sslContextFactory)
|
||||
{
|
||||
super(sslContextFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseWithoutContentType() throws Exception
|
||||
{
|
||||
final byte[] content = new byte[1024];
|
||||
new Random().nextBytes(content);
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.getOutputStream().write(content);
|
||||
}
|
||||
});
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertArrayEquals(content, response.getContent());
|
||||
Assert.assertNull(response.getMediaType());
|
||||
Assert.assertNull(response.getEncoding());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseWithMediaType() throws Exception
|
||||
{
|
||||
final String content = "The quick brown fox jumped over the lazy dog";
|
||||
final String mediaType = "text/plain";
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE.asString(), mediaType);
|
||||
response.getOutputStream().write(content.getBytes("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertEquals(content, response.getContentAsString());
|
||||
Assert.assertEquals(mediaType, response.getMediaType());
|
||||
Assert.assertNull(response.getEncoding());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseWithContentType() throws Exception
|
||||
{
|
||||
final String content = "The quick brown fox jumped over the lazy dog";
|
||||
final String mediaType = "text/plain";
|
||||
final String encoding = "UTF-8";
|
||||
final String contentType = mediaType + "; charset=" + encoding;
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE.asString(), contentType);
|
||||
response.getOutputStream().write(content.getBytes("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertEquals(content, response.getContentAsString());
|
||||
Assert.assertEquals(mediaType, response.getMediaType());
|
||||
Assert.assertEquals(encoding, response.getEncoding());
|
||||
}
|
||||
}
|
|
@ -739,7 +739,7 @@ public class ProxyServletTest
|
|||
protected void onResponseSuccess(HttpServletRequest request, HttpServletResponse response, Response proxyResponse)
|
||||
{
|
||||
byte[] content = temp.remove(request.getRequestURI()).toByteArray();
|
||||
ContentResponse cached = new HttpContentResponse(proxyResponse, content, null);
|
||||
ContentResponse cached = new HttpContentResponse(proxyResponse, content, null, null);
|
||||
cache.put(request.getRequestURI(), cached);
|
||||
super.onResponseSuccess(request, response, proxyResponse);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue