Double asterisk in a request mapping - java

What does it mean when double asterisk is present in a request mapping?
For instance
#RequestMapping(value = { "/", "/welcome**" }, method =
RequestMethod.GET) public ModelAndView welcomePage() { ...

Universally speaking asterisks (in wildcard role) mean
/welcome* : anything in THIS folder or URL section, that starts with "/welcome" and ends before next "/" like /welcomePage.
/welcome** : any URL, that starts with "/welcome" including sub-folders and sub-sections of URL pattern like /welcome/section2/section3/ or /welcomePage/index.
/welcome/* : any file, folder or section inside welcome (before next "/") like /welcome/index.
/welcome/** : any files, folders, sections, sub-folders or sub-sections inside welcome.
In other words one asterisk * ends before next "/", two asterisks ** have no limits.

Ant paths
URL mapping ordering. From Spring Docs:
When a URL matches multiple patterns, a sort is used to find the most
specific match.
A pattern with a lower count of URI variables and wild cards is
considered more specific. For example /hotels/{hotel}/* has 1 URI
variable and 1 wild card and is considered more specific than
/hotels/{hotel}/** which as 1 URI variable and 2 wild cards
...
There are also some additional special rules:
The default mapping pattern /** is less specific than any other pattern. For example /api/{a}/{b}/{c} is more specific.
A prefix pattern such as /public/** is less specific than any other pattern that doesn’t contain double wildcards. For example
/public/path3/{a}/{b}/{c} is more specific.

Related

RequestMapping with slashes and dot

I have to support following URL format
/service/country/city/addr1/addr2/xyz.atom
/service/country/city/addr1/addr2/addr3/xyz.atom
where country and city can be mapped to #PathVariable but after that the path can be dynamic with multiple slashes. The end part will have .atom or similar.
I tried following, but none of the options seem to be working
Wildcard
#RequestMapping(value="/service/{country}/{city}/**")
Regex
#RequestMapping(value="/service/{country}/{city}/{addr:.+}")
UseSuffixPatternMatch
Override method in Config class
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
Looks like combination of slash and dots don't work with above solutions.
I keep getting 406 for non-matching Accept header, or 404
The most dynamic approach would be to use MatrixVariable to manage the list of addresses but it is not applicable in your context since the paths cannot be modified as far as I understand from your question.
The best thing you can do to manage your dynamic path is to proceed in two steps:
Set a RequestMapping that extracts all the data except the addresses
Extract the addresses manually in the method
So for the first step you will have something like that:
#RequestMapping(value="/service/{country}/{city}/**/{file}.atom")
public String service(#PathVariable String country,
#PathVariable String city, #PathVariable String file,
HttpServletRequest request, Model model) {
This mapping matchs with all the required paths and allows to extract the country, the city and the file name.
In the second step we will use what has been extracted to get the addresses by doing something like this:
String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
path = path.substring(String.format("/service/%s/%s/", country, city).length(),
path.length() - String.format("%s.atom", file).length());
String[] addrs = path.split("/");
First we extract from the request the full path
Then we remove what we have already extracted which are here the beginning and the end of the path
Then finally we use String.split to extract all the addresses
At this level you have everything you need.
Can you try this,
#RequestMapping(value="/service/{country}/{city}/{addr:[a-z]+\\\\.(atom|otherExtensions)}")
Just have to specify the complete regex format wherein you are expecting an extension at the end of the url such as atom, since this will be interpreted by default as MediaType by Spring.
another solution is specify the accepted MediaTypes
#RequestMapping(value="/service/{country}/{city}/{addr}", consumes = {MediaType.ATOM, MediaType...})
You can create custom MediaTypes if it is not predefined in Spring.

How to replace double slash with single slash for an url

For the given url like "http://google.com//view/All/builds", i want to replace the double slash with single slash. For example the above url should display as "http://google.com/view/All/builds"
I dint know regular expressions. Can any one help me, how can i achieve this using regular expressions.
To avoid replacing the first // in http:// use the following regex :
String to = from.replaceAll("(?<!http:)//", "/");
PS: if you want to handle https use (?<!(http:|https:))// instead.
Is Regex the right approach?
In case you wanted this solution as part of an exercise to improve your regex skills, then fine. But what is it that you're really trying to achieve? You're probably trying to normalize a URL. Replacing // with / is one aspect of normalizing a URL. But what about other aspects, like removing redundant ./ and collapsing ../ with their parent directories? What about different protocols? What about ///? What about the // at the start? What about /// at the start in case of file:///?
If you want to write a generic, reusable piece of code, using a regular expression is probably not the best appraoch. And it's reinventing the wheel. Instead, consider java.net.URI.normalize().
java.net.URI.normalize()
java.lang.String
String inputUrl = "http://localhost:1234//foo//bar//buzz";
String normalizedUrl = new URI(inputUrl).normalize().toString();
java.net.URL
URL inputUrl = new URL("http://localhost:1234//foo//bar//buzz");
URL normalizedUrl = inputUrl.toURI().normalize().toURL();
java.net.URI
URI inputUri = new URI("http://localhost:1234//foo//bar//buzz");
URI normalizedUri = inputUri.normalize();
Regex
In case you do want to use a regular expression, think of all possibilities. What if, in future, this should also process other protocols, like https, file, ftp, fish, and so on? So, think again, and probably use URI.normalize(). But if you insist on a regular expression, maybe use this one:
String noramlizedUri = uri.replaceAll("(?<!\\w+:/?)//+", "/");
Compared to other solutions, this works with all URLs that look similar to HTTP URLs just with different protocols instead of http, like https, file, ftp and so on, and it will keep the triple-slash /// in case of file:///. But, unlike java.net.URI.normalize(), this does not remove redundant ./, it does not collapse ../ with their parent directories, it does not other aspects of URL normalization that you and I might have forgotten about, and it will not be updated automatically with newer RFCs about URLs, URIs, and such.
String to = from.replaceAll("(?<!(http:|https:))[//]+", "/");
will match two or more slashes.
Here is the regexp:
/(?<=[^:\s])(\/+\/)/g
It finds multiple slashes in url preserving ones after protocol regardless of it.
Handles also protocol relative urls which start from //.
#Test
public void shouldReplaceMultipleSlashes() {
assertEquals("http://google.com/?q=hi", replaceMultipleSlashes("http://google.com///?q=hi"));
assertEquals("https://google.com/?q=hi", replaceMultipleSlashes("https:////google.com//?q=hi"));
assertEquals("//somecdn.com/foo/", replaceMultipleSlashes("//somecdn.com/foo///"));
}
private static String replaceMultipleSlashes(String url) {
return url.replaceAll("(?<=[^:\\s])(\\/+\\/)", "/");
}
Literally means:
(\/+\/) - find group: /+ one or more slashes followed by / slash
(?<=[^:\s]) - which follows the group (*posiive lookbehind) of this (*negated set) [^:\s] that excludes : colon and \s whitespace
g - global search flag
I suggest you simply use String.replace which documentation is http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(java.lang.CharSequence, java.lang.CharSequence)
Something like
`myString.replace("//", "/");
If you want to remove the first occurence:
String[] parts = str.split("//", 2);
str = parts[0] + "//" + parts[1].replaceAll("//", "/");
Which is the simplest way (without regular expression). I don't know the regular expression corresponding, if there is an expert looking at the thread.... ;)

how can i use wild card to map url in java servlet

I want to achieve this:
http:\\localhost:8080\mysite\search\cotton\search.html
http:\\localhost:8080\mysite\search\bean\search.html
http:\\localhost:8080\mysite\search\cosmetic\search.html
http:\\localhost:8080\mysite\search\shoe\search.html
<servlet-mapping>
<servlet-name>abcSearch</servlet-name>
<url-pattern>/search/*/search.html</url-pattern>
</servlet-mapping>
mean one pattern for the above all urls
can any one help out for me???
The rules for mappings are as follows
In the Web application deployment descriptor, the following syntax is
used to define mappings:
A string beginning with a ‘/’ character and ending with a ‘/*’ suffix
is used for path mapping.
A string beginning with a ‘*.’ prefix is used as an extension mapping.
The empty string ("") is a special URL pattern that exactly maps to
the application's context root, i.e., requests of the form
http://host:port/<context-root>/. In this case the path info is ’/’
and the servlet path and context path is empty string (““).
A string containing only the ’/’ character indicates the "default"
servlet of the application. In this case the servlet path is the
request URI minus the context path and the path info is null.
All other strings are used for exact matches only.
So this
/search/*/search.html
would match exactly
http://host/context/search/*/search.html
You can't get path matching at the middle of the path with Servlet's url-patterns.
If you only have the 4 paths, I recommend you put 4 <servlet-mapping> element with each exact path match.
Try to change URLs like:
http:\\localhost:8080/mysite/search/cotton
http:\\localhost:8080/mysite/search/bean
http:\\localhost:8080/mysite/search/cosmetic
http:\\localhost:8080/mysite/search/shoe
or like that:
http:\\localhost:8080/mysite/cotton/search.html
http:\\localhost:8080/mysite/bean/search.html
For the first case pattern will be <url-pattern>/search/*</url-pattern> and for the second one <url-pattern>*/search.html</url-pattern>

Merging two relative file URLs

Let' say I have two paths, first can look like folder/ and second like /anotherFolder/image.png. I would like to merge those two paths in some automated fashion and with option for user to omit the last slash in first string and first slash in second string. So all of these
folder/ + /anotherFolder/image.png
folder + anotherFolder/image.png
folder + /anotherFolder/image.png
should give me folder/anotherFolder/image.png
I need to merge two properties in one of my projects and I want it as dummy as possible:)So is there some trick with URL class or do I have to play around with Strings?
You can do this with java.io.File, by using the constructor which takes a File and a String as arguments, will interpret the String as a relative path to the File.
Or with java.net.URL, you can send an URL and a String to the constructur, which will interpret the URL as a context for the String parameter.
I actually used FileUtils.getFile() from Apache Commons IO but Rolf's solution was working too.

Java : File.toURI().toURL() on Windows file

The system I'm running on is Windows XP, with JRE 1.6.
I do this :
public static void main(String[] args) {
try {
System.out.println(new File("C:\\test a.xml").toURI().toURL());
} catch (Exception e) {
e.printStackTrace();
}
}
and I get this : file:/C:/test%20a.xml
How come the given URL doesn't have two slashes before the C: ? I expected file://C:.... Is it normal behaviour?
EDIT :
From Java source code : java.net.URLStreamHandler.toExternalForm(URL)
result.append(":");
if (u.getAuthority() != null && u.getAuthority().length() > 0) {
result.append("//");
result.append(u.getAuthority());
}
It seems that the Authority part of a file URL is null or empty, and thus the double slash is skipped. So what is the authority part of a URL and is it really absent from the file protocol?
That's an interesting question.
First things first: I get the same results on JRE6. I even get that when I lop off the toURL() part.
RFC2396 does not actually require two slashes. According to section 3:
The URI syntax is dependent upon the
scheme. In general, absolute URI are
written as follows:
<scheme>:<scheme-specific-part>
Having said that, RFC2396 has been superseded by RFC3986, which states
The generic URI syntax consists of a
hierarchical sequence of omponents
referred to as the scheme, authority,
path, query, and fragment.
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
The scheme and path components are
required, though the path may be empty
(no characters). When authority is
present, the path must either be empty
or begin with a slash ("/") character.
When authority is not present, the
path cannot begin with two slash
characters ("//"). These restrictions
result in five different ABNF rules
for a path (Section 3.3), only one of
which will match any given URI
reference.
So, there you go. Since file URIs have no authority segment, they're forbidden from starting with //.
However, that RFC didn't come around until 2005, and Java references RFC2396, so I don't know why it's following this convention, as file URLs before the new RFC have always had two slashes.
To answer why you can have both:
file:/path/file
file:///path/file
file://localhost/path/file
RFC3986 (3.2.2. Host) states:
"If the URI scheme defines a default for host, then that default applies when the host subcomponent is undefined or when the registered name is empty (zero length). For example, the "file" URI scheme is defined so that no authority, an empty host, and "localhost" all mean the end-user's machine, whereas the "http" scheme considers a missing authority or empty host invalid."
So the "file" scheme translates file:///path/file to have a context of the end-user's machine even though the authority is an empty host.
As far as using it in a browser is concerned, it doesn't matter. I have typically seen file:///... but one, two or three '/' will all work. This makes me think (without looking at the java documentation) that it would be normal behavior.

Categories