diff --git a/pom.xml b/pom.xml index 8e95f10179..d6bded8b85 100644 --- a/pom.xml +++ b/pom.xml @@ -269,6 +269,12 @@ 4.13.2 test + + org.apache.httpcomponents + httpmime + 4.5.13 + test + com.tngtech.archunit archunit diff --git a/src/main/java/com/twilio/constant/EnumConstants.java b/src/main/java/com/twilio/constant/EnumConstants.java index 7d2f70b590..3d310e203d 100644 --- a/src/main/java/com/twilio/constant/EnumConstants.java +++ b/src/main/java/com/twilio/constant/EnumConstants.java @@ -9,7 +9,8 @@ public class EnumConstants { @RequiredArgsConstructor public enum ContentType { JSON("application/json"), - FORM_URLENCODED("application/x-www-form-urlencoded"); + FORM_URLENCODED("application/x-www-form-urlencoded"), + MULTIPART_FORM_DATA("multipart/form-data"); private final String value; } diff --git a/src/test/java/com/twilio/ClusterTest.java b/src/test/java/com/twilio/ClusterTest.java index a4dc2e5337..9c41bc4ed5 100644 --- a/src/test/java/com/twilio/ClusterTest.java +++ b/src/test/java/com/twilio/ClusterTest.java @@ -1,7 +1,9 @@ package com.twilio; import com.twilio.base.Page; - +import com.twilio.base.bearertoken.ResourceSet; +import com.twilio.http.CustomHttpClient; +import com.twilio.http.TwilioRestClient; import com.twilio.rest.api.v2010.account.IncomingPhoneNumber; import com.twilio.rest.api.v2010.account.IncomingPhoneNumberReader; import com.twilio.rest.api.v2010.account.Message; @@ -9,6 +11,7 @@ import com.twilio.rest.chat.v2.service.User; import com.twilio.rest.events.v1.Sink; import com.twilio.rest.events.v1.Subscription; +import com.twilio.rest.previewiam.organizations.Account; import org.hamcrest.CoreMatchers; import org.junit.Assume; import org.junit.Before; @@ -19,10 +22,9 @@ import java.util.List; import java.util.Map; -import static org.junit.Assert.*; - -import com.twilio.rest.previewiam.organizations.Account; -import com.twilio.base.bearertoken.ResourceSet; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class ClusterTest { String fromNumber; @@ -32,6 +34,8 @@ public class ClusterTest { String clientSecret; String organisationSid; + TwilioRestClient customRestClient; + @Before public void setUp() { // only run when ClusterTest property is passed (mvn test -Dtest="ClusterTest"), skip test run on mvn test @@ -48,6 +52,9 @@ public void setUp() { clientSecret = System.getenv("TWILIO_ORGS_CLIENT_SECRET"); organisationSid = System.getenv("TWILIO_ORG_SID"); TwilioOrgsTokenAuth.init(grantType, clientId, clientSecret); + + // CustomHttpClient + customRestClient = new TwilioRestClient.Builder(apiKey, secret).accountSid(accountSid).httpClient(new CustomHttpClient()).build(); } @Test @@ -141,4 +148,17 @@ public void testOrgsApi(){ assertNotNull(userId); } + // Test multipart/form-data + @Test + public void testMultiPartFormData() { + Message message = Message.creator( + new com.twilio.type.PhoneNumber(toNumber), new com.twilio.type.PhoneNumber(fromNumber), + "Where's Wallace?") + .create(customRestClient); + assertNotNull(message); + assertTrue(message.getBody().contains("Where's Wallace?")); + assertEquals(fromNumber, message.getFrom().toString()); + assertEquals(toNumber, message.getTo().toString()); + } + } diff --git a/src/test/java/com/twilio/http/CustomHttpClient.java b/src/test/java/com/twilio/http/CustomHttpClient.java new file mode 100644 index 0000000000..9d087555ab --- /dev/null +++ b/src/test/java/com/twilio/http/CustomHttpClient.java @@ -0,0 +1,70 @@ +package com.twilio.http; + +import com.twilio.exception.ApiException; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpResponse; +import org.apache.http.HttpVersion; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.client.utils.HttpClientUtils; +import org.apache.http.entity.BufferedHttpEntity; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.StringBody; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; + +public class CustomHttpClient extends NetworkHttpClient { + + public CustomHttpClient() { + super(); + } + + @Override + public Response makeRequest(T request) { + HttpMethod method = request.getMethod(); + RequestBuilder builder = RequestBuilder.create(method.toString()) + .setUri(request.constructURL().toString()) + .setVersion(HttpVersion.HTTP_1_1) + .setCharset(StandardCharsets.UTF_8); + if (request instanceof Request) { + Request basicRequest = (Request) request; + if (basicRequest.requiresAuthentication()) { + builder.addHeader(HttpHeaders.AUTHORIZATION, basicRequest.getAuthString()); + } + } + + for (Map.Entry> entry : request.getHeaderParams().entrySet()) { + for (String value : entry.getValue()) { + builder.addHeader(entry.getKey(), value); + } + } + MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); + for (Map.Entry> entry : request.getPostParams().entrySet()) { + for (String value : entry.getValue()) { + multipartEntityBuilder.addPart(entry.getKey(), new StringBody(value, ContentType.TEXT_PLAIN)); + } + } + builder.addHeader(HttpHeaders.USER_AGENT, HttpUtility.getUserAgentString(request.getUserAgentExtensions(), true)); + builder.setEntity(multipartEntityBuilder.build()); + HttpResponse response = null; + + try { + response = client.execute(builder.build()); + HttpEntity entity = response.getEntity(); + return new Response( + // Consume the entire HTTP response before returning the stream + entity == null ? null : new BufferedHttpEntity(entity).getContent(), + response.getStatusLine().getStatusCode(), + response.getAllHeaders() + ); + } catch (IOException e) { + throw new ApiException(e.getMessage(), e); + } finally { + HttpClientUtils.closeQuietly(response); + } + } +}