added new annotation @PartParam for multipart form support

This commit is contained in:
Adrian Cole 2010-06-09 17:00:18 -07:00
parent fae1a1930e
commit ab5e8b3ab4
10 changed files with 285 additions and 94 deletions

View File

@ -18,12 +18,6 @@
*/ */
package org.jclouds.blobstore.binders; package org.jclouds.blobstore.binders;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
@ -32,9 +26,6 @@ import org.jclouds.http.MultipartForm;
import org.jclouds.http.MultipartForm.Part; import org.jclouds.http.MultipartForm.Part;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
@ -45,36 +36,14 @@ public class BindBlobToMultipartForm implements Binder {
public void bindToRequest(HttpRequest request, Object payload) { public void bindToRequest(HttpRequest request, Object payload) {
Blob object = (Blob) payload; Blob object = (Blob) payload;
File file = new File(object.getMetadata().getName());
Multimap<String, String> partHeaders = ImmutableMultimap.of("Content-Disposition", String Part part = Part.create(object.getMetadata().getName(), object.getPayload(), object
.format("form-data; name=\"%s\"; filename=\"%s\"", file.getName(), file.getName()), .getMetadata().getContentType());
HttpHeaders.CONTENT_TYPE, checkNotNull(object.getMetadata().getContentType(),
"object.metadata.contentType()"));
Object data = checkNotNull(object.getPayload(), "object.getPayload()").getRawContent();
Part part;
try {
if (data instanceof byte[]) {
part = new Part(partHeaders, (byte[]) data);
} else if (data instanceof String) {
part = new Part(partHeaders, (String) data);
} else if (data instanceof File) {
part = new Part(partHeaders, (File) data);
} else if (data instanceof InputStream) {
part = new Part(partHeaders, (InputStream) data, object.getContentLength());
} else {
throw new IllegalArgumentException("type of part not supported: "
+ data.getClass().getCanonicalName() + "; " + object);
}
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("file for part not found: " + object);
}
MultipartForm form = new MultipartForm(BOUNDARY, part); MultipartForm form = new MultipartForm(BOUNDARY, part);
request.setPayload(form.getData()); request.setPayload(form.getData());
request.getHeaders().put(HttpHeaders.CONTENT_TYPE, request.getHeaders().put(HttpHeaders.CONTENT_TYPE,
"multipart/form-data; boundary=" + BOUNDARY); "multipart/form-data; boundary=" + BOUNDARY);
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, form.getSize() + ""); request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, form.getSize() + "");
} }
} }

View File

