259 lines
8.7 KiB
Java
259 lines
8.7 KiB
Java
/*
|
|
* 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()); }
|
|
* }
|
|
*
|
|
*/
|
|
|
|
}
|