NanoHttpd / nanohttpd

Tiny, easily embeddable HTTP server in Java.
http://nanohttpd.org
BSD 3-Clause "New" or "Revised" License
6.93k stars 1.69k forks source link

streaming big files over http with nanohttpd can cause java.net.SocketException - special handling needed #232

Open bamvenkatesh opened 8 years ago

bamvenkatesh commented 8 years ago

Hi All,

I am new to NanoHttpd. I am using this to stream a video in Android. For just normal playing this works like a charm without any issue. But when I try to seek to different time in the VideoPlayer, immediatly I get the following error and it creates a different socket and resumes to play after some time. But it shows the progress indicator for long time, which I think because of this issue and re-connecting with different socket. And Streaming is from local network server.

java.net.SocketException: sendto failed: EPIPE (Broken pipe)
        at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:546)
        at libcore.io.IoBridge.sendto(IoBridge.java:515)
        at java.net.PlainSocketImpl.write(PlainSocketImpl.java:504)
        at java.net.PlainSocketImpl.access$100(PlainSocketImpl.java:37)
        at java.net.PlainSocketImpl$PlainSocketOutputStream.write(PlainSocketImpl.java:266)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$Response.sendBody(NanoHTTPD.java:1423)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$Response.sendBodyWithCorrectEncoding(NanoHTTPD.java:1396)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$Response.sendBodyWithCorrectTransferAndEncoding(NanoHTTPD.java:1386)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$Response.send(NanoHTTPD.java:1371)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:794)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$ClientHandler.run(NanoHTTPD.java:195)
        at java.lang.Thread.run(Thread.java:818)

 Caused by: android.system.ErrnoException: sendto failed: EPIPE (Broken pipe)
        at libcore.io.Posix.sendtoBytes(Native Method)
        at libcore.io.Posix.sendto(Posix.java:206)
        at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:278)
        at libcore.io.IoBridge.sendto(IoBridge.java:513)
        at java.net.PlainSocketImpl.write(PlainSocketImpl.java:504)
        at java.net.PlainSocketImpl.access$100(PlainSocketImpl.java:37)
        at java.net.PlainSocketImpl$PlainSocketOutputStream.write(PlainSocketImpl.java:266)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$Response.sendBody(NanoHTTPD.java:1423)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$Response.sendBodyWithCorrectEncoding(NanoHTTPD.java:1396)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$Response.sendBodyWithCorrectTransferAndEncoding(NanoHTTPD.java:1386)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$Response.send(NanoHTTPD.java:1371)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:794)
        at me.etrmntonwheels.surfacetest.NanoHTTPD$ClientHandler.run(NanoHTTPD.java:195)
        at java.lang.Thread.run(Thread.java:818)

I am using serveFile function from SimpleWebServer sample to achieve partial content or streaming. I have read different articles and googled through stackoverflow but still could not figure out the reason.I am stuck at this issue from long time. Please help me to resolve this issue.

isabsent commented 8 years ago

I have the same bug on Android 4.1.2 when I "find forward" or "rewind" video placed on a cloud by means of an intermediate NanoHTTPD server.

ritchieGitHub commented 8 years ago

Can anybody help finding the bug behind this behaviour?

Taranmeet commented 8 years ago

@ritchieGitHub Hi I am also facing the same issue. This generally comes when streaming HD files. Normal files are being handled with ease.

chillin0531 commented 8 years ago

I have received the same error while playing the video in loop. Any solution to fix this issue?

ritchieGitHub commented 8 years ago

As I am no android developer, we need someone else who can help! Someone watching? Help would be greatly appreciated!

chillin0531 commented 8 years ago

My issue got solved by following the code as mentioned here. I can able to seek and stream videos continuously in loop.

ritchieGitHub commented 8 years ago

Great! I will repeat the code here for the record. we should find a way to integrate this in the nano code.

@Override
public Response serve(IHTTPSession session) {
    Map<String, String> headers = session.getHeaders();
    Map<String, String> parms = session.getParms();
    Method method = session.getMethod();
    String uri = session.getUri();
    Map<String, String> files = new HashMap<>();

    if (Method.POST.equals(method) || Method.PUT.equals(method)) {
        try {
            session.parseBody(files);
        }
        catch (IOException e) {
            return getResponse("Internal Error IO Exception: " + e.getMessage());
        }
        catch (ResponseException e) {
            return new Response(e.getStatus(), MIME_PLAINTEXT, e.getMessage());
        }
    }

    uri = uri.trim().replace(File.separatorChar, '/');
    if (uri.indexOf('?') >= 0) {
        uri = uri.substring(0, uri.indexOf('?'));
    }

    File f = new File(uri);
    return serveFile(uri, header, f);
}

