1 /*
   2  * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jndi.toolkit.url;
  27 
  28 
  29 import java.net.MalformedURLException;
  30 
  31 
  32 /**
  33  * A Uri object represents an absolute Uniform Resource Identifier
  34  * (URI) as defined by RFC 2396 and updated by RFC 2373 and RFC 2732.
  35  * The most commonly used form of URI is the Uniform Resource Locator (URL).
  36  *
  37  * <p> The java.net.URL class cannot be used to parse URIs since it
  38  * requires the installation of URL stream handlers that may not be
  39  * available.  The hack of getting around this by temporarily
  40  * replacing the scheme part of a URI is not appropriate here: JNDI
  41  * service providers must work on older Java platforms, and we want
  42  * new features and bug fixes that are not available in old versions
  43  * of the URL class.
  44  *
  45  * <p> It may be appropriate to drop this code in favor of the
  46  * java.net.URI class.  The changes would need to be written so as to
  47  * still run on pre-1.4 platforms not containing that class.
  48  *
  49  * <p> The format of an absolute URI (see the RFCs mentioned above) is:
  50  * <blockquote><pre>{@code
  51  *      absoluteURI   = scheme ":" ( hier_part | opaque_part )
  52  *
  53  *      scheme        = alpha *( alpha | digit | "+" | "-" | "." )
  54  *
  55  *      hier_part     = ( net_path | abs_path ) [ "?" query ]
  56  *      opaque_part   = uric_no_slash *uric
  57  *
  58  *      net_path      = "//" authority [ abs_path ]
  59  *      abs_path      = "/"  path_segments
  60  *
  61  *      authority     = server | reg_name
  62  *      reg_name      = 1*( unreserved | escaped | "$" | "," |
  63  *                          ";" | ":" | "@" | "&" | "=" | "+" )
  64  *      server        = [ [ userinfo "@" ] hostport ]
  65  *      userinfo      = *( unreserved | escaped |
  66  *                         ";" | ":" | "&" | "=" | "+" | "$" | "," )
  67  *
  68  *      hostport      = host [ ":" port ]
  69  *      host          = hostname | IPv4address | IPv6reference
  70  *      port          = *digit
  71  *
  72  *      IPv6reference = "[" IPv6address "]"
  73  *      IPv6address   = hexpart [ ":" IPv4address ]
  74  *      IPv4address   = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
  75  *      hexpart       = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
  76  *      hexseq        = hex4 *( ":" hex4)
  77  *      hex4          = 1*4hex
  78  *
  79  *      path          = [ abs_path | opaque_part ]
  80  *      path_segments = segment *( "/" segment )
  81  *      segment       = *pchar *( ";" param )
  82  *      param         = *pchar
  83  *      pchar         = unreserved | escaped |
  84  *                      ":" | "@" | "&" | "=" | "+" | "$" | ","
  85  *
  86  *      query         = *uric
  87  *
  88  *      uric          = reserved | unreserved | escaped
  89  *      uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
  90  *                      "&" | "=" | "+" | "$" | ","
  91  *      reserved      = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
  92  *                      "$" | "," | "[" | "]"
  93  *      unreserved    = alphanum | mark
  94  *      mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
  95  *      escaped       = "%" hex hex
  96  *      unwise        = "{" | "}" | "|" | "\" | "^" | "`"
  97  * }</pre></blockquote>
  98  *
  99  * <p> Currently URIs containing {@code userinfo} or {@code reg_name}
 100  * are not supported.
 101  * The {@code opaque_part} of a non-hierarchical URI is treated as if
 102  * if were a {@code path} without a leading slash.
 103  */
 104 
 105 
 106 public class Uri {
 107 
 108     protected String uri;
 109     protected String scheme;
 110     protected String host = null;
 111     protected int port = -1;
 112     protected boolean hasAuthority;
 113     protected String path;
 114     protected String query = null;
 115 
 116 
 117     /**
 118      * Creates a Uri object given a URI string.
 119      */
 120     public Uri(String uri) throws MalformedURLException {
 121         init(uri);
 122     }
 123 
 124     /**
 125      * Creates an uninitialized Uri object. The init() method must
 126      * be called before any other Uri methods.
 127      */
 128     protected Uri() {
 129     }
 130 
 131     /**
 132      * Initializes a Uri object given a URI string.
 133      * This method must be called exactly once, and before any other Uri
 134      * methods.
 135      */
 136     protected void init(String uri) throws MalformedURLException {
 137         this.uri = uri;
 138         parse(uri);
 139     }
 140 
 141     /**
 142      * Returns the URI's scheme.
 143      */
 144     public String getScheme() {
 145         return scheme;
 146     }
 147 
 148     /**
 149      * Returns the host from the URI's authority part, or null
 150      * if no host is provided.  If the host is an IPv6 literal, the
 151      * delimiting brackets are part of the returned value (see
 152      * {@link java.net.URI#getHost}).
 153      */
 154     public String getHost() {
 155         return host;
 156     }
 157 
 158     /**
 159      * Returns the port from the URI's authority part, or -1 if
 160      * no port is provided.
 161      */
 162     public int getPort() {
 163         return port;
 164     }
 165 
 166     /**
 167      * Returns the URI's path.  The path is never null.  Note that a
 168      * slash following the authority part (or the scheme if there is
 169      * no authority part) is part of the path.  For example, the path
 170      * of "http://host/a/b" is "/a/b".
 171      */
 172     public String getPath() {
 173         return path;
 174     }
 175 
 176     /**
 177      * Returns the URI's query part, or null if no query is provided.
 178      * Note that a query always begins with a leading "?".
 179      */
 180     public String getQuery() {
 181         return query;
 182     }
 183 
 184     /**
 185      * Returns the URI as a string.
 186      */
 187     public String toString() {
 188         return uri;
 189     }
 190 
 191     /*
 192      * Parses a URI string and sets this object's fields accordingly.
 193      */
 194     private void parse(String uri) throws MalformedURLException {
 195         int i;  // index into URI
 196 
 197         i = uri.indexOf(':');                           // parse scheme
 198         if (i < 0) {
 199             throw new MalformedURLException("Invalid URI: " + uri);
 200         }
 201         scheme = uri.substring(0, i);
 202         i++;                                            // skip past ":"
 203 
 204         hasAuthority = uri.startsWith("//", i);
 205         if (hasAuthority) {                             // parse "//host:port"
 206             i += 2;                                     // skip past "//"
 207             int slash = uri.indexOf('/', i);
 208             if (slash < 0) {
 209                 slash = uri.length();
 210             }
 211             if (uri.startsWith("[", i)) {               // at IPv6 literal
 212                 int brac = uri.indexOf(']', i + 1);
 213                 if (brac < 0 || brac > slash) {
 214                     throw new MalformedURLException("Invalid URI: " + uri);
 215                 }
 216                 host = uri.substring(i, brac + 1);      // include brackets
 217                 i = brac + 1;                           // skip past "[...]"
 218             } else {                                    // at host name or IPv4
 219                 int colon = uri.indexOf(':', i);
 220                 int hostEnd = (colon < 0 || colon > slash)
 221                     ? slash
 222                     : colon;
 223                 if (i < hostEnd) {
 224                     host = uri.substring(i, hostEnd);
 225                 }
 226                 i = hostEnd;                            // skip past host
 227             }
 228 
 229             if ((i + 1 < slash) &&
 230                         uri.startsWith(":", i)) {       // parse port
 231                 i++;                                    // skip past ":"
 232                 port = Integer.parseInt(uri.substring(i, slash));
 233             }
 234             i = slash;                                  // skip to path
 235         }
 236         int qmark = uri.indexOf('?', i);                // look for query
 237         if (qmark < 0) {
 238             path = uri.substring(i);
 239         } else {
 240             path = uri.substring(i, qmark);
 241             query = uri.substring(qmark);
 242         }
 243     }
 244 
 245 /*
 246     // Debug
 247     public static void main(String args[]) throws MalformedURLException {
 248         for (int i = 0; i < args.length; i++) {
 249             Uri uri = new Uri(args[i]);
 250 
 251             String h = (uri.getHost() != null) ? uri.getHost() : "";
 252             String p = (uri.getPort() != -1) ? (":" + uri.getPort()) : "";
 253             String a = uri.hasAuthority ? ("//" + h + p) : "";
 254             String q = (uri.getQuery() != null) ? uri.getQuery() : "";
 255 
 256             String str = uri.getScheme() + ":" + a + uri.getPath() + q;
 257             if (! uri.toString().equals(str)) {
 258                 System.out.println(str);
 259             }
 260             System.out.println(h);
 261         }
 262     }
 263 */
 264 }