1 /* ServerNameList.java -- 2 Copyright (C) 2006 Free Software Foundation, Inc. 3 4 This file is a part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or (at 9 your option) any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 19 USA 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package gnu.javax.net.ssl.provider; 40 41 import gnu.javax.net.ssl.provider.Extension.Value; 42 43 import java.io.PrintWriter; 44 import java.io.StringWriter; 45 46 import java.nio.ByteBuffer; 47 import java.nio.ByteOrder; 48 import java.nio.CharBuffer; 49 import java.nio.charset.CharacterCodingException; 50 import java.nio.charset.Charset; 51 import java.nio.charset.CharsetEncoder; 52 import java.util.List; 53 import java.util.NoSuchElementException; 54 55 /** 56 * The ServerName extension. 57 * 58 * <pre> 59 struct { 60 NameType name_type; 61 select (name_type) { 62 case host_name: HostName; 63 } name; 64 } ServerName; 65 66 enum { 67 host_name(0), (255) 68 } NameType; 69 70 opaque HostName<1..2^16-1>; 71 72 struct { 73 ServerName server_name_list<1..2^16-1> 74 } ServerNameList;</pre> 75 * 76 * <p><b>Implementation note: this class does not currently contain a 77 * <code>set</code> method. If you are modifying this list, then use the 78 * {@link #get(int)} method, and modify the returned {@link ServerName}. 79 * 80 * @author csm 81 */ 82 public class ServerNameList extends Value implements Iterable<ServerNameList.ServerName> 83 { 84 private ByteBuffer buffer; 85 ServerNameList(final ByteBuffer buffer)86 public ServerNameList (final ByteBuffer buffer) 87 { 88 this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); 89 } 90 ServerNameList(List<ServerName> names)91 public ServerNameList(List<ServerName> names) 92 { 93 int length = 2; 94 for (ServerName name : names) 95 length += name.length(); 96 buffer = ByteBuffer.allocate(length); 97 buffer.putShort((short) (length - 2)); 98 for (ServerName name : names) 99 buffer.put(name.buffer()); 100 buffer.rewind(); 101 } 102 length()103 public int length() 104 { 105 return (buffer.getShort(0) & 0xFFFF) + 2; 106 } 107 buffer()108 public ByteBuffer buffer() 109 { 110 return (ByteBuffer) buffer.duplicate().limit(length()); 111 } 112 size()113 public int size() 114 { 115 int n = 0; 116 final int len = length(); 117 for (int i = 2; i < len; ) 118 { 119 int l = buffer.getShort(i+1); 120 i += l + 3; 121 n++; 122 } 123 return n; 124 } 125 get(int index)126 public ServerName get (int index) 127 { 128 final int len = length(); 129 if (len == 0) 130 throw new IndexOutOfBoundsException("0; " + index); 131 int n = 0; 132 int i; 133 int l = buffer.getShort(3); 134 for (i = 2; i < len && n < index; ) 135 { 136 l = buffer.getShort(i+1); 137 i += l + 3; 138 n++; 139 } 140 if (n < index) 141 throw new IndexOutOfBoundsException(n + "; " + index); 142 ByteBuffer buf = ((ByteBuffer) buffer.duplicate().position(i).limit(i+l+3)).slice(); 143 return new ServerName (buf); 144 } 145 setLength(final int newLength)146 public void setLength(final int newLength) 147 { 148 if (newLength < 0 || newLength > 65535) 149 throw new IllegalArgumentException("length must be between 0 and 65535"); 150 buffer.putShort(0, (short) newLength); 151 } 152 toString()153 public String toString() 154 { 155 return toString(null); 156 } 157 toString(String prefix)158 public String toString(String prefix) 159 { 160 StringWriter str = new StringWriter(); 161 PrintWriter out = new PrintWriter(str); 162 if (prefix != null) out.print(prefix); 163 out.println ("ServerNameList {"); 164 String subprefix = " "; 165 if (prefix != null) 166 subprefix = prefix + subprefix; 167 for (ServerName name : this) 168 { 169 out.println (name.toString(subprefix)); 170 } 171 if (prefix != null) out.print(prefix); 172 out.print ("};"); 173 return str.toString(); 174 } 175 iterator()176 public java.util.Iterator<ServerName> iterator() 177 { 178 return new Iterator(); 179 } 180 181 public class Iterator implements java.util.Iterator<ServerName> 182 { 183 private int index; 184 Iterator()185 public Iterator() 186 { 187 index = 0; 188 } 189 hasNext()190 public boolean hasNext() 191 { 192 return index < size(); 193 } 194 next()195 public ServerName next() throws NoSuchElementException 196 { 197 try 198 { 199 return get (index++); 200 } 201 catch (IndexOutOfBoundsException ioobe) 202 { 203 throw new NoSuchElementException(); 204 } 205 } 206 remove()207 public void remove() 208 { 209 throw new UnsupportedOperationException(); 210 } 211 } 212 213 public static class ServerName implements Constructed 214 { 215 private ByteBuffer buffer; 216 ServerName(final ByteBuffer buffer)217 public ServerName(final ByteBuffer buffer) 218 { 219 this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); 220 } 221 ServerName(NameType type, String name)222 public ServerName(NameType type, String name) 223 { 224 CharsetEncoder utf8 = Charset.forName("UTF-8").newEncoder(); 225 ByteBuffer nameBuf = null; 226 try 227 { 228 nameBuf = utf8.encode(CharBuffer.wrap(name)); 229 } 230 catch (CharacterCodingException cce) 231 { 232 // We don't expect this to happen; it's UTF-8. 233 throw new IllegalArgumentException(cce); 234 } 235 int length = 3 + nameBuf.remaining(); 236 buffer = ByteBuffer.allocate(length); 237 buffer.put((byte) type.getValue()); 238 buffer.putShort((short) (length - 3)); 239 buffer.put(nameBuf); 240 buffer.rewind(); 241 } 242 length()243 public int length() 244 { 245 return (buffer.getShort(1) & 0xFFFF) + 3; 246 } 247 buffer()248 public ByteBuffer buffer() 249 { 250 return (ByteBuffer) buffer.duplicate().limit(length()); 251 } 252 type()253 public NameType type() 254 { 255 int v = (buffer.get(0) & 0xFF); 256 if (v == 0) 257 { 258 return NameType.HOST_NAME; 259 } 260 throw new IllegalArgumentException ("illegal name type: " + v); 261 } 262 name()263 public String name() 264 { 265 int len = length(); 266 Charset cs = Charset.forName ("UTF-8"); 267 return cs.decode(((ByteBuffer) buffer.duplicate().position(3).limit(len))).toString(); 268 } 269 toString()270 public String toString() 271 { 272 return toString (null); 273 } 274 toString(String prefix)275 public String toString(String prefix) 276 { 277 StringWriter str = new StringWriter(); 278 PrintWriter out = new PrintWriter(str); 279 if (prefix != null) out.print (prefix); 280 out.println ("struct {"); 281 if (prefix != null) out.print (prefix); 282 out.print (" name_type = "); 283 out.print (type()); 284 out.println (";"); 285 if (prefix != null) out.print (prefix); 286 out.print (" server_name = "); 287 out.print (name()); 288 out.println (";"); 289 if (prefix != null) out.print (prefix); 290 out.print ("} ServerName;"); 291 return str.toString(); 292 } 293 } 294 295 public static enum NameType 296 { 297 HOST_NAME (0); 298 299 private final int value; 300 NameType(int value)301 private NameType (int value) 302 { 303 this.value = value; 304 } 305 getValue()306 public int getValue() 307 { 308 return value; 309 } 310 } 311 } 312