private Response serveFile(String uri, Map<String, String> header, File file) {
    Response res;
    String mime = getMimeTypeForFile(uri);
    try {
        // Calculate etag
        String etag = Integer.toHexString((file.getAbsolutePath() +
                file.lastModified() + "" + file.length()).hashCode());

        // Support (simple) skipping:
        long startFrom = 0;
        long endAt = -1;
        String range = header.get("range");
        if (range != null) {
            if (range.startsWith("bytes=")) {
                range = range.substring("bytes=".length());
                int minus = range.indexOf('-');
                try {
                    if (minus > 0) {
                        startFrom = Long.parseLong(range.substring(0, minus));
                        endAt = Long.parseLong(range.substring(minus + 1));
                    }
                } catch (NumberFormatException ignored) {
                }
            }
        }

        // Change return code and add Content-Range header when skipping is requested
        long fileLen = file.length();
        if (range != null && startFrom >= 0) {
            if (startFrom >= fileLen) {
                res = createResponse(Response.Status.RANGE_NOT_SATISFIABLE, MIME_PLAINTEXT, "");
                res.addHeader("Content-Range", "bytes 0-0/" + fileLen);
                res.addHeader("ETag", etag);
            } else {
                if (endAt < 0) {
                    endAt = fileLen - 1;
                }
                long newLen = endAt - startFrom + 1;
                if (newLen < 0) {
                    newLen = 0;
                }

                final long dataLen = newLen;
                FileInputStream fis = new FileInputStream(file) {
                    @Override
                    public int available() throws IOException {
                        return (int) dataLen;
                    }
                };
                fis.skip(startFrom);

                res = createResponse(Response.Status.PARTIAL_CONTENT, mime, fis);
                res.addHeader("Content-Length", "" + dataLen);
                res.addHeader("Content-Range", "bytes " + startFrom + "-" +
                        endAt + "/" + fileLen);
                res.addHeader("ETag", etag);
            }
        } else {
            if (etag.equals(header.get("if-none-match")))
                res = createResponse(Response.Status.NOT_MODIFIED, mime, "");
            else {
                res = createResponse(Response.Status.OK, mime, new FileInputStream(file));
                res.addHeader("Content-Length", "" + fileLen);
                res.addHeader("ETag", etag);
            }
        }
    } catch (IOException ioe) {
        res = getResponse("Forbidden: Reading file failed");
    }

    return (res == null) ? getResponse("Error 404: File not found") : res;
}

// Announce that the file server accepts partial content requests
private Response createResponse(Response.Status status, String mimeType, InputStream message) {
    Response res = new Response(status, mimeType, message);
    res.addHeader("Accept-Ranges", "bytes");
    return res;
}

// Announce that the file server accepts partial content requests
private Response createResponse(Response.Status status, String mimeType, String message) {
    Response res = new Response(status, mimeType, message);
    res.addHeader("Accept-Ranges", "bytes");
    return res;
}

private Response getResponse(String message) {
    return createResponse(Response.Status.OK, "text/plain", message);
}
ritchieGitHub commented 8 years ago

@LordFokas / @elonen sounds like a "plugin" in 3.0.0 ? Should I create a new module with this code, for the time being? I think it is to big for the core, or?

LordFokas commented 8 years ago

I have some kind of Server Extension concept in mind for 3.1.0 (which would allow stuff like webdav), which is significantly different from what I called a "plugin" in the 3.0.0 refactoring thread, and I think this would fit right in. We'll see how it goes.

icefoggy commented 8 years ago

I have the same problem in my android project, and the code above doesn't worked. Any plan to solve it?

alexeyvasilyev commented 8 years ago

Using the latest HTTPD taken from Master branch on Aug 1, 2016. Have the same issue while trying to play MP4 (stream) files on Android.

JarvanMo commented 8 years ago

I occured the same problem too .My PC can play MP4(stream) files from NanoHttpd well, but I have the same issue while trying to play it on Android. Anyone can solve it? The question is I change the way to provide stream then I can play on Android device.However, it can't play on computer's browser.Amazing!!!

mianharisali commented 7 years ago

Facing this exact issue.

