title: Download large files through S3 java sdk 2 without writing to server
body: <p>I am trying to download large files through AWS without saving it to server and so far nothing I have tried has worked.</p>
  
  <p>Here is the code to fetch from AWS.</p>
  
  <pre><code>public ResponseInputStream&lt;GetObjectResponse&gt; downloadFile(String key){
  
  
       return s3client.getObject(GetObjectRequest.builder().bucket(bucketName).key(key).build(),ResponseTransformer.toInputStream());
  
  }
  </code></pre>
  
  <p>And here is the spring boot controller that is trying to send this response stream back.</p>
  
  <pre><code>   @RequestMapping(path = "/download", method = GET)
      public ResponseEntity&lt;Resource&gt; downloadOld(@RequestParam String key, Authentication authentication) throws IOException {
          ResponseInputStream&lt;GetObjectResponse&gt; responseStream = this.amazonClient.downloadFile(key);
          InputStreamResource resource = new InputStreamResource(responseStream);
          HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + key.substring(key.lastIndexOf('/') + 1) + "\"");
          return ResponseEntity.ok()
                  .headers(headers)
                  .contentLength(responseStream.response().contentLength())
                  .contentType(MediaType.parseMediaType(responseStream.response().contentType()))
                  .body(resource);
      }
  </code></pre>
  
  <p>I have partial sucess this controller, the axios response.data does have a response. And text files do download correctly , However when the content type is anything other than plain text ( eg application/pdf etc ) , the size of the downloaded file is 1.5 times the original file size. And needless to saw it is corrupted. ( pdf / zip / png ) nothing would open in my app ( cordova app ).</p>
  
  <p>Then I tried sending a <code>StreamingResponseBody</code>. Here are two code samples I tried , With both of them this time the axios response is empty.</p>
  
  <pre><code>@Async
      @RequestMapping(path = "/download", method = GET)
      public ResponseEntity&lt;StreamingResponseBody&gt; download(@RequestParam String key, Authentication authentication) throws IOException {
          ResponseInputStream&lt;GetObjectResponse&gt; responseStream = this.amazonClient.downloadFile(key);
          final StreamingResponseBody out = (os) -&gt; {
              readAndWrite(responseStream, os);
          };
          HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + key.substring(key.lastIndexOf('/') + 1) + "\"");
          headers.add("Content-Type", "application/pdf");
          headers.add("Pragma", "no-cache");
          headers.add("Cache-Control", "no-cache");
          return (new ResponseEntity&lt;&gt;(out, headers, HttpStatus.OK));
      }
  </code></pre>
  
  <p>Next tried sending the response without header.</p>
  
  <pre><code>@Async
      @RequestMapping(path = "/download", method = GET)
      public StreamingResponseBody download(@RequestParam String key, Authentication authentication) throws IOException {
          ResponseInputStream&lt;GetObjectResponse&gt; responseStream = this.amazonClient.downloadFile(key);
          return (os) -&gt; {
              readAndWrite(responseStream, os);
          };
  
      }
  </code></pre>
  
  <p>Straighforward readAndWrite callback implementation.</p>
  
  <pre><code>private void readAndWrite(final InputStream is, OutputStream os)
              throws IOException {
          byte[] data = new byte[2048];
          int read = 0;
          while ((read = is.read(data)) &gt; 0) {
              os.write(data, 0, read);
          }
          os.flush();
      }
  </code></pre>
  
  <p>You can only imagine the headaches I am going through here.</p>
  
  <p>I also tried the newer sdk in-build async approach , which again did not work. Here is the client call.</p>
  
  <pre><code>@Async
  public CompletableFuture&lt;ResponseBytes&lt;GetObjectResponse&gt;&gt; downloadAsync(String key){
  
  
      return s3AsyncClient.getObject(GetObjectRequest.builder().bucket(bucketName).key(key).build(), AsyncResponseTransformer.toBytes());
  
  }
  </code></pre>
  
  <p>( Couldn't find on example on Amazon AWS site on how return a stream. They have one example where they used a ResponseTransformer to to save to local file, that doesn't help me).</p>
  
  <p>Corresponding controller for above AsyncResponse.</p>
  
  <pre><code> @Async
      @RequestMapping(path = "/downloadAync", method = GET)
      public CompletableFuture&lt;ResponseBytes&lt;GetObjectResponse&gt;&gt; downloadAsync(@RequestParam String key, Authentication authentication) throws IOException {
          return this.amazonClient.downloadAsync(key);
  
      }
  </code></pre>