Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions WordPressComRest/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ afterEvaluate {
name 'Maxime Biais'
email 'maxime@automattic.com'
}

developer {
id 'hypest'
name 'Stefanos Togoulidis'
email 'stefanos.togoulidis@automattic.com'
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.wordpress.rest;

import com.android.volley.AuthFailureError;
import com.android.volley.Request;

import android.net.Uri;
import android.os.Debug;
import android.test.AndroidTestCase;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

public class RestRequestTest extends AndroidTestCase {
private File mTempFile;

@Override
protected void tearDown() throws Exception {
super.tearDown();

if (mTempFile != null) {
mTempFile.delete();
}
}

public void testMultiPartBodyAndContentType() throws AuthFailureError {
final String bodyStr = "request body";
final String bodyContentType = "multipart/form-data; boundary=---------------------1234";

RestRequest restRequest = new RestRequest(Request.Method.POST, "http://url", bodyStr.getBytes(),
bodyContentType, null, null);
assertEquals(bodyStr, new String(restRequest.getBody()));
assertEquals(bodyContentType, restRequest.getBodyContentType());
}

public void testMultiPartBuilderMimeType() throws AuthFailureError, IOException {
MultipartRequestBuilder mpb = new MultipartRequestBuilder();
final String boundary = mpb.getBoundary();

RestRequest request = mpb.build("http://url");
assertEquals("multipart/form-data; boundary=" + boundary, request.getBodyContentType());
}

public void testMultiPartBuilderText() throws AuthFailureError, IOException {
MultipartRequestBuilder mpb = new MultipartRequestBuilder();

final String simpleText = "simple text";
mpb.addPart(simpleText);

RestRequest restRequest = mpb.build("http://url");

// See "7.2.1 Multipart: The common syntax" at https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
final String encapsulationBoundary = "--" + mpb.getBoundary();

final String lineEnd = "\r\n";
assertEquals(encapsulationBoundary + lineEnd + simpleText + lineEnd, new String(restRequest.getBody()));
}

public void testMultiPartBuilderFile() throws AuthFailureError, IOException {
final byte[] bytes = new byte[] {5, 6, 7, 8, 9, 10};

mTempFile = new File(getContext().getCacheDir(), "tempFile.jpg");
FileOutputStream fos = new FileOutputStream(mTempFile);
fos.write(bytes);
fos.flush();
fos.close();

MultipartRequestBuilder mpb = new MultipartRequestBuilder();
mpb.addPart("data", mTempFile);
RestRequest restRequest = mpb.build("http://url");

// See "7.2.1 Multipart: The common syntax" at https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
final String encapsulationBoundary = "--" + mpb.getBoundary();

final String lineEnd = "\r\n";

String expected =
encapsulationBoundary + lineEnd
+ "Content-Disposition: form-data; name=\"data\"; filename=\"" + mTempFile.getName() + "\"" + lineEnd
+ lineEnd
+ new String(bytes)
+ lineEnd
+ encapsulationBoundary
+ "--" + lineEnd;

assertEquals(expected, new String(restRequest.getBody()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.wordpress.rest;

import com.android.volley.Request;
import com.android.volley.Response;

import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class MultipartRequestBuilder {

private final String TWO_HYPHENS = "--";
private final String LINE_END = "\r\n";

private String mBoundary = "-------------" + System.currentTimeMillis();
private String mMimeType = "multipart/form-data; boundary=" + mBoundary;

private ByteArrayOutputStream mByteArrayOutputStream;
private DataOutputStream mDataOutputStream;

private Response.Listener<JSONObject> mListener;
private Response.ErrorListener mErrorListener;

public MultipartRequestBuilder() {
mByteArrayOutputStream = new ByteArrayOutputStream();
mDataOutputStream = new DataOutputStream(mByteArrayOutputStream);
}

public String getBoundary() {
return mBoundary;
}

public String getMimeType() {
return mMimeType;
}

public MultipartRequestBuilder setResponseListener(Response.Listener<JSONObject> listener) {
mListener = listener;
return this;
}

public MultipartRequestBuilder setResponseErrorListener(Response.ErrorListener errorListener) {
mErrorListener = errorListener;
return this;
}

public MultipartRequestBuilder addPart(String textData) throws IOException {
mDataOutputStream.writeBytes(TWO_HYPHENS + mBoundary + LINE_END);
mDataOutputStream.writeBytes(textData);
mDataOutputStream.writeBytes(LINE_END);
return this;
}

public MultipartRequestBuilder addPart(String name, File file) throws IOException {
mDataOutputStream.writeBytes(TWO_HYPHENS + mBoundary + LINE_END);
mDataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"; filename=\""
+ file.getName() + "\"" + LINE_END);
// dataOutputStream.writeBytes("Content-Type: image/jpeg" + LINE_END);
mDataOutputStream.writeBytes(LINE_END);

InputStream inputStream = new FileInputStream(file);
byte[] buffer = new byte[1024];
int bytesRead = 0;

while ((bytesRead = inputStream.read(buffer)) != -1) {
mDataOutputStream.write(buffer, 0, bytesRead);
}

mDataOutputStream.writeBytes(LINE_END);
mDataOutputStream.writeBytes(TWO_HYPHENS + mBoundary + TWO_HYPHENS + LINE_END);
return this;
}

public MultipartRequestBuilder addPart(String parameterName, String parameterValue) throws IOException {
mDataOutputStream.writeBytes(TWO_HYPHENS + mBoundary + LINE_END);
mDataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + LINE_END);
mDataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + LINE_END);
mDataOutputStream.writeBytes(LINE_END);
mDataOutputStream.writeBytes(parameterValue + LINE_END);
return this;
}

public RestRequest build(String url) {
return new RestRequest(Request.Method.POST, url, mByteArrayOutputStream.toByteArray(), mMimeType, mListener,
mErrorListener);
}
}
43 changes: 43 additions & 0 deletions WordPressComRest/src/main/java/com/wordpress/rest/RestRequest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.wordpress.rest;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
Expand Down Expand Up @@ -36,11 +37,43 @@ public interface OnAuthFailedListener {
private final Map<String, String> mParams;
private final Map<String, String> mHeaders = new HashMap<String, String>(2);

private final byte[] mMultipartBody;
private final String mBodyContentType;

/**
* Prepare a REST request based on URL-encoded form data
* @param method HTTP method to execute
* @param url the URL to execute the request against
* @param params the map of form data pairs to encode
* @param listener the listener for successful completion
* @param errorListener the listener for failed completion
*/
public RestRequest(int method, String url, Map<String, String> params,
com.android.volley.Response.Listener<JSONObject> listener,
com.android.volley.Response.ErrorListener errorListener) {
super(method, url, errorListener);
mParams = params;
mMultipartBody = null;
mBodyContentType = null;
mListener = listener;
}

/**
* Prepare a REST request based on MultiPart form data
* @param method HTTP method to execute
* @param url the URL to execute the request against
* @param multipartBody the byte array of the body
* @param bodyContentType the body content type including the parts boundary string
* @param listener the listener for successful completion
* @param errorListener the listener for failed completion
*/
public RestRequest(int method, String url, byte[] multipartBody, String bodyContentType,
com.android.volley.Response.Listener<JSONObject> listener,
com.android.volley.Response.ErrorListener errorListener) {
super(method, url, errorListener);
mParams = null;
mMultipartBody = multipartBody;
mBodyContentType = bodyContentType;
mListener = listener;
}

Expand All @@ -64,6 +97,16 @@ public void setOnAuthFailedListener(OnAuthFailedListener onAuthFailedListener) {
mOnAuthFailedListener = onAuthFailedListener;
}

@Override
public byte[] getBody() throws AuthFailureError {
return (mMultipartBody == null ? super.getBody() : mMultipartBody);
}

@Override
public String getBodyContentType() {
return (mBodyContentType == null ? super.getBodyContentType() : mBodyContentType);
}

@Override
public Map<String, String> getHeaders() {
return mHeaders;
Expand Down