diff a/test/jdk/java/net/httpclient/MultiPartBodyPublisherTest.java b/test/jdk/java/net/httpclient/MultiPartBodyPublisherTest.java --- /dev/null +++ b/test/jdk/java/net/httpclient/MultiPartBodyPublisherTest.java @@ -0,0 +1,84 @@ + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpRequest.BodyPublishers.Part; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.function.BiPredicate; + +public class MultipartBodyPublisherTest { + + public static final BiPredicate ACCEPT_ALL = (x, y) -> true; + static final String BOUNDARY = "gc0p4Jq0M2Yt08jU534c0p"; + + public static void main(String... args) throws Exception { + + // Alternative #1 + var publisher = BodyPublishers.ofMultipart( + "the87665boundary", + new Part(HttpHeaders.of(Map.of("Content-Type", List.of("text/plain; charset=us-ascii")), + ACCEPT_ALL), + BodyPublishers.ofString("Hello World!")) + ); + + // Alternative #2 + var publisher2 = BodyPublishers.ofMultipart2( + "the987654boundary", + List.of(Map.entry(HttpHeaders.of(Map.of("Content-Type", List.of("text/plain; charset=us-ascii")), + ACCEPT_ALL), + BodyPublishers.ofString("Hello World!"))) + ); + + // Alternative #3 + var publisher3 = BodyPublishers.ofMultipart3( + "the12345boundary", + // # part 1 - no explicit headers, implicitly defaults to "text/plain" as per rfc + BodyPublishers.ofString("Hello There"), + + // # part 2 - some text with an explicit content-type header + BodyPublishers.multipartPart( + HttpHeaders.of(Map.of("Content-Type", List.of("text/plain; charset=us-ascii")), + ACCEPT_ALL), + BodyPublishers.ofString("blah blah")), + + // # part 3 - a file + BodyPublishers.multipartPart( + HttpHeaders.of(Map.of("Content-Disposition", List.of("form-data; name=\"files\"; filename=\"file1.txt\""), + "Content-Type", List.of("text/plain")), + ACCEPT_ALL), + BodyPublishers.ofFile(Path.of("/tmp/fff"))) + ); + + // Alternative #3.1 ( re-stack above with locals ) + var part1 = BodyPublishers.ofString("Hello There"); + var part2 = BodyPublishers.multipartPart( + HttpHeaders.of(Map.of("Content-Type", List.of("text/plain; charset=us-ascii")), + ACCEPT_ALL), + BodyPublishers.ofString("blah blah")); + var part3 = BodyPublishers.multipartPart( + HttpHeaders.of(Map.of("Content-Disposition", List.of("form-data; name=\"files\"; filename=\"file1.txt\""), + "Content-Type", List.of("text/plain")), + ACCEPT_ALL), + BodyPublishers.ofFile(Path.of("/tmp/fff"))); + + var publisher31 = BodyPublishers.ofMultipart3("the12345boundary",part1, part2, part3); + + + // -- + + var client = HttpClient.newHttpClient(); + var request = HttpRequest.newBuilder() + .uri(URI.create("http://foo.com/")) + // << User sets multipart + boundary explicitly! e.g. + // multipart/mixed : multipart/digest : multipart/mixed : multipart/alternative : etc + .header("Content-Type", "multipart/mixed; boundary=" + BOUNDARY) + .POST(publisher) + .build(); + client.send(request, BodyHandlers.ofString()); + } +}