Tiberius
Tiberius

Reputation: 31

Java.net BodyPublishers not adding content length header in a POST multipart request (Java 17)

I'm having trouble using the java.net POST request for uploading files with multipart/form-data, when trying to send something to S3 using a pre-signed URL. The response complains about a missing content-length header.

The interesting part is that, we have a library that makes the same thing, the same way and it works, but it's in java 12. Doing the same thing in java 17 returns the missing header error.

We're trying to avoid third-party libraries for safety reasons (okhttp works perfectly).

Multipart params appender:

private HttpRequest.BodyPublisher fileParams(LinkedHashMap<String,Object> data,
                                                 String boundary, String mimeType) throws IOException {
        // Result request body
        List<byte[]> byteArrays = new ArrayList<>();

        // Separator with boundary
        byte[] separator = ("--" + boundary + "\r\nContent-Disposition: form-data; name=").getBytes(StandardCharsets.UTF_8);

        // Iterating over data parts
        for (Object keyAux : data.keySet()) {

            String key = keyAux.toString();
            if (key.equals("file")) continue;
            // Opening boundary
            byteArrays.add(separator);
            byteArrays.add(("\"" + key + "\"\r\n\r\n" + data.get(key) + "\r\n")
                    .getBytes(StandardCharsets.UTF_8));
        }

        if (data.get("file") instanceof Path) {
            var path = (Path) data.get("file");
            byteArrays.add(separator);
            byteArrays.add(("\"" + "file" + "\"; filename=\"" + path.getFileName()
                    + "\"\r\nContent-Type: " + mimeType + "\r\n\r\n").getBytes(StandardCharsets.UTF_8));
            byteArrays.add(Files.readAllBytes(path));
            byteArrays.add("\r\n".getBytes(StandardCharsets.UTF_8));
        }

        // Closing boundary
        byteArrays.add(("--" + boundary + "--").getBytes(StandardCharsets.UTF_8));

        // Serializing as byte array
        return HttpRequest.BodyPublishers.ofByteArrays(byteArrays);
    }

Implementation:

public HttpResponse<String> uploadFile(String url, LinkedHashMap<String, Object> params) throws URISyntaxException, IOException {
        String boundary = UUID.randomUUID().toString();
        String fileContentType = getMimeTypeFromData(params);
        HttpRequest request = HttpRequest.newBuilder()
                .header("Content-Type", "multipart/form-data; boundary=" + boundary)
                .uri(new URI(url))
                .POST(fileParams(params, boundary, fileContentType))
                .build();
        return execute(request);
    }

private HttpResponse<String> execute(HttpRequest request) {
        try {
            return client.send(request, BodyHandlers.ofString());
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

Upvotes: 3

Views: 301

Answers (0)

Related Questions