LordFokas commented 7 years ago

This is a bug more than an enhancement since this is triggered after some random point we don't exactly know. We also don't want this to come back, like, ever, since this issue seems to be nagging a lot of people so we want to make extra sure we add tests for it. Don't mind me, just justifying my label changes.

@ritchieGitHub since you seem to have found the fix for this, do you think you can apply this on top of current 3.0 code or should we wait until 3.0 is finished and then add that on the side?

Ideally this could be implemented at the core and not just fileupload/webserver/whatever to cover every possibility ever :)

mianharisali commented 7 years ago

let me post some logs , with the code that i am using on Android 7.0 it might help you.

this code works fine , the file plays and i can seek to different location.but this error shows in console and nothing happens to playback.

now i want to transfer files in 1MB chunks , i used this endAt=startFrom+1000000;

and everything works fine with VLC (no broken pipe error), but with MXPlayer it shows the same error and stops the stream.

`

@Override
public Response serve(IHTTPSession session)
{
    Map<String, String> headers = session.getHeaders();
    Map<String, String> parms = session.getParms();
    Method method = session.getMethod();
    String uri = session.getUri();
    Map<String, String> files = new HashMap<>();

    if (Method.POST.equals(method) || Method.PUT.equals(method))
    {
        try
        {
            session.parseBody(files);
        }
        catch (IOException e)
        {
            return getResponse("Internal Error IO Exception: " + e.getMessage());
        }
        catch (ResponseException e)
        {
            return newFixedLengthResponse(e.getStatus(), MIME_PLAINTEXT, e.getMessage());
        }
    }

    File f = new File(Environment.getExternalStorageDirectory() + "/"+MainActivity.file);
    return serveFile(uri, headers, f);
}

private Response serveFile(String uri, Map<String, String> header, File file)
{

    System.out.println("--------------------------------------------------------" );
    for (Map.Entry<String, String> entry : header.entrySet())
    {
        String key = entry.getKey().toString();
        String value = entry.getValue();
        System.out.println("key, " + key + " value " + value);
    }
    System.out.println("--------------------------------------------------------" );

    Response res;
    String mime = getMimeTypeForFile(uri);
    try {
        String etag = Integer.toHexString((file.getAbsolutePath() +
                file.lastModified() + "" + file.length()).hashCode());
        long startFrom = 0;
        long endAt = -1;
        String range = header.get("range");
        if (range != null) {
            if (range.startsWith("bytes=")) {
                range = range.substring("bytes=".length());
                int minus = range.indexOf('-');
                try {
                    if (minus > 0) {
                        startFrom = Long.parseLong(range.substring(0, minus));
                        endAt = Long.parseLong(range.substring(minus + 1));
                    }
                } catch (NumberFormatException ignored) {
                }
            }
        }
        long fileLen = file.length();
        if (range != null && startFrom >= 0) {
            if (startFrom >= fileLen) {
                res = createResponse(Response.Status.RANGE_NOT_SATISFIABLE, MIME_PLAINTEXT, "");
                res.addHeader("Content-Range", "bytes 0-0/" + fileLen);
                res.addHeader("ETag", etag);
            } else {
                if (endAt < 0) {
                    endAt = fileLen - 1;
                }
                //endAt=startFrom+1000000;
                long newLen = endAt - startFrom + 1;
                if (newLen < 0) {
                    newLen = 0;
                }

                final long dataLen = newLen;
                FileInputStream fis = new FileInputStream(file) {
                    @Override
                    public int available() throws IOException {
                        return (int) dataLen;
                    }
                };
                fis.skip(startFrom);

                res = createResponse(Response.Status.PARTIAL_CONTENT, mime, fis,dataLen);
                res.addHeader("Content-Length", "" + dataLen);
                res.addHeader("Content-Range", "bytes " + startFrom + "-" +
                        endAt + "/" + fileLen);
                res.addHeader("ETag", etag);
                Log.d("Server", "serveFile --1--: Start:"+startFrom+" End:"+endAt);
            }
        } else {
            if (etag.equals(header.get("if-none-match"))) {
                res = createResponse(Response.Status.NOT_MODIFIED, mime, "");
                Log.d("Server", "serveFile --2--: Start:"+startFrom+" End:"+endAt);
            }
            else
            {
                FileInputStream fis=new FileInputStream(file);
                res = createResponse(Response.Status.OK, mime, fis,fis.available());
                res.addHeader("Content-Length", "" + fileLen);
                res.addHeader("ETag", etag);
                Log.d("Server", "serveFile --3--: Start:"+startFrom+" End:"+endAt);
            }
        }
    } catch (IOException ioe) {
        res = getResponse("Forbidden: Reading file failed");
    }

    return (res == null) ? getResponse("Error 404: File not found") : res;
}

private Response createResponse(Response.Status status, String mimeType, InputStream message,long totalBytes) {
    Response res = newFixedLengthResponse(status, mimeType, message,totalBytes);
    res.addHeader("Accept-Ranges", "bytes");
    return res;
}

private Response createResponse(Response.Status status, String mimeType, String message) {
    Response res = newFixedLengthResponse(status, mimeType, message);
    res.addHeader("Accept-Ranges", "bytes");
    return res;
}

private Response getResponse(String message) {
    return createResponse(Response.Status.OK, "text/plain", message);
}

`

