Tomcat 8 is not able to handle get request with '|' in query parameters?
This behavior is introduced in all major Tomcat releases:
- Tomcat 7.0.73, 8.0.39, 8.5.7
To fix, do one of the following:
- set
relaxedQueryChars
to allow this character
(recommended, see Lincoln's answer) - set
requestTargetAllow
option
(deprecated in Tomcat 8.5) (see Jérémie's answer). - you can downgrade to one of older versions (not recommended - security)
Based on changelog, those changes could affect this behavior:
Tomcat 8.5.3:
Ensure that requests with HTTP method names that are not tokens (as required by RFC 7231) are rejected with a 400 response
Tomcat 8.5.7:
Add additional checks for valid characters to the HTTP request line parsing so invalid request lines are rejected sooner.
The best option (following the standard) - you want to encode your URL on client:
encodeURI("http://localhost:8080/app/handleResponse?msg=name|id|")
> http://localhost:8080/app/handleResponse?msg=name%7Cid%7C
or just query string:
encodeURIComponent("msg=name|id|")
> msg%3Dname%7Cid%7C
It will secure you from other problematic characters (list of invalid URI characters).
How to Allow ^ character in URLs for tomcat 8.5
Ideally you should always URL-encode your query parameters before sending your request to the server. Read: https://www.talisman.org/~erlkonig/misc/lunatech%5Ewhat-every-webdev-must-know-about-url-encoding/
If you want to go down the relaxedQueryChars route, note that the following chars from your query are also in the set that you ought to add to the exception:" { } [ ] ^ |
Try this in your server.xml:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" relaxedQueryChars='^{}[]|"' />
More insight into relaxedQueryChars/relaxedPathChars on the bug ticket 62273. The change was added to all branches of Tomat:
- 9.0.8
- 8.5.31
- 8.0.52
- 7.0.87
I don't think you need the relaxedPathChars attribute at all (this refers to characters on the URL path). However, the Tomcat team's test results seem to suggest that the following could be used for maximum backward-compatibility:
relaxedPathChars='[]|'
relaxedQueryChars='[]|{}^\`"<>' />
nb/ the first arg to your query should be demarcated by ? not &
http://hostname:port/path?param1=...¶m2=...¶m3=...
Characters allowed in GET parameter
There are reserved characters, that have a reserved meanings, those are delimiters — :/?#[]@
— and subdelimiters — !$&'()*+,;=
There is also a set of characters called unreserved characters — alphanumerics and -._~
— which are not to be encoded.
That means, that anything that doesn't belong to unreserved characters set is supposed to be %-encoded, when they do not have special meaning (e.g. when passed as a part of GET
parameter).
See also RFC3986: Uniform Resource Identifier (URI): Generic Syntax
How can I append a query parameter to an existing URL?
This can be done by using the java.net.URI class to construct a new instance using the parts from an existing one, this should ensure it conforms to URI syntax.
The query part will either be null or an existing string, so you can decide to append another parameter with & or start a new query.
public class StackOverflow26177749 {
public static URI appendUri(String uri, String appendQuery) throws URISyntaxException {
URI oldUri = new URI(uri);
String newQuery = oldUri.getQuery();
if (newQuery == null) {
newQuery = appendQuery;
} else {
newQuery += "&" + appendQuery;
}
return new URI(oldUri.getScheme(), oldUri.getAuthority(),
oldUri.getPath(), newQuery, oldUri.getFragment());
}
public static void main(String[] args) throws Exception {
System.out.println(appendUri("http://example.com", "name=John"));
System.out.println(appendUri("http://example.com#fragment", "name=John"));
System.out.println(appendUri("http://example.com?email=john.doe@email.com", "name=John"));
System.out.println(appendUri("http://example.com?email=john.doe@email.com#fragment", "name=John"));
}
}
Shorter alternative
public static URI appendUri(String uri, String appendQuery) throws URISyntaxException {
URI oldUri = new URI(uri);
return new URI(oldUri.getScheme(), oldUri.getAuthority(), oldUri.getPath(),
oldUri.getQuery() == null ? appendQuery : oldUri.getQuery() + "&" + appendQuery, oldUri.getFragment());
}
Output
http://example.com?name=John
http://example.com?name=John#fragment
http://example.com?email=john.doe@email.com&name=John
http://example.com?email=john.doe@email.com&name=John#fragment
Related Topics
How to Read Input Character-By-Character in Java
In Java 8, Is There a Bytestream Class
Sorting Strings That Contains Number in Java
Getting Database Connection in Pure JPA Setup
What Is the Easiest Way to Ignore a JPA Field During Persistence
Arrayindexoutofboundsexception When Iterating Through All the Elements of an Array
Log4J: How to Use Socketappender
Selenium Webdriver + Java - Eclipse: Java.Lang.Noclassdeffounderror
Differences Between "Java -Cp" and "Java -Jar"
Java Sax Parser Split Calls to Characters()
Java Jdbc Access Denied for User
How to Monitor Java Memory Usage
How to Change MySQL Timezone in a Database Connection Using Java