/*
*
*
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.midp.io;
import java.io.IOException;
/**
* A parsed HTTP (or subclass of) URL. Based on RFC 2396.
* <p>
* Handles IPv6 hosts, check host[0] for a "[".
* Can be used for relative URL's that do not have authorities.
* Can be used for FTP URL's that do not have the username and passwords.
* <p>
* Any elements not specified are represented by null, except a
* non-specified port, which is represented by a -1.
*/
public class HttpUrl {
/** Scheme of the URL or null. */
public String scheme;
/** Authority (host [port]) of the URL. */
public String authority;
/** Path of the URL or null. */
public String path;
/** Query of the URL or null. */
public String query;
/** Fragment of the URL or null. */
public String fragment;
/** hHst of the authority or null. */
public String host;
/** Port of the authority or -1 for not specified. */
public int port = -1;
/** Machine of the host or null. */
public String machine;
/** Domain of the host or null. */
public String domain;
/**
* Construct a HttpUrl.
*
* @param url HTTP URL to parse
*
* @exception IllegalArgumentException if there is a space in the URL or
* the port is not numeric
*/
public HttpUrl(String url) {
int afterScheme = 0;
int length;
int endOfScheme;
if (url == null) {
return;
}
length = url.length();
if (length == 0) {
return;
}
// ":" can mark a the scheme in a absolute URL which has a "//".
endOfScheme = url.indexOf(':');
if (endOfScheme != -1) {
if (endOfScheme == length - 1) {
// just a scheme
scheme = url.substring(0, endOfScheme);
return;
}
if (endOfScheme < length - 2 &&
url.charAt(endOfScheme + 1) == '/' &&
url.charAt(endOfScheme + 2) == '/') {
// found "://", get the scheme
scheme = url.substring(0, endOfScheme);
afterScheme = endOfScheme + 1;
}
}
parseAfterScheme(url, afterScheme, length);
}
/**
* Construct a HttpUrl from a scheme and partial HTTP URL.
*
* @param theScheme the protocol component of an HTTP URL
* @param partialUrl HTTP URL to parse
*
* @exception IllegalArgumentException if there is a space in the URL or
* the port is not numeric
*/
public HttpUrl(String theScheme, String partialUrl) {
int length;
scheme = theScheme;
if (partialUrl == null) {
return;
}
length = partialUrl.length();
if (length == 0) {
return;
}
parseAfterScheme(partialUrl, 0, length);
}
/**
* Parse the part of the HTTP URL after the scheme.
*
* @param url the part of the HTTP URL after the ":" of the scheme
* @param afterScheme index of the first char after the scheme
* @param length length of the url
*
* @exception IllegalArgumentException if there is a space in the URL or
* the port is not numeric
*/
private void parseAfterScheme(String url, int afterScheme, int length) {
int start;
int startOfAuthority;
int endOfUrl;
int endOfAuthority;
int endOfPath;
int endOfQuery;
int endOfHost;
int startOfPort;
int endOfPort;
int lastDot;
int startOfDomain;
if (url.indexOf(' ') != -1 || url.indexOf('\r') != -1 ||
url.indexOf('\n') != -1 || url.indexOf('\u0007') != -1) {
throw new IllegalArgumentException("Space character in URL");
}
endOfUrl = length;
endOfAuthority = endOfUrl;
endOfPath = endOfUrl;
endOfQuery = endOfUrl;
if (url.startsWith("//", afterScheme)) {
// do not include the "//"
startOfAuthority = afterScheme + 2;
} else {
// no authority, the path starts at 0 and may not begin with a "/"
startOfAuthority = afterScheme;
}
/*
* Since all of the elements after the authority are optional
* and they can contain the delimiter of the element before it.
* Work backwards since we know the end of the last item and will
* know the end of the next item when find the start of the current
* item.
*/
start = url.indexOf('#', startOfAuthority);
if (start != -1) {
endOfAuthority = start;
endOfPath = start;
endOfQuery = start;
// do not include the "#"
start++;
// do not parse an empty fragment
if (start < endOfUrl) {
fragment = url.substring(start, endOfUrl);
}
}
start = url.indexOf('?', startOfAuthority);
if (start != -1 && start < endOfQuery) {
endOfAuthority = start;
endOfPath = start;
// do not include the "?"
start++;
// do not parse an empty query
if (start < endOfQuery) {
query = url.substring(start, endOfQuery);
}
}
if (startOfAuthority == afterScheme) {
// no authority, the path starts after scheme
start = afterScheme;
} else {
// this is not relative URL so the path must begin with "/"
start = url.indexOf('/', startOfAuthority);
}
// do not parse an empty path
if (start != -1 && start < endOfPath) {
endOfAuthority = start;
path = url.substring(start, endOfPath);
}
if (startOfAuthority >= endOfAuthority) {
return;
}
authority = url.substring(startOfAuthority, endOfAuthority);
endOfPort = authority.length();
// get the port first, to find the end of the host
// IPv6 address have brackets around them and can have ":"'s
start = authority.indexOf(']');
if (start == -1) {
startOfPort = authority.indexOf(':');
} else {
startOfPort = authority.indexOf(':', start);
}
if (startOfPort != -1) {
endOfHost = startOfPort;
// do not include the ":"
startOfPort++;
// do not try parse an empty port
if (startOfPort < endOfPort) {
try {
port = Integer.parseInt(authority.substring(
startOfPort,
endOfPort));
if (port < 0) {
throw new
IllegalArgumentException("invalid port format");
}
if (port == 0 || port > 0xFFFF) {
throw new IllegalArgumentException(
"port out of legal range");
}
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("invalid port format");
}
}
} else {
endOfHost = endOfPort;
}
// there could be a port but no host
if (endOfHost < 1) {
return;
}
// get the host
host = authority.substring(0, endOfHost);
// the last char of the host must not be a minus sign or period
int hostLength = host.length();
if ((host.lastIndexOf('.') == hostLength - 1)
|| (host.lastIndexOf('-') == hostLength - 1)) {
throw new IllegalArgumentException("invalid host format");
}
// find the machine name and domain, if not host is not an IP address
if (host.charAt(0) == '[') {
// IP v6 address
return;
}
lastDot = host.lastIndexOf('.');
if (lastDot != -1 && host.length() > (lastDot + 1) &&
Character.isDigit(host.charAt(lastDot + 1))) {
// IP v4 address
return;
}
startOfDomain = host.indexOf('.');
if (startOfDomain != -1) {
// do not include the "."
startOfDomain++;
if (startOfDomain < host.length()) {
domain = host.substring(startOfDomain, host.length());
}
machine = host.substring(0, startOfDomain - 1);
} else {
machine = host;
}
}
/**
* Adds a base URL to this URL if this URL is a relative one.
* Afterwards this URL will be an absolute URL.
*
* @param baseUrl an absolute URL
*
* @exception IllegalArgumentException if there is a space in the URL or
* the port is not numeric
* @exception IOException if an I/O error occurs processing the URL
*/
public void addBaseUrl(String baseUrl) throws IOException {
addBaseUrl(new HttpUrl(baseUrl));
}
/**
* Adds a base URL to this URL if this URL is a relative one.
* Afterwards this URL will be an absolute URL.
*
* @param baseUrl a parsed absolute URL
*/
public void addBaseUrl(HttpUrl baseUrl) {
String basePath;
if (authority != null) {
return;
}
scheme = baseUrl.scheme;
authority = baseUrl.authority;
if (path == null) {
path = baseUrl.path;
return;
}
if (path.charAt(0) == '/' || baseUrl.path == null ||
baseUrl.path.charAt(0) != '/') {
return;
}
// find the base path
basePath = baseUrl.path.substring(0, baseUrl.path.lastIndexOf('/'));
path = basePath + '/' + path;
}
/**
* Converts this URL into a string.
*
* @return string representation of this URL
*/
public String toString() {
StringBuffer url = new StringBuffer();
if (scheme != null) {
url.append(scheme);
url.append(':');
}
if (authority != null || scheme != null) {
url.append('/');
url.append('/');
}
if (authority != null) {
url.append(authority);
}
if (path != null) {
url.append(path);
}
if (query != null) {
url.append('?');
url.append(query);
}
if (fragment != null) {
url.append('#');
url.append(fragment);
}
return url.toString();
}
}
|