@ -62,7 +62,7 @@ public class BindBlobToMultipartFormTest {
public void testSinglePart() throws IOException { public void testSinglePart() throws IOException {
assertEquals(EXPECTS.length(), 131); assertEquals(EXPECTS.length(), 113);
BindBlobToMultipartForm binder = new BindBlobToMultipartForm(); BindBlobToMultipartForm binder = new BindBlobToMultipartForm();
@ -71,7 +71,7 @@ public class BindBlobToMultipartFormTest {
assertEquals(Utils.toStringAndClose((InputStream) request.getPayload().getRawContent()), assertEquals(Utils.toStringAndClose((InputStream) request.getPayload().getRawContent()),
EXPECTS); EXPECTS);
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), 131 + ""); assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), 113 + "");
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE), assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE),
"multipart/form-data; boundary=" + BOUNDRY); "multipart/form-data; boundary=" + BOUNDRY);
@ -80,7 +80,7 @@ public class BindBlobToMultipartFormTest {
private static void addData(String boundary, String data, StringBuilder builder) { private static void addData(String boundary, String data, StringBuilder builder) {
builder.append(boundary).append("\r\n"); builder.append(boundary).append("\r\n");
builder.append("Content-Disposition").append(": ").append( builder.append("Content-Disposition").append(": ").append(
"form-data; name=\"hello\"; filename=\"hello\"").append("\r\n"); "form-data; name=\"hello\"").append("\r\n");
builder.append("Content-Type").append(": ").append("text/plain").append("\r\n"); builder.append("Content-Type").append(": ").append("text/plain").append("\r\n");
builder.append("\r\n"); builder.append("\r\n");
builder.append(data).append("\r\n"); builder.append(data).append("\r\n");

View File

@ -18,18 +18,24 @@
*/ */
package org.jclouds.http; package org.jclouds.http;
import java.io.ByteArrayInputStream; import static com.google.common.base.Preconditions.checkNotNull;
import java.io.File;
import java.io.FileInputStream; import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashMap;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.jclouds.util.InputStreamChain; import javax.annotation.Nullable;
import org.jclouds.util.Utils; import javax.ws.rs.core.HttpHeaders;
import org.jclouds.http.payloads.FilePayload;
import org.jclouds.util.InputStreamChain;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
/** /**
* *
@ -57,9 +63,9 @@ public class MultipartForm {
} }
private void addData(Part part) { private void addData(Part part) {
chain.addInputStream(part.getData()); chain.addInputStream(part.getContent());
chain.addAsInputStream(rn); chain.addAsInputStream(rn);
size += part.getSize() + rn.length(); size += part.calculateSize() + rn.length();
} }
private void addHeaders(String boundaryrn, Part part) { private void addHeaders(String boundaryrn, Part part) {
@ -83,39 +89,112 @@ public class MultipartForm {
this("__redrose__", parts); this("__redrose__", parts);
} }
public static class Part { public static class Part implements Payload {
private final Multimap<String, String> headers; private final Multimap<String, String> headers;
private final InputStream data; private final Payload delegate;
private final long size;
public Part(Multimap<String, String> headers, InputStream data, long size) { private static class PartMap extends LinkedHashMap<String, String> {
this.headers = headers;
this.data = data; /** The serialVersionUID */
this.size = size; private static final long serialVersionUID = -287387556008320212L;
static PartMap create(String name) {
PartMap map = new PartMap();
map.put("Content-Disposition", String.format("form-data; name=\"%s\"", checkNotNull(
name, "name")));
return map;
}
static PartMap create(String name, String filename) {
PartMap map = new PartMap();
map.put("Content-Disposition", String.format("form-data; name=\"%s\"; filename=\"%s\"",
checkNotNull(name, "name"), checkNotNull(filename, "filename")));
return map;
}
PartMap contentType(@Nullable String type) {
if (type != null)
put(HttpHeaders.CONTENT_TYPE, checkNotNull(type, "type"));
return this;
}
} }
public Part(Multimap<String, String> headers, String data) { private Part(PartMap map, Payload delegate) {
this(headers, Utils.toInputStream(data), data.length()); this.delegate = checkNotNull(delegate, "delegate");
this.headers = ImmutableMultimap.copyOf(Multimaps.forMap((checkNotNull(map, "headers"))));
} }
public Part(Multimap<String, String> headers, File data) throws FileNotFoundException { public static Part create(String name, String value) {
this(headers, new FileInputStream(data), data.length()); return new Part(PartMap.create(name), Payloads.newStringPayload(value));
} }
public Part(Multimap<String, String> headers, byte[] data) { public static Part create(String name, Payload delegate, String contentType) {
this(headers, new ByteArrayInputStream(data), data.length); return new Part(PartMap.create(name).contentType(contentType), delegate);
}
public static Part create(String name, FilePayload delegate, String contentType) {
return new Part(PartMap.create(name, delegate.getRawContent().getName()).contentType(
contentType), delegate);
} }
public Multimap<String, String> getHeaders() { public Multimap<String, String> getHeaders() {
return headers; return headers;
} }
public InputStream getData() { @Override
return data; public Long calculateSize() {
return delegate.calculateSize();
} }
public long getSize() { @Override
return size; public InputStream getContent() {
return delegate.getContent();
}
@Override
public Object getRawContent() {
return delegate.getContent();
}
@Override
public boolean isRepeatable() {
return delegate.isRepeatable();
}
@Override
public void writeTo(OutputStream outstream) throws IOException {
delegate.writeTo(outstream);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((delegate == null) ? 0 : delegate.hashCode());
result = prime * result + ((headers == null) ? 0 : headers.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Part other = (Part) obj;
if (delegate == null) {
if (other.delegate != null)
return false;
} else if (!delegate.equals(other.delegate))
return false;
if (headers == null) {
if (other.headers != null)
return false;
} else if (!headers.equals(other.headers))
return false;
return true;
} }
} }

