Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RestEasy file upload - how correctly determine filename encoding?

I'm using next code for file uploading:

@Path("/files/")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public OrderData uploadFile(MultipartFormDataInput input) {
    List<InputPart> parameterParts = input.getFormDataMap().get("Filename");
    String filename = parameterParts.get(0).getBody(String.class, null);
    ...
}

It works ok for latin characters, but I have problems with cyrillic (As I understand, because Java by default encodes rawpost data to unicode)

How can I correctly determine encoding and encode data from post to valid Java string?

like image 746
Wild Falcon Avatar asked Dec 08 '25 21:12

Wild Falcon


1 Answers

When using multipart/form-data you can specify a Content-Type with encoding for every part:

POST /some-resource HTTP/1.1
Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="file"; filename="file1.txt"
Content-Type: text/plain; charset=utf-8

... contents of file1.txt ...
--AaB03x--

If you add this Content-Type for every part it should work out of the box (at least for the current version 3.0.x of RESTeasy). You can test this with the RESTeasy client:

WebTarget target = client.target("/some-resource");
MultipartFormDataOutput formData = new MultipartFormDataOutput();
formData.addFormData("file", fileContent, MediaType.TEXT_PLAIN_TYPE.withCharset("utf-8"));
Entity<MultipartFormDataOutput> entity = Entity.entity(formData, MediaType.MULTIPART_FORM_DATA);
Response response = target.request().post(entity);

If your client does not give you the possibility to set Content-Type per part you can change the default encoding for instance depending on a custom header (I'm adding a modified code-example because the PreProcessInterceptor is marked @deprecated):

@Provider
public class CharsetFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        String charset = requestContext.getHeaderString("X-Charset");
        if (charset != null) {
            requestContext.setProperty(InputPart.DEFAULT_CHARSET_PROPERTY, charset);
        }
    }

}

If you are using a plain HTML Form you can try to add <input type="hidden" name="_charset_" /> to your form. As defined in the multipart/form-data encoding algorithm the client should populate this field with the charset he is using. You then need to encode the content in your ResourceClass on your own:

@POST
@Path("/form")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public Response uploadForm(MultipartFormDataInput input) throws IOException {
    String charset = input.getFormDataMap().get("_charset_").get(0).getBodyAsString();
    InputPart file = input.getFormDataMap().get("file").get(0);
    InputStream inputStream = file.getBody(InputStream.class, null);
    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset));
    String line;
    StringBuilder content = new StringBuilder();
    while ((line = br.readLine()) != null) {
        content.append(line);
    }
    return Response.ok(content).header("Content-Type", MediaType.TEXT_PLAIN_TYPE.withCharset(charset)).build();
}
like image 144
lefloh Avatar answered Dec 11 '25 09:12

lefloh



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!