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