View File

@ -24,9 +24,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.jclouds.http.MultipartForm.Part; import javax.ws.rs.core.MediaType;
import com.google.common.base.Function;
/** /**
* Designates that this parameter will be bound to a multipart form. * Designates that this parameter will be bound to a multipart form.
@ -36,17 +34,7 @@ import com.google.common.base.Function;
@Target(PARAMETER) @Target(PARAMETER)
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface PartParam { public @interface PartParam {
String name();
public static class ALREADY_PART implements Function<Object, Part> { String contentType() default MediaType.TEXT_PLAIN;
@Override
public Part apply(Object from) {
return Part.class.cast(from);
}
};
/**
* how to convert this to a part.
*/
Class<? extends Function<Object, Part>> value() default ALREADY_PART.class;
} }

View File

@ -62,6 +62,7 @@ import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.http.MultipartForm; import org.jclouds.http.MultipartForm;
import org.jclouds.http.Payloads;
import org.jclouds.http.MultipartForm.Part; import org.jclouds.http.MultipartForm.Part;
import org.jclouds.http.functions.CloseContentAndReturn; import org.jclouds.http.functions.CloseContentAndReturn;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
@ -102,7 +103,6 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.LinkedListMultimap;
@ -195,8 +195,7 @@ public class RestAnnotationProcessor<T> {
@Override @Override
public Part apply(Entry<String, String> from) { public Part apply(Entry<String, String> from) {
return new Part(ImmutableMultimap.of("Content-Disposition", String.format( return Part.create(from.getKey(), from.getValue());
"form-data; name=\"%s\"", from.getKey())), from.getValue());
} }
}; };
@ -1012,8 +1011,9 @@ public class RestAnnotationProcessor<T> {
.get(method); .get(method);
for (Entry<Integer, Set<Annotation>> entry : indexToPartParam.entrySet()) { for (Entry<Integer, Set<Annotation>> entry : indexToPartParam.entrySet()) {
for (Annotation key : entry.getValue()) { for (Annotation key : entry.getValue()) {
PartParam extractor = (PartParam) key; PartParam param = (PartParam) key;
Part part = injector.getInstance(extractor.value()).apply(args[entry.getKey()]); Part part = Part.create(param.name(), Payloads.newPayload(args[entry.getKey()]), param
.contentType());
parts.add(part); parts.add(part);
} }
} }

View File

@ -18,19 +18,24 @@
*/ */
package org.jclouds.http; package org.jclouds.http;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.jclouds.http.MultipartForm.Part; import org.jclouds.http.MultipartForm.Part;
import org.jclouds.http.payloads.FilePayload;
import org.jclouds.http.payloads.StringPayload;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
/** /**
* Tests parsing of a request * Tests parsing of a request
* *
@ -54,10 +59,47 @@ public class MultipartFormTest {
assertEquals(multipartForm.getSize(), 199); assertEquals(multipartForm.getSize(), 199);
} }
public static class MockFilePayload extends FilePayload {
private final StringPayload realPayload;
public MockFilePayload(String content) {
super(createMockFile(content));
this.realPayload = Payloads.newStringPayload(content);
}
private static File createMockFile(String content) {
File file = createMock(File.class);
expect(file.exists()).andReturn(true);
expect(file.getName()).andReturn("testfile.txt");
replay(file);
return file;
}
@Override
public Long calculateSize() {
return realPayload.calculateSize();
}
@Override
public InputStream getContent() {
return realPayload.getContent();
}
@Override
public boolean isRepeatable() {
return realPayload.isRepeatable();
}
@Override
public void writeTo(OutputStream outstream) throws IOException {
realPayload.writeTo(outstream);
}
}
private Part newPart(String data) { private Part newPart(String data) {
return new MultipartForm.Part(ImmutableMultimap.of("Content-Disposition", return Part.create("file", new MockFilePayload(data), MediaType.TEXT_PLAIN);
"form-data; name=\"file\"; filename=\"testfile.txt\"", HttpHeaders.CONTENT_TYPE,
MediaType.TEXT_PLAIN), data);
} }
private void addData(String boundary, String data, StringBuilder builder) { private void addData(String boundary, String data, StringBuilder builder) {

View File

@ -23,6 +23,7 @@ import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull; import static org.testng.Assert.assertNull;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -98,6 +99,7 @@ import org.jclouds.rest.annotations.MapPayloadParam;
import org.jclouds.rest.annotations.MatrixParams; import org.jclouds.rest.annotations.MatrixParams;
import org.jclouds.rest.annotations.OverrideRequestFilters; import org.jclouds.rest.annotations.OverrideRequestFilters;
import org.jclouds.rest.annotations.ParamParser; import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.PartParam;
import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser; import org.jclouds.rest.annotations.ResponseParser;
@ -114,6 +116,7 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -123,6 +126,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.io.Files;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.ConfigurationException; import com.google.inject.ConfigurationException;
@ -612,6 +616,115 @@ public class RestAnnotationProcessorTest {
assertEquals(httpMethod.getPayload().toString(), expected); assertEquals(httpMethod.getPayload().toString(), expected);
} }
@Endpoint(Localhost.class)
static interface TestMultipartForm {
@POST
public void withStringPart(@PartParam(name = "fooble") String path);
@POST
public void withParamStringPart(@FormParam("name") String name,
@PartParam(name = "file") String path);
@POST
public void withParamFilePart(@FormParam("name") String name,
@PartParam(name = "file") File path);
@POST
public void withParamFileBinaryPart(@FormParam("name") String name,
@PartParam(name = "file", contentType = MediaType.APPLICATION_OCTET_STREAM) File path);
}
public void testMultipartWithStringPart() throws SecurityException, NoSuchMethodException,
IOException {
Method method = TestMultipartForm.class.getMethod("withStringPart", String.class);
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class)
.createRequest(method, "foobledata");
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
assertHeadersEqual(httpRequest,
"Content-Length: 119\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
assertPayloadEquals(httpRequest,//
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"fooble\"\r\n" + //
"Content-Type: text/plain\r\n" + //
"\r\n" + //
"foobledata\r\n" + //
"----JCLOUDS----\r\n");
}
public void testMultipartWithParamStringPart() throws SecurityException, NoSuchMethodException,
IOException {
Method method = TestMultipartForm.class.getMethod("withParamStringPart", String.class,
String.class);
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class)
.createRequest(method, "name", "foobledata");
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
assertHeadersEqual(httpRequest,
"Content-Length: 185\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
assertPayloadEquals(httpRequest,//
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"\r\n" + //
"Content-Type: text/plain\r\n" + //
"\r\n" + //
"foobledata\r\n" + //
"----JCLOUDS----\r\n");
}
public void testMultipartWithParamFilePart() throws SecurityException, NoSuchMethodException,
IOException {
Method method = TestMultipartForm.class.getMethod("withParamFilePart", String.class,
File.class);
File file = File.createTempFile("foo", "bar");
Files.append("foobledata", file, Charsets.UTF_8);
file.deleteOnExit();
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class)
.createRequest(method, "name", file);
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
assertHeadersEqual(httpRequest,
"Content-Length: 185\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
assertPayloadEquals(httpRequest,//
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"\r\n" + //
"Content-Type: text/plain\r\n" + //
"\r\n" + //
"foobledata\r\n" + //
"----JCLOUDS----\r\n");
}
public void testMultipartWithParamFileBinaryPart() throws SecurityException,
NoSuchMethodException, IOException {
Method method = TestMultipartForm.class.getMethod("withParamFileBinaryPart", String.class,
File.class);
File file = File.createTempFile("foo", "bar");
Files.write(new byte[] { 17, 26, 39, 40, 50 }, file);
file.deleteOnExit();
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class)
.createRequest(method, "name", file);
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
assertHeadersEqual(httpRequest,
"Content-Length: 194\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
assertPayloadEquals(httpRequest,//
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"\r\n" + //
"Content-Type: application/octet-stream\r\n" + //
"\r\n" + //
"'(2\r\n" + //
"----JCLOUDS----\r\n");
}
@Endpoint(Localhost.class) @Endpoint(Localhost.class)
public class TestPut { public class TestPut {
@PUT @PUT

View File

@ -164,7 +164,7 @@ public class PCSAsyncClientTest extends RestClientTest<PCSAsyncClient> {
assertRequestLineEquals(httpMethod, "POST http://localhost/mycontainer/contents HTTP/1.1"); assertRequestLineEquals(httpMethod, "POST http://localhost/mycontainer/contents HTTP/1.1");
assertHeadersEqual(httpMethod, assertHeadersEqual(httpMethod,
"Content-Length: 131\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n"); "Content-Length: 113\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
assertPayloadEquals(httpMethod, BindBlobToMultipartFormTest.EXPECTS); assertPayloadEquals(httpMethod, BindBlobToMultipartFormTest.EXPECTS);
assertResponseParserClassEquals(method, httpMethod, assertResponseParserClassEquals(method, httpMethod,

View File

@ -92,14 +92,14 @@
<category name="jclouds.headers"> <category name="jclouds.headers">
<priority value="DEBUG" /> <priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" /> <appender-ref ref="ASYNCWIRE" />
</category><!-- </category>
<category name="jclouds.wire"> <category name="jclouds.wire">
<priority value="DEBUG" /> <priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" /> <appender-ref ref="ASYNCWIRE" />
</category> </category>
--><!-- ======================= --> <!-- ======================= -->
<!-- Setup the Root category --> <!-- Setup the Root category -->
<!-- ======================= --> <!-- ======================= -->

View File

@ -84,10 +84,10 @@ public class SDNAsyncClientTest extends RestClientTest<SDNAsyncClient> {
httpMethod, httpMethod,
"POST http://uploader/Upload.ashx?output=json&destFolderPath=adriansmovies&uploadToken=token HTTP/1.1"); "POST http://uploader/Upload.ashx?output=json&destFolderPath=adriansmovies&uploadToken=token HTTP/1.1");
assertHeadersEqual(httpMethod, assertHeadersEqual(httpMethod,
"Content-Length: 131\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n"); "Content-Length: 113\nContent-Type: multipart/form-data; boundary=--JCLOUDS--\n");
StringBuffer expects = new StringBuffer(); StringBuffer expects = new StringBuffer();
expects.append("----JCLOUDS--\r\n"); expects.append("----JCLOUDS--\r\n");
expects.append("Content-Disposition: form-data; name=\"hello\"; filename=\"hello\"\r\n"); expects.append("Content-Disposition: form-data; name=\"hello\"\r\n");
expects.append("Content-Type: text/plain\r\n\r\n"); expects.append("Content-Type: text/plain\r\n\r\n");
expects.append("hello\r\n"); expects.append("hello\r\n");
expects.append("----JCLOUDS----\r\n"); expects.append("----JCLOUDS----\r\n");