New file |
| | |
| | | package com.genersoft.iot.vmp.gb28181.bean; |
| | | |
| | | import gov.nist.core.CommonLogger; |
| | | import gov.nist.core.Host; |
| | | import gov.nist.core.HostNameParser; |
| | | import gov.nist.core.StackLogger; |
| | | import gov.nist.javax.sip.SIPConstants; |
| | | import gov.nist.javax.sip.address.AddressImpl; |
| | | import gov.nist.javax.sip.address.GenericURI; |
| | | import gov.nist.javax.sip.address.SipUri; |
| | | import gov.nist.javax.sip.address.TelephoneNumber; |
| | | import gov.nist.javax.sip.header.*; |
| | | import gov.nist.javax.sip.message.SIPMessage; |
| | | import gov.nist.javax.sip.message.SIPRequest; |
| | | import gov.nist.javax.sip.message.SIPResponse; |
| | | import gov.nist.javax.sip.parser.*; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.text.ParseException; |
| | | |
| | | public class GBStringMsgParser implements MessageParser { |
| | | |
| | | protected static boolean computeContentLengthFromMessage = false; |
| | | |
| | | private static StackLogger logger = CommonLogger.getLogger(StringMsgParser.class); |
| | | |
| | | /** |
| | | * @since v0.9 |
| | | */ |
| | | public GBStringMsgParser() { |
| | | super(); |
| | | } |
| | | |
| | | /** |
| | | * Parse a buffer containing a single SIP Message where the body is an array |
| | | * of un-interpreted bytes. This is intended for parsing the message from a |
| | | * memory buffer when the buffer. Incorporates a bug fix for a bug that was |
| | | * noted by Will Sullin of Callcast |
| | | * |
| | | * @param msgBuffer |
| | | * a byte buffer containing the messages to be parsed. This can |
| | | * consist of multiple SIP Messages concatenated together. |
| | | * @return a SIPMessage[] structure (request or response) containing the |
| | | * parsed SIP message. |
| | | * @exception ParseException |
| | | * is thrown when an illegal message has been encountered |
| | | * (and the rest of the buffer is discarded). |
| | | * @see ParseExceptionListener |
| | | */ |
| | | public SIPMessage parseSIPMessage(byte[] msgBuffer, boolean readBody, boolean strict, ParseExceptionListener parseExceptionListener) throws ParseException { |
| | | if (msgBuffer == null || msgBuffer.length == 0) |
| | | return null; |
| | | |
| | | int i = 0; |
| | | |
| | | // Squeeze out any leading control character. |
| | | try { |
| | | while (msgBuffer[i] < 0x20) |
| | | i++; |
| | | } |
| | | catch (ArrayIndexOutOfBoundsException e) { |
| | | // Array contains only control char, return null. |
| | | if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) { |
| | | logger.logDebug("handled only control char so returning null"); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | // Iterate thru the request/status line and headers. |
| | | String currentLine = null; |
| | | String currentHeader = null; |
| | | boolean isFirstLine = true; |
| | | SIPMessage message = null; |
| | | do |
| | | { |
| | | int lineStart = i; |
| | | |
| | | // Find the length of the line. |
| | | try { |
| | | while (msgBuffer[i] != '\r' && msgBuffer[i] != '\n') |
| | | i++; |
| | | } |
| | | catch (ArrayIndexOutOfBoundsException e) { |
| | | // End of the message. |
| | | break; |
| | | } |
| | | int lineLength = i - lineStart; |
| | | |
| | | // Make it a String. |
| | | try { |
| | | currentLine = new String(msgBuffer, lineStart, lineLength, "UTF-8"); |
| | | } catch (UnsupportedEncodingException e) { |
| | | throw new ParseException("Bad message encoding!", 0); |
| | | } |
| | | |
| | | currentLine = trimEndOfLine(currentLine); |
| | | |
| | | if (currentLine.length() == 0) { |
| | | // Last header line, process the previous buffered header. |
| | | if (currentHeader != null && message != null) { |
| | | processHeader(currentHeader, message, parseExceptionListener, msgBuffer); |
| | | } |
| | | |
| | | } |
| | | else { |
| | | if (isFirstLine) { |
| | | message = processFirstLine(currentLine, parseExceptionListener, msgBuffer); |
| | | } else { |
| | | char firstChar = currentLine.charAt(0); |
| | | if (firstChar == '\t' || firstChar == ' ') { |
| | | if (currentHeader == null) |
| | | throw new ParseException("Bad header continuation.", 0); |
| | | |
| | | // This is a continuation, append it to the previous line. |
| | | currentHeader += currentLine.substring(1); |
| | | } |
| | | else { |
| | | if (currentHeader != null && message != null) { |
| | | processHeader(currentHeader, message, parseExceptionListener, msgBuffer); |
| | | } |
| | | currentHeader = currentLine; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (msgBuffer[i] == '\r' && msgBuffer.length > i+1 && msgBuffer[i+1] == '\n') |
| | | i++; |
| | | |
| | | i++; |
| | | |
| | | isFirstLine = false; |
| | | } while (currentLine.length() > 0); // End do - while |
| | | |
| | | if (message == null) throw new ParseException("Bad message", 0); |
| | | message.setSize(i); |
| | | |
| | | // Check for content legth header |
| | | if (readBody && message.getContentLength() != null ) { |
| | | if ( message.getContentLength().getContentLength() != 0) { |
| | | int bodyLength = msgBuffer.length - i; |
| | | |
| | | byte[] body = new byte[bodyLength]; |
| | | System.arraycopy(msgBuffer, i, body, 0, bodyLength); |
| | | message.setMessageContent(body,!strict,computeContentLengthFromMessage,message.getContentLength().getContentLength()); |
| | | } else if (message.getCSeqHeader().getMethod().equalsIgnoreCase("MESSAGE")) { |
| | | int bodyLength = msgBuffer.length - i; |
| | | |
| | | byte[] body = new byte[bodyLength]; |
| | | System.arraycopy(msgBuffer, i, body, 0, bodyLength); |
| | | message.setMessageContent(body,!strict,computeContentLengthFromMessage,bodyLength); |
| | | }else if (!computeContentLengthFromMessage && strict) { |
| | | String last4Chars = new String(msgBuffer, msgBuffer.length - 4, 4); |
| | | if(!"\r\n\r\n".equals(last4Chars)) { |
| | | throw new ParseException("Extraneous characters at the end of the message ",i); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return message; |
| | | } |
| | | |
| | | protected static String trimEndOfLine(String line) { |
| | | if (line == null) |
| | | return line; |
| | | |
| | | int i = line.length() - 1; |
| | | while (i >= 0 && line.charAt(i) <= 0x20) |
| | | i--; |
| | | |
| | | if (i == line.length() - 1) |
| | | return line; |
| | | |
| | | if (i == -1) |
| | | return ""; |
| | | |
| | | return line.substring(0, i+1); |
| | | } |
| | | |
| | | protected SIPMessage processFirstLine(String firstLine, ParseExceptionListener parseExceptionListener, byte[] msgBuffer) throws ParseException { |
| | | SIPMessage message; |
| | | if (!firstLine.startsWith(SIPConstants.SIP_VERSION_STRING)) { |
| | | message = new SIPRequest(); |
| | | try { |
| | | RequestLine requestLine = new RequestLineParser(firstLine + "\n") |
| | | .parse(); |
| | | ((SIPRequest) message).setRequestLine(requestLine); |
| | | } catch (ParseException ex) { |
| | | if (parseExceptionListener != null) |
| | | try { |
| | | parseExceptionListener.handleException(ex, message, |
| | | RequestLine.class, firstLine, new String(msgBuffer, "UTF-8")); |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | else |
| | | throw ex; |
| | | |
| | | } |
| | | } else { |
| | | message = new SIPResponse(); |
| | | try { |
| | | StatusLine sl = new StatusLineParser(firstLine + "\n").parse(); |
| | | ((SIPResponse) message).setStatusLine(sl); |
| | | } catch (ParseException ex) { |
| | | if (parseExceptionListener != null) { |
| | | try { |
| | | parseExceptionListener.handleException(ex, message, |
| | | StatusLine.class, firstLine, new String(msgBuffer, "UTF-8")); |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } else |
| | | throw ex; |
| | | |
| | | } |
| | | } |
| | | return message; |
| | | } |
| | | |
| | | protected void processHeader(String header, SIPMessage message, ParseExceptionListener parseExceptionListener, byte[] rawMessage) throws ParseException { |
| | | if (header == null || header.length() == 0) |
| | | return; |
| | | |
| | | HeaderParser headerParser = null; |
| | | try { |
| | | headerParser = ParserFactory.createParser(header + "\n"); |
| | | } catch (ParseException ex) { |
| | | // https://java.net/jira/browse/JSIP-456 |
| | | if (parseExceptionListener != null) { |
| | | parseExceptionListener.handleException(ex, message, null, |
| | | header, null); |
| | | return; |
| | | } else { |
| | | throw ex; |
| | | } |
| | | } |
| | | |
| | | try { |
| | | SIPHeader sipHeader = headerParser.parse(); |
| | | message.attachHeader(sipHeader, false); |
| | | } catch (ParseException ex) { |
| | | if (parseExceptionListener != null) { |
| | | String headerName = Lexer.getHeaderName(header); |
| | | Class headerClass = NameMap.getClassFromName(headerName); |
| | | if (headerClass == null) { |
| | | headerClass = ExtensionHeaderImpl.class; |
| | | |
| | | } |
| | | try { |
| | | parseExceptionListener.handleException(ex, message, |
| | | headerClass, header, new String(rawMessage, "UTF-8")); |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Parse an address (nameaddr or address spec) and return and address |
| | | * structure. |
| | | * |
| | | * @param address |
| | | * is a String containing the address to be parsed. |
| | | * @return a parsed address structure. |
| | | * @since v1.0 |
| | | * @exception ParseException |
| | | * when the address is badly formatted. |
| | | */ |
| | | public AddressImpl parseAddress(String address) throws ParseException { |
| | | AddressParser addressParser = new AddressParser(address); |
| | | return addressParser.address(true); |
| | | } |
| | | |
| | | /** |
| | | * Parse a host:port and return a parsed structure. |
| | | * |
| | | * @param hostport |
| | | * is a String containing the host:port to be parsed |
| | | * @return a parsed address structure. |
| | | * @since v1.0 |
| | | * @exception throws |
| | | * a ParseException when the address is badly formatted. |
| | | * |
| | | public HostPort parseHostPort(String hostport) throws ParseException { |
| | | Lexer lexer = new Lexer("charLexer", hostport); |
| | | return new HostNameParser(lexer).hostPort(); |
| | | |
| | | } |
| | | */ |
| | | |
| | | /** |
| | | * Parse a host name and return a parsed structure. |
| | | * |
| | | * @param host |
| | | * is a String containing the host name to be parsed |
| | | * @return a parsed address structure. |
| | | * @since v1.0 |
| | | * @exception ParseException |
| | | * a ParseException when the hostname is badly formatted. |
| | | */ |
| | | public Host parseHost(String host) throws ParseException { |
| | | Lexer lexer = new Lexer("charLexer", host); |
| | | return new HostNameParser(lexer).host(); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * Parse a telephone number return a parsed structure. |
| | | * |
| | | * @param telephone_number |
| | | * is a String containing the telephone # to be parsed |
| | | * @return a parsed address structure. |
| | | * @since v1.0 |
| | | * @exception ParseException |
| | | * a ParseException when the address is badly formatted. |
| | | */ |
| | | public TelephoneNumber parseTelephoneNumber(String telephone_number) |
| | | throws ParseException { |
| | | // Bug fix contributed by Will Scullin |
| | | return new URLParser(telephone_number).parseTelephoneNumber(true); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * Parse a SIP url from a string and return a URI structure for it. |
| | | * |
| | | * @param url |
| | | * a String containing the URI structure to be parsed. |
| | | * @return A parsed URI structure |
| | | * @exception ParseException |
| | | * if there was an error parsing the message. |
| | | */ |
| | | |
| | | public SipUri parseSIPUrl(String url) throws ParseException { |
| | | try { |
| | | return new URLParser(url).sipURL(true); |
| | | } catch (ClassCastException ex) { |
| | | throw new ParseException(url + " Not a SIP URL ", 0); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Parse a uri from a string and return a URI structure for it. |
| | | * |
| | | * @param url |
| | | * a String containing the URI structure to be parsed. |
| | | * @return A parsed URI structure |
| | | * @exception ParseException |
| | | * if there was an error parsing the message. |
| | | */ |
| | | |
| | | public GenericURI parseUrl(String url) throws ParseException { |
| | | return new URLParser(url).parse(); |
| | | } |
| | | |
| | | /** |
| | | * Parse an individual SIP message header from a string. |
| | | * |
| | | * @param header |
| | | * String containing the SIP header. |
| | | * @return a SIPHeader structure. |
| | | * @exception ParseException |
| | | * if there was an error parsing the message. |
| | | */ |
| | | public static SIPHeader parseSIPHeader(String header) throws ParseException { |
| | | int start = 0; |
| | | int end = header.length() - 1; |
| | | try { |
| | | // Squeeze out any leading control character. |
| | | while (header.charAt(start) <= 0x20) |
| | | start++; |
| | | |
| | | // Squeeze out any trailing control character. |
| | | while (header.charAt(end) <= 0x20) |
| | | end--; |
| | | } |
| | | catch (ArrayIndexOutOfBoundsException e) { |
| | | // Array contains only control char. |
| | | throw new ParseException("Empty header.", 0); |
| | | } |
| | | |
| | | StringBuilder buffer = new StringBuilder(end + 1); |
| | | int i = start; |
| | | int lineStart = start; |
| | | boolean endOfLine = false; |
| | | while (i <= end) { |
| | | char c = header.charAt(i); |
| | | if (c == '\r' || c == '\n') { |
| | | if (!endOfLine) { |
| | | buffer.append(header.substring(lineStart, i)); |
| | | endOfLine = true; |
| | | } |
| | | } |
| | | else { |
| | | if (endOfLine) { |
| | | endOfLine = false; |
| | | if (c == ' ' || c == '\t') { |
| | | buffer.append(' '); |
| | | lineStart = i + 1; |
| | | } |
| | | else { |
| | | lineStart = i; |
| | | } |
| | | } |
| | | } |
| | | |
| | | i++; |
| | | } |
| | | buffer.append(header.substring(lineStart, i)); |
| | | buffer.append('\n'); |
| | | |
| | | HeaderParser hp = ParserFactory.createParser(buffer.toString()); |
| | | if (hp == null) |
| | | throw new ParseException("could not create parser", 0); |
| | | return hp.parse(); |
| | | } |
| | | |
| | | /** |
| | | * Parse the SIP Request Line |
| | | * |
| | | * @param requestLine |
| | | * a String containing the request line to be parsed. |
| | | * @return a RequestLine structure that has the parsed RequestLine |
| | | * @exception ParseException |
| | | * if there was an error parsing the requestLine. |
| | | */ |
| | | |
| | | public RequestLine parseSIPRequestLine(String requestLine) |
| | | throws ParseException { |
| | | requestLine += "\n"; |
| | | return new RequestLineParser(requestLine).parse(); |
| | | } |
| | | |
| | | /** |
| | | * Parse the SIP Response message status line |
| | | * |
| | | * @param statusLine |
| | | * a String containing the Status line to be parsed. |
| | | * @return StatusLine class corresponding to message |
| | | * @exception ParseException |
| | | * if there was an error parsing |
| | | * @see StatusLine |
| | | */ |
| | | |
| | | public StatusLine parseSIPStatusLine(String statusLine) |
| | | throws ParseException { |
| | | statusLine += "\n"; |
| | | return new StatusLineParser(statusLine).parse(); |
| | | } |
| | | |
| | | public static void setComputeContentLengthFromMessage( |
| | | boolean computeContentLengthFromMessage) { |
| | | GBStringMsgParser.computeContentLengthFromMessage = computeContentLengthFromMessage; |
| | | } |
| | | } |