0

I have an application that works fine in local, but on the client it crashs because a POST parameter is null.

((HttpServletRequest)request).getParameter("dtid");

This return null.

So I have added a filter to log GET/POST/BODY of the request. In local the log look like this :

[METHOD:POST] [REQUEST URI:/peps/zkau] [REQUEST PARAMETERS:{dtid=z_0n8, uuid_0=x38Pz, data_0={"pageX":372,"pageY":103,"which":1,"x":40.79998779296875,"y":4}, cmd_0=onClick}] [REQUEST BODY:] [REMOTE ADDRESS:0:0:0:0:0:0:0:1]

I have dtid in request param and the body is empty. On the client the same log looks like this :

[METHOD:POST] [REQUEST URI:/peps/zkau] [REQUEST PARAMETERS:{}] [REQUESTBODY:dtid=z_cb50&cmd_0=onOpen&uuid_0=l2sT30&data_0=%7B%22open%22%3Atrue%2C%22reference%22%3A%22l2sT20%22%7D&cmd_1=onClick&uuid_1=l2sT40&data_1=%7B%22pageX%22%3A323%2C%22pageY%22%3A138%2C%22which%22%3A1%2C%22x%22%3A323%2C%22y%22%3A138%7D&cmd_2=onOpen&uuid_2=l2sT30&data_2=%7B%22open%22%3Afalse%7D] [REMOTE ADDRESS:x.x.x.x]

Parameters is an empty map, but the body is full. The body appears to be un processed what can cause this ? Why isn't the body parsed and inject in the parameter map ?

Thanks

Here is my Filter :

public class PepsParamFilter implements Filter {

    private static final Logger LOG = Logger.getLogger(PepsParamFilter.class.getName());

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;

            Map<String, String> requestMap = this.getTypesafeRequestMap(httpServletRequest);
            BufferedRequestWrapper bufferedReqest = new BufferedRequestWrapper(httpServletRequest);            

            chain.doFilter(bufferedReqest, response);

             //Request
                final StringBuilder reqMessage = new StringBuilder("").append("[METHOD:")
                        .append(httpServletRequest.getMethod())                        
                        .append("] [REQUEST URI:")
                        .append(httpServletRequest.getRequestURI())                        
                        .append("] [REQUEST PARAMETERS:").append(requestMap)
                        .append("] [REQUEST BODY:")
                        .append(bufferedReqest.getRequestBody())
                        .append("] [REMOTE ADDRESS:")
                        .append(httpServletRequest.getRemoteAddr()).append("]");
                if(!httpServletRequest.getRequestURI().endsWith(".gif")
                    && !httpServletRequest.getRequestURI().endsWith(".png")
                    && !httpServletRequest.getRequestURI().endsWith(".css")
                    ) {
                    LOG.info(reqMessage);
                }



        } catch (Throwable a) {
            LOG.error(a.getMessage(),a);
        }
    }

    private Map<String, String> getTypesafeRequestMap(HttpServletRequest request) {
        Map<String, String> typesafeRequestMap = new HashMap<String, String>();
        Enumeration<?> requestParamNames = request.getParameterNames();
        while (requestParamNames.hasMoreElements()) {
            String requestParamName = (String) requestParamNames.nextElement();
            String requestParamValue = request.getParameter(requestParamName);
            typesafeRequestMap.put(requestParamName, requestParamValue);
        }
        return typesafeRequestMap;
    }

    @Override
    public void destroy() {
    }

    private static final class BufferedRequestWrapper extends
            HttpServletRequestWrapper {

        private ByteArrayInputStream bais = null;
        private ByteArrayOutputStream baos = null;
        private BufferedServletInputStream bsis = null;
        private byte[] buffer = null;

        public BufferedRequestWrapper(HttpServletRequest req)
                throws IOException {
            super(req);
            // Read InputStream and store its content in a buffer.
            InputStream is = req.getInputStream();
            this.baos = new ByteArrayOutputStream();
            byte buf[] = new byte[1024];
            int letti;
            while ((letti = is.read(buf)) > 0) {
                this.baos.write(buf, 0, letti);
            }
            this.buffer = this.baos.toByteArray();
        }

        @Override
        public ServletInputStream getInputStream() {
            this.bais = new ByteArrayInputStream(this.buffer);
            this.bsis = new BufferedServletInputStream(this.bais);

            return this.bsis;
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(this.getInputStream()));
        }

        String getRequestBody() throws IOException {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    this.getInputStream()));
            String line = null;
            StringBuilder inputBuffer = new StringBuilder();
            do {
                line = reader.readLine();
                if (null != line) {
                    inputBuffer.append(line.trim());
                }
            } while (line != null);
            reader.close();
            return inputBuffer.toString().trim();
        }

    }

    private static final class BufferedServletInputStream extends
            ServletInputStream {

        private ByteArrayInputStream bais;

        public BufferedServletInputStream(ByteArrayInputStream bais) {
            this.bais = bais;
        }

        @Override
        public int available() {
            return this.bais.available();
        }

        @Override
        public int read() {
            return this.bais.read();
        }

        @Override
        public int read(byte[] buf, int off, int len) {
            return this.bais.read(buf, off, len);
        }

    }

    public class TeeServletOutputStream extends ServletOutputStream {

        private final TeeOutputStream targetStream;

        public TeeServletOutputStream(OutputStream one, OutputStream two) {
            targetStream = new TeeOutputStream(one, two);
        }

        @Override
        public void write(int arg0) throws IOException {
            this.targetStream.write(arg0);
        }

        public void flush() throws IOException {
            super.flush();
            this.targetStream.flush();
        }

        public void close() throws IOException {
            super.close();
            this.targetStream.close();
        }
    }


}
jpprade
  • 3,497
  • 3
  • 45
  • 58

2 Answers2

2

Section 3.1.1 of the Servlet-spec states:

3.1.1 When Parameters Are Available

The following are the conditions that must be met before post form data will be populated to the parameter set:

  1. The request is an HTTP or HTTPS request.
  2. The HTTP method is POST.
  3. The content type is application/x-www-form-urlencoded.
  4. The servlet has made an initial call of any of the getParameter family of methods on the request object.

If the conditions are not met and the post form data is not included in the parameter set, the post data must still be available to the servlet via the request object’s input stream. If the conditions are met, post form data will no longer be available for reading directly from the request object’s input stream.

You have to check if any of these conditions apply differently to your local or client system.

There might be other filters (in the filter chain before yours), which already process the request body, or change the content type, or previously accessed one of the getParameter* methods, or wrapped the request ... (you get the point)

In essence, both states are valid depending on what happened to your request earlier.

The first thing to check would be whether or not the browser sends the same request(/body) and headers. E.g. in the browser's developer tools. If those are identical, check your web.xml for additional filters (e.g. security filters are often different between local dev and production environments).

cor3000
  • 936
  • 1
  • 6
  • 16
0

With a POST call, parameters will be sent in request body which is happening in the logs from your server. So you will need to get request body to access the parameters you need, refer this question on how to get post data.