I have a Gateway implementation, which redirects requests, but also I'm adding a capability to decrypt the body of the received request. The thing is that I've found a lot of answers here on SO with instructions to implement it, wrapping the original request, but in some point, I do not know why, the request get lost before reaching the target and throws an IOException (the decryption works perfectly). This is my implementation:
public class MyRequestWraper extends HttpServletRequestWrapper {
public MyRequestWraper(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
try {
String decryptedPayload = decryptPayload(getRequest().getInputStream(), getRequest().getCharacterEncoding());
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decryptedPayload.getBytes(getRequest().getCharacterEncoding()));
return new ServletInputStream(){
@SuppressWarnings("unused")
private ReadListener readListener = null;
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
@Override
public void close() throws IOException {
byteArrayInputStream.close();
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return byteArrayInputStream.read(b, off, len);
}
@Override
public boolean isFinished() {
return byteArrayInputStream.available() > 0;
}
@Override
public boolean isReady() {
return isFinished();
}
@Override
public void setReadListener(ReadListener readListener) {
this.readListener = readListener;
if (!isFinished()) {
try {
readListener.onDataAvailable();
} catch (IOException e) {
readListener.onError(e);
}
} else {
try {
readListener.onAllDataRead();
} catch (IOException e) {
readListener.onError(e);
}
}
}
};
} catch (Exception e) {
e.printStackTrace();
return super.getInputStream();
}
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
And this is the exception I get:
org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: UT000128: Remote peer closed connection before all data could be read
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:243)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:225)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:201)
The wrapper instance is used inside a Filter implementation, so I'm passing in it to the "chain.doFilter" (and as I said, I can see that the decryption is executed and successful). Any clue will be appreciated.
EDIT
Also tried to use a byte[]
instead of ByteArrayInputStream
for the getInputStream()
implementation, based on this comment
Finally I made it work, the problem was with the content length of the request (keep in mind that my original request was encrypted, and the new input stream is decrypted, so the length differs). I have to overwrite the getContentLength method, and some other minor changes:
public class MyRequestWraper extends HttpServletRequestWrapper {
private byte[] content;
public MyRequestWraper(HttpServletRequest request) {
super(request);
content = decryptPayload(getRequest().getInputStream(), getRequest().getCharacterEncoding());
}
@Override
public int getContentLength() {
if (content != null) {
return content.length;
}
return super.getContentLength();
}
@Override
public ServletInputStream getInputStream() throws IOException {
try {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(content);
return new ServletInputStream(){
@SuppressWarnings("unused")
private ReadListener readListener = null;
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
@Override
public void close() throws IOException {
byteArrayInputStream.close();
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return byteArrayInputStream.read(b, off, len);
}
@Override
public boolean isFinished() {
return byteArrayInputStream.available() > 0;
}
@Override
public boolean isReady() {
return isFinished();
}
@Override
public void setReadListener(ReadListener readListener) {
this.readListener = readListener;
if (!isFinished()) {
try {
readListener.onDataAvailable();
} catch (IOException e) {
readListener.onError(e);
}
} else {
try {
readListener.onAllDataRead();
} catch (IOException e) {
readListener.onError(e);
}
}
}
};
} catch (Exception e) {
e.printStackTrace();
return super.getInputStream();
}
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}