Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-2221

Undertow can add unwanted semicolon to path parameter when client http request packets are separated in the middle of path parameter

XMLWordPrintable

    • Hide

      1. Extract helloworld-rs-matrixparam.zip and copy "helloworld-rs-matrixparam" folder under JBoss EAP 7.4 QuickStarts folder because this depends on the top-level pom.xml of the QuickStart.

      2. Build with Maven

      mvn clean package
      

      3. Deploy the generated helloworld-rs.war by copying it into "$JBOSS_HOME/standalone/deployments/" directory.

      4. Start JBoss EAP 7

      5. Execute the following curl to send matrix parameters:

      $ curl "http://localhost:8080/helloworld-rs/rest/matrix/example;foo=bar;hoge=fuga;test=test;"
      Matrix Param List:<br/>
      Path: example, Matrix Params {test=[test], hoge=[fuga], foo=[bar]}<br/>
      

      This can get the expected result. The server can receive 3 matrix parameters "foo=bar", "hoge=fuga" and "test=test".

      6. Execute the reproducible test client TestClient.java included in the attached helloworld-rs-matrixparam.zip. The client sends the same matrix parameters, but it calls flush() in the middle of writing HTTP path matrix parameters. So, request packets are separated between the path matrix parameter.

      $ cat TestClient.java
      ///usr/bin/env jbang "$0" "$@" ; exit $?
      
      import static java.lang.System.*;
      import java.io.*;
      import java.net.*;
      import java.util.*;
      
      public class TestClient {
          private static final String CRLF = "\r\n";
      
          public static void main(String... args) throws IOException {
              Socket socket = new Socket("127.0.0.1", 8080);
              OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
      
              // reproduce the issue by flushing request in the middle of http request path parameter
              out.write("GET");
              out.write(" ");
              out.write("/helloworld-rs/rest/matrix/example;");
              out.write("foo=bar;");
              out.write("hoge=fu");
              out.flush();
              sleep(100);
              out.write("ga;");
              out.write("test=te");
              out.flush();
              sleep(100);
              out.write("st;");
              out.write(" HTTP/1.1");
              out.write(CRLF); // end of http request line
      
              out.write("User-Agent: TestClient" + CRLF);
              out.write("Host: 127.0.0.1:8080" + CRLF);
              out.write(CRLF);
              out.flush();
      
              try (BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));) {
                  System.out.println("response from server:");
                  br.lines().forEach(text -> {
                      System.out.println(text);
                  }); 
              }
          }   
      
          private static void sleep(long millis) {
              try {
                  Thread.sleep(millis);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }   
          }   
      }
      $ javac TestClient.java
      $ java TestClient
      response from server:
      HTTP/1.1 200 OK
      Connection: keep-alive
      Content-Type: application/octet-stream
      Content-Length: 115 
      Date: Thu, 05 Jan 2023 06:18:56 GMT 
      
      Matrix Param List:<br/>
      Path: example, Matrix Params {st=[null], test=[te], hoge=[fu], foo=[bar], ga=[null]}<br/>
      

      This cannot get the expected result. The server cannot receive 3 matrix parameters "foo=bar", "hoge=fuga" and "test=test" correctly. Because path parameters are processed as "foo=bar;hoge=fu;ga;test=te;st;" with unwanted semicolons in the parameter.
      Also, you can see the following request line with unwanted semicolons in the access log entry.

      "GET /helloworld-rs/rest/matrix/example;foo=bar;hoge=fu;ga;test=te;st; HTTP/1.1"
      
      Show
      1. Extract helloworld-rs-matrixparam.zip and copy "helloworld-rs-matrixparam" folder under JBoss EAP 7.4 QuickStarts folder because this depends on the top-level pom.xml of the QuickStart. 2. Build with Maven mvn clean package 3. Deploy the generated helloworld-rs.war by copying it into "$JBOSS_HOME/standalone/deployments/" directory. 4. Start JBoss EAP 7 5. Execute the following curl to send matrix parameters: $ curl "http: //localhost:8080/helloworld-rs/ rest /matrix/example;foo=bar;hoge=fuga;test=test;" Matrix Param List:<br/> Path: example, Matrix Params {test=[test], hoge=[fuga], foo=[bar]}<br/> This can get the expected result. The server can receive 3 matrix parameters "foo=bar", "hoge=fuga" and "test=test". 6. Execute the reproducible test client TestClient.java included in the attached helloworld-rs-matrixparam.zip. The client sends the same matrix parameters, but it calls flush() in the middle of writing HTTP path matrix parameters. So, request packets are separated between the path matrix parameter. $ cat TestClient.java ///usr/bin/env jbang "$0" "$@" ; exit $? import static java.lang. System .*; import java.io.*; import java.net.*; import java.util.*; public class TestClient { private static final String CRLF = "\r\n" ; public static void main( String ... args) throws IOException { Socket socket = new Socket( "127.0.0.1" , 8080); OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream()); // reproduce the issue by flushing request in the middle of http request path parameter out.write( "GET" ); out.write( " " ); out.write( "/helloworld-rs/ rest /matrix/example;" ); out.write( "foo=bar;" ); out.write( "hoge=fu" ); out.flush(); sleep(100); out.write( "ga;" ); out.write( "test=te" ); out.flush(); sleep(100); out.write( "st;" ); out.write( " HTTP/1.1" ); out.write(CRLF); // end of http request line out.write( "User-Agent: TestClient" + CRLF); out.write( "Host: 127.0.0.1:8080" + CRLF); out.write(CRLF); out.flush(); try (BufferedReader br = new BufferedReader( new InputStreamReader(socket.getInputStream()));) { System .out.println( "response from server:" ); br.lines().forEach(text -> { System .out.println(text); }); } } private static void sleep( long millis) { try { Thread .sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } } $ javac TestClient.java $ java TestClient response from server: HTTP/1.1 200 OK Connection: keep-alive Content-Type: application/octet-stream Content-Length: 115 Date: Thu, 05 Jan 2023 06:18:56 GMT Matrix Param List:<br/> Path: example, Matrix Params {st=[ null ], test=[te], hoge=[fu], foo=[bar], ga=[ null ]}<br/> This cannot get the expected result. The server cannot receive 3 matrix parameters "foo=bar", "hoge=fuga" and "test=test" correctly. Because path parameters are processed as "foo=bar;hoge=fu;ga;test=te;st;" with unwanted semicolons in the parameter. Also, you can see the following request line with unwanted semicolons in the access log entry. "GET /helloworld-rs/ rest /matrix/example;foo=bar;hoge=fu;ga;test=te;st; HTTP/1.1"

      Undertow can add an unwanted semicolon to a path parameter when client HTTP request packets are separated in the middle of the path parameter.

      It appears this issue can happen in JBoss EAP 7.2.8+, 7.3.1+, and 7.4.0+ because of this code which is incorporated as fix for UNDERTOW-1464.

              thofman Tomas Hofman
              thofman Tomas Hofman
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Created:
                Updated:
                Resolved: