Search code examples
javaxpageslotus-domino

xAgent ServletInputStream read method always returns -1


Hello everyone once again. I can't seem to read POST content using this xpage/xAgent:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false"
    viewState="nostate" xmlns:xe="http://www.ibm.com/xsp/coreex">
    <xp:this.beforeRenderResponse>
        <![CDATA[#{javascript:
            var xagentprocessor = new com.my.test.XagentProcessor;  
            xagentprocessor.process();
        }]]>
    </xp:this.beforeRenderResponse>
</xp:view>

Which is running this code to simply reflect back to the browser the data that was submitted:

public class XagentProcessor {
    public void process() {
        try {
            byte[] body = Util.getPostRequestBytes();
            Util.sendResponseBytes(body);
        } catch (Exception e) {
            System.out.println("Error in XagentProcessor process() method:"+e.toString());
        }
    }
}

Which invokes this static method in my utility class (thanks John Dalsgaard for the tip there) which uses code I pinched from here.

public static byte[] getPostRequestBytes() {
        HttpServletRequest request = getHttpRequest();
        try {
            ServletInputStream is = request.getInputStream();
            int length=request.getContentLength(); //This is definitely nonzero
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int nRead;
            byte[] data = new byte[16384];
            while ((nRead = is.read(data, 0, data.length)) != -1) {
              buffer.write(data, 0, nRead);
            }
            return buffer.toByteArray();
        } catch (IOException e) {
            System.out.print("Error in Util.getPostRequestText() method:" + e.toString());
        }
        return new byte[0];
    }

My issue is that this returns no content, the first read of the inputstream returns -1. This might be related to this post in that if I don't put a $$viewid field in the POST request then it throws an error. This leads me to believe that domino has already read the input stream (as it knows about the missing field) so it's not available to the getPostRequestBytes method.

Any ideas anyone? My options are to either read the stream again, which I don't think is possible or get Domino not to read it to check for the $$viewid field. I'm really scratching my head now. All help very much appreciated indeed!


Solution

  • As per this post, the issue when submitting forms with xsp.csrf.protection setting equals to true causes domino to capture the stream and look for the $$viewid field, thus preventing any data from the ServletInputStream being read (as it's been read once already). This now works for all content types other than multipart/form-data. To work around this, set xsp.csrf.protection=false in the application configuration -> Xsp Properties. Set Content-Type to application/octet-stream in the client side script when building the request (e.g. using the Fetch API) and the request body is then made available to the agent.

    Any CSRF protection would have to be baked in manually, however.