java.io.IOException: Stream closed in HandlerInterceptor - java

I have a problem with Interceptor in SpringBoot I am trying to read the body in a request at preHandle() method.
public class LogInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
System.out.println("Error reading the request body...");
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
System.out.println("Error closing bufferedReader...");
}
}
}
String body = stringBuilder.toString();
System.out.println("--Body--"+body);
}
}
This code print body correctly but when I try to made a POST petition with Postman I receive the following error.
I/O error while reading input message; nested exception is java.io.IOException: Stream closed
If I do the same petition witouth this code the petition works correctly.
Could anyone help to me ? Or said a better solution to intercept body ?

Related

How to modify the request body in HttpServletRequest method using HandlerInterceptorAdapter

I tried using HttpRequestWrapper but it keeps giving me stream closed exception. Below is my HttpRequestWrapper code. I was trying to modify the request body in preHandle method. after modifying the request body I want to send it to the controller. It seems like HandlerInterceptorAdapter been called twice. In the second time it complains that the stream is closed. I've seen post related to this issue but I could not find a solution.
public class RequestWrapper extends HttpServletRequestWrapper {
private final String body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
#Override public boolean isFinished() {
return false;
}
#Override public boolean isReady() {
return false;
}
#Override public void setReadListener(ReadListener readListener) {
}
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}

InputStream is not working properly

I am a beginner in android. I am trying to work on Sockets. But my InputStream is not reading the data as expected. It is getting out of the method after j = inputStream.read(arrayOfByte, 0, i); Please help me.
public void readinputstreamforid(final String ip, final int port){
AsyncTask asyncTask = new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
try {
socket=new Socket(ip,port);
} catch (IOException e) {
e.printStackTrace();
}
final byte[] arrayOfByte = new byte[10000];
InputStream inputStream = null;
try {
inputStream = socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
while (socket.isConnected()) {
int j = 0;
int i = arrayOfByte.length;
try {
j = inputStream.read(arrayOfByte, 0, i);
if (j == -1)
throw new IOException("not working");
if (j == 0)
continue;
} catch (IOException e) {
e.printStackTrace();
}
final String strData = new String(arrayOfByte, 0, j).replace("\r", "").replace("\n", "");
Log.d("hello","recieved: "+strData);
}
try {
IOUtils.write("!##\n",socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
asyncTask.execute();
}
If an error happens, you are logging it, but then you continue with the code, where more errors can then happen. When an error happens, STOP looping and exit the function. InputStream.read() returns -1 when the end of the stream is reached. For a socket, that means when the connection is closed. That is not really an error condition, so you don't need to throw an exception. Just break the loop. You can wrap the InputStream inside of a BufferedReader so you can use its readLine() method instead of reading bytes manually.
Also, you are trying to write to the socket's OutputStream after the socket has already disconnected. That will never work.
Try something more like this:
public void readinputstreamforid(final String ip, final int port){
AsyncTask asyncTask = new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
try {
socket = new Socket(ip, port);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
OutputDataStream out = socket.getOutputStream();
do {
String data = in.readLine();
if (data == null)
break;
Log.d("hello", data);
IOUtils.write("!##\n", out, StandardCharsets.UTF_8);
}
while (true);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
asyncTask.execute();
}

How to Mock a javax.servlet.ServletInputStream

I am creating some unit testing and trying to Mock out some calls. Here is what I have in my working code:
String soapRequest = (SimUtil.readInputStream(request.getInputStream())).toString();
if (soapRequest.equals("My String")) { ... }
and SimUtil.readInputSteam looks like this:
StringBuffer sb = new StringBuffer();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(inputStream));
final int buffSize = 1024;
char[] buf = new char[buffSize];
int numRead = 0;
while ((numRead = reader.read(buf)) != -1) {
String readData = String.valueOf(buf, 0, numRead);
sb.append(readData);
buf = new char[buffSize];
}
} catch (IOException e) {
LOG.error(e.getMessage(), e);
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}
}
What I am trying to do is the request.getInputStream(), the stream returns certain String.
HttpServletRequest request = mock(HttpServletRequest.class);
ServletInputStream inputStream = mock(ServletInputStream.class);
when(request.getInputStream()).thenReturn(inputStream);
So This is the code I want to condition
when(inputStream.read()).thenReturn("My String".toInt());
Any Help would be greatly appreciated.
Don't mock the InputStream. Instead, transform the String to an array of bytes using the
getBytes() method. Then create a ByteArrayInputStream with the array as input, so that it returns the String when consumed, each byte at a time. Next, create a ServletInputStream that wraps a regular InputStream like the one from Spring:
public class DelegatingServletInputStream extends ServletInputStream {
private final InputStream sourceStream;
/**
* Create a DelegatingServletInputStream for the given source stream.
* #param sourceStream the source stream (never <code>null</code>)
*/
public DelegatingServletInputStream(InputStream sourceStream) {
Assert.notNull(sourceStream, "Source InputStream must not be null");
this.sourceStream = sourceStream;
}
/**
* Return the underlying source stream (never <code>null</code>).
*/
public final InputStream getSourceStream() {
return this.sourceStream;
}
public int read() throws IOException {
return this.sourceStream.read();
}
public void close() throws IOException {
super.close();
this.sourceStream.close();
}
}
and finally, the HttpServletRequest mock would return this DelegatingServletInputStream object.

Why do I need to catch a close() exception in BufferedReader but not in PrintWriter?

I have a simple file read and write function.
private void WriteToFile(String filename, String val) {
PrintWriter outStream = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filename);
outStream = new PrintWriter(new OutputStreamWriter(fos));
outStream.print(val);
outStream.close();
} catch (Exception e) {
if (outStream != null) {
outStream.close();
}
}
}
private String ReadFile(String filename) {
String output = "";
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(filename);
br = new BufferedReader(fr);
output = br.readLine();
br.close();
} catch (Exception e) {
if (br != null) {
br.close();
}
}
return output;
}
When building I get:
unreported exception java.io.IOException; must be caught or declared to be thrown
br.close();
^
Why do I need to catch br.close but it doesn't complain about WriteToFile's close()?
Taken from the source code of java.io.PrintWriter:
public void close() {
try {
synchronized (lock) {
if (out == null)
return;
out.close();
out = null;
}
}
catch (IOException x) {
trouble = true;
}
}
The IOException was eaten up within the close() method in PrintWriter
From source code of java.io.BufferedReader:
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
in.close();
in = null;
cb = null;
}
}
BufferedReader throws the IOException.
That should answer your question.
Why do I need to catch br.close but it doesn't complain about WriteToFile's close()?
You can check the Java Docs for this. The close() method for BufferedReader :
public void close()
throws IOException
And the close() method for PrintWriter :
public void close()
That answer's your question as to why JVM doesn't complain. Because it is clear from the method signatures;
PrinterWriter.close() doesn't throw any Exception.
If you call fos.close(), it will ask you to catch/throw the exception.
In the PrintWriter.java. The exception is caught and handled. So you needn't catch it while using.
Java Source:
public void close() {
try {
synchronized (lock) {
if (out == null)
return;
out.close();
out = null;
}
}
catch (IOException x) {
trouble = true;
}
}
But in BufferedReader the exception is thrown. So you have to catch it when using.
Java Source:
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
in.close();
in = null;
cb = null;
}
}

