title: Strange behaviour of POST handler in Spring Boot after enabling SSL
body: <p>I've been experiencing a strange issue with handling of a POST method in my controller after enabling the SSL in my Spring Boot application. Here's what I've done:</p>
  <ol>
  <li>Created a self-signed certificate using keytool (one on localhost and one on remote host)</li>
  <li>Enabled SSL in application.properties like so:</li>
  </ol>
  <blockquote>
  <pre><code>server.port=8444
  server.ssl.key-store-type=PKCS12
  server.ssl.key-store=classpath:keystore/cert.p12
  server.ssl.key-store-password=somepwd
  server.ssl.key-alias=cert
  </code></pre>
  </blockquote>
  <ol start="3">
  <li>Placed the cert.p12 as per property above</li>
  </ol>
  <p>What I experience now is the following:</p>
  <ol>
  <li>On localhost</li>
  </ol>
  <ul>
  <li>get requests work just fine when using HTTPS</li>
  <li>post requests work just fine when using HTTPS</li>
  </ul>
  <ol start="2">
  <li>After deploying it on another host (of course with updated certificate)</li>
  </ol>
  <ul>
  <li><p>get requests work just fine when using HTTPS</p>
  </li>
  <li><p>post requests don't work when using HTTPS and return the following message:</p>
  <blockquote>
  <p><em>Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public org.springframework.http.ResponseEntity&lt;java.lang.String&gt; com.app.updateData(java.lang.String)]</em></p>
  </blockquote>
  </li>
  </ul>
  <p><strong>Some background</strong></p>
  <p>Here's how my method looks like:</p>
  <pre><code>@CrossOrigin(origins = &quot;*&quot;) 
  @PostMapping(path=&quot;/api/data-update&quot;)
  public ResponseEntity&lt;String&gt; updateData(@RequestBody String data) {...}
  </code></pre>
  <p>I test it in the following way (using curl).</p>
  <p>On localhost (which works just fine):</p>
  <pre><code>curl -k -X POST -H &quot;Content-Type: application/json&quot; -H &quot;Content-Encoding: gzip&quot; --data-binary @./test_data.gzip https://localhost:8444/api/data-update
  </code></pre>
  <p>On remote server (which returns the error I listed above):</p>
  <pre><code>curl -k -X POST -H &quot;Content-Type: application/json&quot; -H &quot;Content-Encoding: gzip&quot; --data-binary @./test_data.gzip https://remoteserver:8444/api/data-update
  </code></pre>
  <p>So basically what I do is to submit via POST a zipped JSON file.
  Note that this method works just fine when I disable the SSL configuration (meaning that I use HTTP), as well as, when I test it on the localhost. It stops working only when trying to execute the curl above to an external server.</p>
  <p>I hope I provided all the details that may be needed for someone to suggest a possible solution to this issue.</p>
  <p>Many thanks in advance!</p>
  <p><strong>UPDATE:</strong></p>
  <p>Initially I thought I cannot be because of the filter I have included, in order to processes the GZIP file, but it turns out that the problem described above occurs only for the binary data I'm trying to POST using curl. If I POST text JSON data to another controller, it works just fine. I don't think it is the filter itself because other filters work, so my prime suspect is this GZIP extraction but I can't find anything wrong with it.</p>
  <p>Here's my filter class:</p>
  <pre><code>package com.app.filter;
  
  import java.io.ByteArrayInputStream;
  import java.io.EOFException;
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.Map;
  import java.util.zip.GZIPInputStream;
  
  import javax.servlet.Filter;
  import javax.servlet.FilterChain;
  import javax.servlet.ReadListener;
  import javax.servlet.ServletException;
  import javax.servlet.ServletInputStream;
  import javax.servlet.ServletRequest;
  import javax.servlet.ServletResponse;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletRequestWrapper;
  
  import org.apache.commons.io.IOUtils;
  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
  import org.springframework.stereotype.Component;
  
  @Component
  public class GzipBodyDecompressFilter implements Filter {
  
      private static final Logger logger = LogManager.getLogger(GzipBodyDecompressFilter.class);
  
      @Override
      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
              throws IOException, ServletException {
  
          HttpServletRequest request = (HttpServletRequest) servletRequest;
  
          String encoding = request.getHeader(&quot;Content-Encoding&quot;);
          if (encoding != null &amp;&amp; encoding.equals(&quot;gzip&quot;)) {
              logger.info(&quot;GZIP extraction&quot;);
              request = new GzippedInputStreamWrapper((HttpServletRequest) servletRequest);
          }
  
          chain.doFilter(request, servletResponse);
      }
  
      final class GzippedInputStreamWrapper extends HttpServletRequestWrapper {
  
          public static final String DEFAULT_ENCODING = &quot;ISO-8859-1&quot;;
          private byte[] bytes;
  
          public GzippedInputStreamWrapper(final HttpServletRequest request) throws IOException {
              super(request);
  
              try {
                  final InputStream in = new GZIPInputStream(request.getInputStream());
                  bytes = IOUtils.toByteArray(in);
              } catch (EOFException e) {
                  bytes = new byte[0];
              }
          }
  
          @Override
          public ServletInputStream getInputStream() throws IOException {
              final ByteArrayInputStream sourceStream = new ByteArrayInputStream(bytes);
  
              return new ServletInputStream() {
                  public int read() throws IOException {
                      return sourceStream.read();
                  }
  
                  @Override
                  public void setReadListener(ReadListener listener) {
                      // TODO Auto-generated method stub
  
                  }
  
                  @Override
                  public boolean isFinished() {
                      // TODO Auto-generated method stub
                      return false;
                  }
  
                  @Override
                  public boolean isReady() {
                      // TODO Auto-generated method stub
                      return false;
                  }
  
                  public void close() throws IOException {
                      super.close();
                      sourceStream.close();
                  }
              };
          }
  
          @Override
          public Map getParameterMap() {
              return super.getParameterMap();
          }
      }
  }
  </code></pre>
  <p><strong>UPDATE 2:</strong></p>
  <p>Just by an accident I tried to submit another JSON file that is much smaller (~1.2KB) and it worked. So there must be something in the Tomcat settings that is blocking the requests, but I can't find anything (again, it works fine for HTTP, in only rejects larger HTTPS requests).</p>