diff --git a/web-modules/javax-servlets-2/pom.xml b/web-modules/javax-servlets-2/pom.xml
index 81616e0055..9ba12352fd 100644
--- a/web-modules/javax-servlets-2/pom.xml
+++ b/web-modules/javax-servlets-2/pom.xml
@@ -22,6 +22,11 @@
commons-fileupload
${commons-fileupload.version}
+
+ org.apache.commons
+ commons-text
+ ${commons-text.version}
+
javax.servlet
@@ -76,6 +81,16 @@
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+ ${jetty-maven-plugin.version}
+
+
+ /
+
+
+
@@ -84,6 +99,8 @@
1.49
5.3.20
2.22.2
+ 10.0.4
+ 1.10.0
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/LanguageServlet.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/LanguageServlet.java
new file mode 100644
index 0000000000..983066ec51
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/LanguageServlet.java
@@ -0,0 +1,21 @@
+package com.baeldung.setparam;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.*;
+
+@WebServlet(name = "LanguageServlet", urlPatterns = "/setparam/lang")
+public class LanguageServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+
+ SetParameterRequestWrapper requestWrapper = new SetParameterRequestWrapper(request);
+ requestWrapper.setParameter("locale", Locale.getDefault().getLanguage());
+ request.getRequestDispatcher("/setparam/3rd_party_module.jsp").forward(requestWrapper, response);
+ }
+
+}
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersFilter.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersFilter.java
new file mode 100644
index 0000000000..3f93591bd9
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersFilter.java
@@ -0,0 +1,17 @@
+package com.baeldung.setparam;
+
+import java.io.IOException;
+import javax.servlet.*;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+
+@WebFilter(urlPatterns = { "/setparam/with-sanitize.jsp" })
+public class SanitizeParametersFilter implements Filter {
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest httpReq = (HttpServletRequest) request;
+ chain.doFilter(new SanitizeParametersRequestWrapper(httpReq), response);
+ }
+
+}
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersRequestWrapper.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersRequestWrapper.java
new file mode 100644
index 0000000000..e4c2870ca6
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersRequestWrapper.java
@@ -0,0 +1,46 @@
+package com.baeldung.setparam;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+import org.apache.commons.text.StringEscapeUtils;
+
+public class SanitizeParametersRequestWrapper extends HttpServletRequestWrapper {
+
+ private final Map sanitizedMap;
+
+ public SanitizeParametersRequestWrapper(HttpServletRequest request) {
+ super(request);
+ sanitizedMap = Collections.unmodifiableMap(
+ request.getParameterMap().entrySet().stream()
+ .collect(Collectors.toMap(
+ Map.Entry::getKey,
+ entry -> Arrays.stream(entry.getValue())
+ .map(StringEscapeUtils::escapeHtml4)
+ .toArray(String[]::new)
+ )));
+ }
+
+ @Override
+ public Map getParameterMap() {
+ return sanitizedMap;
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ return Optional.ofNullable(getParameterMap().get(name))
+ .map(values -> Arrays.copyOf(values, values.length))
+ .orElse(null);
+ }
+
+ @Override
+ public String getParameter(String name) {
+ return Optional.ofNullable(getParameterValues(name))
+ .map(values -> values[0])
+ .orElse(null);
+ }
+
+}
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SetParameterRequestWrapper.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SetParameterRequestWrapper.java
new file mode 100644
index 0000000000..7b2ab4597c
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SetParameterRequestWrapper.java
@@ -0,0 +1,40 @@
+package com.baeldung.setparam;
+
+import java.util.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+public class SetParameterRequestWrapper extends HttpServletRequestWrapper {
+
+ private final Map paramMap;
+
+ public SetParameterRequestWrapper(HttpServletRequest request) {
+ super(request);
+ paramMap = new HashMap<>(request.getParameterMap());
+ }
+
+ @Override
+ public Map getParameterMap() {
+ return Collections.unmodifiableMap(paramMap);
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ return Optional.ofNullable(getParameterMap().get(name))
+ .map(values -> Arrays.copyOf(values, values.length))
+ .orElse(null);
+ }
+
+ @Override
+ public String getParameter(String name) {
+ return Optional.ofNullable(getParameterValues(name))
+ .map(values -> values[0])
+ .orElse(null);
+ }
+
+ public void setParameter(String name, String value) {
+ paramMap.put(name, new String[] {value});
+ }
+
+}
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/main/webapp/setparam/3rd_party_module.jsp b/web-modules/javax-servlets-2/src/main/webapp/setparam/3rd_party_module.jsp
new file mode 100644
index 0000000000..9ab4fd2c00
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/main/webapp/setparam/3rd_party_module.jsp
@@ -0,0 +1,13 @@
+<%@ page import="java.util.*"%>
+
+
+ 3rd party Module
+
+
+ <%
+ String localeStr = request.getParameter("locale");
+ Locale currentLocale = (localeStr != null ? new Locale(localeStr) : null);
+ %>
+ The language you have selected: <%=currentLocale != null ? currentLocale.getDisplayLanguage(currentLocale) : " None"%>
+
+
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/main/webapp/setparam/with-sanitize.jsp b/web-modules/javax-servlets-2/src/main/webapp/setparam/with-sanitize.jsp
new file mode 100644
index 0000000000..68704d6133
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/main/webapp/setparam/with-sanitize.jsp
@@ -0,0 +1,10 @@
+
+
+ Sanitized request parameter
+
+
+ The text below comes from request parameter "input":
+
+ <%=request.getParameter("input")%>
+
+
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/main/webapp/setparam/without-sanitize.jsp b/web-modules/javax-servlets-2/src/main/webapp/setparam/without-sanitize.jsp
new file mode 100644
index 0000000000..f5437164ef
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/main/webapp/setparam/without-sanitize.jsp
@@ -0,0 +1,10 @@
+
+
+ Non sanitized request parameter
+
+
+ The text below comes from request parameter "input":
+
+ <%=request.getParameter("input")%>
+
+
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/LanguageServletIntegrationTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/LanguageServletIntegrationTest.java
new file mode 100644
index 0000000000..893ba06ce4
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/LanguageServletIntegrationTest.java
@@ -0,0 +1,34 @@
+package com.baeldung.setparam;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Locale;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+import org.junit.Test;
+
+public class LanguageServletIntegrationTest {
+
+ @Test
+ public void whenGetRequestUsingHttpClient_thenResponseBodyContainsDefaultLanguage() throws Exception {
+
+ // When
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpGet method = new HttpGet("http://localhost:8080/setparam/lang");
+ HttpResponse httpResponse = client.execute(method);
+
+ // Then
+ Locale defaultLocale = Locale.getDefault();
+ String expectedLanguage = defaultLocale.getDisplayLanguage(defaultLocale);
+
+ HttpEntity entity = httpResponse.getEntity();
+ String responseBody = EntityUtils.toString(entity, "UTF-8");
+ assertTrue(responseBody.contains("The language you have selected: " + expectedLanguage));
+ }
+
+}
diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestIntegrationTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestIntegrationTest.java
new file mode 100644
index 0000000000..047d5431f6
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestIntegrationTest.java
@@ -0,0 +1,40 @@
+package com.baeldung.setparam;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class SanitizeParametersRequestIntegrationTest {
+
+ private static String PARAM_INPUT;
+
+ @BeforeClass
+ public static void init() throws UnsupportedEncodingException {
+ PARAM_INPUT = URLEncoder.encode("", "UTF-8");
+ }
+
+ @Test
+ public void whenInputParameterContainsXss_thenResponseBodyContainsSanitizedValue() throws Exception {
+
+ // When
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpGet method = new HttpGet(String.format("http://localhost:8080/setparam/with-sanitize.jsp?input=%s", PARAM_INPUT));
+ HttpResponse httpResponse = client.execute(method);
+
+ // Then
+ HttpEntity entity = httpResponse.getEntity();
+ String responseBody = EntityUtils.toString(entity, "UTF-8");
+ assertTrue(responseBody.contains("<script>alert('Hello');</script>"));
+ }
+
+}
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestWrapperUnitTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestWrapperUnitTest.java
new file mode 100644
index 0000000000..4f246e0953
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestWrapperUnitTest.java
@@ -0,0 +1,60 @@
+package com.baeldung.setparam;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SanitizeParametersRequestWrapperUnitTest {
+
+ private String NEW_VALUE = "NEW VALUE";
+
+ private Map parameterMap;
+
+ @Mock
+ private HttpServletRequest request;
+
+ @Before
+ public void initBeforeEachTest() {
+ parameterMap = new HashMap<>();
+ parameterMap.put("input", new String[] {""});
+ when(request.getParameterMap()).thenReturn(parameterMap);
+ }
+
+ @Test
+ public void whenGetParameterViaWrapper_thenParameterReturnedIsSanitized() {
+ SanitizeParametersRequestWrapper wrapper = new SanitizeParametersRequestWrapper(request);
+ String actualValue = wrapper.getParameter("input");
+
+ assertEquals(actualValue, "<script>alert('Hello');</script>");
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void whenPutValueToWrapperParameterMap_thenThrowsUnsupportedOperationException() {
+ SanitizeParametersRequestWrapper wrapper = new SanitizeParametersRequestWrapper(request);
+ Map wrapperParamMap = wrapper.getParameterMap();
+ wrapperParamMap.put("input", new String[] {NEW_VALUE});
+ }
+
+ @Test
+ public void whenSetValueToWrapperParametersStringArray_thenThe2ndCallShouldNotEqualToNewValue() {
+ SanitizeParametersRequestWrapper wrapper = new SanitizeParametersRequestWrapper(request);
+ String[] firstCallValues = wrapper.getParameterValues("input");
+
+ firstCallValues[0] = NEW_VALUE;
+ String[] secondCallValues = wrapper.getParameterValues("input");
+ assertNotEquals(firstCallValues, secondCallValues);
+ }
+
+}
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SetParameterRequestWrapperUnitTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SetParameterRequestWrapperUnitTest.java
new file mode 100644
index 0000000000..32343abb93
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SetParameterRequestWrapperUnitTest.java
@@ -0,0 +1,61 @@
+package com.baeldung.setparam;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SetParameterRequestWrapperUnitTest {
+
+ private String NEW_VALUE = "NEW VALUE";
+
+ private Map parameterMap;
+
+ @Mock
+ private HttpServletRequest request;
+
+ @Before
+ public void initBeforeEachTest() {
+ parameterMap = new HashMap<>();
+ parameterMap.put("input", new String[] {"inputValue"});
+ when(request.getParameterMap()).thenReturn(parameterMap);
+ }
+
+ @Test
+ public void whenSetParameterViaWrapper_thenGetParameterShouldReturnTheSameValue() {
+ SetParameterRequestWrapper wrapper = new SetParameterRequestWrapper(request);
+ wrapper.setParameter("newInput", "newInputValue");
+ String actualValue = wrapper.getParameter("newInput");
+
+ assertEquals(actualValue, "newInputValue");
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void whenPutValueToWrapperParameterMap_thenThrowsUnsupportedOperationException() {
+ SetParameterRequestWrapper wrapper = new SetParameterRequestWrapper(request);
+ Map wrapperParamMap = wrapper.getParameterMap();
+ wrapperParamMap.put("input", new String[] {NEW_VALUE});
+ }
+
+ @Test
+ public void whenSetValueToWrapperParametersStringArray_thenThe2ndCallShouldNotEqualToNewValue() {
+ SetParameterRequestWrapper wrapper = new SetParameterRequestWrapper(request);
+ String[] firstCallValues = wrapper.getParameterValues("input");
+
+ firstCallValues[0] = NEW_VALUE;
+ String[] secondCallValues = wrapper.getParameterValues("input");
+ assertNotEquals(firstCallValues, secondCallValues);
+ }
+
+}
\ No newline at end of file
diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/UnsanitizedParametersRequestIntegrationTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/UnsanitizedParametersRequestIntegrationTest.java
new file mode 100644
index 0000000000..a00944b6a4
--- /dev/null
+++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/UnsanitizedParametersRequestIntegrationTest.java
@@ -0,0 +1,42 @@
+package com.baeldung.setparam;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class UnsanitizedParametersRequestIntegrationTest {
+
+ private static final String TAG_SCRIPT = "";
+
+ private static String PARAM_INPUT;
+
+ @BeforeClass
+ public static void init() throws UnsupportedEncodingException {
+ PARAM_INPUT = URLEncoder.encode(TAG_SCRIPT, "UTF-8");
+ }
+
+ @Test
+ public void whenInputParameterContainsXss_thenResponseBodyContainsUnsanitizedValue() throws Exception {
+
+ // When
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpGet method = new HttpGet(String.format("http://localhost:8080/setparam/without-sanitize.jsp?input=%s", PARAM_INPUT));
+ HttpResponse httpResponse = client.execute(method);
+
+ // Then
+ HttpEntity entity = httpResponse.getEntity();
+ String responseBody = EntityUtils.toString(entity, "UTF-8");
+ assertTrue(responseBody.contains(TAG_SCRIPT));
+ }
+
+}
\ No newline at end of file