----------------log--------------------

log.txt

Khoosham commented 7 years ago

am getting the same error when i try to play MP3 file. what i need to do? is it fix yet ?

JarvanMo commented 7 years ago

If we try to visit large files on NanoHttpd through android devices ,we may have the exception above.I don't know why.These codes work well if we use computer to visit it.Finally I find another way to implement my function.However, if I do this, I can't visit it through computer.

Khoosham commented 7 years ago

@JarvanMo can you post your workaround here i wanna see if i can make a way ty 👍

JarvanMo commented 7 years ago

It still have some problems but it works.

` private Response createResponse(IHTTPSession session, String contentType, InputStream inputStream) throws IOException {

    Response response = null;
    if (inputStream == null) {
        return null;
    }
    int totalLength = inputStream.available();

    String requestRange = session.getHeaders().get("range");
    if (requestRange == null) {
        //http 200"video/mp4"
        response = NanoHTTPD.newFixedLengthResponse(Response.Status.OK, contentType, inputStream, totalLength);
    } else {
        //http 206

        //region get RangeStart from head
        Matcher matcher = Pattern.compile("bytes=(\\d+)-(\\d*)").matcher(requestRange);
        matcher.find();
        long start = 0;
        try {
            start = Long.parseLong(matcher.group(1));
        } catch (Exception e) {

            e.printStackTrace();
        }
        //endregion

        inputStream.skip(start);

        long restLength = totalLength - start;
        response = NanoHTTPD.newFixedLengthResponse(Response.Status.PARTIAL_CONTENT, contentType, inputStream, restLength);

        String contentRange = String.format("bytes %d-%d/%d", start, totalLength, totalLength);
        response.addHeader("Content-Range", contentRange);
    }

    return response;
}`
Khoosham commented 7 years ago

i have use the code provided by @ritchieGitHub above. its working for mp3 and video file seeking but i get the error broken pipe only when i play mp3 and not on videos (mp4) the error occurs only the first time the mp3 file is loaded and not by seeking any workaround for that ??

magnusja commented 7 years ago

I experience this bug with MX Player and with the standard video view but not with VLC.

JarvanMo commented 7 years ago

@magnusja I use MediaPlayer

magnusja commented 7 years ago

@JarvanMo Yeah I think VideoView is based on that. Can you maybe also try VLC?

JarvanMo commented 7 years ago

@magnusja I'm sorry I've removed VLC library.But I can tell you something I know. VideoVieew is based on MediaPlayer. Before I changed the way to response streams, there was a BROKEN PIPE error while playing large mp4 files. After I used the method I mentioned above, it seemed OK and everything worked well.However, I found something different through logcat. The NanoHttpd is a local server.But when the MediaPlayer try to play files on NanoHttpd, the MediaPlayer will request the server at least 3 times. I don't know why. So does the VLC. I've tried PLDroidPlayer, and PLDroidPlayer doesn't request so many times. Maybe we can try ExoPlayer.

magnusja commented 7 years ago

@JarvanMo So the code snippet above is definitely against the HTTP standard because it completely ignores the end of the range header. Usually the media players first wants to gather some information about the video stream in general that is why it only consumes a few bytes during some initial request(s) after that it streams the whole file and plays. This is pretty normal.

EDIT: It also does not work for me

JarvanMo commented 7 years ago

@magnusja Thanks. But there's an exception before it plays.

LordFokas commented 7 years ago

@JarvanMo always check what HTTP method you received. Some methods like HEAD and OPTIONS don't have a body. Browsers and other applications will often use such requests to gather metadata about the files they are about to request (like cache timings, available encodings, etc) and only then they will send a GET to actually receive the file.

