Skip to content

Commit 6500018

Browse files
committed
HtmlUnitRequestBuilder decodes request parameter names (backport)
Issue: SPR-14177
1 parent fa624cd commit 6500018

File tree

2 files changed

+65
-47
lines changed

2 files changed

+65
-47
lines changed

spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ public MockHttpServletRequest buildRequest(ServletContext servletContext) {
105105
String httpMethod = this.webRequest.getHttpMethod().name();
106106
UriComponents uriComponents = uriComponents();
107107

108-
MockHttpServletRequest request = new HtmlUnitMockHttpServletRequest(servletContext, httpMethod,
109-
uriComponents.getPath());
108+
MockHttpServletRequest request = new HtmlUnitMockHttpServletRequest(
109+
servletContext, httpMethod, uriComponents.getPath());
110110
parent(request, this.parentBuilder);
111111
request.setServerName(uriComponents.getHost()); // needs to be first for additional headers
112112
authType(request);
@@ -123,7 +123,7 @@ public MockHttpServletRequest buildRequest(ServletContext servletContext) {
123123
request.setProtocol("HTTP/1.1");
124124
request.setQueryString(uriComponents.getQuery());
125125
request.setScheme(uriComponents.getScheme());
126-
pathInfo(uriComponents,request);
126+
request.setPathInfo(null);
127127

128128
return postProcess(request);
129129
}
@@ -223,14 +223,14 @@ private void content(MockHttpServletRequest request, String charset) {
223223
try {
224224
request.setContent(requestBody.getBytes(charset));
225225
}
226-
catch (UnsupportedEncodingException e) {
227-
throw new RuntimeException(e);
226+
catch (UnsupportedEncodingException ex) {
227+
throw new IllegalStateException(ex);
228228
}
229229
}
230230

231231
private void contentType(MockHttpServletRequest request) {
232232
String contentType = header("Content-Type");
233-
request.setContentType(contentType == null ? MediaType.ALL_VALUE.toString() : contentType);
233+
request.setContentType(contentType != null ? contentType : MediaType.ALL_VALUE);
234234
}
235235

236236
private void contextPath(MockHttpServletRequest request, UriComponents uriComponents) {
@@ -245,8 +245,8 @@ private void contextPath(MockHttpServletRequest request, UriComponents uriCompon
245245
}
246246
else {
247247
if (!uriComponents.getPath().startsWith(this.contextPath)) {
248-
throw new IllegalArgumentException(uriComponents.getPath() + " should start with contextPath "
249-
+ this.contextPath);
248+
throw new IllegalArgumentException(uriComponents.getPath() + " should start with contextPath " +
249+
this.contextPath);
250250
}
251251
request.setContextPath(this.contextPath);
252252
}
@@ -360,21 +360,26 @@ private void locales(MockHttpServletRequest request) {
360360
private void params(MockHttpServletRequest request, UriComponents uriComponents) {
361361
for (Entry<String, List<String>> entry : uriComponents.getQueryParams().entrySet()) {
362362
String name = entry.getKey();
363+
String urlDecodedName = urlDecode(name);
363364
for (String value : entry.getValue()) {
364-
try {
365-
value = (value != null ? URLDecoder.decode(value, "UTF-8") : "");
366-
request.addParameter(name, value);
367-
}
368-
catch (UnsupportedEncodingException e) {
369-
throw new RuntimeException(e);
370-
}
365+
value = (value != null ? urlDecode(value) : "");
366+
request.addParameter(urlDecodedName, value);
371367
}
372368
}
373369
for (NameValuePair param : this.webRequest.getRequestParameters()) {
374370
request.addParameter(param.getName(), param.getValue());
375371
}
376372
}
377373

374+
private String urlDecode(String value) {
375+
try {
376+
return URLDecoder.decode(value, "UTF-8");
377+
}
378+
catch (UnsupportedEncodingException ex) {
379+
throw new IllegalStateException(ex);
380+
}
381+
}
382+
378383
private Locale parseLocale(String locale) {
379384
Matcher matcher = LOCALE_PATTERN.matcher(locale);
380385
if (!matcher.matches()) {
@@ -392,10 +397,6 @@ private Locale parseLocale(String locale) {
392397
return new Locale(language, country, qualifier);
393398
}
394399

395-
private void pathInfo(UriComponents uriComponents, MockHttpServletRequest request) {
396-
request.setPathInfo(null);
397-
}
398-
399400
private void servletPath(MockHttpServletRequest request, String requestPath) {
400401
String servletPath = requestPath.substring(request.getContextPath().length());
401402
if ("".equals(servletPath)) {
@@ -426,8 +427,7 @@ private void ports(UriComponents uriComponents, MockHttpServletRequest request)
426427

427428
private UriComponents uriComponents() {
428429
URL url = this.webRequest.getUrl();
429-
UriComponentsBuilder uriBldr = UriComponentsBuilder.fromUriString(url.toExternalForm());
430-
return uriBldr.build();
430+
return UriComponentsBuilder.fromUriString(url.toExternalForm()).build();
431431
}
432432

433433
@Override
@@ -450,14 +450,18 @@ public Object merge(Object parent) {
450450
return this;
451451
}
452452

453+
private CookieManager getCookieManager() {
454+
return this.webClient.getCookieManager();
455+
}
456+
453457

454458
/**
455-
* An extension to {@link MockHttpServletRequest} that ensures that
456-
* when a new {@link HttpSession} is created, it is added to the managed sessions.
459+
* An extension to {@link MockHttpServletRequest} that ensures that when a
460+
* new {@link HttpSession} is created, it is added to the managed sessions.
457461
*/
458462
private final class HtmlUnitMockHttpServletRequest extends MockHttpServletRequest {
459463

460-
private HtmlUnitMockHttpServletRequest(ServletContext servletContext, String method, String requestURI) {
464+
public HtmlUnitMockHttpServletRequest(ServletContext servletContext, String method, String requestURI) {
461465
super(servletContext, method, requestURI);
462466
}
463467

@@ -486,16 +490,17 @@ public void setSession(HttpSession session) {
486490
}
487491
}
488492

493+
489494
/**
490495
* An extension to {@link MockHttpSession} that ensures when
491-
* {@link #invalidate()} is called that the {@link HttpSession} is
492-
* removed from the managed sessions.
496+
* {@link #invalidate()} is called that the {@link HttpSession}
497+
* is removed from the managed sessions.
493498
*/
494499
private final class HtmlUnitMockHttpSession extends MockHttpSession {
495500

496501
private final MockHttpServletRequest request;
497502

498-
private HtmlUnitMockHttpSession(MockHttpServletRequest request) {
503+
public HtmlUnitMockHttpSession(MockHttpServletRequest request) {
499504
super(request.getServletContext());
500505
this.request = request;
501506
}
@@ -514,8 +519,4 @@ public void invalidate() {
514519
}
515520
}
516521

517-
private CookieManager getCookieManager() {
518-
return this.webClient.getCookieManager();
519-
}
520-
521522
}

spring-test/src/test/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilderTests.java

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.test.web.servlet.htmlunit;
1818

19+
import java.io.InputStreamReader;
1920
import java.net.MalformedURLException;
2021
import java.net.URL;
2122
import java.util.Collections;
@@ -27,9 +28,11 @@
2728
import javax.servlet.http.Cookie;
2829
import javax.servlet.http.HttpSession;
2930

30-
import org.apache.commons.io.IOUtils;
31+
import com.gargoylesoftware.htmlunit.HttpMethod;
32+
import com.gargoylesoftware.htmlunit.WebClient;
33+
import com.gargoylesoftware.htmlunit.WebRequest;
34+
import com.gargoylesoftware.htmlunit.util.NameValuePair;
3135
import org.apache.http.auth.UsernamePasswordCredentials;
32-
3336
import org.junit.Before;
3437
import org.junit.Test;
3538

@@ -39,16 +42,12 @@
3942
import org.springframework.test.util.ReflectionTestUtils;
4043
import org.springframework.test.web.servlet.MockMvc;
4144
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
45+
import org.springframework.util.FileCopyUtils;
4246

43-
import com.gargoylesoftware.htmlunit.HttpMethod;
44-
import com.gargoylesoftware.htmlunit.WebClient;
45-
import com.gargoylesoftware.htmlunit.WebRequest;
46-
import com.gargoylesoftware.htmlunit.util.NameValuePair;
47-
48-
import static java.util.Arrays.asList;
47+
import static java.util.Arrays.*;
4948
import static org.hamcrest.Matchers.*;
50-
import static org.junit.Assert.assertThat;
51-
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
49+
import static org.junit.Assert.*;
50+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
5251

5352
/**
5453
* Unit tests for {@link HtmlUnitRequestBuilder}.
@@ -77,7 +76,6 @@ public void setUp() throws Exception {
7776
requestBuilder = new HtmlUnitRequestBuilder(sessions, webClient, webRequest);
7877
}
7978

80-
// --- constructor
8179

8280
@Test(expected = IllegalArgumentException.class)
8381
public void constructorNullSessions() {
@@ -94,8 +92,6 @@ public void constructorNullWebRequest() {
9492
new HtmlUnitRequestBuilder(sessions, webClient, null);
9593
}
9694

97-
// --- buildRequest
98-
9995
@Test
10096
@SuppressWarnings("deprecation")
10197
public void buildRequestBasicAuth() {
@@ -245,7 +241,8 @@ public void buildRequestInputStream() throws Exception {
245241

246242
MockHttpServletRequest actualRequest = requestBuilder.buildRequest(servletContext);
247243

248-
assertThat(IOUtils.toString(actualRequest.getInputStream()), equalTo(content));
244+
assertThat(FileCopyUtils.copyToString(new InputStreamReader(actualRequest.getInputStream(), "ISO-8859-1")),
245+
equalTo(content));
249246
}
250247

251248
@Test
@@ -411,6 +408,26 @@ public void buildRequestParameterMapFromSingleQueryParam() throws Exception {
411408
assertThat(actualRequest.getParameter("name"), equalTo("value"));
412409
}
413410

411+
@Test // SPR-14177
412+
public void buildRequestParameterMapDecodesParameterName() throws Exception {
413+
webRequest.setUrl(new URL("http://example.com/example/?row%5B0%5D=value"));
414+
415+
MockHttpServletRequest actualRequest = requestBuilder.buildRequest(servletContext);
416+
417+
assertThat(actualRequest.getParameterMap().size(), equalTo(1));
418+
assertThat(actualRequest.getParameter("row[0]"), equalTo("value"));
419+
}
420+
421+
@Test
422+
public void buildRequestParameterMapDecodesParameterValue() throws Exception {
423+
webRequest.setUrl(new URL("http://example.com/example/?name=row%5B0%5D"));
424+
425+
MockHttpServletRequest actualRequest = requestBuilder.buildRequest(servletContext);
426+
427+
assertThat(actualRequest.getParameterMap().size(), equalTo(1));
428+
assertThat(actualRequest.getParameter("name"), equalTo("row[0]"));
429+
}
430+
414431
@Test
415432
public void buildRequestParameterMapFromSingleQueryParamWithoutValueAndWithoutEqualsSign() throws Exception {
416433
webRequest.setUrl(new URL("http://example.com/example/?name"));
@@ -544,7 +561,7 @@ public void buildRequestReader() throws Exception {
544561

545562
MockHttpServletRequest actualRequest = requestBuilder.buildRequest(servletContext);
546563

547-
assertThat(IOUtils.toString(actualRequest.getReader()), equalTo(expectedBody));
564+
assertThat(FileCopyUtils.copyToString(actualRequest.getReader()), equalTo(expectedBody));
548565
}
549566

550567
@Test

0 commit comments

Comments
 (0)