How to build a relative URL securely?

Asked

Viewed 348 times

1

A method takes snippets from a URL and needs to concatenate them coherently, but without presupposing details about each one.

Examples:

http://server + /path + /resource.js   => http://server/path/resource.js
http://server/ + /path/ + /resource.js => http://server/path/resource.js        
http://server + path + resource.js     => http://server/path/resource.js
//server + path + resource.js          => //server/path/resource.js

Basically, coherence is in leaving only one bar / between each element and not change the structure of the URL as a whole, as in the last example where the protocols remains missing.

My first approach was simply to create a routine that brings together two parts by checking the bars:

String joinUrlSafely(final String s1, final String s2) {
    final boolean s1HasSlash = s1.endsWith("/");
    final boolean s2HasSlash = s2.startsWith("/");
    if (s1HasSlash && s2HasSlash) {
        return s1 + s2.substring(1); //os dois tem barra, remove uma
    } else if (!s1HasSlash && !s2HasSlash) {
        return s1 + "/" + s2; //nenhum tem barra, coloca uma
    } else {
        return s1 + d2; //um dos dois tem barra, deixa ela lá
    }
}

However, I was not satisfied and the question remains:

Is there an API in Java or in some commonly used library (Apache, Guava, ...) that does this in a more secure and standardized way? Some kind of UrlBuilder?

  • 1

    I do not know if there is such a thing, because as your code shows, it is a trivial task. By the way, I would do something very similar to what you’re doing.

1 answer

1

You can use the Java API itself: java.net.URI e java.net.URL.

@Test
public void urlTest() throws URISyntaxException, MalformedURLException {
    String base = "http://server///";
    String p1 = "/path/";
    String r1 = "/resource.js";
    String newUri = concat(base, p1);

    assertEquals("http://server/path/", newUri);
    assertEquals("http://server/path/resource.js", concat(newUri, r1));

}

private String concat(String s1, String s2) throws URISyntaxException, MalformedURLException {
    URL url = new URL(s1);
    return new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile()+s2).toURI().normalize().toString();
}

Take a look at this post. EDIT

Another way is to always concatenate a "/" before each String and then before returning the value remove the duplicated "/" with a regular expression. Thus saves some ifs.

url.replaceAll("(?<!(http:|https:))[//]+", "/");
  • Can you do this without the protocol? This is important for referencing Resources relative to the protocol (HTTP or HTTPS).

  • @utluiz Not like this. Do it like this: concatenate everything with "/", then before returning remove the duplicated "/" with a regular expression like: . replaceAll("(? <! https:)\/\/", "/");

  • Interesting. I could add that to your reply?

  • blz, but did you see if it works? I didn’t have time to test.

  • I didn’t test it, but I understood the main idea. I’m just not quite convinced that the approach is "safe and standardized" as I mentioned in the question. I will wait a little longer to see if anyone else has any alternative. Anyway, thanks for the reply.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.