📄 uri.java
字号:
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
* conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This
* product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this
* acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear.
* 4. The names "Xalan" and "Apache Software Foundation" must not be used to endorse or promote products derived from this
* software without prior written permission. For written permission, please contact apache@apache.org.
* 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE
* FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus Development Corporation., http://www.lotus.com. For more information on
* the Apache Software Foundation, please see <http://www.apache.org/> .
*
*
*
* Adapted for use as a standalone class in Maverick by removing references to XSLMessages and XSLErrorResources.
*/
package com.sslexplorer.vpn.util;
import java.io.IOException;
import java.io.Serializable;
/**
* A class to represent a Uniform Resource Identifier (URI). This class is designed to handle the parsing of URIs and provide
* access to the various components (scheme, host, port, userinfo, path, query string and fragment) that may constitute a URI.
* <p>
* Parsing of a URI specification is done according to the URI syntax described in RFC 2396
* <http://www.ietf.org/rfc/rfc2396.txt?number=2396>. Every URI consists of a scheme, followed by a colon (':'), followed by a
* scheme-specific part. For URIs that follow the "generic URI" syntax, the scheme- specific part begins with two slashes ("//")
* and may be followed by an authority segment (comprised of user information, host, and port), path segment, query segment and
* fragment. Note that RFC 2396 no longer specifies the use of the parameters segment and excludes the "user:password" syntax as
* part of the authority segment. If "user:password" appears in a URI, the entire user/password string is stored as userinfo.
* <p>
* For URIs that do not follow the "generic URI" syntax (e.g. mailto), the entire scheme-specific part is treated as the "path"
* portion of the URI.
* <p>
* Note that, unlike the java.net.URL class, this class does not provide any built-in network access functionality nor does it
* provide any scheme-specific functionality (for example, it does not know a default port for a specific scheme). Rather, it only
* knows the grammar and basic set of operations that can be applied to a URI.
*
*
*/
public class URI
implements Serializable {
/**
* MalformedURIExceptions are thrown in the process of building a URI or setting fields on a URI when an operation would result
* in an invalid URI specification.
*
*/
public static class MalformedURIException
extends IOException {
/**
* Constructs a <code>MalformedURIException</code> with no specified detail message.
*/
public MalformedURIException() {
super();
}
/**
* Constructs a <code>MalformedURIException</code> with the specified detail message.
*
* @param p_msg the detail message.
*/
public MalformedURIException(String p_msg) {
super(p_msg);
}
}
/** reserved characters */
private static final String RESERVED_CHARACTERS = ";/?:@&=+$,";
/**
* URI punctuation mark characters - these, combined with alphanumerics, constitute the "unreserved" characters
*/
private static final String MARK_CHARACTERS = "-_.!~*'() ";
/** scheme can be composed of alphanumerics and these characters */
private static final String SCHEME_CHARACTERS = "+-.";
/**
* userinfo can be composed of unreserved, escaped and these characters
*/
private static final String USERINFO_CHARACTERS = ";:&=+$,";
/**
* Stores the scheme (usually the protocol) for this URI.
*
* @serial
*/
private String m_scheme = null;
/**
* If specified, stores the userinfo for this URI; otherwise null.
*
* @serial
*/
private String m_userinfo = null;
/**
* If specified, stores the host for this URI; otherwise null.
*
* @serial
*/
private String m_host = null;
/**
* If specified, stores the port for this URI; otherwise -1.
*
* @serial
*/
private int m_port = -1;
/**
* If specified, stores the path for this URI; otherwise null.
*
* @serial
*/
private String m_path = null;
/**
* If specified, stores the query string for this URI; otherwise null.
*
* @serial
*/
private String m_queryString = null;
/**
* If specified, stores the fragment for this URI; otherwise null.
*
* @serial
*/
private String m_fragment = null;
/** Indicate whether in DEBUG mode */
private static boolean DEBUG = false;
/**
* Construct a new and uninitialized URI.
*/
public URI() {
}
/**
* Construct a new URI from another URI. All fields for this URI are set equal to the fields of the URI passed in.
*
* @param p_other the URI to copy (cannot be null)
*/
public URI(URI p_other) {
initialize(p_other);
}
/**
* Construct a new URI from a URI specification string. If the specification follows the "generic URI" syntax, (two slashes
* following the first colon), the specification will be parsed accordingly - setting the scheme, userinfo, host,port, path,
* query string and fragment fields as necessary. If the specification does not follow the "generic URI" syntax, the
* specification is parsed into a scheme and scheme-specific part (stored as the path) only.
*
* @param p_uriSpec the URI specification string (cannot be null or empty)
*
* @throws MalformedURIException if p_uriSpec violates any syntax rules
*/
public URI(String p_uriSpec) throws MalformedURIException {
this( (URI)null, p_uriSpec);
}
/**
* Construct a new URI from a base URI and a URI specification string. The URI specification string may be a relative URI.
*
* @param p_base the base URI (cannot be null if p_uriSpec is null or empty)
* @param p_uriSpec the URI specification string (cannot be null or empty if p_base is null)
*
* @throws MalformedURIException if p_uriSpec violates any syntax rules
*/
public URI(URI p_base, String p_uriSpec) throws MalformedURIException {
initialize(p_base, p_uriSpec);
}
/**
* Construct a new URI that does not follow the generic URI syntax. Only the scheme and scheme-specific part (stored as the
* path) are initialized.
*
* @param p_scheme the URI scheme (cannot be null or empty)
* @param p_schemeSpecificPart the scheme-specific part (cannot be null or empty)
*
* @throws MalformedURIException if p_scheme violates any syntax rules
*/
public URI(String p_scheme, String p_schemeSpecificPart) throws
MalformedURIException {
if (p_scheme == null || p_scheme.trim().length() == 0) {
throw new MalformedURIException(
"Cannot construct URI with null/empty scheme!");
}
if (p_schemeSpecificPart == null ||
p_schemeSpecificPart.trim().length() == 0) {
throw new MalformedURIException(
"Cannot construct URI with null/empty scheme-specific part!");
}
setScheme(p_scheme);
setPath(p_schemeSpecificPart);
}
/**
* Construct a new URI that follows the generic URI syntax from its component parts. Each component is validated for syntax and
* some basic semantic checks are performed as well. See the individual setter methods for specifics.
*
* @param p_scheme the URI scheme (cannot be null or empty)
* @param p_host the hostname or IPv4 address for the URI
* @param p_path the URI path - if the path contains '?' or '#', then the query string and/or fragment will be set from the
* path; however, if the query and fragment are specified both in the path and as separate parameters, an exception
* is thrown
* @param p_queryString the URI query string (cannot be specified if path is null)
* @param p_fragment the URI fragment (cannot be specified if path is null)
*
* @throws MalformedURIException if any of the parameters violates syntax rules or semantic rules
*/
public URI(String p_scheme, String p_host, String p_path,
String p_queryString, String p_fragment) throws
MalformedURIException {
this(p_scheme, null, p_host, -1, p_path, p_queryString, p_fragment);
}
/**
* Construct a new URI that follows the generic URI syntax from its component parts. Each component is validated for syntax and
* some basic semantic checks are performed as well. See the individual setter methods for specifics.
*
* @param p_scheme the URI scheme (cannot be null or empty)
* @param p_userinfo the URI userinfo (cannot be specified if host is null)
* @param p_host the hostname or IPv4 address for the URI
* @param p_port the URI port (may be -1 for "unspecified"; cannot be specified if host is null)
* @param p_path the URI path - if the path contains '?' or '#', then the query string and/or fragment will be set from the
* path; however, if the query and fragment are specified both in the path and as separate parameters, an exception
* is thrown
* @param p_queryString the URI query string (cannot be specified if path is null)
* @param p_fragment the URI fragment (cannot be specified if path is null)
*
* @throws MalformedURIException if any of the parameters violates syntax rules or semantic rules
*/
public URI(
String p_scheme,
String p_userinfo,
String p_host,
int p_port,
String p_path,
String p_queryString,
String p_fragment) throws MalformedURIException {
if (p_scheme == null || p_scheme.trim().length() == 0) {
throw new MalformedURIException("Scheme is required!");
}
if (p_host == null) {
if (p_userinfo != null) {
throw new MalformedURIException(
"Userinfo may not be specified if host is not specified!");
}
if (p_port != -1) {
throw new MalformedURIException(
"Port may not be specified if host is not specified!");
}
}
if (p_path != null) {
if (p_path.indexOf('?') != -1 && p_queryString != null) {
throw new MalformedURIException(
"Query string cannot be specified in path and query string!");
}
if (p_path.indexOf('#') != -1 && p_fragment != null) {
throw new MalformedURIException(
"Fragment cannot be specified in both the path and fragment!");
}
}
setScheme(p_scheme);
setHost(p_host);
setPort(p_port);
setUserinfo(p_userinfo);
setPath(p_path);
setQueryString(p_queryString);
setFragment(p_fragment);
}
/**
* Initialize all fields of this URI from another URI.
*
* @param p_other the URI to copy (cannot be null)
*/
private void initialize(URI p_other) {
m_scheme = p_other.getScheme();
m_userinfo = p_other.getUserinfo();
m_host = p_other.getHost();
m_port = p_other.getPort();
m_path = p_other.getPath();
m_queryString = p_other.getQueryString();
m_fragment = p_other.getFragment();
}
/**
* Initializes this URI from a base URI and a URI specification string. See RFC 2396 Section 4 and Appendix B for
* specifications on parsing the URI and Section 5 for specifications on resolving relative URIs and relative paths.
*
* @param p_base the base URI (may be null if p_uriSpec is an absolute URI)
* @param p_uriSpec the URI spec string which may be an absolute or relative URI (can only be null/empty if p_base is not null)
*
* @throws MalformedURIException if p_base is null and p_uriSpec is not an absolute URI or if p_uriSpec violates syntax rules
*/
private void initialize(URI p_base, String p_uriSpec) throws
MalformedURIException {
if (p_base == null && (p_uriSpec == null || p_uriSpec.trim().length() == 0)) {
throw new MalformedURIException(
"Cannot initialize URI with empty parameters.");
}
// just make a copy of the base if spec is empty
if (p_uriSpec == null || p_uriSpec.trim().length() == 0) {
initialize(p_base);
return;
}
String uriSpec = p_uriSpec.trim();
int uriSpecLen = uriSpec.length();
int index = 0;
// check for scheme
if (uriSpec.indexOf(':') == -1) {
if (p_base == null) {
throw new MalformedURIException("No scheme found in URI: " + uriSpec);
}
}
else {
initializeScheme(uriSpec);
index = m_scheme.length() + 1;
}
// two slashes means generic URI syntax, so we get the authority
if ( ( (index + 1) < uriSpecLen) &&
(uriSpec.substring(index).startsWith("//"))) {
index += 2;
int startPos = index;
// get authority - everything up to path, query or fragment
char testChar = '\0';
while (index < uriSpecLen) {
testChar = uriSpec.charAt(index);
if (testChar == '/' || testChar == '?' || testChar == '#') {
break;
}
index++;
}
// if we found authority, parse it out, otherwise we set the
// host to empty string
if (index > startPos) {
initializeAuthority(uriSpec.substring(startPos, index));
}
else {
m_host = "";
}
}
initializePath(uriSpec.substring(index));
// Resolve relative URI to base URI - see RFC 2396 Section 5.2
// In some cases, it might make more sense to throw an exception
// (when scheme is specified is the string spec and the base URI
// is also specified, for example), but we're just following the
// RFC specifications
if (p_base != null) {
// check to see if this is the current doc - RFC 2396 5.2 #2
// note that this is slightly different from the RFC spec in that
// we don't include the check for query string being null
// - this handles cases where the urispec is just a query
// string or a fragment (e.g. "?y" or "#s") -
// see <http://www.ics.uci.edu/~fielding/url/test1.html> which
// identified this as a bug in the RFC
if (m_path.length() == 0 && m_scheme == null && m_host == null) {
m_scheme = p_base.getScheme();
m_userinfo = p_base.getUserinfo();
m_host = p_base.getHost();
m_port = p_base.getPort();
m_path = p_base.getPath();
if (m_queryString == null) {
m_queryString = p_base.getQueryString();
}
return;
}
// check for scheme - RFC 2396 5.2 #3
// if we found a scheme, it means absolute URI, so we're done
if (m_scheme == null) {
m_scheme = p_base.getScheme();
}
else {
return;
}
// check for authority - RFC 2396 5.2 #4
// if we found a host, then we've got a network path, so we're done
if (m_host == null) {
m_userinfo = p_base.getUserinfo();
m_host = p_base.getHost();
m_port = p_base.getPort();
}
else {
return;
}
// check for absolute path - RFC 2396 5.2 #5
if (m_path.length() > 0 && m_path.startsWith("/")) {
return;
}
// if we get to this point, we need to resolve relative path
// RFC 2396 5.2 #6
String path = new String();
String basePath = p_base.getPath();
// 6a - get all but the last segment of the base URI path
if (basePath != null) {
int lastSlash = basePath.lastIndexOf('/');
if (lastSlash != -1) {
path = basePath.substring(0, lastSlash + 1);
}
}
// 6b - append the relative URI path
path = path.concat(m_path);
// 6c - remove all "./" where "." is a complete path segment
index = -1;
while ( (index = path.indexOf("/./")) != -1) {
path = path.substring(0, index + 1).concat(path.substring(index + 3));
}
// 6d - remove "." if path ends with "." as a complete path segment
if (path.endsWith("/.")) {
path = path.substring(0, path.length() - 1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -