/* * Conditions Of Use * * This software was developed by employees of the National Institute of * Standards and Technology (NIST), an agency of the Federal Government. * Pursuant to title 15 Untied States Code Section 105, works of NIST * employees are not subject to copyright protection in the United States * and are considered to be in the public domain. As a result, a formal * license is not needed to use the software. * * This software is provided by NIST as a service and is expressly * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT * AND DATA ACCURACY. NIST does not warrant or make any representations * regarding the use of the software or the results thereof, including but * not limited to the correctness, accuracy, reliability or usefulness of * the software. * * Permission to use this software is contingent upon your acceptance * of the terms of this agreement * * . * */ package gov.nist.javax.sip.parser; import gov.nist.javax.sip.header.*; import gov.nist.core.*; import java.text.ParseException; /** * Parser for via headers. * * @version 1.2 $Revision: 1.13 $ $Date: 2010-05-06 14:07:45 $ * @since 1.1 * * @author Olivier Deruelle * @author M. Ranganathan */ public class ViaParser extends HeaderParser { public ViaParser(String via) { super(via); } public ViaParser(Lexer lexer) { super(lexer); } /** * a parser for the essential part of the via header. */ private void parseVia(Via v) throws ParseException { // The protocol lexer.match(TokenTypes.ID); Token protocolName = lexer.getNextToken(); this.lexer.SPorHT(); // consume the "/" lexer.match('/'); this.lexer.SPorHT(); lexer.match(TokenTypes.ID); this.lexer.SPorHT(); Token protocolVersion = lexer.getNextToken(); this.lexer.SPorHT(); // We consume the "/" lexer.match('/'); this.lexer.SPorHT(); lexer.match(TokenTypes.ID); this.lexer.SPorHT(); Token transport = lexer.getNextToken(); this.lexer.SPorHT(); Protocol protocol = new Protocol(); protocol.setProtocolName(protocolName.getTokenValue()); protocol.setProtocolVersion(protocolVersion.getTokenValue()); protocol.setTransport(transport.getTokenValue()); v.setSentProtocol(protocol); // sent-By HostNameParser hnp = new HostNameParser(this.getLexer()); HostPort hostPort = hnp.hostPort( true ); v.setSentBy(hostPort); // Ignore blanks this.lexer.SPorHT(); // parameters while (lexer.lookAhead(0) == ';') { this.lexer.consume(1); this.lexer.SPorHT(); NameValue nameValue = this.nameValue(); String name = nameValue.getName(); if (name.equals(Via.BRANCH)) { String branchId = (String) nameValue.getValueAsObject(); if (branchId == null) throw new ParseException("null branch Id", lexer.getPtr()); } v.setParameter(nameValue); this.lexer.SPorHT(); } // // JvB Note: RFC3261 does not allow a comment in Via headers anymore // if (lexer.lookAhead(0) == '(') { this.lexer.selectLexer("charLexer"); lexer.consume(1); StringBuilder comment = new StringBuilder(); while (true) { char ch = lexer.lookAhead(0); if (ch == ')') { lexer.consume(1); break; } else if (ch == '\\') { // Escaped character Token tok = lexer.getNextToken(); comment.append(tok.getTokenValue()); lexer.consume(1); tok = lexer.getNextToken(); comment.append(tok.getTokenValue()); lexer.consume(1); } else if (ch == '\n') { break; } else { comment.append(ch); lexer.consume(1); } } v.setComment(comment.toString()); } } /** * Overrides the superclass nameValue parser because we have to tolerate * IPV6 addresses in the received parameter. */ protected NameValue nameValue() throws ParseException { if (debug) dbg_enter("nameValue"); try { lexer.match(LexerCore.ID); Token name = lexer.getNextToken(); // eat white space. lexer.SPorHT(); try { boolean quoted = false; char la = lexer.lookAhead(0); if (la == '=') { lexer.consume(1); lexer.SPorHT(); String str = null; if (name.getTokenValue().compareToIgnoreCase(Via.RECEIVED) == 0) { // Allow for IPV6 Addresses. // these could have : in them! str = lexer.byteStringNoSemicolon(); } else { if (lexer.lookAhead(0) == '\"') { str = lexer.quotedString(); quoted = true; } else { lexer.match(LexerCore.ID); Token value = lexer.getNextToken(); str = value.getTokenValue(); } } NameValue nv = new NameValue(name.getTokenValue() .toLowerCase(), str); if (quoted) nv.setQuotedValue(); return nv; } else { return new NameValue(name.getTokenValue().toLowerCase(), null); } } catch (ParseException ex) { return new NameValue(name.getTokenValue(), null); } } finally { if (debug) dbg_leave("nameValue"); } } public SIPHeader parse() throws ParseException { if (debug) dbg_enter("parse"); try { ViaList viaList = new ViaList(); // The first via header. this.lexer.match(TokenTypes.VIA); this.lexer.SPorHT(); // ignore blanks this.lexer.match(':'); // expect a colon. this.lexer.SPorHT(); // ingore blanks. while (true) { Via v = new Via(); parseVia(v); viaList.add(v); this.lexer.SPorHT(); // eat whitespace. if (this.lexer.lookAhead(0) == ',') { this.lexer.consume(1); // Consume the comma this.lexer.SPorHT(); // Ignore space after. } if (this.lexer.lookAhead(0) == '\n') break; } this.lexer.match('\n'); return viaList; } finally { if (debug) dbg_leave("parse"); } } /** * * public static void main(String args[]) throws ParseException { String * via[] = { "Via: SIP/2.0/UDP 135.180.130.133;branch=-12345\n", "Via: * SIP/2.0/UDP 166.34.120.100;branch=0000045d-00000001"+ ",SIP/2.0/UDP * 166.35.224.216:5000\n", "Via: SIP/2.0/UDP sip33.example.com,"+ " * SIP/2.0/UDP sip32.example.com (oli),"+ "SIP/2.0/UDP sip31.example.com\n", * "Via: SIP/2.0/UDP host.example.com;received=::133;"+ " * branch=C1C3344E2710000000E299E568E7potato10potato0potato0\n", "Via: * SIP/2.0/UDP host.example.com;received=135.180.130.133;"+ " * branch=C1C3344E2710000000E299E568E7potato10potato0potato0\n", "Via: * SIP/2.0/UDP company.com:5604 ( Hello )"+ ", SIP / 2.0 / UDP * 135.180.130.133\n", "Via: SIP/2.0/UDP * 129.6.55.9:7060;received=stinkbug.antd.nist.gov\n", * * "Via: SIP/2.0/UDP ss2.wcom.com:5060;branch=721e418c4.1"+ ", SIP/2.0/UDP * ss1.wcom.com:5060;branch=2d4790.1"+ " , SIP/2.0/UDP here.com:5060( Hello * the big world) \n" ,"Via: SIP/2.0/UDP * ss1.wcom.com:5060;branch=2d4790.1\n", "Via: SIP/2.0/UDP * first.example.com:4000;ttl=16"+ ";maddr=224.2.0.1 ;branch=a7c6a8dlze.1 * (Acme server)\n" }; * * for (int i = 0; i < via.length; i++ ) { ViaParser vp = new * ViaParser(via[i]); System.out.println("toParse = " + via[i]); ViaList vl = * (ViaList) vp.parse(); System.out.println("encoded = " + vl.encode()); } * } * */ }