javafilesocketspoststream

File uploads get corrupted when reading a POST request body


I'm building an android app that needs to receive a file from a web application.
I'm using Java ServerSocket to deal with that.

I handled the POST request headers and all works fine but when I write the file to disk it gets corrupted.

I displayed the first few bytes of both the original and the corrupted file to see what bytes were written wrong and I have no clue how to deal with it.

enter image description here

I use this code to read the part of the POST request which contains the file data util I get the boundary string.

I prefixed the boundary string with "\r\n" because I don't want that included in my file especially when it's not part of it.

// Handle POST request


File file_upload = new File(Environment.getExternalStorageDirectory(), "Download/" + filename);
if (file_upload.createNewFile()) {
    BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file_upload)));

    // boundary index
    int bi = 0;
    // char
    int c;

    // this is boundary prefixed with \r\n--
    String __boundary = "\r\n--" + boundary;

    StringBuilder buffer = new StringBuilder();

    // `br` is BufferedReader
    // I start reading the file content here. br.read() reads the first byte and keeps reading until it meets the boundary.
    
    while ((c = br.read()) != -1) {
        if ((char) c == __boundary.charAt(bi)) {
            buffer.append((char) c);
            bi++;
            if (bi == __boundary.length()) {
                break;
            }
        } else {
            if (buffer.length() != 0) {
                out.write(buffer.toString());
                buffer.setLength(0);
            } else {
                bi = 0;
            }
            out.write((char) c);
        }
    }
    out.close();
}

Solution

  • You're reading the stream as if it were text. It's not - it's a PNG, so binary data. It should be treated as binary data. You may need to detect the boundary using the bytes of \r\n-- with an assumption of a particular character encoding, but other than that, you should read and write the data as text - no BufferedWriter, no BufferedReader, just InputStream and OutputStream-based classes.

    (If you can change your approach to requests and responses so that each request/response only contains one file of data, that would avoid you having to look at the boundary at all. We don't really have enough context to know whether that's feasible, but it seems unlikely that you should have to do boundary detection in your code - even if you need to use multi-part requests and responses, I'd expect an HTTP client to handle that for you.)