blob: 0ebb8e3b8e978d1585654d929904b0151a608f9c [file] [log] [blame]
/*
* Copyright 2011 Google Inc.
*
* 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 com.google.gwt.safehtml.shared;
import com.google.gwt.core.client.GWT;
import com.google.gwt.thirdparty.guava.common.base.Preconditions;
import java.net.URI;
import java.net.URISyntaxException;
/**
* SafeUri utilities whose implementation differs between Development and Production Mode.
*
* <p>
* This class has a super-source peer that provides the Production Mode implementation.
*
* <p>
* Do not use this class - it is used for implementation only, and its methods may change in the
* future.
*/
public class SafeUriHostedModeUtils {
/**
* All valid Web Addresses discrete characters, i.e. the reserved, iunreserved, href-ucschar, and
* href-pct-form productions from RFC 3986 and RFC 3987bis, with the exception of character
* ranges.
*
* @see <a href="http://tools.ietf.org/html/rfc3986#section-2">RFC 3986</a>
* @see <a href="http://tools.ietf.org/html/draft-ietf-iri-3987bis-05#section-7.2">RFC 3987bis Web Addresses</a>
*/
static final String HREF_DISCRETE_UCSCHAR = ":/?#[]@!$&'()*+,;=" // reserved
+ "-._~" // iunreserved
+ " <>\"{}|\\^`" // href-ucschar
+ "%"; // href-pct-form
/**
* Name of system property that if set, enables checks in server-side code (even if assertions are
* disabled).
*/
public static final String FORCE_CHECK_VALID_URI = "com.google.gwt.safehtml.ForceCheckValidUri";
private static boolean forceCheckValidUri;
static {
setForceCheckValidUriFromProperty();
}
/**
* Tests whether all characters in the given URI are valid Web Addresses characters.
*/
// @VisibleForTesting
public static boolean isValidUriCharset(String uri) {
int len = uri.length();
int i = 0;
while (i < len) {
int codePoint = uri.codePointAt(i);
i += Character.charCount(codePoint);
if (Character.isSupplementaryCodePoint(codePoint)) {
continue;
}
if (HREF_DISCRETE_UCSCHAR.indexOf(codePoint) >= 0) {
continue;
}
// iunreserved ranges
if (('a' <= codePoint && codePoint <= 'z') || ('A' <= codePoint && codePoint <= 'Z')
|| ('0' <= codePoint && codePoint <= '9')) {
continue;
}
// href-ucschar ranges
if ((0 <= codePoint && codePoint <= 0x1F) || (0x7F <= codePoint && codePoint <= 0xD7FF)
|| (0xE000 <= codePoint && codePoint <= 0xFFFD)) {
continue;
}
return false;
}
return true;
}
/**
* Checks if the provided URI is a valid Web Address (per RFC 3987bis).
*
* @param uri the URL to check
*/
public static void maybeCheckValidUri(String uri) {
if (GWT.isClient() || forceCheckValidUri) {
Preconditions.checkArgument(isValidUri(uri), "String is not a valid URI: %s", uri);
} else {
assert isValidUri(uri) : "String is not a valid URI: " + uri;
}
}
/**
* Sets a global flag that controls whether or not {@link #maybeCheckValidUri(String)} should
* perform its check in a server-side environment.
*
* @param check if true, perform server-side checks.
*/
public static void setForceCheckValidUri(boolean check) {
forceCheckValidUri = check;
}
/**
* Sets a global flag that controls whether or not {@link #maybeCheckValidUri(String)} should
* perform its check in a server-side environment from the value of the {@value
* FORCE_CHECK_VALID_URI} property.
*/
// The following annotation causes javadoc to crash on Mac OS X 10.5.8,
// using java 1.5.0_24.
//
// See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6442982
//
// @VisibleForTesting
public static void setForceCheckValidUriFromProperty() {
forceCheckValidUri = System.getProperty(FORCE_CHECK_VALID_URI) != null;
}
private static boolean isValidUri(String uri) {
if (!isValidUriCharset(uri)) {
return false;
}
// pre-process to turn href-ucschars into ucschars, and encode to URI.
uri = UriUtils.encodeAllowEscapes(uri);
try {
new URI(uri);
return true;
} catch (URISyntaxException e) {
return false;
}
}
}