1 /*
   2  * Copyright (c) 1999, 2011, 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.cosnaming;
  27 
  28 import javax.naming.Name;
  29 import javax.naming.NamingException;
  30 
  31 import java.net.MalformedURLException;
  32 import java.util.Vector;
  33 import java.util.StringTokenizer;
  34 import com.sun.jndi.toolkit.url.UrlUtil;
  35 
  36 /**
  37  * Extract components of an "iiop" or "iiopname" URL.
  38  *
  39  * The format of an iiopname URL is defined in INS 98-10-11 as follows:
  40  *
  41  * iiopname url = "iiopname://" [addr_list]["/" string_name]
  42  * addr_list    = [address ","]* address
  43  * address      = [version host [":" port]]
  44  * host         = DNS style host name | IP address
  45  * version      = major "." minor "@" | empty_string
  46  * port         = number
  47  * major        = number
  48  * minor        = number
  49  * string_name = stringified name | empty_string
  50  *
  51  * The default port is 9999. The default version is "1.0"
  52  * US-ASCII alphanumeric characters are not escaped. Any characters outside
  53  * of this range are escaped except for the following:
  54  * ; / : ? : @ & = + $ , - _ . ! ~ *  ' ( )
  55  * Escaped characters is escaped by using a % followed by its 2 hexadecimal
  56  * numbers representing the octet.
  57  *
  58  * For backward compatibility,  the "iiop" URL as defined in INS 97-6-6
  59  * is also supported:
  60  *
  61  * iiop url     = "iiop://" [host [":" port]] ["/" string_name]
  62  * The default port is 900.
  63  *
  64  * @author Rosanna Lee
  65  */
  66 
  67 public final class IiopUrl {
  68     static final private int DEFAULT_IIOPNAME_PORT = 9999;
  69     static final private int DEFAULT_IIOP_PORT = 900;
  70     static final private String DEFAULT_HOST = "localhost";
  71     private Vector<Address> addresses;
  72     private String stringName;
  73 
  74     public static class Address {
  75         public int port = -1;
  76         public int major, minor;
  77         public String host;
  78 
  79         public Address(String hostPortVers, boolean oldFormat)
  80             throws MalformedURLException {
  81             // [version host [":" port]]
  82             int start;
  83 
  84             // Parse version
  85             int at;
  86             if (oldFormat || (at = hostPortVers.indexOf('@')) < 0) {
  87                 major = 1;
  88                 minor = 0;
  89                 start = 0;     // start at the beginning
  90             } else {
  91                 int dot = hostPortVers.indexOf('.');
  92                 if (dot < 0) {
  93                     throw new MalformedURLException(
  94                         "invalid version: " + hostPortVers);
  95                 }
  96                 try {
  97                     major = Integer.parseInt(hostPortVers.substring(0, dot));
  98                     minor = Integer.parseInt(hostPortVers.substring(dot+1, at));
  99                 } catch (NumberFormatException e) {
 100                     throw new MalformedURLException(
 101                         "Nonnumeric version: " + hostPortVers);
 102                 }
 103                 start = at + 1;  // skip '@' sign
 104             }
 105 
 106             // Parse host and port
 107             int slash = hostPortVers.indexOf('/', start);
 108             if (slash < 0) {
 109                 slash = hostPortVers.length();
 110             }
 111             if (hostPortVers.startsWith("[", start)) {  // at IPv6 literal
 112                 int brac = hostPortVers.indexOf(']', start + 1);
 113                 if (brac < 0 || brac > slash) {
 114                     throw new IllegalArgumentException(
 115                         "IiopURL: name is an Invalid URL: " + hostPortVers);
 116                 }
 117 
 118                 // include brackets
 119                 host = hostPortVers.substring(start, brac + 1);
 120                 start = brac + 1;
 121             } else {      // at hostname or IPv4
 122                 int colon = hostPortVers.indexOf(':', start);
 123                 int hostEnd = (colon < 0 || colon > slash)
 124                     ? slash
 125                     : colon;
 126                 if (start < hostEnd) {
 127                     host = hostPortVers.substring(start, hostEnd);
 128                 }
 129                 start = hostEnd;   // skip past host
 130             }
 131             if ((start + 1 < slash)) {
 132                 if ( hostPortVers.startsWith(":", start)) { // parse port
 133                     start++;    // skip past ":"
 134                     port = Integer.parseInt(hostPortVers.
 135                                             substring(start, slash));
 136                 } else {
 137                     throw new IllegalArgumentException(
 138                         "IiopURL: name is an Invalid URL: " + hostPortVers);
 139                 }
 140             }
 141             start = slash;
 142             if ("".equals(host) || host == null) {
 143                 host = DEFAULT_HOST ;
 144             }
 145             if (port == -1) {
 146                 port = (oldFormat ? DEFAULT_IIOP_PORT :
 147                                 DEFAULT_IIOPNAME_PORT);
 148             }
 149         }
 150     }
 151 
 152     public Vector<Address> getAddresses() {
 153         return addresses;
 154     }
 155 
 156     /**
 157      * Returns a possibly empty but non-null string that is the "string_name"
 158      * portion of the URL.
 159      */
 160     public String getStringName() {
 161         return stringName;
 162     }
 163 
 164     public Name getCosName() throws NamingException {
 165         return CNCtx.parser.parse(stringName);
 166     }
 167 
 168     public IiopUrl(String url) throws MalformedURLException {
 169         int addrStart;
 170         boolean oldFormat;
 171 
 172         if (url.startsWith("iiopname://")) {
 173             oldFormat = false;
 174             addrStart = 11;
 175         } else if (url.startsWith("iiop://")) {
 176             oldFormat = true;
 177             addrStart = 7;
 178         } else {
 179             throw new MalformedURLException("Invalid iiop/iiopname URL: " + url);
 180         }
 181         int addrEnd = url.indexOf('/', addrStart);
 182         if (addrEnd < 0) {
 183             addrEnd = url.length();
 184             stringName = "";
 185         } else {
 186             stringName = UrlUtil.decode(url.substring(addrEnd+1));
 187         }
 188         addresses = new Vector<>(3);
 189         if (oldFormat) {
 190             // Only one host:port part, not multiple
 191             addresses.addElement(
 192                 new Address(url.substring(addrStart, addrEnd), oldFormat));
 193         } else {
 194             StringTokenizer tokens =
 195                 new StringTokenizer(url.substring(addrStart, addrEnd), ",");
 196             while (tokens.hasMoreTokens()) {
 197                 addresses.addElement(new Address(tokens.nextToken(), oldFormat));
 198             }
 199             if (addresses.size() == 0) {
 200                 addresses.addElement(new Address("", oldFormat));
 201             }
 202         }
 203     }
 204 
 205     // for testing only
 206     /*public static void main(String[] args) {
 207         try {
 208             IiopUrl url = new IiopUrl(args[0]);
 209             Vector addrs = url.getAddresses();
 210             String name = url.getStringName();
 211 
 212             for (int i = 0; i < addrs.size(); i++) {
 213                 Address addr = (Address)addrs.elementAt(i);
 214                 System.out.println("host: " + addr.host);
 215                 System.out.println("port: " + addr.port);
 216                 System.out.println("version: " + addr.major + " " + addr.minor);
 217             }
 218             System.out.println("name: " + name);
 219         } catch (MalformedURLException e) {
 220             e.printStackTrace();
 221         }
 222     } */
 223 }