Home > Blockchain >  How to completely abort the output stream download?
How to completely abort the output stream download?

Time:12-28

we're currently working on the service that would archive the data and return it to the user as a ZipOutputStream. What we're currently looking for is an option to completely terminate the operation if something goes wrong on the server side. With our current implementation (just closing the response output stream) errors result in a malformed zip at the user side, but it can't be told if the archive is malformed or not before attempting to unzip it. The desired behavior would be something like download termination (from a browser perspective, for instance, it would result in an unsuccessful download indication (red cross icon or something similar, depending on the browser) explicitly telling the user that something went wrong). We're using Spring Boot, so any java code examples would really be appreciated, but if you know the underlying HTTP mechanism that is responsible for this kind of behavior, and can point in the right direction, that would be much appreciated too. Here's what we have as of now (output being a response output stream of a Spring REST controller (HttpServletResponse.getOutputStream()) :

try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
        try {
            for (ZipRecordFile fileInfo : zipRecord.listZipFileOverride()) {
                InputStream fileStream = getFileStream(fileInfo.s3region(), fileInfo.s3bucket(),
                    fileInfo.s3key());
                ZipEntry zipEntry = new ZipEntry(fileInfo.fileName());
                zipOutputStream.putNextEntry(zipEntry);
                fileStream.transferTo(zipOutputStream);
            }
        }
        catch (Exception e) {
            outputStream.close();
        }
    }

CodePudding user response:

I think you should throw the exception instead of handling it.

With your catch block, you are handling the exception.

    catch (Exception e) {
        outputStream.close();
    }

Also, as your code is using try-with-resources block, you shouldn't need another try block and don't need to explicitly close zipOutputStream.

CodePudding user response:

There isn't a (clean) way to do what you want:

Once you have started writing the ZIP file to the output stream, it is too late to change the HTTP response code. The response code is sent at the start of response.

Therefore, there is no proper way for the HTTP server to tell the HTTP client: "Hey ... ignore that ZIP file I sent you 'cos it is corrupt".

So what are the alternatives?

  1. On the server side, create the entire ZIP as an in-memory object or write it to a temporary file. If you succeed, send an 2xx response followed by the ZIP data. If you fail, send a 4xx or 5xx response.

    The main problem is that you need enough memory or file system space to hold the ZIP file.

  2. Redesign your HTTP API so that the client can sent a second request to check if the first request's response contained a complete ZIP file.

  3. You might be able to exploit MIME multipart encoding. Each part of a well-formed MIME multipart has a start marker and an end-marker. What you could try is to have your web-app construct the multipart stream containing the ZIP "by hand". If it decides it must abort the ZIP, it could just close the output stream without adding the required end marker.

    The main problem with this is that you are depending on the HTTP stack on the client side to tell the browser (or whatever) that the multipart is corrupted. Furthermore, the browser (or whatever) must not pass on the partial (i.e. corrupt) ZIP file on to the user. I'm not sure if you can rely on (particular) web browsers to do that.

  4. If you are running the download via custom code on the client side, you could conceivably implement your own encapsulation protocol. The effect would be the same as for 3 ... but you wouldn't be abusing the MIME spec.

  • Related