IllegalStateException on redirect

I have a PhaseListener which listens on phaseId RENDER_RESPONSE. This faceListener calls this method:
public void doLogin(ServletRequest request) throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
HttpServletRequest req = (HttpServletRequest) request;
String code = req.getParameter("code");
if (StringUtil.isNotBlankString(code)) {
String authURL = Facebook.getAuthURL(code);
URL url = new URL(authURL);
try {
....
if (accessToken != null && expires != null) {
boolean isLoginOk = service.authFacebookLogin(accessToken);
if (isLoginOk) {
fc.getApplication().getNavigationHandler().handleNavigation(fc, "/welcome.xhtml", "logged-in");
}
} else {
throw new RuntimeException("Access token and expires not found");
}
} catch (IOException e) {
throw new RuntimeException(e);
} catch (FacebookException e) {
Logger.getLogger(FBOauth.class.getName()).log(Level.SEVERE, "Facebook error", e);
}
}
}
private String readURL(URL url) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = url.openStream();
int r;
while ((r = is.read()) != -1) {
baos.write(r);
}
return new String(baos.toByteArray());
}
When it redirects I get the following exception which I cant really find any solution to. From what I understand it is thrown because response is already comitted but why is it already comitted?
java.lang.IllegalStateException at
org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:522)
at com.sun.faces.context.ExternalContextImpl.redirect(ExternalContextImpl.java:572)
at com.sun.faces.application.NavigationHandlerImpl.handleNavigation(NavigationHandlerImpl.java:182)
at wmc.web.facebook.FBOauth.doLogin(FBOauth.java:57)
at wmc.web.listeners.FacebookSignInListener.afterPhase(FacebookSignInListener.java:56)
at com.sun.faces.lifecycle.Phase.handleAfterPhase(Phase.java:189)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:107)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:313)
By the way I really appreciate all the help I get in here :)
Your phaselistener is apparently hooking on afterPhase of RENDER_RESPONSE. It's too late to change the response then. The response is already been sent to the client. Rather hook on beforePhase() of the `RENDER_RESPONSE.
My guess would be that before the sendRedirect() is executed some part of your code has already streamed text to the servlet repsonse, maybe some generic information that is send to all responses?

Categories

Resources