66import java .io .InputStream ;
77import java .math .BigInteger ;
88import java .security .SecureRandom ;
9+ import java .util .Map ;
910
11+ import com .google .common .annotations .VisibleForTesting ;
1012import com .microsoft .graph .options .HeaderOption ;
1113
1214/**
@@ -20,6 +22,8 @@ public class Multipart {
2022 private String boundary ;
2123 private static final String RETURN = "\r \n " ;
2224 private ByteArrayOutputStream out ;
25+ public static final String MULTIPART_ENCODING = "US-ASCII" ;
26+ private String contentType = "multipart/form-data" ;
2327
2428 /**
2529 * Create a new multipart object
@@ -33,56 +37,160 @@ public Multipart() {
3337 * Get the multipart boundary for use in the request header
3438 * @return the multipart boundary
3539 */
36- public String boundary () {
40+ public String getBoundary () {
3741 return boundary ;
3842 }
3943
44+ /**
45+ * Set the multipart boundary for use in the request header
46+ * @param boundary The multipart boundary
47+ */
48+ public void setBoundary (String boundary ) {
49+ this .boundary = boundary ;
50+ }
51+
52+ /**
53+ * Get the contentType for use in the request header
54+ * @return the multipart Content-Type
55+ */
56+ public String getContentType () {
57+ return contentType ;
58+ }
59+
60+ /**
61+ * Set the contentType for use in the request header
62+ * @param contentType The multipart Content-Type
63+ */
64+ public void setContentType (String contentType ) {
65+ this .contentType = contentType ;
66+ }
67+
4068 /**
4169 * Get the Content-Type header to send the multipart request
4270 * @return the multipart header option
4371 */
4472 public HeaderOption header () {
45- return new HeaderOption ("Content-Type" , "multipart/form-data; boundary=\" " + boundary + "\" " );
73+ return new HeaderOption ("Content-Type" , contentType + "; boundary=\" " + boundary + "\" " );
74+ }
75+
76+ private void writePartData (String partContent , byte [] byteArray ) throws IOException {
77+ out .write (partContent .getBytes (MULTIPART_ENCODING ));
78+ out .write (byteArray );
79+ String returnContent = RETURN + RETURN ;
80+ out .write (returnContent .getBytes (MULTIPART_ENCODING ));
4681 }
4782
4883 /**
49- * Add a string part to the multipart body
84+ * Create content headers value and parameter
85+ * @param name The content header name
86+ * @param contentType The content header Content-Type
87+ * @param filename The content header filename
88+ * @return content header value and parameter string
89+ */
90+ @ VisibleForTesting String createPartHeader (String name , String contentType , String filename ) {
91+ StringBuilder partContent = new StringBuilder (addBoundary ());
92+ partContent .append ("Content-Disposition: form-data" );
93+ if (filename != null ) {
94+ if (name != null )
95+ partContent .append ("; name=\" " ).append (name ).append ("\" ; filename=\" " ).append (filename ).append ("\" " );
96+ else
97+ partContent .append ("; filename=\" " ).append (filename ).append ("\" " );
98+ }
99+ else if (name != null )
100+ partContent .append ("; name=\" " ).append (name ).append ("\" " );
101+ if (contentType != null )
102+ partContent .append (RETURN ).append ("Content-Type: " ).append (contentType );
103+ partContent .append (RETURN ).append (RETURN );
104+ return partContent .toString ();
105+ }
106+
107+ /**
108+ * Create content headers value and parameter
109+ * @param contentValue The content header value
110+ * @param contentDispParameter Map containing content paramter's key and value pair
111+ * @return content header value and parameter string
112+ */
113+ public static String createContentHeaderValue (String contentValue , Map <String , String > contentDispParameter ) {
114+ String contentHeaderValue = contentValue ;
115+
116+ if (contentDispParameter != null ) {
117+ for (Map .Entry <String ,String > entry : contentDispParameter .entrySet ())
118+ contentHeaderValue += ";" + entry .getKey () + "=\" " + entry .getValue () + "\" " ;
119+ }
120+ return contentHeaderValue ;
121+ }
122+
123+ /**
124+ * Create content headers header-name, value and parameter string
125+ * @param headers Map containing Header-name and header-value pair
126+ */
127+ private String createPartHeader (Map <String , String > headers ) {
128+ String partContent = addBoundary ();
129+ String defaultPartContent = "Content-Disposition: form-data;" + RETURN + "Content-Type: " + contentType + RETURN + RETURN ;
130+
131+ if (headers != null ) {
132+ for (Map .Entry <String ,String > entry : headers .entrySet ())
133+ partContent += entry .getKey () +": " +entry .getValue () + RETURN ;
134+ partContent += RETURN ;
135+ }
136+ else
137+ partContent += defaultPartContent ;
138+ return partContent ;
139+ }
140+
141+ /**
142+ * Add multipart content headers and byte content
143+ * @param name The multipart content name
144+ * @param contentType The multipart Content-Type
145+ * @param filename The multipart content file name
146+ * @param byteArray The multipart byte content
147+ * @throws IOException
148+ */
149+ private void addData (String name , String contentType , String filename , byte [] byteArray ) throws IOException {
150+ String partContent = createPartHeader (name , contentType , filename );
151+ writePartData (partContent , byteArray );
152+ }
153+
154+ /**
155+ * Add a part to the multipart body
50156 * @param name The name of the part
51- * @param contentType The MIME type (text/html, text/plain , etc.)
52- * @param content The string content to include
157+ * @param contentType The MIME type (text/html, video/mp4 , etc.)
158+ * @param byteArray The byte[] contents of the resource
53159 * @throws IOException Throws an exception if the output stream cannot be written to
54160 */
55- public void addPart (String name , String contentType , String content ) throws IOException {
56- addPart (name , contentType , content . getBytes () );
161+ public void addFormData (String name , String contentType , byte [] byteArray ) throws IOException {
162+ addData (name , contentType , null , byteArray );
57163 }
58164
59165 /**
60166 * Add a part to the multipart body
61- * @param name The name of the part
62167 * @param contentType The MIME type (text/html, video/mp4, etc.)
63168 * @param byteArray The byte[] contents of the resource
64169 * @throws IOException Throws an exception if the output stream cannot be written to
65170 */
66- public void addPart (String name , String contentType , byte [] byteArray ) throws IOException {
67- String partContent = addBoundary ();
68- partContent +=
69- "Content-Disposition:form-data; name=\" " + name + "\" " + RETURN +
70- "Content-Type:" + contentType + RETURN +
71- RETURN ;
72- out .write (partContent .getBytes ());
73- out .write (byteArray );
74- String returnContent = RETURN + RETURN ;
75- out .write (returnContent .getBytes ());
171+ public void addPart (String contentType , byte [] byteArray ) throws IOException {
172+ addData (null , contentType , null , byteArray );
76173 }
77174
175+ /**
176+ * Add a part to the multipart body
177+ * @param headers Map containing Header's header-name(eg: Content-Disposition, Content-Type, etc..) and header's value-parameter string
178+ * @param content The byte[] contents of the resource
179+ * @throws IOException Throws an exception if the output stream cannot be written to
180+ */
181+ public void addPart (Map <String , String > headers , byte [] content ) throws IOException {
182+ String partContent = createPartHeader (headers );
183+ writePartData (partContent , content );
184+ }
185+
78186 /**
79187 * Add an HTML part to the multipart body
80188 * @param name The name of the part
81189 * @param content The HTML body for the part
82190 * @throws IOException Throws an exception if the output stream cannot be written to
83191 */
84- public void addHtmlPart (String name , String content ) throws IOException {
85- addPart (name , "text/html" , content );
192+ public void addHtmlPart (String name , byte [] content ) throws IOException {
193+ addFormData (name , "text/html" , content );
86194 }
87195
88196 /**
@@ -95,7 +203,7 @@ public void addHtmlPart(String name, String content) throws IOException {
95203 public void addFilePart (String name , String contentType , java .io .File file ) throws IOException {
96204 InputStream fileStream = new FileInputStream (file );
97205 byte [] fileBytes = getByteArray (fileStream );
98- addPart (name , contentType , fileBytes );
206+ addData (name , contentType , file . getName () , fileBytes );
99207 }
100208
101209 /**
@@ -121,7 +229,7 @@ private String addEnding() {
121229 */
122230 public byte [] content () throws IOException {
123231 ByteArrayOutputStream finalStream = out ;
124- finalStream .write (addEnding ().getBytes ());
232+ finalStream .write (addEnding ().getBytes (MULTIPART_ENCODING ));
125233 return finalStream .toByteArray ();
126234 }
127235
0 commit comments