/** * This is input reading thread for the pipelined parser. You feed it input through the input * stream (see the constructor) and it calls back an event listener interface for message * processing or error. It cleans up the input - dealing with things like line continuation */ public void run() { Pipeline inputStream = this.rawInputStream; // inputStream = new MyFilterInputStream(this.rawInputStream); // I cannot use buffered reader here because we may need to switch // encodings to read the message body. try { while (true) { this.sizeCounter = this.maxMessageSize; // this.messageSize = 0; StringBuffer inputBuffer = new StringBuffer(); if (Debug.parserDebug) Debug.println("Starting parse!"); String line1; String line2 = null; while (true) { try { line1 = readLine(inputStream); // ignore blank lines. if (line1.equals("\n")) { if (Debug.parserDebug) Debug.println("Discarding " + line1); continue; } else break; } catch (IOException ex) { Debug.printStackTrace(ex); this.rawInputStream.stopTimer(); return; } } inputBuffer.append(line1); // Guard against bad guys. this.rawInputStream.startTimer(); while (true) { try { line2 = readLine(inputStream); inputBuffer.append(line2); if (line2.trim().equals("")) break; } catch (IOException ex) { this.rawInputStream.stopTimer(); Debug.printStackTrace(ex); return; } } // Stop the timer that will kill the read. this.rawInputStream.stopTimer(); inputBuffer.append(line2); StringMsgParser smp = new StringMsgParser(sipMessageListener); smp.readBody = false; SIPMessage sipMessage = null; try { sipMessage = smp.parseSIPMessage(inputBuffer.toString()); if (sipMessage == null) { this.rawInputStream.stopTimer(); continue; } } catch (ParseException ex) { // Just ignore the parse exception. continue; } if (Debug.parserDebug) Debug.println("Completed parsing message"); ContentLength cl = (ContentLength) sipMessage.getContentLength(); int contentLength = 0; if (cl != null) { contentLength = cl.getContentLength(); } else { contentLength = 0; } if (Debug.parserDebug) { Debug.println("contentLength " + contentLength); Debug.println("sizeCounter " + this.sizeCounter); Debug.println("maxMessageSize " + this.maxMessageSize); } if (contentLength == 0) { sipMessage.removeContent(); } else if (maxMessageSize == 0 || contentLength < this.sizeCounter) { byte[] message_body = new byte[contentLength]; int nread = 0; while (nread < contentLength) { // Start my starvation timer. // This ensures that the other end // writes at least some data in // or we will close the pipe from // him. This prevents DOS attack // that takes up all our connections. this.rawInputStream.startTimer(); try { int readlength = inputStream.read(message_body, nread, contentLength - nread); if (readlength > 0) { nread += readlength; } else { break; } } catch (IOException ex) { ex.printStackTrace(); break; } finally { // Stop my starvation timer. this.rawInputStream.stopTimer(); } } sipMessage.setMessageContent(message_body); } // Content length too large - process the message and // return error from there. if (sipMessageListener != null) { try { sipMessageListener.processMessage(sipMessage); } catch (Exception ex) { // fatal error in processing - close the // connection. break; } } } } finally { try { inputStream.close(); } catch (IOException e) { InternalErrorHandler.handleException(e); } } }
/** * 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 exhandler) 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. return null; } // Iterate thru the request/status line and headers. char[] currentLine = null; char[] currentHeader = null; boolean isFirstLine = true; SIPMessage message = null; do { currentLine = null; 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; ByteBuffer bb = ByteBuffer.wrap(msgBuffer, lineStart, lineLength); currentLine = charset.decode(bb).array(); currentLine = trimEndOfLine(currentLine); if (currentLine.length == 0) { // Last header line, process the previous buffered header. if (currentHeader != null && message != null) { processHeader(currentHeader, message, exhandler, msgBuffer); } } else { if (isFirstLine) { message = processFirstLine(currentLine, exhandler, msgBuffer); } else { char firstChar = currentLine[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); char[] retval = new char[currentHeader.length + currentLine.length - 1]; System.arraycopy(currentHeader, 0, retval, 0, currentHeader.length); System.arraycopy( currentHeader, currentHeader.length, currentLine, 1, currentLine.length); } else { if (currentHeader != null && message != null) { processHeader(currentHeader, message, exhandler, msgBuffer); } currentHeader = new char[currentLine.length + 1]; System.arraycopy(currentLine, 0, currentHeader, 0, currentLine.length); currentHeader[currentLine.length] = '\n'; } } } if (msgBuffer[i] == '\r' && msgBuffer.length > i + 1 && msgBuffer[i + 1] == '\n') i++; i++; isFirstLine = false; } while (currentLine.length > 0); // End do - while currentLine = null; currentHeader = null; 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 (!computeContentLengthFromMessage && message.getContentLength().getContentLength() == 0 & 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; }