This may answer on why you are being requested the same content several times, however, streaming apps may still request the same thing multiple times if, for example, they have small buffers. Implementation details are always a shady thing and you'll always find applications behaving in strange manners internally, thus you should prepare to handle that (as in, have as little overhead as possible, not attempting to understand them).

I hope I have cast a bit of light on that.

Shrikant-B commented 7 years ago

Hi, i know its late but I'm streaming video file using nanohttpd. Though it seems to be working fine on brower, I get errors in logcat. And I'm using following solution for reference

log: logfile.txt

`private Response serveFile(String uri, Map<String, String> header, File file) { Response res; String mime = getMimeTypeForFile(uri); try { // Calculate etag String etag = Integer.toHexString((file.getAbsolutePath() + file.lastModified() + "" + file.length()).hashCode());

    // Support (simple) skipping:
    long startFrom = 0;
    long endAt = -1;
    String range = header.get("range");
    if (range != null) {
        if (range.startsWith("bytes=")) {
            range = range.substring("bytes=".length());
            int minus = range.indexOf('-');
            try {
                if (minus > 0) {
                    startFrom = Long.parseLong(range.substring(0, minus));
                    endAt = Long.parseLong(range.substring(minus + 1));
                }
            } catch (NumberFormatException ignored) {
            }
        }
    }

    // Change return code and add Content-Range header when skipping is requested
    long fileLen = file.length();
    if (range != null && startFrom >= 0) {
        if (startFrom >= fileLen) {
            res = createResponse(Response.Status.RANGE_NOT_SATISFIABLE, MIME_PLAINTEXT, "");
            res.addHeader("Content-Range", "bytes 0-0/" + fileLen);
            res.addHeader("ETag", etag);
        } else {
            if (endAt < 0) {
                endAt = fileLen - 1;
            }
            long newLen = endAt - startFrom + 1;
            if (newLen < 0) {
                newLen = 0;
            }

            final long dataLen = newLen;
            FileInputStream fis = new FileInputStream(file) {
                @Override
                public int available() throws IOException {
                    return (int) dataLen;
                }
            };
            fis.skip(startFrom);

            res = createResponse(Response.Status.PARTIAL_CONTENT, mime, fis);
            res.addHeader("Content-Length", "" + dataLen);
            res.addHeader("Content-Range", "bytes " + startFrom + "-" +
                    endAt + "/" + fileLen);
            res.addHeader("ETag", etag);
        }
    } else {
        if (etag.equals(header.get("if-none-match")))
            res = createResponse(Response.Status.NOT_MODIFIED, mime, "");
        else {
            res = createResponse(Response.Status.OK, mime, new FileInputStream(file));
            res.addHeader("Content-Length", "" + fileLen);
            res.addHeader("ETag", etag);
        }
    }
} catch (IOException ioe) {
    res = getResponse("Forbidden: Reading file failed");
}

return (res == null) ? getResponse("Error 404: File not found") : res;

}

// Announce that the file server accepts partial content requests private Response createResponse(Response.Status status, String mimeType, InputStream message) { Response res = new Response(status, mimeType, message); res.addHeader("Accept-Ranges", "bytes"); return res; }

// Announce that the file server accepts partial content requests private Response createResponse(Response.Status status, String mimeType, String message) { Response res = new Response(status, mimeType, message); res.addHeader("Accept-Ranges", "bytes"); return res; }

private Response getResponse(String message) { return createResponse(Response.Status.OK, "text/plain", message); }`

dernasherbrezon commented 6 years ago

You could experience "Broken pipe" if nanohttpd behind nginx. Here is the sequence:

  1. Client sends request
  2. Nginx proxies request to nanohttpd
  3. nanohttpd start responding to it
  4. Client closes connection
  5. Nginx respond 499 status code to client (i.e. put into access.logs)
  6. Nginx closes connection to nanohttpd
  7. nanohttpd throws Exception.

Could be reproduced easily if you hit F5 many-many-many times (at least in Safari).

Although closing connection in the middle of process is OK, nanohttpd doesn't like that/doesn't handle well. This could be fixed on nginx side using the proxy_ignore_client_abort property.

Gibitop commented 6 years ago

One more workaround is to add try-catch block to the "sendBody" method, so it closes the connection to the client if the client can't accept data


