1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* Conditions Of Use
3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang*
4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* This software was developed by employees of the National Institute of
5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* Standards and Technology (NIST), an agency of the Federal Government.
6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* Pursuant to title 15 Untied States Code Section 105, works of NIST
7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* employees are not subject to copyright protection in the United States
8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* and are considered to be in the public domain.  As a result, a formal
9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* license is not needed to use the software.
10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang*
11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* This software is provided by NIST as a service and is expressly
12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* AND DATA ACCURACY.  NIST does not warrant or make any representations
16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* regarding the use of the software or the results thereof, including but
17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* not limited to the correctness, accuracy, reliability or usefulness of
18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* the software.
19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang*
20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* Permission to use this software is contingent upon your acceptance
21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* of the terms of this agreement
22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang*
23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* .
24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang*
25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang*/
26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/>
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Network Research Team (http://www-r2.u-strasbg.fr))<br/>
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Louis Pasteur University - Strasbourg - France<br/>
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *Bug fixes for corner cases were contributed by Thomas Froment.
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.core;
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
362fea0dd4d93ae38af69622213b7904d1c213a5ceChia-chi Yeh// BEGIN android-deleted
372fea0dd4d93ae38af69622213b7904d1c213a5ceChia-chi Yeh//import gov.nist.javax.sdp.parser.Lexer;
382fea0dd4d93ae38af69622213b7904d1c213a5ceChia-chi Yeh// END android-deleted
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.text.ParseException;
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Parser for host names.
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *@version 1.2
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *@author M. Ranganathan
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class HostNameParser extends ParserCore {
512fea0dd4d93ae38af69622213b7904d1c213a5ceChia-chi Yeh// BEGIN android-added
522fea0dd4d93ae38af69622213b7904d1c213a5ceChia-chi Yeh    private static LexerCore Lexer;
532fea0dd4d93ae38af69622213b7904d1c213a5ceChia-chi Yeh// END android-added
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Determines whether or not we should tolerate and strip address scope
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * zones from IPv6 addresses. Address scope zones are sometimes returned
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * at the end of IPv6 addresses generated by InetAddress.getHostAddress().
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * They are however not part of the SIP semantics so basically this method
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * determines whether or not the parser should be stripping them (as
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * opposed simply being blunt and throwing an exception).
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private boolean stripAddressScopeZones = false;
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public HostNameParser(String hname) {
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.lexer = new LexerCore("charLexer", hname);
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        stripAddressScopeZones
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES");
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * The lexer is initialized with the buffer.
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public HostNameParser(LexerCore lexer) {
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.lexer = lexer;
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        lexer.selectLexer("charLexer");
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        stripAddressScopeZones
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES");
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static final char[] VALID_DOMAIN_LABEL_CHAR =
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        new char[] {LexerCore.ALPHADIGIT_VALID_CHARS, '-', '.'};
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void consumeDomainLabel() throws ParseException {
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (debug)
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dbg_enter("domainLabel");
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            lexer.consumeValidChars(VALID_DOMAIN_LABEL_CHAR);
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (debug)
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                dbg_leave("domainLabel");
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected String ipv6Reference() throws ParseException {
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        StringBuffer retval = new StringBuffer();
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (debug)
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dbg_enter("ipv6Reference");
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if(stripAddressScopeZones){
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (lexer.hasMoreChars()) {
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    char la = lexer.lookAhead(0);
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    //'%' is ipv6 address scope zone. see detail at
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    //java.sun.com/j2se/1.5.0/docs/api/java/net/Inet6Address.html
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (LexerCore.isHexDigit(la) || la == '.' || la == ':'
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            || la == '[' ) {
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        lexer.consume(1);
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        retval.append(la);
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else if (la == ']') {
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        lexer.consume(1);
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        retval.append(la);
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return retval.toString();
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else if (la == '%'){
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        //we need to strip the address scope zone.
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        lexer.consume(1);
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        String rest = lexer.getRest();
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if(rest == null || rest.length() == 0){
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            //head for the parse exception
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            break;
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        //we strip everything until either the end of the string
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        //or a closing square bracket (])
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        int stripLen = rest.indexOf(']');
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (stripLen == -1){
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            //no square bracket -> not a valid ipv6 reference
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            break;
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        lexer.consume(stripLen+1);
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        retval.append("]");
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return retval.toString();
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        break;
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            {
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (lexer.hasMoreChars())
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                {
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    char la = lexer.lookAhead(0);
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (LexerCore.isHexDigit(la) || la == '.'
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            || la == ':' || la == '[') {
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        lexer.consume(1);
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        retval.append(la);
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else if (la == ']') {
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        lexer.consume(1);
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        retval.append(la);
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return retval.toString();
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    break;
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException(
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                lexer.getBuffer() + ": Illegal Host name ",
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                lexer.getPtr());
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (debug)
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                dbg_leave("ipv6Reference");
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Host host() throws ParseException {
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (debug)
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dbg_enter("host");
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String hostname;
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            //IPv6 referene
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (lexer.lookAhead(0) == '[') {
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                hostname = ipv6Reference();
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            //IPv6 address (i.e. missing square brackets)
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else if( isIPv6Address(lexer.getRest()) )
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            {
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                int startPtr = lexer.getPtr();
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                lexer.consumeValidChars(
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        new char[] {LexerCore.ALPHADIGIT_VALID_CHARS, ':'});
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                hostname
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    = new StringBuffer("[").append(
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        lexer.getBuffer().substring(startPtr, lexer.getPtr()))
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .append("]").toString();
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            //IPv4 address or hostname
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else {
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                int startPtr = lexer.getPtr();
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                consumeDomainLabel();
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                hostname = lexer.getBuffer().substring(startPtr, lexer.getPtr());
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (hostname.length() == 0)
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new ParseException(
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    lexer.getBuffer() + ": Missing host name",
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    lexer.getPtr());
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return new Host(hostname);
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (debug)
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                dbg_leave("host");
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Tries to determine whether the address in <tt>uriHeader</tt> could be
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * an IPv6 address by counting the number of colons that appear in it.
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param uriHeader the string (supposedly the value of a URI header) that
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * we have received for parsing.
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return true if the host part of <tt>uriHeader</tt> could be an IPv6
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * address (i.e. contains at least two colons) and false otherwise.
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private boolean isIPv6Address(String uriHeader)
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    {
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // approximately detect the end the host part.
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        //first check if we have an uri param
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int hostEnd = uriHeader.indexOf(Lexer.QUESTION);
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        //if not or if it appears after a semi-colon then the end of the
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        //address would be a header param.
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int semiColonIndex = uriHeader.indexOf(Lexer.SEMICOLON);
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if ( hostEnd == -1
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            || (semiColonIndex!= -1 && hostEnd > semiColonIndex) )
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            hostEnd = semiColonIndex;
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        //if there was no header param either the address
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        //continues until the end of the string
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if ( hostEnd == -1 )
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            hostEnd = uriHeader.length();
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        //extract the address
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String host = uriHeader.substring(0, hostEnd);
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int firstColonIndex = host.indexOf(Lexer.COLON);
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if(firstColonIndex == -1)
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return false;
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int secondColonIndex = host.indexOf(Lexer.COLON, firstColonIndex + 1);
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if(secondColonIndex == -1)
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return false;
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return true;
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parses a host:port string
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param allowWS - whether whitespace is allowed around ':', only true for Via headers
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws ParseException
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public HostPort hostPort( boolean allowWS ) throws ParseException {
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (debug)
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dbg_enter("hostPort");
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Host host = this.host();
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            HostPort hp = new HostPort();
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            hp.setHost(host);
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Has a port?
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (allowWS) lexer.SPorHT(); // white space before ":port" should be accepted
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (lexer.hasMoreChars()) {
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                char la = lexer.lookAhead(0);
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                switch (la)
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                {
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case ':':
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    lexer.consume(1);
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (allowWS) lexer.SPorHT(); // white space before port number should be accepted
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    try {
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        String port = lexer.number();
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        hp.setPort(Integer.parseInt(port));
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } catch (NumberFormatException nfe) {
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        throw new ParseException(
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            lexer.getBuffer() + " :Error parsing port ",
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            lexer.getPtr());
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    break;
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case ',':	// allowed in case of multi-headers, e.g. Route
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                			// Could check that current header is a multi hdr
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case ';':   // OK, can appear in URIs (parameters)
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case '?':   // same, header parameters
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case '>':   // OK, can appear in headers
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case ' ':   // OK, allow whitespace
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case '\t':
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case '\r':
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case '\n':
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case '/':   // e.g. http://[::1]/xyz.html
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    break;
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                case '%':
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if(stripAddressScopeZones){
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        break;//OK,allow IPv6 address scope zone
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                default:
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (!allowWS) {
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        throw new ParseException( lexer.getBuffer() +
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                " Illegal character in hostname:" + lexer.lookAhead(0),
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                lexer.getPtr() );
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return hp;
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (debug)
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                dbg_leave("hostPort");
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static void main(String args[]) throws ParseException {
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String hostNames[] =
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            {
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                "foo.bar.com:1234",
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                "proxima.chaplin.bt.co.uk",
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                "129.6.55.181:2345",
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ":1234",
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                "foo.bar.com:         1234",
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                "foo.bar.com     :      1234   ",
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                "MIK_S:1234"
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            };
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        for (int i = 0; i < hostNames.length; i++) {
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                HostNameParser hnp = new HostNameParser(hostNames[i]);
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                HostPort hp = hnp.hostPort(true);
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                System.out.println("["+hp.encode()+"]");
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (ParseException ex) {
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                System.out.println("exception text = " + ex.getMessage());
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
343