/*
* 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.12 $ $Date: 2009/07/17 18:58:07 $
* @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);
StringBuffer comment = new StringBuffer();
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()); }
* }
*
*/
}