
io.datakernel.http.UrlBuilder Maven / Gradle / Ivy
/*
* Copyright (C) 2015-2018 SoftIndex LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.datakernel.http;
import org.jetbrains.annotations.Nullable;
import java.io.UnsupportedEncodingException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URLEncoder;
import java.util.*;
import static java.nio.charset.StandardCharsets.UTF_8;
public class UrlBuilder {
@Nullable
private final String scheme;
private final List path = new LinkedList<>();
private final Map query = new LinkedHashMap<>();
@Nullable
private String userInfo;
@Nullable
private String host;
@Nullable
private String port;
@Nullable
private String fragment;
private UrlBuilder(@Nullable String scheme) {
this.scheme = scheme;
}
public static UrlBuilder of(String scheme) {
return new UrlBuilder(scheme);
}
public static UrlBuilder http() {
return new UrlBuilder("http");
}
public static UrlBuilder https() {
return new UrlBuilder("https");
}
public UrlBuilder withAuthority(String userInfo, InetSocketAddress address) {
String host;
if (address.isUnresolved()) {
host = address.getHostName();
} else {
InetAddress inetAddress = address.getAddress();
host = inetAddress.getHostAddress();
if (inetAddress instanceof Inet6Address) {
host = '[' + host.replace("%", "%25") + ']'; // yay, IPv6 syntax?
}
}
return withAuthority(userInfo, host, address.getPort());
}
public UrlBuilder withAuthority(String host) {
this.host = host;
return this;
}
public UrlBuilder withAuthority(String host, int port) {
assert port >= 0 && port <= 49151; // exclude ephemeral ports (https://tools.ietf.org/html/rfc6335#section-6)
this.port = Integer.toString(port);
return withAuthority(host);
}
public UrlBuilder withAuthority(String userInfo, String host) {
this.userInfo = userInfo;
return withAuthority(host);
}
public UrlBuilder withAuthority(String userInfo, String host, int port) {
this.userInfo = userInfo;
return withAuthority(host, port);
}
public UrlBuilder withAuthority(InetSocketAddress address) {
return withAuthority(address.isUnresolved() ? address.getHostName() : address.getAddress().getHostAddress(), address.getPort());
}
public static UrlBuilder relative() {
return new UrlBuilder(null);
}
public static String mapToQuery(Map query) {
StringBuilder sb = new StringBuilder();
query.forEach((k, v) -> sb.append(urlEncode(k)).append('=').append(urlEncode(v.toString())).append('&'));
sb.setLength(sb.length() - 1); // drop last '&'
return sb.toString();
}
public UrlBuilder appendPathPart(String part) {
path.add(part);
return this;
}
public UrlBuilder appendPathPart(HttpPathPart pathPart) {
path.add(pathPart.toString());
return this;
}
public UrlBuilder appendPath(String pathTail) {
path.addAll(Arrays.asList(pathTail.split("/")));
return this;
}
public UrlBuilder appendQuery(String key, Object value) {
query.put(key, value.toString());
return this;
}
public UrlBuilder withFragment(String fragment) {
this.fragment = fragment;
return this;
}
public static String urlEncode(String str) {
try {
return URLEncoder.encode(str, UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new AssertionError("Apparently, UTF-8 no longer exists", e);
}
}
public String build() {
return toString();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (scheme != null) {
sb.append(scheme).append(':');
}
if (host != null) {
sb.append("//");
if (userInfo != null) {
sb.append(userInfo).append('@');
}
sb.append(host);
if (port != null) {
sb.append(':').append(port);
}
sb.append('/');
}
if (!path.isEmpty()) {
path.forEach(p -> sb.append(urlEncode(p)).append('/'));
sb.setLength(sb.length() - 1); // drop last '/'
}
if (!query.isEmpty()) {
sb.append('?');
query.forEach((k, v) -> sb.append(urlEncode(k)).append('=').append(urlEncode(v)).append('&'));
sb.setLength(sb.length() - 1); // drop last '&'
}
if (fragment != null) {
sb.append('#').append(fragment);
}
return sb.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy