Skip to content

Commit

Permalink
Merge pull request #200 from watson-developer-cloud/multipart-form-re…
Browse files Browse the repository at this point in the history
…move-encoding

Remove base64 encoding when building multipart/form-data
  • Loading branch information
lpatino10 authored Aug 30, 2019
2 parents 235425d + 800cafd commit 2b4aa61
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 41 deletions.
6 changes: 3 additions & 3 deletions force-app/main/default/classes/IBMWatsonClient.cls
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ public class IBMWatsonClient {
if (request.getMethod().equals('POST') || request.getMethod().equals('PUT')) {
if (request.getBody() instanceof IBMWatsonMultipartBody) {
// form-multipart request will be send as Base64 request
String form64 = ((IBMWatsonMultipartBody)request.getBody()).form64();
httpRequest.setBodyAsBlob(EncodingUtil.base64Decode(form64));
httpRequest.setHeader('Content-Length', String.valueof(form64.length()));
String multipartBody = ((IBMWatsonMultipartBody)request.getBody()).multipartBody();
httpRequest.setBodyAsBlob(Blob.valueOf(multipartBody));
httpRequest.setHeader('Content-Length', String.valueof(multipartBody.length()));
} else if (request.getBody().contentType.toString().contains(IBMWatsonHttpMediaType.APPLICATION_JSON)) {
httpRequest.setBody(IBMWatsonJSONUtil.serialize(request.getBody().content));
} else {
Expand Down
53 changes: 18 additions & 35 deletions force-app/main/default/classes/IBMWatsonMultipartBody.cls
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ public class IBMWatsonMultipartBody extends IBMWatsonRequestBody {
private IBMWatsonMediaType originalType;
private IBMWatsonMediaType contentType;
private List<Part> parts;
private String form64;
private String multipartBody;
private Blob formBlob;
private Map<String, String> headers;
private long contentLength = -1L;

IBMWatsonMultipartBody(String boundary, IBMWatsonMediaType mediaType, List<Part> parts) {
this.boundary = boundary;
this.originalType = mediaType;
this.contentType = IBMWatsonMediaType.parse(mediaType + '; boundary=' + EncodingUtil.urlEncode(boundary, 'UTF-8'));
this.contentType = IBMWatsonMediaType.parse(mediaType + '; boundary=' + boundary);
this.parts = parts;
this.headers = new Map<String, String>();
this.contentLength = 0;
writeForm64(parts);
writeMultipartBody(parts);
}

public IBMWatsonMediaType contentType() {
Expand All @@ -42,32 +42,32 @@ public class IBMWatsonMultipartBody extends IBMWatsonRequestBody {
return formBlob;
}

public String form64() {
return form64;
public String multipartBody() {
return multipartBody;
}

public long contentLength() {
return contentLength;
}

private long writeForm64(List<Part> parts) {
headers.put('Content-Type', 'multipart/form-data; boundary="' + boundary + '"');
form64 = '';
private long writeMultipartBody(List<Part> parts) {
headers.put('Content-Type', 'multipart/form-data; boundary=' + boundary);
multipartBody = '';
for (Integer i = 0; i < parts.size(); i++) {
Part p = parts[i];
Boolean isEndingPart = (i == parts.size() - 1);
if (p.body().hasBase64Data()) {
String fileName = p.body().name;
String mimeType = p.body.bodyContentType().toString();
String file64Body = EncodingUtil.base64Encode(p.body().blobContent);
form64 += writeBlobBody(p.headers().get('Content-Disposition'), file64Body, mimeType, isEndingPart);
multipartBody += writeBlobBody(p.headers().get('Content-Disposition'), file64Body, mimeType, isEndingPart);
} else {
form64 += writeBoundary();
form64 += writeBodyParameter(p.headers().get('Content-Disposition'), p.body().content, isEndingPart);
multipartBody += writeBoundary();
multipartBody += writeBodyParameter(p.headers().get('Content-Disposition'), p.body().content, isEndingPart);
}
}

return form64.length();
return multipartBody.length();
}

/**
Expand All @@ -93,23 +93,14 @@ public class IBMWatsonMultipartBody extends IBMWatsonRequestBody {
public String writeBodyParameter(String key, String value, Boolean isEndingPart) {
String contentDisposition = 'Content-Disposition: ' + key;
String contentDispositionCrLf = contentDisposition + CRLF + CRLF;
Blob contentDispositionCrLfBlob = blob.valueOf(contentDispositionCrLf);
String contentDispositionCrLf64 = EncodingUtil.base64Encode(contentDispositionCrLfBlob);
String content = safelyPad(contentDisposition, contentDispositionCrLf64, CRLF + CRLF);
String content = contentDispositionCrLf;

String valueCrLf = value + CRLF;
Blob valueCrLfBlob = blob.valueOf(valueCrLf);
String valueCrLf64 = EncodingUtil.base64Encode(valueCrLfBlob);
content += valueCrLf;

content += safelyPad(value, valueCrLf64, CRLF);
if (isEndingPart == true) {
String footer = '--' + this.boundary + '--';
Blob footerBlob = blob.valueOf(footer);
String footerEncoded = EncodingUtil.base64Encode(footerBlob);
while (footerEncoded.endsWith('=')) {
footer += ' ';
footerEncoded = EncodingUtil.base64Encode(blob.valueOf(footer));
}
content += safelyPad(footer, footerEncoded, CRLF);
content = content + footer;
}
return content;
}
Expand Down Expand Up @@ -165,15 +156,7 @@ public class IBMWatsonMultipartBody extends IBMWatsonRequestBody {
}

public String writeBoundary() {
String value = '--' + boundary;
String valueCrlf = value + CRLF;
Blob valueBlob = blob.valueOf(valueCrlf);
String boundaryEncoded = EncodingUtil.base64Encode(valueBlob);
while (boundaryEncoded.endsWith('=')) {
valueCrlf += ' ';
boundaryEncoded = EncodingUtil.base64Encode(blob.valueOf(valueCrlf));
}
return boundaryEncoded;
return '--' + this.boundary + CRLF;
}

public Map<String, String> getAllHeaders() {
Expand Down Expand Up @@ -257,7 +240,7 @@ public class IBMWatsonMultipartBody extends IBMWatsonRequestBody {
private static String generateRandomBoundaryString() {
Blob b = Crypto.GenerateAESKey(128);
String h = EncodingUtil.ConvertTohex(b);
String boundaryString = h.substring(0, 8);
String boundaryString = h.substring(0, 16);
return boundaryString;
}

Expand Down
5 changes: 2 additions & 3 deletions force-app/main/default/classes/IBMWatsonServiceTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -363,11 +363,10 @@ private class IBMWatsonServiceTest {
.addPart(new Map<String, String>{'test' => 'test', 'Content-Disposition'=>'Content-Disposition'}, IBMWatsonRequestBody.create())
.addFormDataPart('key', 'value')
.build();
System.assertEquals(IBMWatsonMultipartBody.safelyPad('test', 'test=test=', 'test'), EncodingUtil.base64Encode(blob.valueOf('test test')));
System.assertEquals(multipartBody.writeBodyParameter('test', 'test', false), 'Q29udGVudC1EaXNwb3NpdGlvbjogdGVzdCANCg0KdGVzdA0K');
System.assertEquals('Content-Disposition: test\r\n\r\ntest\r\n', multipartBody.writeBodyParameter('test', 'test', false));
System.assertEquals(multipartBody.parts().size(), 2);
System.assert(multipartBody.getAllHeaders().get('Content-Type').contains('multipart/form-data; boundary'));
System.assert(multipartBody.form64().contains(multipartBody.writeBoundary()));
System.assert(multipartBody.multipartBody().contains(multipartBody.writeBoundary()));
Test.stopTest();
}

Expand Down

0 comments on commit 2b4aa61

Please sign in to comment.