Skip to content

Using @RequestHeader(ACCEPT_LANGUAGE) Locale locale) throws MethodArgumentTypeMismatchException when a quality value is sent #34065

@NathanD001

Description

@NathanD001

Sending accept-language with a quality value such as Accept-Language: en-us, en-BA;q=0.1 is part of the ietf standard in https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.5

When this is sent and the code uses @RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) Locale locale) the framework throws a MethodArgumentTypeMismatchException due to

https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/util/StringUtils.java#L935

	private static void validateLocalePart(String localePart) {
		for (int i = 0; i < localePart.length(); i++) {
			char ch = localePart.charAt(i);
			if (ch != ' ' && ch != '_' && ch != '-' && ch != '#' && !Character.isLetterOrDigit(ch)) {
				throw new IllegalArgumentException(
						"Locale part \"" + localePart + "\" contains invalid characters");
			}
		}
	}

being called from
https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/core/convert/support/StringToLocaleConverter.java#L41

There are easy workarounds such as simply removing the @RequestHeader annotation or using the Tomcat HttpServletRequest getLocale() method which uses https://github.com/apache/tomcat/blob/main/java/org/apache/catalina/connector/Request.java#L2951

@RestController
public class TestLocale {

  private final HttpServletRequest httpServletRequest;

  @Autowired
  public TestLocale(final HttpServletRequest httpServletRequest) {
    this.httpServletRequest = httpServletRequest;
  }

  // Works with "en-us". Fails with "en-us, en-BA;q=0.1"
  @GetMapping(path = "/test-header")
  public String localeUsingHeader(@RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) Locale locale) {
    return locale.toLanguageTag();
  }

  // Works with "en-us" and with "en-us, en-BA;q=0.1"
  @GetMapping(path = "/test-servlet")
  public String testServlet() {
    return httpServletRequest.getLocale().toLanguageTag();
  }

  // Works with "en-us" and with "en-us, en-BA;q=0.1"
  @GetMapping(path = "/test-locale")
  public String testLocale(Locale locale) {
    return locale.toLanguageTag();
  }
}

The full request being sent

curl --location 'http://localhost:8080/test-header' \
--header 'Content-Type: application/json' \
--header 'Accept-Language: en-us, en-BA;q=0.1' \
--header 'Accept: application/json'

Metadata

Metadata

Assignees

No one assigned

    Labels

    in: webIssues in web modules (web, webmvc, webflux, websocket)status: invalidAn issue that we don't feel is valid

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions