• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Conditions Of Use
3 *
4 * This software was developed by employees of the National Institute of
5 * Standards and Technology (NIST), an agency of the Federal Government.
6 * Pursuant to title 15 Untied States Code Section 105, works of NIST
7 * employees are not subject to copyright protection in the United States
8 * and are considered to be in the public domain.  As a result, a formal
9 * license is not needed to use the software.
10 *
11 * This software is provided by NIST as a service and is expressly
12 * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13 * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15 * AND DATA ACCURACY.  NIST does not warrant or make any representations
16 * regarding the use of the software or the results thereof, including but
17 * not limited to the correctness, accuracy, reliability or usefulness of
18 * the software.
19 *
20 * Permission to use this software is contingent upon your acceptance
21 * of the terms of this agreement
22 *
23 * .
24 *
25 */
26 /*
27  *
28  * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/>
29  * Network Research Team (http://www-r2.u-strasbg.fr))<br/>
30  * Louis Pasteur University - Strasbourg - France<br/>
31  *
32  *Bug fixes for corner cases were contributed by Thomas Froment.
33  */
34 package gov.nist.core;
35 
36 // BEGIN android-deleted
37 //import gov.nist.javax.sdp.parser.Lexer;
38 // END android-deleted
39 
40 import java.text.ParseException;
41 
42 /**
43  * Parser for host names.
44  *
45  *@version 1.2
46  *
47  *@author M. Ranganathan
48  */
49 
50 public class HostNameParser extends ParserCore {
51 // BEGIN android-added
52     private static LexerCore Lexer;
53 // END android-added
54 
55     /**
56      * Determines whether or not we should tolerate and strip address scope
57      * zones from IPv6 addresses. Address scope zones are sometimes returned
58      * at the end of IPv6 addresses generated by InetAddress.getHostAddress().
59      * They are however not part of the SIP semantics so basically this method
60      * determines whether or not the parser should be stripping them (as
61      * opposed simply being blunt and throwing an exception).
62      */
63     private boolean stripAddressScopeZones = false;
64 
HostNameParser(String hname)65     public HostNameParser(String hname) {
66         this.lexer = new LexerCore("charLexer", hname);
67 
68         stripAddressScopeZones
69             = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES");
70     }
71 
72     /**
73      * The lexer is initialized with the buffer.
74      */
HostNameParser(LexerCore lexer)75     public HostNameParser(LexerCore lexer) {
76         this.lexer = lexer;
77         lexer.selectLexer("charLexer");
78 
79         stripAddressScopeZones
80             = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES");
81     }
82 
83     private static final char[] VALID_DOMAIN_LABEL_CHAR =
84         new char[] {LexerCore.ALPHADIGIT_VALID_CHARS, '-', '.'};
consumeDomainLabel()85     protected void consumeDomainLabel() throws ParseException {
86         if (debug)
87             dbg_enter("domainLabel");
88         try {
89             lexer.consumeValidChars(VALID_DOMAIN_LABEL_CHAR);
90         } finally {
91             if (debug)
92                 dbg_leave("domainLabel");
93         }
94     }
95 
ipv6Reference()96     protected String ipv6Reference() throws ParseException {
97         StringBuffer retval = new StringBuffer();
98         if (debug)
99             dbg_enter("ipv6Reference");
100 
101         try {
102 
103             if(stripAddressScopeZones){
104                 while (lexer.hasMoreChars()) {
105                     char la = lexer.lookAhead(0);
106                     //'%' is ipv6 address scope zone. see detail at
107                     //java.sun.com/j2se/1.5.0/docs/api/java/net/Inet6Address.html
108                     if (LexerCore.isHexDigit(la) || la == '.' || la == ':'
109                             || la == '[' ) {
110                         lexer.consume(1);
111                         retval.append(la);
112                     } else if (la == ']') {
113                         lexer.consume(1);
114                         retval.append(la);
115                         return retval.toString();
116                     } else if (la == '%'){
117                         //we need to strip the address scope zone.
118                         lexer.consume(1);
119 
120                         String rest = lexer.getRest();
121 
122                         if(rest == null || rest.length() == 0){
123                             //head for the parse exception
124                             break;
125                         }
126 
127                         //we strip everything until either the end of the string
128                         //or a closing square bracket (])
129                         int stripLen = rest.indexOf(']');
130 
131                         if (stripLen == -1){
132                             //no square bracket -> not a valid ipv6 reference
133                             break;
134                         }
135 
136                         lexer.consume(stripLen+1);
137                         retval.append("]");
138                         return retval.toString();
139 
140                     } else
141                         break;
142                 }
143             }
144             else
145             {
146                 while (lexer.hasMoreChars())
147                 {
148                     char la = lexer.lookAhead(0);
149                     if (LexerCore.isHexDigit(la) || la == '.'
150                             || la == ':' || la == '[') {
151                         lexer.consume(1);
152                         retval.append(la);
153                     } else if (la == ']') {
154                         lexer.consume(1);
155                         retval.append(la);
156                         return retval.toString();
157                     } else
158                     break;
159                 }
160             }
161 
162             throw new ParseException(
163                 lexer.getBuffer() + ": Illegal Host name ",
164                 lexer.getPtr());
165         } finally {
166             if (debug)
167                 dbg_leave("ipv6Reference");
168         }
169     }
170 
host()171     public Host host() throws ParseException {
172         if (debug)
173             dbg_enter("host");
174         try {
175             String hostname;
176 
177             //IPv6 referene
178             if (lexer.lookAhead(0) == '[') {
179                 hostname = ipv6Reference();
180             }
181             //IPv6 address (i.e. missing square brackets)
182             else if( isIPv6Address(lexer.getRest()) )
183             {
184                 int startPtr = lexer.getPtr();
185                 lexer.consumeValidChars(
186                         new char[] {LexerCore.ALPHADIGIT_VALID_CHARS, ':'});
187                 hostname
188                     = new StringBuffer("[").append(
189                         lexer.getBuffer().substring(startPtr, lexer.getPtr()))
190                         .append("]").toString();
191             }
192             //IPv4 address or hostname
193             else {
194                 int startPtr = lexer.getPtr();
195                 consumeDomainLabel();
196                 hostname = lexer.getBuffer().substring(startPtr, lexer.getPtr());
197             }
198 
199             if (hostname.length() == 0)
200                 throw new ParseException(
201                     lexer.getBuffer() + ": Missing host name",
202                     lexer.getPtr());
203             else
204                 return new Host(hostname);
205         } finally {
206             if (debug)
207                 dbg_leave("host");
208         }
209     }
210 
211     /**
212      * Tries to determine whether the address in <tt>uriHeader</tt> could be
213      * an IPv6 address by counting the number of colons that appear in it.
214      *
215      * @param uriHeader the string (supposedly the value of a URI header) that
216      * we have received for parsing.
217      *
218      * @return true if the host part of <tt>uriHeader</tt> could be an IPv6
219      * address (i.e. contains at least two colons) and false otherwise.
220      */
isIPv6Address(String uriHeader)221     private boolean isIPv6Address(String uriHeader)
222     {
223         // approximately detect the end the host part.
224         //first check if we have an uri param
225         int hostEnd = uriHeader.indexOf(Lexer.QUESTION);
226 
227         //if not or if it appears after a semi-colon then the end of the
228         //address would be a header param.
229         int semiColonIndex = uriHeader.indexOf(Lexer.SEMICOLON);
230         if ( hostEnd == -1
231             || (semiColonIndex!= -1 && hostEnd > semiColonIndex) )
232             hostEnd = semiColonIndex;
233 
234         //if there was no header param either the address
235         //continues until the end of the string
236         if ( hostEnd == -1 )
237             hostEnd = uriHeader.length();
238 
239         //extract the address
240         String host = uriHeader.substring(0, hostEnd);
241 
242         int firstColonIndex = host.indexOf(Lexer.COLON);
243 
244         if(firstColonIndex == -1)
245             return false;
246 
247         int secondColonIndex = host.indexOf(Lexer.COLON, firstColonIndex + 1);
248 
249         if(secondColonIndex == -1)
250             return false;
251 
252         return true;
253     }
254     /**
255      * Parses a host:port string
256      *
257      * @param allowWS - whether whitespace is allowed around ':', only true for Via headers
258      * @return
259      * @throws ParseException
260      */
hostPort( boolean allowWS )261     public HostPort hostPort( boolean allowWS ) throws ParseException {
262         if (debug)
263             dbg_enter("hostPort");
264         try {
265             Host host = this.host();
266             HostPort hp = new HostPort();
267             hp.setHost(host);
268             // Has a port?
269             if (allowWS) lexer.SPorHT(); // white space before ":port" should be accepted
270             if (lexer.hasMoreChars()) {
271                 char la = lexer.lookAhead(0);
272                 switch (la)
273                 {
274                 case ':':
275                     lexer.consume(1);
276                     if (allowWS) lexer.SPorHT(); // white space before port number should be accepted
277                     try {
278                         String port = lexer.number();
279                         hp.setPort(Integer.parseInt(port));
280                     } catch (NumberFormatException nfe) {
281                         throw new ParseException(
282                             lexer.getBuffer() + " :Error parsing port ",
283                             lexer.getPtr());
284                     }
285                     break;
286 
287                 case ',':	// allowed in case of multi-headers, e.g. Route
288                 			// Could check that current header is a multi hdr
289 
290                 case ';':   // OK, can appear in URIs (parameters)
291                 case '?':   // same, header parameters
292                 case '>':   // OK, can appear in headers
293                 case ' ':   // OK, allow whitespace
294                 case '\t':
295                 case '\r':
296                 case '\n':
297                 case '/':   // e.g. http://[::1]/xyz.html
298                     break;
299                 case '%':
300                     if(stripAddressScopeZones){
301                         break;//OK,allow IPv6 address scope zone
302                     }
303 
304                 default:
305                     if (!allowWS) {
306                         throw new ParseException( lexer.getBuffer() +
307                                 " Illegal character in hostname:" + lexer.lookAhead(0),
308                                 lexer.getPtr() );
309                     }
310                 }
311             }
312             return hp;
313         } finally {
314             if (debug)
315                 dbg_leave("hostPort");
316         }
317     }
318 
main(String args[])319     public static void main(String args[]) throws ParseException {
320         String hostNames[] =
321             {
322                 "foo.bar.com:1234",
323                 "proxima.chaplin.bt.co.uk",
324                 "129.6.55.181:2345",
325                 ":1234",
326                 "foo.bar.com:         1234",
327                 "foo.bar.com     :      1234   ",
328                 "MIK_S:1234"
329             };
330 
331         for (int i = 0; i < hostNames.length; i++) {
332             try {
333                 HostNameParser hnp = new HostNameParser(hostNames[i]);
334                 HostPort hp = hnp.hostPort(true);
335                 System.out.println("["+hp.encode()+"]");
336             } catch (ParseException ex) {
337                 System.out.println("exception text = " + ex.getMessage());
338             }
339         }
340 
341     }
342 }
343