2

I have a relative url string, know host and protocol. How can I build an absolute url string?

Seems easy? Yes at first look, but until escaped characters coming. I have to build absolute url from 302 code http(s) response Location header.

lets consider an example

protocol: http
host: example.com
location: /path/path?param1=param1Data&param2= " 

First I tried to build url string like:

Sting urlString = protocol+host+location

Constructor of URL class not escapes spaces and double quotes:

new URL(urlString)

Constructors of URI class fail with exception:

new URI(urlString)

URI.resolve method also fails with exception

Then I found URI can escape params in query string, but only with few constructors like for example:

URI uri = new URI("http", "example.com", 
    "/path/path", "param1=param1Data&param2= \"", null);

This constructor needs path and query be a separate arguments, but I have a relative URL, and it not split by path and query parts.

I could consider to check if relative URL contains "?" question sign and think everything before it is path, and everything after it is query, but what if relative url not contain path, but query only, and query contains "?" sign? Then this will not works because part of query will be considered as path.

Now I cannot get how to build absolute url from relative url.

These accepted answers seems just wrong:

It could be nice to consider scenario when relative url was given in relation to url with both host and some path part:

initial url http://example.com/...some path... relative /home?...query here ...

It would be great to get java core solution, though it still possible to use a good lib.

7
  • 1
    @AustinSchäfer Are you sure? Did you read the question? Commented Mar 6, 2018 at 12:51
  • Not completely. I am wrong about it being a duplicate, but the question name should probably be updated to reflect it being a special case. Commented Mar 6, 2018 at 12:57
  • @AustinSchäfer I think actually the question is right, because I ask not about special case but much more in general, then others topics I mentioned. It could have sense to rename them instead, to not confuse. What you think? Commented Mar 6, 2018 at 13:16
  • I think you already answered your own question, use the URI constructor with separate path, query and fragment arguments. The first ? should define the limits between path and query and the first # should define the limit of the fragment Commented Mar 6, 2018 at 13:17
  • @whoever who put: This question may already have an answer here: to top of my question. Could you give me a favor and read the question before you do such things. Thanks. Commented Mar 6, 2018 at 13:18

2 Answers 2

5

The first ? indicates where the query string begins:

3.4. Query

[...] The query component is indicated by the first question mark (?) character and terminated by a number sign (#) character or by the end of the URI.

A simple approach (that won't handle fragments and assumes that the query string is always present) is as simple as:

String protocol = "http";
String host = "example.com";
String location = "/path/path?key1=value1&key2=value2";

String path = location.substring(0, location.indexOf("?"));
String query = location.substring(location.indexOf("?") + 1);

URI uri = new URI(protocol, host, path, query, null);

A better approach that can also handle fragments could be :

String protocol = "http";
String host = "example.com";
String location = "/path/path?key1=value1&key2=value2#fragment";

// Split the location without removing the delimiters
String[] parts = location.split("(?=\\?)|(?=#)");

String path = null;
String query = null;
String fragment = null;

// Iterate over the parts to find path, query and fragment
for (String part : parts) {
    
    // The query string starts with ?
    if (part.startsWith("?")) {
        query = part.substring(1); 
        continue;
    }
    
    // The fragment starts with #
    if (part.startsWith("#")) {
        fragment = part.substring(1);
        continue;
    }
    
    // Path is what's left
    path = part;
}

URI uri = new URI(protocol, host, path, query, fragment);
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. I was not able to solve this because was not familiar with RFC3986 before.
0

The best way seems to be to create a URI object with the multi piece constructors, and then convert it to a URL like so:

URI uri = new URI("https", "sitename.domain.tld", "/path/goes/here", "param1=value&param2=otherValue");
URL url = uri.toURL();

2 Comments

As mentioned in question I consider this as one of possible ways to go, but how I will split relative url by parts to know path and query?
Find the third / in your string to find the sub-path, and find the first ? to find the query parameters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.