diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java index 82ea5f02b0d..bfeb16afa0e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java @@ -110,6 +110,15 @@ public abstract class HttpConnection implements Connection // Add content headers if (content != null) { + if (content instanceof ContentProvider.Typed) + { + if (!headers.containsKey(HttpHeader.CONTENT_TYPE.asString())) + { + String contentType = ((ContentProvider.Typed)content).getContentType(); + if (contentType != null) + headers.put(HttpHeader.CONTENT_TYPE, contentType); + } + } long contentLength = content.getLength(); if (contentLength >= 0) { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java index 5f2590c6f78..9ec21ca7da8 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java @@ -549,9 +549,7 @@ public class HttpRequest implements Request @Override public Request file(Path file, String contentType) throws IOException { - if (contentType != null) - header(HttpHeader.CONTENT_TYPE, contentType); - return content(new PathContentProvider(file)); + return content(new PathContentProvider(contentType, file)); } @Override diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java index f8bcd4642d7..371b22bd821 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java @@ -28,17 +28,15 @@ import org.eclipse.jetty.client.util.PathContentProvider; /** * {@link ContentProvider} provides a source of request content. - *

+ *

* Implementations should return an {@link Iterator} over the request content. * If the request content comes from a source that needs to be closed (for * example, an {@link InputStream}), then the iterator implementation class * must implement {@link Closeable} and will be closed when the request is * completed (either successfully or failed). - *

+ *

* Applications should rely on utility classes such as {@link ByteBufferContentProvider} * or {@link PathContentProvider}. - *

- * */ public interface ContentProvider extends Iterable { @@ -46,4 +44,17 @@ public interface ContentProvider extends Iterable * @return the content length, if known, or -1 if the content length is unknown */ long getLength(); + + /** + * An extension of {@link ContentProvider} that provides a content type string + * to be used as a {@code Content-Type} HTTP header in requests. + */ + public interface Typed extends ContentProvider + { + /** + * @return the content type string such as "application/octet-stream" or + * "application/json;charset=UTF8", or null if no content type must be set + */ + public String getContentType(); + } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractTypedContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractTypedContentProvider.java new file mode 100644 index 00000000000..39da5a0ee1f --- /dev/null +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractTypedContentProvider.java @@ -0,0 +1,37 @@ +// +// ======================================================================== +// 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 org.eclipse.jetty.client.api.ContentProvider; + +public abstract class AbstractTypedContentProvider implements ContentProvider.Typed +{ + private final String contentType; + + protected AbstractTypedContentProvider(String contentType) + { + this.contentType = contentType; + } + + @Override + public String getContentType() + { + return contentType; + } +} diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java index dcf0022fde6..e8a695f0d63 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java @@ -31,13 +31,19 @@ import org.eclipse.jetty.client.api.ContentProvider; * and each invocation of the {@link #iterator()} method returns a {@link ByteBuffer#slice() slice} * of the original {@link ByteBuffer}. */ -public class ByteBufferContentProvider implements ContentProvider +public class ByteBufferContentProvider extends AbstractTypedContentProvider { private final ByteBuffer[] buffers; private final int length; public ByteBufferContentProvider(ByteBuffer... buffers) { + this("application/octet-stream", buffers); + } + + public ByteBufferContentProvider(String contentType, ByteBuffer... buffers) + { + super(contentType); this.buffers = buffers; int length = 0; for (ByteBuffer buffer : buffers) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java index dae7c2ef666..7b356ef1a63 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java @@ -27,13 +27,19 @@ import org.eclipse.jetty.client.api.ContentProvider; /** * A {@link ContentProvider} for byte arrays. */ -public class BytesContentProvider implements ContentProvider +public class BytesContentProvider extends AbstractTypedContentProvider { private final byte[][] bytes; private final long length; public BytesContentProvider(byte[]... bytes) { + this("application/octet-stream", bytes); + } + + public BytesContentProvider(String contentType, byte[]... bytes) + { + super(contentType); this.bytes = bytes; long length = 0; for (byte[] buffer : bytes) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java index de79b973727..676c7916091 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java @@ -40,7 +40,7 @@ import org.eclipse.jetty.util.log.Logger; * It is possible to specify, at the constructor, a buffer size used to read content from the * stream, by default 4096 bytes. */ -public class PathContentProvider implements ContentProvider +public class PathContentProvider extends AbstractTypedContentProvider { private static final Logger LOG = Log.getLogger(PathContentProvider.class); @@ -55,6 +55,17 @@ public class PathContentProvider implements ContentProvider public PathContentProvider(Path filePath, int bufferSize) throws IOException { + this("application/octet-stream", filePath, bufferSize); + } + + public PathContentProvider(String contentType, Path filePath) throws IOException + { + this(contentType, filePath, 4096); + } + + public PathContentProvider(String contentType, Path filePath, int bufferSize) throws IOException + { + super(contentType); if (!Files.isRegularFile(filePath)) throw new NoSuchFileException(filePath.toString()); if (!Files.isReadable(filePath)) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java index 1f8a83eb4b6..7475c3febf7 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java @@ -43,6 +43,11 @@ public class StringContentProvider extends BytesContentProvider public StringContentProvider(String content, Charset charset) { - super(content.getBytes(charset)); + this("text/plain;charset=" + charset.name(), content, charset); + } + + public StringContentProvider(String contentType, String content, Charset charset) + { + super(contentType, content.getBytes(charset)); } }