11/*
2- * Copyright 2002-2016 the original author or authors.
2+ * Copyright 2002-2017 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.
1717package org .springframework .test .web .servlet .htmlunit ;
1818
1919import java .io .UnsupportedEncodingException ;
20+ import java .lang .reflect .Method ;
2021import java .net .URL ;
2122import java .net .URLDecoder ;
23+ import java .nio .charset .Charset ;
2224import java .util .ArrayList ;
2325import java .util .Enumeration ;
2426import java .util .List ;
5052import org .springframework .test .web .servlet .request .MockMvcRequestBuilders ;
5153import org .springframework .test .web .servlet .request .RequestPostProcessor ;
5254import org .springframework .util .Assert ;
55+ import org .springframework .util .ClassUtils ;
5356import org .springframework .util .ObjectUtils ;
57+ import org .springframework .util .ReflectionUtils ;
5458import org .springframework .util .StringUtils ;
5559import org .springframework .web .util .UriComponents ;
5660import org .springframework .web .util .UriComponentsBuilder ;
5963 * Internal class used to transform a {@link WebRequest} into a
6064 * {@link MockHttpServletRequest} using Spring MVC Test's {@link RequestBuilder}.
6165 *
62- * <p>By default the first path segment of the URL is used as the contextPath .
66+ * <p>By default the first path segment of the URL is used as the context path .
6367 * To override this default see {@link #setContextPath(String)}.
6468 *
6569 * @author Rob Winch
@@ -71,6 +75,11 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable {
7175
7276 private static final Pattern LOCALE_PATTERN = Pattern .compile ("^\\ s*(\\ w{2})(?:-(\\ w{2}))?(?:;q=(\\ d+\\ .\\ d+))?$" );
7377
78+ private static final Charset DEFAULT_CHARSET = Charset .forName ("ISO-8859-1" );
79+
80+
81+ private static final Method getCharsetMethod = ClassUtils .getMethodIfAvailable (WebRequest .class , "getCharset" );
82+
7483 private final Map <String , MockHttpSession > sessions ;
7584
7685 private final WebClient webClient ;
@@ -98,23 +107,23 @@ public HtmlUnitRequestBuilder(Map<String, MockHttpSession> sessions, WebClient w
98107 Assert .notNull (sessions , "Sessions Map must not be null" );
99108 Assert .notNull (webClient , "WebClient must not be null" );
100109 Assert .notNull (webRequest , "WebRequest must not be null" );
101-
102110 this .sessions = sessions ;
103111 this .webClient = webClient ;
104112 this .webRequest = webRequest ;
105113 }
106114
115+
107116 public MockHttpServletRequest buildRequest (ServletContext servletContext ) {
108- String charset = getCharset ();
117+ Charset charset = getCharset ();
109118 String httpMethod = this .webRequest .getHttpMethod ().name ();
110119 UriComponents uriComponents = uriComponents ();
111120
112121 MockHttpServletRequest request = new HtmlUnitMockHttpServletRequest (
113122 servletContext , httpMethod , uriComponents .getPath ());
114123 parent (request , this .parentBuilder );
115- request .setServerName (uriComponents .getHost ()); // needs to be first for additional headers
124+ request .setServerName (uriComponents .getHost ()); // needs to be first for additional headers
116125 authType (request );
117- request .setCharacterEncoding (charset );
126+ request .setCharacterEncoding (charset . name () );
118127 content (request , charset );
119128 contextPath (request , uriComponents );
120129 contentType (request );
@@ -132,6 +141,21 @@ public MockHttpServletRequest buildRequest(ServletContext servletContext) {
132141 return postProcess (request );
133142 }
134143
144+ private Charset getCharset () {
145+ if (getCharsetMethod != null ) {
146+ Object value = ReflectionUtils .invokeMethod (getCharsetMethod , this .webRequest );
147+ if (value instanceof Charset ) {
148+ // HtmlUnit 2.25: a Charset
149+ return (Charset ) value ;
150+ }
151+ else if (value != null ) {
152+ // HtmlUnit up until 2.24: a String
153+ return Charset .forName (value .toString ());
154+ }
155+ }
156+ return DEFAULT_CHARSET ;
157+ }
158+
135159 private MockHttpServletRequest postProcess (MockHttpServletRequest request ) {
136160 if (this .parentPostProcessor != null ) {
137161 request = this .parentPostProcessor .postProcessRequest (request );
@@ -220,17 +244,12 @@ private void authType(MockHttpServletRequest request) {
220244 }
221245 }
222246
223- private void content (MockHttpServletRequest request , String charset ) {
247+ private void content (MockHttpServletRequest request , Charset charset ) {
224248 String requestBody = this .webRequest .getRequestBody ();
225249 if (requestBody == null ) {
226250 return ;
227251 }
228- try {
229- request .setContent (requestBody .getBytes (charset ));
230- }
231- catch (UnsupportedEncodingException ex ) {
232- throw new IllegalStateException (ex );
233- }
252+ request .setContent (requestBody .getBytes (charset ));
234253 }
235254
236255 private void contentType (MockHttpServletRequest request ) {
@@ -256,8 +275,8 @@ private void contextPath(MockHttpServletRequest request, UriComponents uriCompon
256275 }
257276 else {
258277 if (!uriComponents .getPath ().startsWith (this .contextPath )) {
259- throw new IllegalArgumentException (uriComponents .getPath () + " should start with contextPath " +
260- this .contextPath );
278+ throw new IllegalArgumentException (" \" " + uriComponents .getPath () +
279+ " \" should start with context path \" " + this .contextPath + " \" " );
261280 }
262281 request .setContextPath (this .contextPath );
263282 }
@@ -273,7 +292,7 @@ private void cookies(MockHttpServletRequest request) {
273292 String cookieName = tokens .nextToken ().trim ();
274293 if (!tokens .hasMoreTokens ()) {
275294 throw new IllegalArgumentException ("Expected value for cookie name '" + cookieName +
276- "'. Full cookie was " + cookieHeaderValue );
295+ "': full cookie header was [ " + cookieHeaderValue + "]" );
277296 }
278297 String cookieValue = tokens .nextToken ().trim ();
279298 processCookie (request , cookies , new Cookie (cookieName , cookieValue ));
@@ -305,14 +324,6 @@ private void processCookie(MockHttpServletRequest request, List<Cookie> cookies,
305324 }
306325 }
307326
308- private String getCharset () {
309- String charset = this .webRequest .getCharset ();
310- if (charset == null ) {
311- return "ISO-8859-1" ;
312- }
313- return charset ;
314- }
315-
316327 private String header (String headerName ) {
317328 return this .webRequest .getAdditionalHeaders ().get (headerName );
318329 }
@@ -394,7 +405,7 @@ private String urlDecode(String value) {
394405 private Locale parseLocale (String locale ) {
395406 Matcher matcher = LOCALE_PATTERN .matcher (locale );
396407 if (!matcher .matches ()) {
397- throw new IllegalArgumentException ("Invalid locale " + locale );
408+ throw new IllegalArgumentException ("Invalid locale value [ " + locale + "]" );
398409 }
399410 String language = matcher .group (1 );
400411 String country = matcher .group (2 );
0 commit comments