Configuring Liberty web applications to reread POST data

Your web application can reread the POST data of the request in scope by using the input stream, a reader, or parsed parameters. Set the web container property to use this reread behavior.

Before you begin

The Java™ servlet specification allows a web application to read POST data of a request by using an input stream, by using a reader, or by using parsed parameters. However, the web application can use only one of these methods in the scope of a request to read the POST data.

When you set the web container property, your web application can reread the POST data multiple times. However, a reader or an input stream must be closed to complete the read operation before a new read operation can be started. The data does not need to be fully read before a reader or input stream is closed. Partial reading of the data can be completed. For parsed parameters, the web container reads the entire POST data and then closes the read operation after all of the parameters are parsed.

Your application can do a non-blocking reread of POST data. For example, the application can do a non-blocking read by using the asynchronous read listener (AsyncReadListener), doing a close, and then doing a blocking read. The application can also do, for example, a non-blocking read by using the asynchronous read listener, doing a close, and then doing a second non-blocking read by using a new asynchronous read listener.

When your application does a subsequent read of the POST data by using a non-blocking read, the server first provides the data that was previously read. If the previous completed read did not read all of the post data that was sent in the request, the new read does a block when the application reads the remaining POST data.

About this task

You set the web container property to true. Then, you run a web application that can reread POST data. Examples are provided.

Procedure

  1. Enable the rereading of POST data.

    When you set the enablemultireadofpostdata custom property to true in the server.xml file, the custom property is set at the server level. The reread behavior applies to all web applications on the server. If you want the reread behavior to apply to a specific web application, then set the com.ibm.ws.webcontainer.SET_MULTI_READ_WEBAPP context parameter to true in the web.xml file. For a particular web application, the setting at the web application level overrides the setting at the server level.

    The default for both the enablemultireadofpostdata custom property and the com.ibm.ws.webcontainer.SET_MULTI_READ_WEBAPP context parameter is false.

    To enable this behavior at the server level, add the following statement to the server.xml file:
    <webContainer enablemultireadofpostdata="true" />
    To enable this behavior at the web application level, add the following context-param statement to the web.xml file:
                    
    <context-param>                 
        <param-name>com.ibm.ws.webcontainer.SET_MULTI_READ_WEBAPP</param-name>                    
        <param-value>true</param-value>                
    </context-param>
  2. Run a web application that can reread POST data.

Examples

Blocking read example

The following steps and snippet of code show how an application can reread POST data by using the getInputStream () method, the getParameter () method, and the getReader () method. However, you can use the methods in your application in any combination.
  1. Get the input stream by using the getInputStream () method.
  2. Read the data.
  3. Close the input stream.
  4. Get the new input stream by using the getInputStream () method.
  5. Read the data.
  6. Close the input stream.
  7. Get a parameter by using the getParameter () method.
  8. Get the reader by using the getReader () method.
  9. Read the data.
  10. Close the reader.
  11. Get the parameter again by using the getParameter () method.

          java.io.InputStream in = request.getInputStream();
          byte[] inBytes = new byte[5];

          int readLen = in.read(inBytes);
          if (readLen > 0){
		
	     }              
          if (close)
                in.close();
	
	  java.io.InputStream in2 = request.getInputStream();
          byte[] inBytes = new byte[2048];

          for (int n; (n = in2.read(inBytes, 0, 2048)) != -1;) {
                readLen += n;
          }
          if (close)
                in2.close();

	  String param = request.getParameter("Test");
		
	  java.io.BufferedReader rdr = request.getReader();         
          StringBuffer inBuffer = new StringBuffer();
          char[] inChars = new char[1024];
          for (int n; (n = rdr.read(inChars,0,1024)) != -1;) {
             inBuffer.append(new String(inChars, 0, n));
          }
          rdr.close();

	  String param2 = request.getParameter("Test");

Non-blocking read example

The following steps and snippet of code show how an application can reread POST data by using the getInputStream () method and the getParameter () method. However, you can use the methods in your application in any combination.
  1. Get the input stream by using the getInputStream () method.
  2. Get the listener from the servlet input stream by using the setReadListener () method.
  3. Read the data in the onDataAvailable () method.
  4. Close the input stream.

    After the input stream closes, the onAllDataRead () method and the onError () method are not called for this listener.

  5. Get a parameter by using the getParameter () method.
  6. Get the new input stream by using the getInputStream () method.
  7. Get a new listener from the servlet input stream by using the setReadListener () method.
  8. Read the data in the onDataAvailable () method.
  9. If all the data is read, then the onAllDataRead () method is called for this listener.
        java.io.InputStream input = request.getInputStream();
	RL1 = ((ServletInputStream) input).setReadListener(readListener);
	
	RL1
	onDataAvailable(){

		if (input.isReady()) {
                         Len = input.read(inBytes);                 
                }
		input.close();

	        String param = request.getParameter("Test");

       	        java.io.InputStream input = request.getInputStream();
		RL2 = ((ServletInputStream) input).setReadListener(readListener);
	}

        RL1 // onAllDataRead() or onError() will not be called for RL1, as the stream has been closed for RL1
     
        RL2
        onDataAvailable(){

		if (input.isReady()) {
                        Len = input.read(inBytes);                 
               }

	 }
	
	 RL2 // If all data read
	 onAllDataRead(){
	 	 AsncContext.complete();
	 }