mirror of https://github.com/etesync/android
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
491 lines
15 KiB
491 lines
15 KiB
/*
|
|
* ====================================================================
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you 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.
|
|
* ====================================================================
|
|
*
|
|
* This software consists of voluntary contributions made by many
|
|
* individuals on behalf of the Apache Software Foundation. For more
|
|
* information on the Apache Software Foundation, please see
|
|
* <http://www.apache.org/>.
|
|
*
|
|
*/
|
|
package org.apache.http.client.utils;
|
|
|
|
import java.net.URI;
|
|
import java.net.URISyntaxException;
|
|
import java.nio.charset.Charset;
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
|
|
import org.apache.http.Consts;
|
|
import org.apache.http.NameValuePair;
|
|
import org.apache.http.annotation.NotThreadSafe;
|
|
import org.apache.http.conn.util.InetAddressUtilsHC4;
|
|
import org.apache.http.message.BasicNameValuePair;
|
|
|
|
/**
|
|
* Builder for {@link URI} instances.
|
|
*
|
|
* @since 4.2
|
|
*/
|
|
@NotThreadSafe
|
|
public class URIBuilder {
|
|
|
|
private String scheme;
|
|
private String encodedSchemeSpecificPart;
|
|
private String encodedAuthority;
|
|
private String userInfo;
|
|
private String encodedUserInfo;
|
|
private String host;
|
|
private int port;
|
|
private String path;
|
|
private String encodedPath;
|
|
private String encodedQuery;
|
|
private List<NameValuePair> queryParams;
|
|
private String query;
|
|
private String fragment;
|
|
private String encodedFragment;
|
|
|
|
/**
|
|
* Constructs an empty instance.
|
|
*/
|
|
public URIBuilder() {
|
|
super();
|
|
this.port = -1;
|
|
}
|
|
|
|
/**
|
|
* Construct an instance from the string which must be a valid URI.
|
|
*
|
|
* @param string a valid URI in string form
|
|
* @throws URISyntaxException if the input is not a valid URI
|
|
*/
|
|
public URIBuilder(final String string) throws URISyntaxException {
|
|
super();
|
|
digestURI(new URI(string));
|
|
}
|
|
|
|
/**
|
|
* Construct an instance from the provided URI.
|
|
* @param uri
|
|
*/
|
|
public URIBuilder(final URI uri) {
|
|
super();
|
|
digestURI(uri);
|
|
}
|
|
|
|
private List <NameValuePair> parseQuery(final String query, final Charset charset) {
|
|
if (query != null && query.length() > 0) {
|
|
return URLEncodedUtilsHC4.parse(query, charset);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Builds a {@link URI} instance.
|
|
*/
|
|
public URI build() throws URISyntaxException {
|
|
return new URI(buildString());
|
|
}
|
|
|
|
private String buildString() {
|
|
final StringBuilder sb = new StringBuilder();
|
|
if (this.scheme != null) {
|
|
sb.append(this.scheme).append(':');
|
|
}
|
|
if (this.encodedSchemeSpecificPart != null) {
|
|
sb.append(this.encodedSchemeSpecificPart);
|
|
} else {
|
|
if (this.encodedAuthority != null) {
|
|
sb.append("//").append(this.encodedAuthority);
|
|
} else if (this.host != null) {
|
|
sb.append("//");
|
|
if (this.encodedUserInfo != null) {
|
|
sb.append(this.encodedUserInfo).append("@");
|
|
} else if (this.userInfo != null) {
|
|
sb.append(encodeUserInfo(this.userInfo)).append("@");
|
|
}
|
|
if (InetAddressUtilsHC4.isIPv6Address(this.host)) {
|
|
sb.append("[").append(this.host).append("]");
|
|
} else {
|
|
sb.append(this.host);
|
|
}
|
|
if (this.port >= 0) {
|
|
sb.append(":").append(this.port);
|
|
}
|
|
}
|
|
if (this.encodedPath != null) {
|
|
sb.append(normalizePath(this.encodedPath));
|
|
} else if (this.path != null) {
|
|
sb.append(encodePath(normalizePath(this.path)));
|
|
}
|
|
if (this.encodedQuery != null) {
|
|
sb.append("?").append(this.encodedQuery);
|
|
} else if (this.queryParams != null) {
|
|
sb.append("?").append(encodeUrlForm(this.queryParams));
|
|
} else if (this.query != null) {
|
|
sb.append("?").append(encodeUric(this.query));
|
|
}
|
|
}
|
|
if (this.encodedFragment != null) {
|
|
sb.append("#").append(this.encodedFragment);
|
|
} else if (this.fragment != null) {
|
|
sb.append("#").append(encodeUric(this.fragment));
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
private void digestURI(final URI uri) {
|
|
this.scheme = uri.getScheme();
|
|
this.encodedSchemeSpecificPart = uri.getRawSchemeSpecificPart();
|
|
this.encodedAuthority = uri.getRawAuthority();
|
|
this.host = uri.getHost();
|
|
this.port = uri.getPort();
|
|
this.encodedUserInfo = uri.getRawUserInfo();
|
|
this.userInfo = uri.getUserInfo();
|
|
this.encodedPath = uri.getRawPath();
|
|
this.path = uri.getPath();
|
|
this.encodedQuery = uri.getRawQuery();
|
|
this.queryParams = parseQuery(uri.getRawQuery(), Consts.UTF_8);
|
|
this.encodedFragment = uri.getRawFragment();
|
|
this.fragment = uri.getFragment();
|
|
}
|
|
|
|
private String encodeUserInfo(final String userInfo) {
|
|
return URLEncodedUtilsHC4.encUserInfo(userInfo, Consts.UTF_8);
|
|
}
|
|
|
|
private String encodePath(final String path) {
|
|
return URLEncodedUtilsHC4.encPath(path, Consts.UTF_8);
|
|
}
|
|
|
|
private String encodeUrlForm(final List<NameValuePair> params) {
|
|
return URLEncodedUtilsHC4.format(params, Consts.UTF_8);
|
|
}
|
|
|
|
private String encodeUric(final String fragment) {
|
|
return URLEncodedUtilsHC4.encUric(fragment, Consts.UTF_8);
|
|
}
|
|
|
|
/**
|
|
* Sets URI scheme.
|
|
*/
|
|
public URIBuilder setScheme(final String scheme) {
|
|
this.scheme = scheme;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets URI user info. The value is expected to be unescaped and may contain non ASCII
|
|
* characters.
|
|
*/
|
|
public URIBuilder setUserInfo(final String userInfo) {
|
|
this.userInfo = userInfo;
|
|
this.encodedSchemeSpecificPart = null;
|
|
this.encodedAuthority = null;
|
|
this.encodedUserInfo = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets URI user info as a combination of username and password. These values are expected to
|
|
* be unescaped and may contain non ASCII characters.
|
|
*/
|
|
public URIBuilder setUserInfo(final String username, final String password) {
|
|
return setUserInfo(username + ':' + password);
|
|
}
|
|
|
|
/**
|
|
* Sets URI host.
|
|
*/
|
|
public URIBuilder setHost(final String host) {
|
|
this.host = host;
|
|
this.encodedSchemeSpecificPart = null;
|
|
this.encodedAuthority = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets URI port.
|
|
*/
|
|
public URIBuilder setPort(final int port) {
|
|
this.port = port < 0 ? -1 : port;
|
|
this.encodedSchemeSpecificPart = null;
|
|
this.encodedAuthority = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets URI path. The value is expected to be unescaped and may contain non ASCII characters.
|
|
*/
|
|
public URIBuilder setPath(final String path) {
|
|
this.path = path;
|
|
this.encodedSchemeSpecificPart = null;
|
|
this.encodedPath = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Removes URI query.
|
|
*/
|
|
public URIBuilder removeQuery() {
|
|
this.queryParams = null;
|
|
this.query = null;
|
|
this.encodedQuery = null;
|
|
this.encodedSchemeSpecificPart = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets URI query.
|
|
* <p>
|
|
* The value is expected to be encoded form data.
|
|
*
|
|
* @deprecated (4.3) use {@link #setParameters(List)} or {@link #setParameters(NameValuePair...)}
|
|
*
|
|
* @see URLEncodedUtilsHC4#parse
|
|
*/
|
|
@Deprecated
|
|
public URIBuilder setQuery(final String query) {
|
|
this.queryParams = parseQuery(query, Consts.UTF_8);
|
|
this.query = null;
|
|
this.encodedQuery = null;
|
|
this.encodedSchemeSpecificPart = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets URI query parameters. The parameter name / values are expected to be unescaped
|
|
* and may contain non ASCII characters.
|
|
* <p/>
|
|
* Please note query parameters and custom query component are mutually exclusive. This method
|
|
* will remove custom query if present.
|
|
*
|
|
* @since 4.3
|
|
*/
|
|
public URIBuilder setParameters(final List <NameValuePair> nvps) {
|
|
if (this.queryParams == null) {
|
|
this.queryParams = new ArrayList<NameValuePair>();
|
|
} else {
|
|
this.queryParams.clear();
|
|
}
|
|
this.queryParams.addAll(nvps);
|
|
this.encodedQuery = null;
|
|
this.encodedSchemeSpecificPart = null;
|
|
this.query = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds URI query parameters. The parameter name / values are expected to be unescaped
|
|
* and may contain non ASCII characters.
|
|
* <p/>
|
|
* Please note query parameters and custom query component are mutually exclusive. This method
|
|
* will remove custom query if present.
|
|
*
|
|
* @since 4.3
|
|
*/
|
|
public URIBuilder addParameters(final List <NameValuePair> nvps) {
|
|
if (this.queryParams == null) {
|
|
this.queryParams = new ArrayList<NameValuePair>();
|
|
}
|
|
this.queryParams.addAll(nvps);
|
|
this.encodedQuery = null;
|
|
this.encodedSchemeSpecificPart = null;
|
|
this.query = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets URI query parameters. The parameter name / values are expected to be unescaped
|
|
* and may contain non ASCII characters.
|
|
* <p/>
|
|
* Please note query parameters and custom query component are mutually exclusive. This method
|
|
* will remove custom query if present.
|
|
*
|
|
* @since 4.3
|
|
*/
|
|
public URIBuilder setParameters(final NameValuePair... nvps) {
|
|
if (this.queryParams == null) {
|
|
this.queryParams = new ArrayList<NameValuePair>();
|
|
} else {
|
|
this.queryParams.clear();
|
|
}
|
|
for (final NameValuePair nvp: nvps) {
|
|
this.queryParams.add(nvp);
|
|
}
|
|
this.encodedQuery = null;
|
|
this.encodedSchemeSpecificPart = null;
|
|
this.query = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds parameter to URI query. The parameter name and value are expected to be unescaped
|
|
* and may contain non ASCII characters.
|
|
* <p/>
|
|
* Please note query parameters and custom query component are mutually exclusive. This method
|
|
* will remove custom query if present.
|
|
*/
|
|
public URIBuilder addParameter(final String param, final String value) {
|
|
if (this.queryParams == null) {
|
|
this.queryParams = new ArrayList<NameValuePair>();
|
|
}
|
|
this.queryParams.add(new BasicNameValuePair(param, value));
|
|
this.encodedQuery = null;
|
|
this.encodedSchemeSpecificPart = null;
|
|
this.query = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets parameter of URI query overriding existing value if set. The parameter name and value
|
|
* are expected to be unescaped and may contain non ASCII characters.
|
|
* <p/>
|
|
* Please note query parameters and custom query component are mutually exclusive. This method
|
|
* will remove custom query if present.
|
|
*/
|
|
public URIBuilder setParameter(final String param, final String value) {
|
|
if (this.queryParams == null) {
|
|
this.queryParams = new ArrayList<NameValuePair>();
|
|
}
|
|
if (!this.queryParams.isEmpty()) {
|
|
for (final Iterator<NameValuePair> it = this.queryParams.iterator(); it.hasNext(); ) {
|
|
final NameValuePair nvp = it.next();
|
|
if (nvp.getName().equals(param)) {
|
|
it.remove();
|
|
}
|
|
}
|
|
}
|
|
this.queryParams.add(new BasicNameValuePair(param, value));
|
|
this.encodedQuery = null;
|
|
this.encodedSchemeSpecificPart = null;
|
|
this.query = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Clears URI query parameters.
|
|
*
|
|
* @since 4.3
|
|
*/
|
|
public URIBuilder clearParameters() {
|
|
this.queryParams = null;
|
|
this.encodedQuery = null;
|
|
this.encodedSchemeSpecificPart = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets custom URI query. The value is expected to be unescaped and may contain non ASCII
|
|
* characters.
|
|
* <p/>
|
|
* Please note query parameters and custom query component are mutually exclusive. This method
|
|
* will remove query parameters if present.
|
|
*
|
|
* @since 4.3
|
|
*/
|
|
public URIBuilder setCustomQuery(final String query) {
|
|
this.query = query;
|
|
this.encodedQuery = null;
|
|
this.encodedSchemeSpecificPart = null;
|
|
this.queryParams = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Sets URI fragment. The value is expected to be unescaped and may contain non ASCII
|
|
* characters.
|
|
*/
|
|
public URIBuilder setFragment(final String fragment) {
|
|
this.fragment = fragment;
|
|
this.encodedFragment = null;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* @since 4.3
|
|
*/
|
|
public boolean isAbsolute() {
|
|
return this.scheme != null;
|
|
}
|
|
|
|
/**
|
|
* @since 4.3
|
|
*/
|
|
public boolean isOpaque() {
|
|
return this.path == null;
|
|
}
|
|
|
|
public String getScheme() {
|
|
return this.scheme;
|
|
}
|
|
|
|
public String getUserInfo() {
|
|
return this.userInfo;
|
|
}
|
|
|
|
public String getHost() {
|
|
return this.host;
|
|
}
|
|
|
|
public int getPort() {
|
|
return this.port;
|
|
}
|
|
|
|
public String getPath() {
|
|
return this.path;
|
|
}
|
|
|
|
public List<NameValuePair> getQueryParams() {
|
|
if (this.queryParams != null) {
|
|
return new ArrayList<NameValuePair>(this.queryParams);
|
|
} else {
|
|
return new ArrayList<NameValuePair>();
|
|
}
|
|
}
|
|
|
|
public String getFragment() {
|
|
return this.fragment;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return buildString();
|
|
}
|
|
|
|
private static String normalizePath(final String path) {
|
|
String s = path;
|
|
if (s == null) {
|
|
return null;
|
|
}
|
|
int n = 0;
|
|
for (; n < s.length(); n++) {
|
|
if (s.charAt(n) != '/') {
|
|
break;
|
|
}
|
|
}
|
|
if (n > 1) {
|
|
s = s.substring(n - 1);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
}
|