private void sendBody(OutputStream outputStream, long pending) throws IOException {
    try {
        long BUFFER_SIZE = 16 * 1024;
        byte[] buff = new byte[(int) BUFFER_SIZE];
        boolean sendEverything = pending == -1;
        while (pending > 0 || sendEverything) {
            long bytesToRead = sendEverything ? BUFFER_SIZE : Math.min(pending, BUFFER_SIZE);
            int read = this.data.read(buff, 0, (int) bytesToRead);
            if (read <= 0) {
                break;
            }
            outputStream.write(buff, 0, read);
            if (!sendEverything) {
                pending -= read;
            }
        }
    } catch (IOException e) {
        // TODO: REMOVE WORKAROUND
        outputStream.close();
    }
}
`
proninyaroslav commented 5 years ago

@Gibitop I don't think that is a solution, since after there download is not restored. This is a big problem that I encountered when writing a streaming service.

olegazyx commented 5 years ago

@proninyaroslav How did you solve this issue?

proninyaroslav commented 5 years ago

@OLEG4120 unfortunately so far I haven't found solution.

proninyaroslav commented 5 years ago

@OLEG4120 I used master version of NanoHTTPD (not 2.3.1), and it seems it doesn't have this problem.

LordFokas commented 5 years ago

Well if 2.3.2 broke all the shit that's a starting point. But I think that error is way older than that, in fact I think this particular error predates me being on the team.

Do you think you could come up with a unit test that fails specifically on this error?

AbhilashRath commented 3 years ago

Faced the similar exception. Simply sending a file of average size 500kb from client android device to device hosting the server using multipart request to 192.168.43.1:8080. The file is reaching server and is also being processed but client receives response as TimeoutError and this exception is thrown in server hosting android app: 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: Could not send response to the client 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: java.net.SocketException: Broken pipe 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at java.net.SocketOutputStream.socketWrite0(Native Method) 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:117) 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at java.net.SocketOutputStream.write(SocketOutputStream.java:149) 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at fi.iki.elonen.NanoHTTPD$Response$ChunkedOutputStream.write(NanoHTTPD.java:1442) 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at java.util.zip.GZIPOutputStream.finish(GZIPOutputStream.java:164) 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at fi.iki.elonen.NanoHTTPD$Response.sendBodyWithCorrectEncoding(NanoHTTPD.java:1665) 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at fi.iki.elonen.NanoHTTPD$Response.sendBodyWithCorrectTransferAndEncoding(NanoHTTPD.java:1654) 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at fi.iki.elonen.NanoHTTPD$Response.send(NanoHTTPD.java:1624) 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at fi.iki.elonen.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:957) 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at fi.iki.elonen.NanoHTTPD$ClientHandler.run(NanoHTTPD.java:192) 04-09 00:55:57.921 3711 19640 E fi.iki.elonen.NanoHTTPD: at java.lang.Thread.run(Thread.java:919)

My code which is handling file: `
public Response processEvents(Map<String, List> params, Map<String, String> files) throws IOException { Map<String,byte[]> eventMap = new HashMap<>();

    for(Map.Entry<String,List<String>>param:params.entrySet()){
        if(!param.getKey().equals("xyzEventJson")){
            String[] originalFilename = param.getValue().get(0).split(":");
            String eventName = originalFilename[0] + "_" + originalFilename[1];
            String eventAbsolutePath = files.get(param.getKey());
            File eventFile = new File(eventAbsolutePath);
            byte[] eventBytes = new byte[(int)eventFile.length()];
            DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(eventFile)));
            dataInputStream.readFully(eventBytes);
            eventMap.put(eventName,eventBytes);
            eventFile.delete();
        }
    }
    String EventJson = URLDecoder.decode(params.get("EventJson").get(0),"UTF-8");
    Gson gson = new Gson();
  EventDTO EventDTO = gson.fromJson(EventJson,EventDTO.class);
    for(EventFrame eventFrame : EventDTO.getEventFrames()){
        String eventkey = String.format("%s_%d",eventFrame.getFrameType(),eventFrame.getFrameOrder());
        byte[] eventBytes = eventMap.get(eventkey);
        eventFrame.setImageBytes(eventBytes);
    }
    remoteMethods.insertEvent(this.context,EventDTO);
    return newFixedLengthResponse("{}");
}

` Basically I am just returning newFixedLengthResponse to the client whatever be the processing. This happened very rarely but once this happened it broke the whole master slave communication architecture.