0

running an xml-rcp server and client. trying to log the requests to the server. But get Premature end of file error. Can anyone see what I am doing wrong?

 public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException

 ServletInputStream sis = req.getInputStream();
 int len = req.getContentLength();
 byte[] bytes = new byte[len]; 

 int offset = 0;  
 int numRead = 0;  
 while ((offset < bytes.length) && (numRead=sis.read(bytes, offset, bytes.length-offset)) >= 0) {  
       offset += numRead;  
   }  

   if (offset < bytes.length) {  
       throw new IOException("Could not complete reading request body");  
   }  

   sis.close();  

   FileOutputStream f = new FileOutputStream(new File("C:\\Users\\test\\file.log"), true);
   f.write(bytes);  
   f.flush();
   f.close();

   super.doPost(req, res);
 }

[Fatal Error] :1:1: Premature end of file.

redstone.xmlrpc.XmlRpcException: A problem occured during parsing at redstone.xmlrpc.XmlRpcParser.parse(Unknown Source) at redstone.xmlrpc.XmlRpcDispatcher.dispatch(Unknown Source) at redstone.xmlrpc.XmlRpcServer.execute(Unknown Source) at redstone.xmlrpc.XmlRpcServlet.doPost(Unknown Source) at com.devices.test.servlet.MyXmlRpcServlet.doPost(MyXmlRpcServlet.java:93) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:565) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:479) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1031) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:406) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:965) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111) at org.eclipse.jetty.server.Server.handle(Server.java:349) at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:452) at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:894) at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:948) at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:857) at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:77) at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:609) at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:45) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:599) at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:534) at java.lang.Thread.run(Thread.java:722) Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1236) ... 26 more

solution:

 import javax.servlet.ServletException;
 import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;

 public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
 {
 CustomHttpServletRequestWrapper wrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) req);

 ServletInputStream sis = wrapper.getInputStream();
 String StringFromInputStream = IOUtils.toString(sis, "UTF-8");
 LOG.info( "request:");
 LOG.info( StringFromInputStream );
 super.doPost(wrapper, res);
 }


 public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper
 {

  private final String body;
  private final Logger LOG = LoggerFactory.getLogger( CustomHttpServletRequestWrapper.class );

  public CustomHttpServletRequestWrapper( final HttpServletRequest request )
  {
     super( request );

     final StringBuilder stringBuilder = new StringBuilder();
     BufferedReader bufferedReader = null;

     try
     {
        final InputStream inputStream = request.getInputStream();

        if (inputStream != null)
        {
           bufferedReader = new BufferedReader( new InputStreamReader( inputStream ) );

           final char[] charBuffer = new char[128];
           int bytesRead = -1;

           while (( bytesRead = bufferedReader.read( charBuffer ) ) > 0)
           {
              stringBuilder.append( charBuffer, 0, bytesRead );
           }
        }
        else
        {
           stringBuilder.append( "" );
        }
     }
     catch (final IOException ex)
     {
        LOG.error( "Error reading the request body..." );
     }
     finally
     {
        if (bufferedReader != null)
        {
           try
           {
              bufferedReader.close();
           }
           catch (final IOException ex)
           {
              LOG.error( "Error closing bufferedReader..." );
           }
        }
     }

     body = stringBuilder.toString();
     LOG.info( "body:" );
     LOG.info( body );
  }

  @Override
  public ServletInputStream getInputStream() throws IOException
  {
     final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( body.getBytes() );

     final ServletInputStream inputStream = new ServletInputStream()
     {
        @Override
        public int read() throws IOException
        {
           return byteArrayInputStream.read();
        }
     };

     return inputStream;
  }

}

user840930
  • 5,214
  • 21
  • 65
  • 94
  • I suggest that you use Apache IOUtils to read the Inputstream to the Byte[]. It looks to me as if this is the source of your problem. – Randy Nov 12 '13 at 12:03
  • tried this. But get the same error message. ServletInputStream sis = wrapper.getInputStream(); String StringFromInputStream = IOUtils.toString(sis, "UTF-8"); – user840930 Nov 12 '13 at 12:52

1 Answers1

2

You already consumed all data sent with the request, so there's nothing left for the super.doPost(...) method!

You could instead pass a HttpServletRequestWrapper to super.doPost(...). It should wrap the original request but returns a different InputStream that is backed by the bytes array you've already read in this method. Also note that it will be necessary to also wrap the reader that can be obtained from the request (HttpServletRequest#getReader()).

See also How to log response content from a java web server, there you can find a complete code sample about the opposite side of logging. I think it can easily be adopted to what you need.

Community
  • 1
  • 1
isnot2bad
  • 24,105
  • 2
  • 29
  • 50
  • What is the proper way of doing this? I have tried several examples I found on the web, but still get the same error. – user840930 Nov 12 '13 at 12:51
  • Okay, I got it. You are correct. Put the request in the wrapper. use the wrapper to get the InputStream to process for me AND also give the wrapper to the super class super.doPost(wrapper, ...). From what I tried, I either didn't send the wrapper to the super or didn't use the wrapper for myself. Once the request is wrapped. the wrapper should be used for all cases, never the request. – user840930 Nov 12 '13 at 14:19
  • Yes, but not necessarily. It's just important that the request that you're passing to super.doPost(...) has still all data as if it were "new". I also suggest to use a Filter instead of subclassing the Servlet. The filter can then be used for all kind of requests. – isnot2bad Nov 12 '13 at 14:37