mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URIUtils.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * ====================================================================
michael@0 3 *
michael@0 4 * Licensed to the Apache Software Foundation (ASF) under one or more
michael@0 5 * contributor license agreements. See the NOTICE file distributed with
michael@0 6 * this work for additional information regarding copyright ownership.
michael@0 7 * The ASF licenses this file to You under the Apache License, Version 2.0
michael@0 8 * (the "License"); you may not use this file except in compliance with
michael@0 9 * the License. You may obtain a copy of the License at
michael@0 10 *
michael@0 11 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 12 *
michael@0 13 * Unless required by applicable law or agreed to in writing, software
michael@0 14 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 16 * See the License for the specific language governing permissions and
michael@0 17 * limitations under the License.
michael@0 18 * ====================================================================
michael@0 19 *
michael@0 20 * This software consists of voluntary contributions made by many
michael@0 21 * individuals on behalf of the Apache Software Foundation. For more
michael@0 22 * information on the Apache Software Foundation, please see
michael@0 23 * <http://www.apache.org/>.
michael@0 24 *
michael@0 25 */
michael@0 26
michael@0 27 package ch.boye.httpclientandroidlib.client.utils;
michael@0 28
michael@0 29 import java.net.URI;
michael@0 30 import java.net.URISyntaxException;
michael@0 31 import java.util.Stack;
michael@0 32
michael@0 33 import ch.boye.httpclientandroidlib.annotation.Immutable;
michael@0 34
michael@0 35 import ch.boye.httpclientandroidlib.HttpHost;
michael@0 36
michael@0 37 /**
michael@0 38 * A collection of utilities for {@link URI URIs}, to workaround
michael@0 39 * bugs within the class or for ease-of-use features.
michael@0 40 *
michael@0 41 * @since 4.0
michael@0 42 */
michael@0 43 @Immutable
michael@0 44 public class URIUtils {
michael@0 45
michael@0 46 /**
michael@0 47 * Constructs a {@link URI} using all the parameters. This should be
michael@0 48 * used instead of
michael@0 49 * {@link URI#URI(String, String, String, int, String, String, String)}
michael@0 50 * or any of the other URI multi-argument URI constructors.
michael@0 51 *
michael@0 52 * @param scheme
michael@0 53 * Scheme name
michael@0 54 * @param host
michael@0 55 * Host name
michael@0 56 * @param port
michael@0 57 * Port number
michael@0 58 * @param path
michael@0 59 * Path
michael@0 60 * @param query
michael@0 61 * Query
michael@0 62 * @param fragment
michael@0 63 * Fragment
michael@0 64 *
michael@0 65 * @throws URISyntaxException
michael@0 66 * If both a scheme and a path are given but the path is
michael@0 67 * relative, if the URI string constructed from the given
michael@0 68 * components violates RFC&nbsp;2396, or if the authority
michael@0 69 * component of the string is present but cannot be parsed
michael@0 70 * as a server-based authority
michael@0 71 */
michael@0 72 public static URI createURI(
michael@0 73 final String scheme,
michael@0 74 final String host,
michael@0 75 int port,
michael@0 76 final String path,
michael@0 77 final String query,
michael@0 78 final String fragment) throws URISyntaxException {
michael@0 79
michael@0 80 StringBuilder buffer = new StringBuilder();
michael@0 81 if (host != null) {
michael@0 82 if (scheme != null) {
michael@0 83 buffer.append(scheme);
michael@0 84 buffer.append("://");
michael@0 85 }
michael@0 86 buffer.append(host);
michael@0 87 if (port > 0) {
michael@0 88 buffer.append(':');
michael@0 89 buffer.append(port);
michael@0 90 }
michael@0 91 }
michael@0 92 if (path == null || !path.startsWith("/")) {
michael@0 93 buffer.append('/');
michael@0 94 }
michael@0 95 if (path != null) {
michael@0 96 buffer.append(path);
michael@0 97 }
michael@0 98 if (query != null) {
michael@0 99 buffer.append('?');
michael@0 100 buffer.append(query);
michael@0 101 }
michael@0 102 if (fragment != null) {
michael@0 103 buffer.append('#');
michael@0 104 buffer.append(fragment);
michael@0 105 }
michael@0 106 return new URI(buffer.toString());
michael@0 107 }
michael@0 108
michael@0 109 /**
michael@0 110 * A convenience method for creating a new {@link URI} whose scheme, host
michael@0 111 * and port are taken from the target host, but whose path, query and
michael@0 112 * fragment are taken from the existing URI. The fragment is only used if
michael@0 113 * dropFragment is false.
michael@0 114 *
michael@0 115 * @param uri
michael@0 116 * Contains the path, query and fragment to use.
michael@0 117 * @param target
michael@0 118 * Contains the scheme, host and port to use.
michael@0 119 * @param dropFragment
michael@0 120 * True if the fragment should not be copied.
michael@0 121 *
michael@0 122 * @throws URISyntaxException
michael@0 123 * If the resulting URI is invalid.
michael@0 124 */
michael@0 125 public static URI rewriteURI(
michael@0 126 final URI uri,
michael@0 127 final HttpHost target,
michael@0 128 boolean dropFragment) throws URISyntaxException {
michael@0 129 if (uri == null) {
michael@0 130 throw new IllegalArgumentException("URI may nor be null");
michael@0 131 }
michael@0 132 if (target != null) {
michael@0 133 return URIUtils.createURI(
michael@0 134 target.getSchemeName(),
michael@0 135 target.getHostName(),
michael@0 136 target.getPort(),
michael@0 137 normalizePath(uri.getRawPath()),
michael@0 138 uri.getRawQuery(),
michael@0 139 dropFragment ? null : uri.getRawFragment());
michael@0 140 } else {
michael@0 141 return URIUtils.createURI(
michael@0 142 null,
michael@0 143 null,
michael@0 144 -1,
michael@0 145 normalizePath(uri.getRawPath()),
michael@0 146 uri.getRawQuery(),
michael@0 147 dropFragment ? null : uri.getRawFragment());
michael@0 148 }
michael@0 149 }
michael@0 150
michael@0 151 private static String normalizePath(String path) {
michael@0 152 if (path == null) {
michael@0 153 return null;
michael@0 154 }
michael@0 155 int n = 0;
michael@0 156 for (; n < path.length(); n++) {
michael@0 157 if (path.charAt(n) != '/') {
michael@0 158 break;
michael@0 159 }
michael@0 160 }
michael@0 161 if (n > 1) {
michael@0 162 path = path.substring(n - 1);
michael@0 163 }
michael@0 164 return path;
michael@0 165 }
michael@0 166
michael@0 167 /**
michael@0 168 * A convenience method for
michael@0 169 * {@link URIUtils#rewriteURI(URI, HttpHost, boolean)} that always keeps the
michael@0 170 * fragment.
michael@0 171 */
michael@0 172 public static URI rewriteURI(
michael@0 173 final URI uri,
michael@0 174 final HttpHost target) throws URISyntaxException {
michael@0 175 return rewriteURI(uri, target, false);
michael@0 176 }
michael@0 177
michael@0 178 /**
michael@0 179 * Resolves a URI reference against a base URI. Work-around for bug in
michael@0 180 * java.net.URI (<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
michael@0 181 *
michael@0 182 * @param baseURI the base URI
michael@0 183 * @param reference the URI reference
michael@0 184 * @return the resulting URI
michael@0 185 */
michael@0 186 public static URI resolve(final URI baseURI, final String reference) {
michael@0 187 return URIUtils.resolve(baseURI, URI.create(reference));
michael@0 188 }
michael@0 189
michael@0 190 /**
michael@0 191 * Resolves a URI reference against a base URI. Work-around for bugs in
michael@0 192 * java.net.URI (e.g. <http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
michael@0 193 *
michael@0 194 * @param baseURI the base URI
michael@0 195 * @param reference the URI reference
michael@0 196 * @return the resulting URI
michael@0 197 */
michael@0 198 public static URI resolve(final URI baseURI, URI reference){
michael@0 199 if (baseURI == null) {
michael@0 200 throw new IllegalArgumentException("Base URI may nor be null");
michael@0 201 }
michael@0 202 if (reference == null) {
michael@0 203 throw new IllegalArgumentException("Reference URI may nor be null");
michael@0 204 }
michael@0 205 String s = reference.toString();
michael@0 206 if (s.startsWith("?")) {
michael@0 207 return resolveReferenceStartingWithQueryString(baseURI, reference);
michael@0 208 }
michael@0 209 boolean emptyReference = s.length() == 0;
michael@0 210 if (emptyReference) {
michael@0 211 reference = URI.create("#");
michael@0 212 }
michael@0 213 URI resolved = baseURI.resolve(reference);
michael@0 214 if (emptyReference) {
michael@0 215 String resolvedString = resolved.toString();
michael@0 216 resolved = URI.create(resolvedString.substring(0,
michael@0 217 resolvedString.indexOf('#')));
michael@0 218 }
michael@0 219 return removeDotSegments(resolved);
michael@0 220 }
michael@0 221
michael@0 222 /**
michael@0 223 * Resolves a reference starting with a query string.
michael@0 224 *
michael@0 225 * @param baseURI the base URI
michael@0 226 * @param reference the URI reference starting with a query string
michael@0 227 * @return the resulting URI
michael@0 228 */
michael@0 229 private static URI resolveReferenceStartingWithQueryString(
michael@0 230 final URI baseURI, final URI reference) {
michael@0 231 String baseUri = baseURI.toString();
michael@0 232 baseUri = baseUri.indexOf('?') > -1 ?
michael@0 233 baseUri.substring(0, baseUri.indexOf('?')) : baseUri;
michael@0 234 return URI.create(baseUri + reference.toString());
michael@0 235 }
michael@0 236
michael@0 237 /**
michael@0 238 * Removes dot segments according to RFC 3986, section 5.2.4
michael@0 239 *
michael@0 240 * @param uri the original URI
michael@0 241 * @return the URI without dot segments
michael@0 242 */
michael@0 243 private static URI removeDotSegments(URI uri) {
michael@0 244 String path = uri.getPath();
michael@0 245 if ((path == null) || (path.indexOf("/.") == -1)) {
michael@0 246 // No dot segments to remove
michael@0 247 return uri;
michael@0 248 }
michael@0 249 String[] inputSegments = path.split("/");
michael@0 250 Stack<String> outputSegments = new Stack<String>();
michael@0 251 for (int i = 0; i < inputSegments.length; i++) {
michael@0 252 if ((inputSegments[i].length() == 0)
michael@0 253 || (".".equals(inputSegments[i]))) {
michael@0 254 // Do nothing
michael@0 255 } else if ("..".equals(inputSegments[i])) {
michael@0 256 if (!outputSegments.isEmpty()) {
michael@0 257 outputSegments.pop();
michael@0 258 }
michael@0 259 } else {
michael@0 260 outputSegments.push(inputSegments[i]);
michael@0 261 }
michael@0 262 }
michael@0 263 StringBuilder outputBuffer = new StringBuilder();
michael@0 264 for (String outputSegment : outputSegments) {
michael@0 265 outputBuffer.append('/').append(outputSegment);
michael@0 266 }
michael@0 267 try {
michael@0 268 return new URI(uri.getScheme(), uri.getAuthority(),
michael@0 269 outputBuffer.toString(), uri.getQuery(), uri.getFragment());
michael@0 270 } catch (URISyntaxException e) {
michael@0 271 throw new IllegalArgumentException(e);
michael@0 272 }
michael@0 273 }
michael@0 274
michael@0 275 /**
michael@0 276 * Extracts target host from the given {@link URI}.
michael@0 277 *
michael@0 278 * @param uri
michael@0 279 * @return the target host if the URI is absolute or <code>null</null> if the URI is
michael@0 280 * relative or does not contain a valid host name.
michael@0 281 *
michael@0 282 * @since 4.1
michael@0 283 */
michael@0 284 public static HttpHost extractHost(final URI uri) {
michael@0 285 if (uri == null) {
michael@0 286 return null;
michael@0 287 }
michael@0 288 HttpHost target = null;
michael@0 289 if (uri.isAbsolute()) {
michael@0 290 int port = uri.getPort(); // may be overridden later
michael@0 291 String host = uri.getHost();
michael@0 292 if (host == null) { // normal parse failed; let's do it ourselves
michael@0 293 // authority does not seem to care about the valid character-set for host names
michael@0 294 host = uri.getAuthority();
michael@0 295 if (host != null) {
michael@0 296 // Strip off any leading user credentials
michael@0 297 int at = host.indexOf('@');
michael@0 298 if (at >= 0) {
michael@0 299 if (host.length() > at+1 ) {
michael@0 300 host = host.substring(at+1);
michael@0 301 } else {
michael@0 302 host = null; // @ on its own
michael@0 303 }
michael@0 304 }
michael@0 305 // Extract the port suffix, if present
michael@0 306 if (host != null) {
michael@0 307 int colon = host.indexOf(':');
michael@0 308 if (colon >= 0) {
michael@0 309 if (colon+1 < host.length()) {
michael@0 310 port = Integer.parseInt(host.substring(colon+1));
michael@0 311 }
michael@0 312 host = host.substring(0,colon);
michael@0 313 }
michael@0 314 }
michael@0 315 }
michael@0 316 }
michael@0 317 String scheme = uri.getScheme();
michael@0 318 if (host != null) {
michael@0 319 target = new HttpHost(host, port, scheme);
michael@0 320 }
michael@0 321 }
michael@0 322 return target;
michael@0 323 }
michael@0 324
michael@0 325 /**
michael@0 326 * This class should not be instantiated.
michael@0 327 */
michael@0 328 private URIUtils() {
michael@0 329 }
michael@0 330
michael@0 331 }

mercurial