mirror of
https://github.com/roytam1/palemoon26.git
synced 2026-05-27 09:11:15 +00:00
332 lines
11 KiB
Java
332 lines
11 KiB
Java
/*
|
|
* ====================================================================
|
|
*
|
|
* 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 ch.boye.httpclientandroidlib.client.utils;
|
|
|
|
import java.net.URI;
|
|
import java.net.URISyntaxException;
|
|
import java.util.Stack;
|
|
|
|
import ch.boye.httpclientandroidlib.annotation.Immutable;
|
|
|
|
import ch.boye.httpclientandroidlib.HttpHost;
|
|
|
|
/**
|
|
* A collection of utilities for {@link URI URIs}, to workaround
|
|
* bugs within the class or for ease-of-use features.
|
|
*
|
|
* @since 4.0
|
|
*/
|
|
@Immutable
|
|
public class URIUtils {
|
|
|
|
/**
|
|
* Constructs a {@link URI} using all the parameters. This should be
|
|
* used instead of
|
|
* {@link URI#URI(String, String, String, int, String, String, String)}
|
|
* or any of the other URI multi-argument URI constructors.
|
|
*
|
|
* @param scheme
|
|
* Scheme name
|
|
* @param host
|
|
* Host name
|
|
* @param port
|
|
* Port number
|
|
* @param path
|
|
* Path
|
|
* @param query
|
|
* Query
|
|
* @param fragment
|
|
* Fragment
|
|
*
|
|
* @throws URISyntaxException
|
|
* If both a scheme and a path are given but the path is
|
|
* relative, if the URI string constructed from the given
|
|
* components violates RFC 2396, or if the authority
|
|
* component of the string is present but cannot be parsed
|
|
* as a server-based authority
|
|
*/
|
|
public static URI createURI(
|
|
final String scheme,
|
|
final String host,
|
|
int port,
|
|
final String path,
|
|
final String query,
|
|
final String fragment) throws URISyntaxException {
|
|
|
|
StringBuilder buffer = new StringBuilder();
|
|
if (host != null) {
|
|
if (scheme != null) {
|
|
buffer.append(scheme);
|
|
buffer.append("://");
|
|
}
|
|
buffer.append(host);
|
|
if (port > 0) {
|
|
buffer.append(':');
|
|
buffer.append(port);
|
|
}
|
|
}
|
|
if (path == null || !path.startsWith("/")) {
|
|
buffer.append('/');
|
|
}
|
|
if (path != null) {
|
|
buffer.append(path);
|
|
}
|
|
if (query != null) {
|
|
buffer.append('?');
|
|
buffer.append(query);
|
|
}
|
|
if (fragment != null) {
|
|
buffer.append('#');
|
|
buffer.append(fragment);
|
|
}
|
|
return new URI(buffer.toString());
|
|
}
|
|
|
|
/**
|
|
* A convenience method for creating a new {@link URI} whose scheme, host
|
|
* and port are taken from the target host, but whose path, query and
|
|
* fragment are taken from the existing URI. The fragment is only used if
|
|
* dropFragment is false.
|
|
*
|
|
* @param uri
|
|
* Contains the path, query and fragment to use.
|
|
* @param target
|
|
* Contains the scheme, host and port to use.
|
|
* @param dropFragment
|
|
* True if the fragment should not be copied.
|
|
*
|
|
* @throws URISyntaxException
|
|
* If the resulting URI is invalid.
|
|
*/
|
|
public static URI rewriteURI(
|
|
final URI uri,
|
|
final HttpHost target,
|
|
boolean dropFragment) throws URISyntaxException {
|
|
if (uri == null) {
|
|
throw new IllegalArgumentException("URI may nor be null");
|
|
}
|
|
if (target != null) {
|
|
return URIUtils.createURI(
|
|
target.getSchemeName(),
|
|
target.getHostName(),
|
|
target.getPort(),
|
|
normalizePath(uri.getRawPath()),
|
|
uri.getRawQuery(),
|
|
dropFragment ? null : uri.getRawFragment());
|
|
} else {
|
|
return URIUtils.createURI(
|
|
null,
|
|
null,
|
|
-1,
|
|
normalizePath(uri.getRawPath()),
|
|
uri.getRawQuery(),
|
|
dropFragment ? null : uri.getRawFragment());
|
|
}
|
|
}
|
|
|
|
private static String normalizePath(String path) {
|
|
if (path == null) {
|
|
return null;
|
|
}
|
|
int n = 0;
|
|
for (; n < path.length(); n++) {
|
|
if (path.charAt(n) != '/') {
|
|
break;
|
|
}
|
|
}
|
|
if (n > 1) {
|
|
path = path.substring(n - 1);
|
|
}
|
|
return path;
|
|
}
|
|
|
|
/**
|
|
* A convenience method for
|
|
* {@link URIUtils#rewriteURI(URI, HttpHost, boolean)} that always keeps the
|
|
* fragment.
|
|
*/
|
|
public static URI rewriteURI(
|
|
final URI uri,
|
|
final HttpHost target) throws URISyntaxException {
|
|
return rewriteURI(uri, target, false);
|
|
}
|
|
|
|
/**
|
|
* Resolves a URI reference against a base URI. Work-around for bug in
|
|
* java.net.URI (<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
|
|
*
|
|
* @param baseURI the base URI
|
|
* @param reference the URI reference
|
|
* @return the resulting URI
|
|
*/
|
|
public static URI resolve(final URI baseURI, final String reference) {
|
|
return URIUtils.resolve(baseURI, URI.create(reference));
|
|
}
|
|
|
|
/**
|
|
* Resolves a URI reference against a base URI. Work-around for bugs in
|
|
* java.net.URI (e.g. <http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
|
|
*
|
|
* @param baseURI the base URI
|
|
* @param reference the URI reference
|
|
* @return the resulting URI
|
|
*/
|
|
public static URI resolve(final URI baseURI, URI reference){
|
|
if (baseURI == null) {
|
|
throw new IllegalArgumentException("Base URI may nor be null");
|
|
}
|
|
if (reference == null) {
|
|
throw new IllegalArgumentException("Reference URI may nor be null");
|
|
}
|
|
String s = reference.toString();
|
|
if (s.startsWith("?")) {
|
|
return resolveReferenceStartingWithQueryString(baseURI, reference);
|
|
}
|
|
boolean emptyReference = s.length() == 0;
|
|
if (emptyReference) {
|
|
reference = URI.create("#");
|
|
}
|
|
URI resolved = baseURI.resolve(reference);
|
|
if (emptyReference) {
|
|
String resolvedString = resolved.toString();
|
|
resolved = URI.create(resolvedString.substring(0,
|
|
resolvedString.indexOf('#')));
|
|
}
|
|
return removeDotSegments(resolved);
|
|
}
|
|
|
|
/**
|
|
* Resolves a reference starting with a query string.
|
|
*
|
|
* @param baseURI the base URI
|
|
* @param reference the URI reference starting with a query string
|
|
* @return the resulting URI
|
|
*/
|
|
private static URI resolveReferenceStartingWithQueryString(
|
|
final URI baseURI, final URI reference) {
|
|
String baseUri = baseURI.toString();
|
|
baseUri = baseUri.indexOf('?') > -1 ?
|
|
baseUri.substring(0, baseUri.indexOf('?')) : baseUri;
|
|
return URI.create(baseUri + reference.toString());
|
|
}
|
|
|
|
/**
|
|
* Removes dot segments according to RFC 3986, section 5.2.4
|
|
*
|
|
* @param uri the original URI
|
|
* @return the URI without dot segments
|
|
*/
|
|
private static URI removeDotSegments(URI uri) {
|
|
String path = uri.getPath();
|
|
if ((path == null) || (path.indexOf("/.") == -1)) {
|
|
// No dot segments to remove
|
|
return uri;
|
|
}
|
|
String[] inputSegments = path.split("/");
|
|
Stack<String> outputSegments = new Stack<String>();
|
|
for (int i = 0; i < inputSegments.length; i++) {
|
|
if ((inputSegments[i].length() == 0)
|
|
|| (".".equals(inputSegments[i]))) {
|
|
// Do nothing
|
|
} else if ("..".equals(inputSegments[i])) {
|
|
if (!outputSegments.isEmpty()) {
|
|
outputSegments.pop();
|
|
}
|
|
} else {
|
|
outputSegments.push(inputSegments[i]);
|
|
}
|
|
}
|
|
StringBuilder outputBuffer = new StringBuilder();
|
|
for (String outputSegment : outputSegments) {
|
|
outputBuffer.append('/').append(outputSegment);
|
|
}
|
|
try {
|
|
return new URI(uri.getScheme(), uri.getAuthority(),
|
|
outputBuffer.toString(), uri.getQuery(), uri.getFragment());
|
|
} catch (URISyntaxException e) {
|
|
throw new IllegalArgumentException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extracts target host from the given {@link URI}.
|
|
*
|
|
* @param uri
|
|
* @return the target host if the URI is absolute or <code>null</null> if the URI is
|
|
* relative or does not contain a valid host name.
|
|
*
|
|
* @since 4.1
|
|
*/
|
|
public static HttpHost extractHost(final URI uri) {
|
|
if (uri == null) {
|
|
return null;
|
|
}
|
|
HttpHost target = null;
|
|
if (uri.isAbsolute()) {
|
|
int port = uri.getPort(); // may be overridden later
|
|
String host = uri.getHost();
|
|
if (host == null) { // normal parse failed; let's do it ourselves
|
|
// authority does not seem to care about the valid character-set for host names
|
|
host = uri.getAuthority();
|
|
if (host != null) {
|
|
// Strip off any leading user credentials
|
|
int at = host.indexOf('@');
|
|
if (at >= 0) {
|
|
if (host.length() > at+1 ) {
|
|
host = host.substring(at+1);
|
|
} else {
|
|
host = null; // @ on its own
|
|
}
|
|
}
|
|
// Extract the port suffix, if present
|
|
if (host != null) {
|
|
int colon = host.indexOf(':');
|
|
if (colon >= 0) {
|
|
if (colon+1 < host.length()) {
|
|
port = Integer.parseInt(host.substring(colon+1));
|
|
}
|
|
host = host.substring(0,colon);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
String scheme = uri.getScheme();
|
|
if (host != null) {
|
|
target = new HttpHost(host, port, scheme);
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
|
|
/**
|
|
* This class should not be instantiated.
|
|
*/
|
|
private URIUtils() {
|
|
}
|
|
|
|
}
|