Home | History | Annotate | Download | only in parser
      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 package gov.nist.javax.sip.parser;
     27 
     28 import gov.nist.javax.sip.header.*;
     29 import gov.nist.core.*;
     30 import java.text.ParseException;
     31 
     32 /**
     33  * Parser for via headers.
     34  *
     35  * @version 1.2 $Revision: 1.12 $ $Date: 2009/07/17 18:58:07 $
     36  * @since 1.1
     37  *
     38  * @author Olivier Deruelle
     39  * @author M. Ranganathan
     40  */
     41 public class ViaParser extends HeaderParser {
     42 
     43     public ViaParser(String via) {
     44         super(via);
     45     }
     46 
     47     public ViaParser(Lexer lexer) {
     48         super(lexer);
     49     }
     50 
     51     /**
     52      * a parser for the essential part of the via header.
     53      */
     54     private void parseVia(Via v) throws ParseException {
     55         // The protocol
     56         lexer.match(TokenTypes.ID);
     57         Token protocolName = lexer.getNextToken();
     58 
     59         this.lexer.SPorHT();
     60         // consume the "/"
     61         lexer.match('/');
     62         this.lexer.SPorHT();
     63         lexer.match(TokenTypes.ID);
     64         this.lexer.SPorHT();
     65         Token protocolVersion = lexer.getNextToken();
     66 
     67         this.lexer.SPorHT();
     68 
     69         // We consume the "/"
     70         lexer.match('/');
     71         this.lexer.SPorHT();
     72         lexer.match(TokenTypes.ID);
     73         this.lexer.SPorHT();
     74 
     75         Token transport = lexer.getNextToken();
     76         this.lexer.SPorHT();
     77 
     78         Protocol protocol = new Protocol();
     79         protocol.setProtocolName(protocolName.getTokenValue());
     80         protocol.setProtocolVersion(protocolVersion.getTokenValue());
     81         protocol.setTransport(transport.getTokenValue());
     82         v.setSentProtocol(protocol);
     83 
     84         // sent-By
     85         HostNameParser hnp = new HostNameParser(this.getLexer());
     86         HostPort hostPort = hnp.hostPort( true );
     87         v.setSentBy(hostPort);
     88 
     89         // Ignore blanks
     90         this.lexer.SPorHT();
     91 
     92         // parameters
     93         while (lexer.lookAhead(0) == ';') {
     94             this.lexer.consume(1);
     95             this.lexer.SPorHT();
     96             NameValue nameValue = this.nameValue();
     97             String name = nameValue.getName();
     98             if (name.equals(Via.BRANCH)) {
     99                 String branchId = (String) nameValue.getValueAsObject();
    100                 if (branchId == null)
    101                     throw new ParseException("null branch Id", lexer.getPtr());
    102 
    103             }
    104             v.setParameter(nameValue);
    105             this.lexer.SPorHT();
    106         }
    107 
    108         //
    109         // JvB Note: RFC3261 does not allow a comment in Via headers anymore
    110         //
    111         if (lexer.lookAhead(0) == '(') {
    112             this.lexer.selectLexer("charLexer");
    113             lexer.consume(1);
    114             StringBuffer comment = new StringBuffer();
    115             while (true) {
    116                 char ch = lexer.lookAhead(0);
    117                 if (ch == ')') {
    118                     lexer.consume(1);
    119                     break;
    120                 } else if (ch == '\\') {
    121                     // Escaped character
    122                     Token tok = lexer.getNextToken();
    123                     comment.append(tok.getTokenValue());
    124                     lexer.consume(1);
    125                     tok = lexer.getNextToken();
    126                     comment.append(tok.getTokenValue());
    127                     lexer.consume(1);
    128                 } else if (ch == '\n') {
    129                     break;
    130                 } else {
    131                     comment.append(ch);
    132                     lexer.consume(1);
    133                 }
    134             }
    135             v.setComment(comment.toString());
    136         }
    137 
    138     }
    139 
    140     /**
    141      * Overrides the superclass nameValue parser because we have to tolerate
    142      * IPV6 addresses in the received parameter.
    143      */
    144     protected NameValue nameValue() throws ParseException {
    145         if (debug)
    146             dbg_enter("nameValue");
    147         try {
    148 
    149             lexer.match(LexerCore.ID);
    150             Token name = lexer.getNextToken();
    151             // eat white space.
    152             lexer.SPorHT();
    153             try {
    154 
    155                 boolean quoted = false;
    156 
    157                 char la = lexer.lookAhead(0);
    158 
    159                 if (la == '=') {
    160                     lexer.consume(1);
    161                     lexer.SPorHT();
    162                     String str = null;
    163                     if (name.getTokenValue().compareToIgnoreCase(Via.RECEIVED) == 0) {
    164                         // Allow for IPV6 Addresses.
    165                         // these could have : in them!
    166                         str = lexer.byteStringNoSemicolon();
    167                     } else {
    168                         if (lexer.lookAhead(0) == '\"') {
    169                             str = lexer.quotedString();
    170                             quoted = true;
    171                         } else {
    172                             lexer.match(LexerCore.ID);
    173                             Token value = lexer.getNextToken();
    174                             str = value.getTokenValue();
    175                         }
    176                     }
    177                     NameValue nv = new NameValue(name.getTokenValue()
    178                             .toLowerCase(), str);
    179                     if (quoted)
    180                         nv.setQuotedValue();
    181                     return nv;
    182                 } else {
    183                     return new NameValue(name.getTokenValue().toLowerCase(),
    184                             null);
    185                 }
    186             } catch (ParseException ex) {
    187                 return new NameValue(name.getTokenValue(), null);
    188             }
    189 
    190         } finally {
    191             if (debug)
    192                 dbg_leave("nameValue");
    193         }
    194 
    195     }
    196 
    197     public SIPHeader parse() throws ParseException {
    198         if (debug)
    199             dbg_enter("parse");
    200         try {
    201             ViaList viaList = new ViaList();
    202             // The first via header.
    203             this.lexer.match(TokenTypes.VIA);
    204             this.lexer.SPorHT(); // ignore blanks
    205             this.lexer.match(':'); // expect a colon.
    206             this.lexer.SPorHT(); // ingore blanks.
    207 
    208             while (true) {
    209                 Via v = new Via();
    210                 parseVia(v);
    211                 viaList.add(v);
    212                 this.lexer.SPorHT(); // eat whitespace.
    213                 if (this.lexer.lookAhead(0) == ',') {
    214                     this.lexer.consume(1); // Consume the comma
    215                     this.lexer.SPorHT(); // Ignore space after.
    216                 }
    217                 if (this.lexer.lookAhead(0) == '\n')
    218                     break;
    219             }
    220             this.lexer.match('\n');
    221             return viaList;
    222         } finally {
    223             if (debug)
    224                 dbg_leave("parse");
    225         }
    226 
    227     }
    228 
    229     /**
    230      *
    231      * public static void main(String args[]) throws ParseException { String
    232      * via[] = { "Via: SIP/2.0/UDP 135.180.130.133;branch=-12345\n", "Via:
    233      * SIP/2.0/UDP 166.34.120.100;branch=0000045d-00000001"+ ",SIP/2.0/UDP
    234      * 166.35.224.216:5000\n", "Via: SIP/2.0/UDP sip33.example.com,"+ "
    235      * SIP/2.0/UDP sip32.example.com (oli),"+ "SIP/2.0/UDP sip31.example.com\n",
    236      * "Via: SIP/2.0/UDP host.example.com;received=::133;"+ "
    237      * branch=C1C3344E2710000000E299E568E7potato10potato0potato0\n", "Via:
    238      * SIP/2.0/UDP host.example.com;received=135.180.130.133;"+ "
    239      * branch=C1C3344E2710000000E299E568E7potato10potato0potato0\n", "Via:
    240      * SIP/2.0/UDP company.com:5604 ( Hello )"+ ", SIP / 2.0 / UDP
    241      * 135.180.130.133\n", "Via: SIP/2.0/UDP
    242      * 129.6.55.9:7060;received=stinkbug.antd.nist.gov\n",
    243      *
    244      * "Via: SIP/2.0/UDP ss2.wcom.com:5060;branch=721e418c4.1"+ ", SIP/2.0/UDP
    245      * ss1.wcom.com:5060;branch=2d4790.1"+ " , SIP/2.0/UDP here.com:5060( Hello
    246      * the big world) \n" ,"Via: SIP/2.0/UDP
    247      * ss1.wcom.com:5060;branch=2d4790.1\n", "Via: SIP/2.0/UDP
    248      * first.example.com:4000;ttl=16"+ ";maddr=224.2.0.1 ;branch=a7c6a8dlze.1
    249      * (Acme server)\n" };
    250      *
    251      * for (int i = 0; i < via.length; i++ ) { ViaParser vp = new
    252      * ViaParser(via[i]); System.out.println("toParse = " + via[i]); ViaList vl =
    253      * (ViaList) vp.parse(); System.out.println("encoded = " + vl.encode()); }
    254      *  }
    255      *
    256      */
    257 
    258 }
    259