1 
 2 import java.net.URI;
 3 import java.net.http.HttpClient;
 4 import java.net.http.HttpHeaders;
 5 import java.net.http.HttpRequest;
 6 import java.net.http.HttpRequest.BodyPublishers;
 7 import java.net.http.HttpRequest.BodyPublishers.Part;
 8 import java.net.http.HttpResponse.BodyHandlers;
 9 import java.nio.file.Path;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.function.BiPredicate;
13 
14 public class MultipartBodyPublisherTest {
15 
16     public static final BiPredicate<String,String> ACCEPT_ALL = (x, y) -> true;
17     static final String BOUNDARY = "gc0p4Jq0M2Yt08jU534c0p";
18 
19     public static void main(String... args) throws Exception {
20 
21         // Alternative #1
22         var publisher = BodyPublishers.ofMultipart(
23                 "the87665boundary",
24                 new Part(HttpHeaders.of(Map.of("Content-Type", List.of("text/plain; charset=us-ascii")),
25                                         ACCEPT_ALL),
26                          BodyPublishers.ofString("Hello World!"))
27         );
28 
29         // Alternative #2
30         var publisher2 = BodyPublishers.ofMultipart2(
31                 "the987654boundary",
32                 List.of(Map.entry(HttpHeaders.of(Map.of("Content-Type", List.of("text/plain; charset=us-ascii")),
33                                                  ACCEPT_ALL),
34                                   BodyPublishers.ofString("Hello World!")))
35         );
36 
37         // Alternative #3
38         var publisher3 = BodyPublishers.ofMultipart3(
39                 "the12345boundary",
40                 // # part 1  - no explicit headers, implicitly defaults to "text/plain" as per rfc
41                 BodyPublishers.ofString("Hello There"),
42 
43                 // # part 2  - some text with an explicit content-type header
44                 BodyPublishers.multipartPart(
45                         HttpHeaders.of(Map.of("Content-Type", List.of("text/plain; charset=us-ascii")),
46                                        ACCEPT_ALL),
47                         BodyPublishers.ofString("blah blah")),
48 
49                 // # part 3  - a file
50                 BodyPublishers.multipartPart(
51                         HttpHeaders.of(Map.of("Content-Disposition", List.of("form-data; name=\"files\"; filename=\"file1.txt\""),
52                                               "Content-Type", List.of("text/plain")),
53                                        ACCEPT_ALL),
54                         BodyPublishers.ofFile(Path.of("/tmp/fff")))
55         );
56 
57         // Alternative #3.1 ( re-stack above with locals )
58         var part1 = BodyPublishers.ofString("Hello There");
59         var part2 = BodyPublishers.multipartPart(
60                         HttpHeaders.of(Map.of("Content-Type", List.of("text/plain; charset=us-ascii")),
61                                        ACCEPT_ALL),
62                         BodyPublishers.ofString("blah blah"));
63         var part3 = BodyPublishers.multipartPart(
64                         HttpHeaders.of(Map.of("Content-Disposition", List.of("form-data; name=\"files\"; filename=\"file1.txt\""),
65                                               "Content-Type", List.of("text/plain")),
66                                        ACCEPT_ALL),
67                         BodyPublishers.ofFile(Path.of("/tmp/fff")));
68 
69         var publisher31 = BodyPublishers.ofMultipart3("the12345boundary",part1, part2, part3);
70 
71 
72         // --
73 
74         var client = HttpClient.newHttpClient();
75         var request = HttpRequest.newBuilder()
76                 .uri(URI.create("http://foo.com/"))
77                 // << User sets multipart + boundary explicitly! e.g.
78                 //  multipart/mixed : multipart/digest : multipart/mixed : multipart/alternative : etc
79                 .header("Content-Type", "multipart/mixed; boundary=" + BOUNDARY)
80                 .POST(publisher)
81                 .build();
82         client.send(request, BodyHandlers.ofString());
83     }
84 }